PageRenderTime 23ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/hphp/runtime/vm/jit/ir-builder.h

https://gitlab.com/iranjith4/hhvm
C Header | 375 lines | 138 code | 53 blank | 184 comment | 0 complexity | 016a271e5ed6ed25ca673382635c3e21 MD5 | raw file
  1. /*
  2. +----------------------------------------------------------------------+
  3. | HipHop for PHP |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2010-2016 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. +----------------------------------------------------------------------+
  15. */
  16. #ifndef incl_HPHP_VM_IRBUILDER_H_
  17. #define incl_HPHP_VM_IRBUILDER_H_
  18. #include "hphp/runtime/vm/jit/block.h"
  19. #include "hphp/runtime/vm/jit/cfg.h"
  20. #include "hphp/runtime/vm/jit/containers.h"
  21. #include "hphp/runtime/vm/jit/frame-state.h"
  22. #include "hphp/runtime/vm/jit/guard-constraints.h"
  23. #include "hphp/runtime/vm/jit/ir-opcode.h"
  24. #include "hphp/runtime/vm/jit/ir-unit.h"
  25. #include "hphp/runtime/vm/jit/region-selection.h"
  26. #include "hphp/runtime/vm/jit/simplify.h"
  27. #include "hphp/runtime/vm/jit/state-vector.h"
  28. #include "hphp/runtime/vm/jit/type-constraint.h"
  29. #include "hphp/runtime/vm/jit/type.h"
  30. #include <folly/Optional.h>
  31. #include <folly/ScopeGuard.h>
  32. #include <functional>
  33. namespace HPHP { namespace jit { namespace irgen {
  34. ///////////////////////////////////////////////////////////////////////////////
  35. struct ExnStackState {
  36. FPInvOffset syncedSpLevel{0};
  37. };
  38. /*
  39. * This module provides the basic utilities for generating the IR instructions
  40. * in a trace and emitting control flow. It also performs some optimizations
  41. * while generating IR, and may be reinvoked for a second optimization pass.
  42. *
  43. * This module is also responsible for organizing a few types of
  44. * gen-time optimizations:
  45. *
  46. * - preOptimize pass
  47. *
  48. * Before an instruction is linked into the trace, IRBuilder
  49. * internally runs preOptimize() on it, which can do some
  50. * tracelet-state related modifications to the instruction. For
  51. * example, it can eliminate redundant guards.
  52. *
  53. * - simplification pass
  54. *
  55. * After the preOptimize pass, IRBuilder calls out to
  56. * Simplifier to perform state-independent optimizations, like
  57. * copy propagation and strength reduction. (See simplify.h.)
  58. */
  59. struct IRBuilder {
  60. IRBuilder(IRUnit&, BCMarker);
  61. /*
  62. * Accessors.
  63. */
  64. IRUnit& unit() const { return m_unit; }
  65. FrameStateMgr& fs() { return m_state; }
  66. BCMarker curMarker() const { return m_curMarker; }
  67. /*
  68. * Update the marker for instructions that were generated without one.
  69. */
  70. void setCurMarker(BCMarker);
  71. /*
  72. * Exception handling and IRBuilder.
  73. *
  74. * Normally HHBC opcodes that throw don't have any effects before they throw.
  75. * By default, when you gen() instructions that could throw, IRBuilder
  76. * automatically creates catch blocks that take the current frame-state
  77. * information, except spill the stack as if the instruction has not yet
  78. * started.
  79. *
  80. * There are some exceptions, and so there are two ways to modify this
  81. * behavior. If an HHBC opcode should have some effects on the stack prior
  82. * to throwing, the lowering function can call exceptionStackBoundary after
  83. * doing this to inform IRBuilder that it's not a bug---in this case the
  84. * automatically created catch blocks will spill the stack as of the last
  85. * boundary.
  86. *
  87. * The other way is to set a custom catch creator function. This is
  88. * basically for the minstr instructions, which has various temporary stack
  89. * state to clean up during unwinding.
  90. */
  91. void exceptionStackBoundary();
  92. const ExnStackState& exceptionStackState() const { return m_exnStack; }
  93. /*
  94. * Tracked state for bytecode locations.
  95. *
  96. * These simply constrain the location, then delegate to fs().
  97. */
  98. const LocalState& local(uint32_t id, TypeConstraint tc);
  99. const StackState& stack(IRSPRelOffset offset, TypeConstraint tc);
  100. SSATmp* valueOf(Location l, TypeConstraint tc);
  101. Type typeOf(Location l, TypeConstraint tc);
  102. /*
  103. * Helper for unboxing predicted types.
  104. *
  105. * @returns: ldRefReturn(fs().local(id).predictedType.unbox())
  106. * ldRefReturn(fs().stack(id).predictedType.unbox())
  107. */
  108. Type predictedLocalInnerType(uint32_t id) const;
  109. Type predictedStackInnerType(IRSPRelOffset) const;
  110. /////////////////////////////////////////////////////////////////////////////
  111. /*
  112. * Guard relaxation.
  113. *
  114. * Whenever the semantics of an HHIR instruction depends on the type of one
  115. * of its input values, that value's type must be constrained using one of
  116. * these functions. This happens automatically for most values, when obtained
  117. * through irgen-internal functions like popC (and friends).
  118. */
  119. /*
  120. * All the guards in the managed IRUnit.
  121. */
  122. const GuardConstraints* guards() const { return &m_constraints; }
  123. /*
  124. * Return true iff `tc' is more specific than the existing constraint for the
  125. * guard `inst'.
  126. *
  127. * This does not necessarily constrain the guard, if `tc.weak' is true.
  128. */
  129. bool constrainGuard(const IRInstruction* inst, TypeConstraint tc);
  130. /*
  131. * Trace back to the guard that provided the type of `val', if any, then
  132. * constrain it so that its type will not be relaxed beyond `tc'.
  133. *
  134. * Like constrainGuard(), this returns true iff `tc' is more specific than
  135. * the existing constraint, and does not constrain the guard if `tc.weak' is
  136. * true.
  137. */
  138. bool constrainValue(SSATmp* const val, TypeConstraint tc);
  139. /*
  140. * Constrain the type sources of the given bytecode location.
  141. */
  142. bool constrainLocal(uint32_t id, TypeConstraint tc, const std::string& why);
  143. bool constrainStack(IRSPRelOffset offset, TypeConstraint tc);
  144. /*
  145. * Whether `val' might have its type relaxed by guard relaxation.
  146. *
  147. * If `val' is nullptr, only conditions that apply to all values are checked.
  148. */
  149. bool typeMightRelax(SSATmp* val = nullptr) const;
  150. /////////////////////////////////////////////////////////////////////////////
  151. // Bytecode-level control flow helpers.
  152. /*
  153. * The block that we're currently emitting code to.
  154. */
  155. Block* curBlock() { return m_curBlock; }
  156. /*
  157. * Return whether we have state saved for `block'---which indicates that it's
  158. * currently reachable from the unit's entry block.
  159. */
  160. bool canStartBlock(Block* block) const;
  161. /*
  162. * Start `block', returning success.
  163. *
  164. * We fail if `canStartBlock(block)' is false.
  165. */
  166. bool startBlock(Block* block, bool hasUnprocessedPred);
  167. /*
  168. * Create a new block corresponding to bytecode control flow.
  169. */
  170. Block* makeBlock(SrcKey sk, uint64_t profCount);
  171. /*
  172. * Check or set the block corresponding to `sk'.
  173. */
  174. bool hasBlock(SrcKey sk) const;
  175. void setBlock(SrcKey sk, Block* block);
  176. /*
  177. * Clear the SrcKey-to-block map.
  178. */
  179. void resetOffsetMapping();
  180. /*
  181. * Append `block' to the unit.
  182. */
  183. void appendBlock(Block* block);
  184. /*
  185. * Get, set, or null out the block to branch to in case of a guard failure.
  186. *
  187. * A nullptr guard fail block indicates that guard failures should end the
  188. * region and perform a service request.
  189. */
  190. Block* guardFailBlock() const;
  191. void setGuardFailBlock(Block* block);
  192. void resetGuardFailBlock();
  193. /*
  194. * To emit code to a block other than the current block, call pushBlock(),
  195. * emit instructions as usual with gen(...), then call popBlock(). This is
  196. * best done using the BlockPusher struct:
  197. *
  198. * gen(CodeForMainBlock, ...);
  199. * {
  200. * BlockPusher<PauseExit> bp(m_irb, marker, exitBlock);
  201. * gen(CodeForExitBlock, ...);
  202. * }
  203. * gen(CodeForMainBlock, ...);
  204. */
  205. void pushBlock(BCMarker marker, Block* b);
  206. void popBlock();
  207. /*
  208. * Conditionally append a new instruction to the current Block, depending on
  209. * what some optimizations have to say about it.
  210. */
  211. enum class CloneFlag { Yes, No };
  212. SSATmp* optimizeInst(IRInstruction* inst,
  213. CloneFlag doClone,
  214. Block* srcBlock);
  215. /////////////////////////////////////////////////////////////////////////////
  216. // Internal API.
  217. private:
  218. template<class... Args>
  219. SSATmp* gen(Opcode op, Args&&... args) {
  220. return makeInstruction(
  221. [this] (IRInstruction* inst) {
  222. return optimizeInst(inst, CloneFlag::Yes, nullptr);
  223. },
  224. op,
  225. m_curMarker,
  226. std::forward<Args>(args)...
  227. );
  228. }
  229. /*
  230. * Location wrapper helpers.
  231. */
  232. Location loc(uint32_t) const;
  233. Location stk(IRSPRelOffset) const;
  234. /*
  235. * preOptimize() and helpers.
  236. */
  237. SSATmp* preOptimizeCheckLocation(IRInstruction*, Location);
  238. SSATmp* preOptimizeCheckLoc(IRInstruction*);
  239. SSATmp* preOptimizeCheckStk(IRInstruction*);
  240. SSATmp* preOptimizeHintLocInner(IRInstruction*);
  241. SSATmp* preOptimizeAssertTypeOp(IRInstruction* inst,
  242. Type oldType,
  243. SSATmp* oldVal,
  244. const IRInstruction* typeSrc);
  245. SSATmp* preOptimizeAssertType(IRInstruction*);
  246. SSATmp* preOptimizeAssertLocation(IRInstruction*, Location);
  247. SSATmp* preOptimizeAssertLoc(IRInstruction*);
  248. SSATmp* preOptimizeAssertStk(IRInstruction*);
  249. SSATmp* preOptimizeCheckCtxThis(IRInstruction*);
  250. SSATmp* preOptimizeLdCtx(IRInstruction*);
  251. SSATmp* preOptimizeLdLocation(IRInstruction*, Location);
  252. SSATmp* preOptimizeLdLoc(IRInstruction*);
  253. SSATmp* preOptimizeLdStk(IRInstruction*);
  254. SSATmp* preOptimizeCastStk(IRInstruction*);
  255. SSATmp* preOptimizeCoerceStk(IRInstruction*);
  256. SSATmp* preOptimizeLdMBase(IRInstruction*);
  257. SSATmp* preOptimize(IRInstruction*);
  258. void appendInstruction(IRInstruction* inst);
  259. /*
  260. * Type constraint helpers.
  261. */
  262. bool constrainLocation(Location l, TypeConstraint tc,
  263. const std::string& why);
  264. bool constrainCheck(const IRInstruction* inst,
  265. TypeConstraint tc, Type srcType);
  266. bool constrainAssert(const IRInstruction* inst,
  267. TypeConstraint tc, Type srcType,
  268. folly::Optional<Type> knownType = folly::none);
  269. bool constrainTypeSrc(TypeSource typeSrc, TypeConstraint tc);
  270. bool shouldConstrainGuards() const;
  271. /////////////////////////////////////////////////////////////////////////////
  272. private:
  273. struct BlockState {
  274. Block* block;
  275. BCMarker marker;
  276. ExnStackState exnStack;
  277. std::function<Block* ()> catchCreator;
  278. };
  279. private:
  280. IRUnit& m_unit;
  281. BCMarker m_initialMarker;
  282. BCMarker m_curMarker;
  283. FrameStateMgr m_state;
  284. /*
  285. * m_savedBlocks will be nonempty iff we're emitting code to a block other
  286. * than the main block. m_curMarker, and m_curBlock are all set from the
  287. * most recent call to pushBlock() or popBlock().
  288. */
  289. jit::vector<BlockState> m_savedBlocks;
  290. Block* m_curBlock;
  291. ExnStackState m_exnStack;
  292. bool m_enableSimplification{false};
  293. GuardConstraints m_constraints;
  294. // Keep track of blocks created to support bytecode control flow.
  295. jit::flat_map<SrcKey,Block*> m_skToBlockMap;
  296. // Keeps the block to branch to (if any) in case a guard fails.
  297. // This holds nullptr if the guard failures should perform a service
  298. // request (REQ_RETRANSLATE or REQ_BIND_JMP).
  299. Block* m_guardFailBlock{nullptr};
  300. };
  301. ///////////////////////////////////////////////////////////////////////////////
  302. /*
  303. * RAII helper for emitting code to exit traces. See IRBuilder::pushBlock
  304. * for usage.
  305. */
  306. struct BlockPusher {
  307. BlockPusher(IRBuilder& irb, BCMarker marker, Block* block)
  308. : m_irb(irb)
  309. {
  310. irb.pushBlock(marker, block);
  311. }
  312. ~BlockPusher() {
  313. m_irb.popBlock();
  314. }
  315. private:
  316. IRBuilder& m_irb;
  317. };
  318. ///////////////////////////////////////////////////////////////////////////////
  319. bool typeMightRelax(const SSATmp* tmp);
  320. ///////////////////////////////////////////////////////////////////////////////
  321. }}}
  322. #endif