Improve AliasAnalysis::may_alias
[hiphop-php.git] / hphp / runtime / vm / jit / ir-builder.h
blobc1370807b58e33768cdd1dcc59da0a7e6a62a9ab
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
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_
20 #include <functional>
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 {
42 FPInvOffset spOffset;
43 FPInvOffset syncedSpLevel;
44 uint32_t stackDeficit;
45 EvalStack evalStack;
46 SSATmp* sp;
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:
57 * - preOptimize pass
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.
75 struct IRBuilder {
76 IRBuilder(IRUnit&, BCMarker);
79 * Updates the marker used for instructions generated without one
80 * supplied.
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
97 * started.
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
104 * boundary.
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; }
168 public:
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
183 * block.
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
199 * bytecode offset.
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
232 * request.
234 Block* guardFailBlock() const;
236 public:
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);
250 void popBlock();
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,
258 CloneFlag doClone,
259 Block* srcBlock);
262 private:
263 struct BlockState {
264 Block* block;
265 BCMarker marker;
266 ExnStackState exnStack;
267 std::function<Block* ()> catchCreator;
270 private:
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);
280 m_curMarker,
281 std::forward<Args>(args)...
285 private:
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,
292 Type oldType,
293 SSATmp* oldVal,
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*);
308 private:
309 void appendInstruction(IRInstruction* inst);
310 bool constrainSlot(int32_t idOrOffset,
311 TypeSource typeSrc,
312 TypeConstraint tc,
313 const std::string& why);
315 private:
316 IRUnit& m_unit;
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;
327 Block* m_curBlock;
328 ExnStackState m_exnStack{
329 FPInvOffset{0},
330 FPInvOffset{0},
332 EvalStack{},
333 nullptr
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
357 * for usage.
359 struct BlockPusher {
360 BlockPusher(IRBuilder& irb, BCMarker marker, Block* block)
361 : m_irb(irb)
363 irb.pushBlock(marker, block);
366 ~BlockPusher() {
367 m_irb.popBlock();
370 private:
371 IRBuilder& m_irb;
374 //////////////////////////////////////////////////////////////////////
378 #endif