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>
23 #include <folly/Optional.h>
25 #include "hphp/runtime/vm/jit/block.h"
26 #include "hphp/runtime/vm/jit/cfg.h"
27 #include "hphp/runtime/vm/jit/containers.h"
28 #include "hphp/runtime/vm/jit/cse.h"
29 #include "hphp/runtime/vm/jit/frame-state.h"
30 #include "hphp/runtime/vm/jit/guard-constraints.h"
31 #include "hphp/runtime/vm/jit/ir-opcode.h"
32 #include "hphp/runtime/vm/jit/ir-unit.h"
33 #include "hphp/runtime/vm/jit/region-selection.h"
34 #include "hphp/runtime/vm/jit/simplify.h"
35 #include "hphp/runtime/vm/jit/state-vector.h"
36 #include "hphp/runtime/vm/jit/type-constraint.h"
37 #include "hphp/runtime/vm/jit/type.h"
39 namespace HPHP
{ namespace jit
{
41 //////////////////////////////////////////////////////////////////////
43 struct ExnStackState
{
45 FPAbsOffset syncedSpLevel
;
46 uint32_t stackDeficit
;
52 * This module provides the basic utilities for generating the IR instructions
53 * in a trace and emitting control flow. It also performs some optimizations
54 * while generating IR, and may be reinvoked for a second optimization pass.
56 * This module is also responsible for organizing a few types of
57 * gen-time optimizations:
61 * Before an instruction is linked into the trace, IRBuilder
62 * internally runs preOptimize() on it, which can do some
63 * tracelet-state related modifications to the instruction. For
64 * example, it can eliminate redundant guards.
68 * After preOptimize, instructions that support it are hashed and
69 * looked up in the CSEHash for this trace. If we find an
70 * available expression for the same value, instead of linking a
71 * new instruction into the trace we will just add a use to the
74 * - simplification pass
76 * After the preOptimize pass, IRBuilder calls out to
77 * Simplifier to perform state-independent optimizations, like
78 * copy propagation and strength reduction. (See simplify.h.)
81 * After all the instructions are linked into the trace, this module can also
82 * be used to perform a second round of the above two optimizations via the
83 * reoptimize() entry point.
86 IRBuilder(IRUnit
&, BCMarker
);
89 * Updates the marker used for instructions generated without one
92 void setCurMarker(BCMarker
);
95 * Called before we start lowering each bytecode instruction. Right now all
96 * this does is cause an implicit exceptionStackBoundary. See below.
98 void prepareForNextHHBC();
101 * Exception handling and IRBuilder.
103 * Normally HHBC opcodes that throw don't have any effects before they throw.
104 * By default, when you gen() instructions that could throw, IRBuilder
105 * automatically creates catch blocks that take the current frame-state
106 * information, except spill the stack as if the instruction has not yet
109 * There are some exceptions, and so there are two ways to modify this
110 * behavior. If an HHBC opcode should have some effects on the stack prior
111 * to throwing, the lowering function can call exceptionStackBoundary after
112 * doing this to inform IRBuilder that it's not a bug---in this case the
113 * automatically created catch blocks will spill the stack as of the last
116 * The other way is to set a custom catch creator function. This is
117 * basically for the minstr instructions, which has various temporary stack
118 * state to clean up during unwinding.
120 void exceptionStackBoundary();
121 const ExnStackState
& exceptionStackState() const { return m_exnStack
; }
124 * The following functions are an abstraction layer we probably don't need.
125 * You can keep using them until we find time to remove them.
127 IRUnit
& unit() const { return m_unit
; }
128 BCMarker
curMarker() const { return m_curMarker
; }
129 const Func
* curFunc() const { return m_state
.func(); }
130 FPAbsOffset
spOffset() { return m_state
.spOffset(); }
131 SSATmp
* sp() const { return m_state
.sp(); }
132 SSATmp
* fp() const { return m_state
.fp(); }
133 uint32_t stackDeficit() const { return m_state
.stackDeficit(); }
134 void incStackDeficit() { m_state
.incStackDeficit(); }
135 void clearStackDeficit() { m_state
.clearStackDeficit(); }
136 void setStackDeficit(uint32_t d
) { m_state
.setStackDeficit(d
); }
137 void syncEvalStack() { m_state
.syncEvalStack(); }
138 EvalStack
& evalStack() { return m_state
.evalStack(); }
139 FPAbsOffset
syncedSpLevel() const { return m_state
.syncedSpLevel(); }
140 bool thisAvailable() const { return m_state
.thisAvailable(); }
141 void setThisAvailable() { m_state
.setThisAvailable(); }
142 Type
localType(uint32_t id
, TypeConstraint tc
);
143 Type
stackType(IRSPOffset
, TypeConstraint tc
);
144 Type
predictedInnerType(uint32_t id
);
145 Type
predictedLocalType(uint32_t id
);
146 SSATmp
* localValue(uint32_t id
, TypeConstraint tc
);
147 SSATmp
* stackValue(IRSPOffset offset
, TypeConstraint tc
);
148 TypeSourceSet
localTypeSources(uint32_t id
) const {
149 return m_state
.localTypeSources(id
);
151 TypeSourceSet
stackTypeSources(IRSPOffset offset
) const {
152 return m_state
.stackTypeSources(offset
);
154 bool frameMaySpanCall() const { return m_state
.frameMaySpanCall(); }
155 Type
stackInnerTypePrediction(IRSPOffset
) const;
156 const PostConditions
& postConds(Block
* b
) const {
157 return m_state
.postConds(b
);
161 * Support for guard relaxation.
163 * Whenever the semantics of an hhir operation depends on the type of one of
164 * its input values, that value's type must be constrained using one of these
165 * methods. This happens automatically for most values, when obtained through
166 * irgen-internal functions like popC (and friends).
168 void setConstrainGuards(bool constrain
) { m_constrainGuards
= constrain
; }
169 bool shouldConstrainGuards() const { return m_constrainGuards
; }
170 bool constrainGuard(const IRInstruction
* inst
, TypeConstraint tc
);
171 bool constrainValue(SSATmp
* const val
, TypeConstraint tc
);
172 bool constrainLocal(uint32_t id
, TypeConstraint tc
, const std::string
& why
);
173 bool constrainStack(IRSPOffset offset
, TypeConstraint tc
);
174 bool typeMightRelax(SSATmp
* val
= nullptr) const;
175 const GuardConstraints
* guards() const { return &m_constraints
; }
179 * API for managing state when building IR with bytecode-level control flow.
183 * Start the given block. Returns whether or not it succeeded. A failure
184 * may occur in case the block turned out to be unreachable.
186 bool startBlock(Block
* block
, const BCMarker
& marker
, bool isLoopHeader
);
189 * Create a new block corresponding to bytecode control flow.
191 Block
* makeBlock(Offset offset
);
194 * Clear the map from bytecode offsets to Blocks.
196 void resetOffsetMapping();
199 * Checks whether or not there's a block associated with the given
202 bool hasBlock(Offset offset
) const;
205 * Set the block associated with the given offset in the offset->block map.
207 void setBlock(Offset offset
, Block
* block
);
210 * Get the block that we're currently emitting code to.
212 Block
* curBlock() { return m_curBlock
; }
215 * Append a new block to the unit.
217 void appendBlock(Block
* block
);
220 * Set the block to branch to in case a guard fails.
222 void setGuardFailBlock(Block
* block
);
225 * Resets the guard failure block to nullptr.
227 void resetGuardFailBlock();
230 * Returns the block to branch to in case of a guard failure. This
231 * returns nullptr if no such block has been set, and therefore
232 * guard failures should end the region and perform a service
235 Block
* guardFailBlock() const;
239 * To emit code to a block other than the current block, call pushBlock(),
240 * emit instructions as usual with gen(...), then call popBlock(). This is
241 * best done using the BlockPusher struct:
243 * gen(CodeForMainBlock, ...);
245 * BlockPusher<PauseExit> bp(m_irb, marker, exitBlock);
246 * gen(CodeForExitBlock, ...);
248 * gen(CodeForMainBlock, ...);
250 void pushBlock(BCMarker marker
, Block
* b
);
254 * Run another pass of IRBuilder-managed optimizations on this
260 * Conditionally-append a new instruction to the current Block, depending on
261 * what some optimizations have to say about it.
263 enum class CloneFlag
{ Yes
, No
};
264 SSATmp
* optimizeInst(IRInstruction
* inst
,
267 const folly::Optional
<IdomVector
>&);
274 ExnStackState exnStack
;
275 std::function
<Block
* ()> catchCreator
;
279 // Helper for cond() and such. We should move them out of IRBuilder so they
280 // can just use irgen::gen.
281 template<class... Args
>
282 SSATmp
* gen(Opcode op
, Args
&&... args
) {
283 return makeInstruction(
284 [this] (IRInstruction
* inst
) {
285 return optimizeInst(inst
, CloneFlag::Yes
, nullptr, folly::none
);
289 std::forward
<Args
>(args
)...
294 SSATmp
* preOptimizeCheckTypeOp(IRInstruction
*, Type
);
295 SSATmp
* preOptimizeCheckType(IRInstruction
*);
296 SSATmp
* preOptimizeCheckStk(IRInstruction
*);
297 SSATmp
* preOptimizeCheckLoc(IRInstruction
*);
298 SSATmp
* preOptimizeHintLocInner(IRInstruction
*);
299 SSATmp
* preOptimizeAssertTypeOp(IRInstruction
* inst
,
302 const IRInstruction
* typeSrc
);
303 SSATmp
* preOptimizeAssertType(IRInstruction
*);
304 SSATmp
* preOptimizeAssertStk(IRInstruction
*);
305 SSATmp
* preOptimizeAssertLoc(IRInstruction
*);
306 SSATmp
* preOptimizeCheckCtxThis(IRInstruction
*);
307 SSATmp
* preOptimizeLdCtx(IRInstruction
*);
308 SSATmp
* preOptimizeDecRefThis(IRInstruction
*);
309 SSATmp
* preOptimizeLdLocPseudoMain(IRInstruction
*);
310 SSATmp
* preOptimizeLdLoc(IRInstruction
*);
311 SSATmp
* preOptimizeStLoc(IRInstruction
*);
312 SSATmp
* preOptimizeCastStk(IRInstruction
*);
313 SSATmp
* preOptimizeCoerceStk(IRInstruction
*);
314 SSATmp
* preOptimizeLdStk(IRInstruction
*);
315 SSATmp
* preOptimize(IRInstruction
*);
318 void appendInstruction(IRInstruction
* inst
);
319 SSATmp
* cseLookup(const IRInstruction
&,
321 const folly::Optional
<IdomVector
>&) const;
323 const CSEHash
& cseHashTable(const IRInstruction
& inst
) const;
324 CSEHash
& cseHashTable(const IRInstruction
& inst
);
325 void cseUpdate(const IRInstruction
& inst
);
326 bool constrainSlot(int32_t idOrOffset
,
329 const std::string
& why
);
333 BCMarker m_initialMarker
;
334 BCMarker m_curMarker
;
335 FrameStateMgr m_state
;
337 bool m_enableCse
{false};
340 * m_savedBlocks will be nonempty iff we're emitting code to a block other
341 * than the main block. m_curMarker, and m_curBlock are all set from the
342 * most recent call to pushBlock() or popBlock().
344 jit::vector
<BlockState
> m_savedBlocks
;
346 ExnStackState m_exnStack
{
354 bool m_enableSimplification
{false};
355 bool m_constrainGuards
;
357 GuardConstraints m_constraints
;
359 // Keep track of blocks created to support bytecode control flow.
361 // TODO(t3730559): Offset is used here since it's passed from
362 // emitJmp*, but SrcKey might be better in case of inlining.
363 jit::flat_map
<Offset
,Block
*> m_offsetToBlockMap
;
365 // Keeps the block to branch to (if any) in case a guard fails.
366 // This holds nullptr if the guard failures should perform a service
367 // request (REQ_RETRANSLATE or REQ_BIND_JMP).
368 Block
* m_guardFailBlock
{nullptr};
371 //////////////////////////////////////////////////////////////////////
374 * RAII helper for emitting code to exit traces. See IRBuilder::pushBlock
378 BlockPusher(IRBuilder
& irb
, BCMarker marker
, Block
* block
)
381 irb
.pushBlock(marker
, block
);
392 //////////////////////////////////////////////////////////////////////