2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2014 Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #ifndef incl_HPHP_VM_IRBUILDER_H_
18 #define incl_HPHP_VM_IRBUILDER_H_
22 #include <folly/ScopeGuard.h>
24 #include "hphp/runtime/vm/jit/block.h"
25 #include "hphp/runtime/vm/jit/cfg.h"
26 #include "hphp/runtime/vm/jit/containers.h"
27 #include "hphp/runtime/vm/jit/frame-state.h"
28 #include "hphp/runtime/vm/jit/guard-constraints.h"
29 #include "hphp/runtime/vm/jit/ir-opcode.h"
30 #include "hphp/runtime/vm/jit/ir-unit.h"
31 #include "hphp/runtime/vm/jit/region-selection.h"
32 #include "hphp/runtime/vm/jit/simplify.h"
33 #include "hphp/runtime/vm/jit/state-vector.h"
34 #include "hphp/runtime/vm/jit/type-constraint.h"
35 #include "hphp/runtime/vm/jit/type.h"
37 namespace HPHP
{ namespace jit
{
39 //////////////////////////////////////////////////////////////////////
41 struct ExnStackState
{
43 FPInvOffset syncedSpLevel
;
44 uint32_t stackDeficit
;
50 * This module provides the basic utilities for generating the IR instructions
51 * in a trace and emitting control flow. It also performs some optimizations
52 * while generating IR, and may be reinvoked for a second optimization pass.
54 * This module is also responsible for organizing a few types of
55 * gen-time optimizations:
59 * Before an instruction is linked into the trace, IRBuilder
60 * internally runs preOptimize() on it, which can do some
61 * tracelet-state related modifications to the instruction. For
62 * example, it can eliminate redundant guards.
64 * - simplification pass
66 * After the preOptimize pass, IRBuilder calls out to
67 * Simplifier to perform state-independent optimizations, like
68 * copy propagation and strength reduction. (See simplify.h.)
71 * After all the instructions are linked into the trace, this module can also
72 * be used to perform a second round of the above two optimizations via the
73 * reoptimize() entry point.
76 IRBuilder(IRUnit
&, BCMarker
);
79 * Updates the marker used for instructions generated without one
82 void setCurMarker(BCMarker
);
85 * Called before we start lowering each bytecode instruction. Right now all
86 * this does is cause an implicit exceptionStackBoundary. See below.
88 void prepareForNextHHBC();
91 * Exception handling and IRBuilder.
93 * Normally HHBC opcodes that throw don't have any effects before they throw.
94 * By default, when you gen() instructions that could throw, IRBuilder
95 * automatically creates catch blocks that take the current frame-state
96 * information, except spill the stack as if the instruction has not yet
99 * There are some exceptions, and so there are two ways to modify this
100 * behavior. If an HHBC opcode should have some effects on the stack prior
101 * to throwing, the lowering function can call exceptionStackBoundary after
102 * doing this to inform IRBuilder that it's not a bug---in this case the
103 * automatically created catch blocks will spill the stack as of the last
106 * The other way is to set a custom catch creator function. This is
107 * basically for the minstr instructions, which has various temporary stack
108 * state to clean up during unwinding.
110 void exceptionStackBoundary();
111 const ExnStackState
& exceptionStackState() const { return m_exnStack
; }
114 * The following functions are an abstraction layer we probably don't need.
115 * You can keep using them until we find time to remove them.
117 IRUnit
& unit() const { return m_unit
; }
118 BCMarker
curMarker() const { return m_curMarker
; }
119 const Func
* curFunc() const { return m_state
.func(); }
120 FPInvOffset
spOffset() { return m_state
.spOffset(); }
121 SSATmp
* sp() const { return m_state
.sp(); }
122 SSATmp
* fp() const { return m_state
.fp(); }
123 uint32_t stackDeficit() const { return m_state
.stackDeficit(); }
124 void incStackDeficit() { m_state
.incStackDeficit(); }
125 void clearStackDeficit() { m_state
.clearStackDeficit(); }
126 void setStackDeficit(uint32_t d
) { m_state
.setStackDeficit(d
); }
127 void syncEvalStack() { m_state
.syncEvalStack(); }
128 EvalStack
& evalStack() { return m_state
.evalStack(); }
129 FPInvOffset
syncedSpLevel() const { return m_state
.syncedSpLevel(); }
130 bool thisAvailable() const { return m_state
.thisAvailable(); }
131 void setThisAvailable() { m_state
.setThisAvailable(); }
132 Type
localType(uint32_t id
, TypeConstraint tc
);
133 Type
stackType(IRSPOffset
, TypeConstraint tc
);
134 Type
predictedInnerType(uint32_t id
);
135 Type
predictedLocalType(uint32_t id
);
136 Type
predictedStackType(IRSPOffset
);
137 SSATmp
* localValue(uint32_t id
, TypeConstraint tc
);
138 SSATmp
* stackValue(IRSPOffset offset
, TypeConstraint tc
);
139 TypeSourceSet
localTypeSources(uint32_t id
) const {
140 return m_state
.localTypeSources(id
);
142 TypeSourceSet
stackTypeSources(IRSPOffset offset
) const {
143 return m_state
.stackTypeSources(offset
);
145 bool frameMaySpanCall() const { return m_state
.frameMaySpanCall(); }
146 Type
stackInnerTypePrediction(IRSPOffset
) const;
147 const PostConditions
& postConds(Block
* b
) const {
148 return m_state
.postConds(b
);
152 * Support for guard relaxation.
154 * Whenever the semantics of an hhir operation depends on the type of one of
155 * its input values, that value's type must be constrained using one of these
156 * methods. This happens automatically for most values, when obtained through
157 * irgen-internal functions like popC (and friends).
159 void setConstrainGuards(bool constrain
) { m_constrainGuards
= constrain
; }
160 bool shouldConstrainGuards() const { return m_constrainGuards
; }
161 bool constrainGuard(const IRInstruction
* inst
, TypeConstraint tc
);
162 bool constrainValue(SSATmp
* const val
, TypeConstraint tc
);
163 bool constrainLocal(uint32_t id
, TypeConstraint tc
, const std::string
& why
);
164 bool constrainStack(IRSPOffset offset
, TypeConstraint tc
);
165 bool typeMightRelax(SSATmp
* val
= nullptr) const;
166 const GuardConstraints
* guards() const { return &m_constraints
; }
170 * API for managing state when building IR with bytecode-level control flow.
174 * Start the given block. Returns whether or not it succeeded. A failure
175 * may occur in case the block turned out to be unreachable.
177 bool startBlock(Block
* block
, bool hasUnprocPred
);
180 * Returns whether or not `block' will succeed if passed to
181 * startBlock, which implies that we have state saved for `block',
182 * and therefore it's currently reachable from the unit's entry
185 bool canStartBlock(Block
* block
) const;
188 * Create a new block corresponding to bytecode control flow.
190 Block
* makeBlock(Offset offset
);
193 * Clear the map from bytecode offsets to Blocks.
195 void resetOffsetMapping();
198 * Checks whether or not there's a block associated with the given
201 bool hasBlock(Offset offset
) const;
204 * Set the block associated with the given offset in the offset->block map.
206 void setBlock(Offset offset
, Block
* block
);
209 * Get the block that we're currently emitting code to.
211 Block
* curBlock() { return m_curBlock
; }
214 * Append a new block to the unit.
216 void appendBlock(Block
* block
);
219 * Set the block to branch to in case a guard fails.
221 void setGuardFailBlock(Block
* block
);
224 * Resets the guard failure block to nullptr.
226 void resetGuardFailBlock();
229 * Returns the block to branch to in case of a guard failure. This
230 * returns nullptr if no such block has been set, and therefore
231 * guard failures should end the region and perform a service
234 Block
* guardFailBlock() const;
238 * To emit code to a block other than the current block, call pushBlock(),
239 * emit instructions as usual with gen(...), then call popBlock(). This is
240 * best done using the BlockPusher struct:
242 * gen(CodeForMainBlock, ...);
244 * BlockPusher<PauseExit> bp(m_irb, marker, exitBlock);
245 * gen(CodeForExitBlock, ...);
247 * gen(CodeForMainBlock, ...);
249 void pushBlock(BCMarker marker
, Block
* b
);
253 * Conditionally-append a new instruction to the current Block, depending on
254 * what some optimizations have to say about it.
256 enum class CloneFlag
{ Yes
, No
};
257 SSATmp
* optimizeInst(IRInstruction
* inst
,
266 ExnStackState exnStack
;
267 std::function
<Block
* ()> catchCreator
;
271 // Helper for cond() and such. We should move them out of IRBuilder so they
272 // can just use irgen::gen.
273 template<class... Args
>
274 SSATmp
* gen(Opcode op
, Args
&&... args
) {
275 return makeInstruction(
276 [this] (IRInstruction
* inst
) {
277 return optimizeInst(inst
, CloneFlag::Yes
, nullptr);
281 std::forward
<Args
>(args
)...
286 SSATmp
* preOptimizeCheckTypeOp(IRInstruction
*, Type
);
287 SSATmp
* preOptimizeCheckType(IRInstruction
*);
288 SSATmp
* preOptimizeCheckStk(IRInstruction
*);
289 SSATmp
* preOptimizeCheckLoc(IRInstruction
*);
290 SSATmp
* preOptimizeHintLocInner(IRInstruction
*);
291 SSATmp
* preOptimizeAssertTypeOp(IRInstruction
* inst
,
294 const IRInstruction
* typeSrc
);
295 SSATmp
* preOptimizeAssertType(IRInstruction
*);
296 SSATmp
* preOptimizeAssertStk(IRInstruction
*);
297 SSATmp
* preOptimizeAssertLoc(IRInstruction
*);
298 SSATmp
* preOptimizeCheckCtxThis(IRInstruction
*);
299 SSATmp
* preOptimizeLdCtx(IRInstruction
*);
300 SSATmp
* preOptimizeLdLocPseudoMain(IRInstruction
*);
301 SSATmp
* preOptimizeLdLoc(IRInstruction
*);
302 SSATmp
* preOptimizeStLoc(IRInstruction
*);
303 SSATmp
* preOptimizeCastStk(IRInstruction
*);
304 SSATmp
* preOptimizeCoerceStk(IRInstruction
*);
305 SSATmp
* preOptimizeLdStk(IRInstruction
*);
306 SSATmp
* preOptimize(IRInstruction
*);
309 void appendInstruction(IRInstruction
* inst
);
310 bool constrainSlot(int32_t idOrOffset
,
313 const std::string
& why
);
317 BCMarker m_initialMarker
;
318 BCMarker m_curMarker
;
319 FrameStateMgr m_state
;
322 * m_savedBlocks will be nonempty iff we're emitting code to a block other
323 * than the main block. m_curMarker, and m_curBlock are all set from the
324 * most recent call to pushBlock() or popBlock().
326 jit::vector
<BlockState
> m_savedBlocks
;
328 ExnStackState m_exnStack
{
336 bool m_enableSimplification
{false};
337 bool m_constrainGuards
;
339 GuardConstraints m_constraints
;
341 // Keep track of blocks created to support bytecode control flow.
343 // TODO(t3730559): Offset is used here since it's passed from
344 // emitJmp*, but SrcKey might be better in case of inlining.
345 jit::flat_map
<Offset
,Block
*> m_offsetToBlockMap
;
347 // Keeps the block to branch to (if any) in case a guard fails.
348 // This holds nullptr if the guard failures should perform a service
349 // request (REQ_RETRANSLATE or REQ_BIND_JMP).
350 Block
* m_guardFailBlock
{nullptr};
353 //////////////////////////////////////////////////////////////////////
356 * RAII helper for emitting code to exit traces. See IRBuilder::pushBlock
360 BlockPusher(IRBuilder
& irb
, BCMarker marker
, Block
* block
)
363 irb
.pushBlock(marker
, block
);
374 //////////////////////////////////////////////////////////////////////