PageRenderTime 42ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 1ms

/hphp/runtime/vm/jit/block.h

https://github.com/tstarling/hiphop-php
C Header | 290 lines | 182 code | 52 blank | 56 comment | 31 complexity | 60e77ba47e452a4d55f8db68e4b60558 MD5 | raw file
  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. +----------------------------------------------------------------------+
  15. */
  16. #ifndef incl_HPHP_VM_BLOCK_H_
  17. #define incl_HPHP_VM_BLOCK_H_
  18. #include "hphp/runtime/base/smart-containers.h"
  19. #include <algorithm>
  20. #include "hphp/runtime/vm/jit/ir.h"
  21. #include "hphp/runtime/vm/jit/edge.h"
  22. #include "hphp/runtime/vm/jit/ir-instruction.h"
  23. namespace HPHP { namespace JIT {
  24. /*
  25. * A Block refers to a basic block: single-entry, single-exit, list of
  26. * instructions. The instruction list is an intrusive list, so each
  27. * instruction can only be in one block at a time. Likewise, a block
  28. * can only be owned by one trace at a time.
  29. *
  30. * Block owns the InstructionList, but exposes several list methods itself
  31. * so usually you can use Block directly. These methods also update
  32. * IRInstruction::m_block transparently.
  33. */
  34. struct Block : boost::noncopyable {
  35. typedef InstructionList::iterator iterator;
  36. typedef InstructionList::const_iterator const_iterator;
  37. typedef InstructionList::reference reference;
  38. typedef InstructionList::const_reference const_reference;
  39. // Execution frequency hint; codegen will put Unlikely blocks in astubs.
  40. enum class Hint { Neither, Likely, Unlikely };
  41. explicit Block(unsigned id)
  42. : m_id(id)
  43. , m_hint(Hint::Neither)
  44. {}
  45. uint32_t id() const { return m_id; }
  46. Hint hint() const { return m_hint; }
  47. void setHint(Hint hint) { m_hint = hint; }
  48. // Returns true if this block has no successors.
  49. bool isExit() const { return !taken() && !next(); }
  50. // Returns whether this block is the initial entry block for the tracelet.
  51. bool isEntry() const { return id() == 0; }
  52. // Returns whether this block starts with BeginCatch
  53. bool isCatch() const;
  54. // return the fallthrough block. Should be nullptr if the last instruction
  55. // is a Terminal.
  56. Block* next() const { return back().next(); }
  57. Edge* nextEdge() { return back().nextEdge(); }
  58. // return the target block if the last instruction is a branch.
  59. Block* taken() const { return back().taken(); }
  60. Edge* takenEdge() { return back().takenEdge(); }
  61. // returns the number of successors.
  62. size_t numSuccs() const { return (bool)taken() + (bool)next(); }
  63. // return the postorder number of this block. (updated each time
  64. // sortBlocks() is called.
  65. // Insert inst after this block's optional DefLabel and BeginCatch,
  66. // then return an iterator to the newly inserted instruction.
  67. iterator prepend(IRInstruction* inst);
  68. // return iterator to first instruction after the DefLabel (if
  69. // present) and BeginCatch (if present).
  70. iterator skipHeader();
  71. const_iterator skipHeader() const;
  72. // return iterator to last instruction
  73. iterator backIter();
  74. // return an iterator to a specific instruction
  75. iterator iteratorTo(IRInstruction* inst);
  76. // Accessors of list of predecessor edges. Each edge has a inst() property
  77. // which is the instruction in the predecessor block.
  78. EdgeList& preds() { return m_preds; }
  79. const EdgeList& preds() const { return m_preds; }
  80. size_t numPreds() const { return m_preds.size(); }
  81. // Remove edge from its destination's predecessor list and insert it in
  82. // new_to's predecessor list.
  83. static Block* updatePreds(Edge* edge, Block* new_to);
  84. // visit each src that provides a value to label->dsts[i]. body
  85. // should take an IRInstruction* and an SSATmp*.
  86. template<typename L> void forEachSrc(unsigned i, L body) const;
  87. // return the first src providing a value to label->dsts[i] for
  88. // which body(src) returns true, or nullptr if none are found.
  89. template<typename L> SSATmp* findSrc(unsigned i, L body);
  90. // execute body(P) for each predecessor block P of this block
  91. template <typename L> void forEachPred(L body);
  92. // list-compatible interface; these delegate to m_instrs but also update
  93. // inst.m_block
  94. InstructionList& instrs() { return m_instrs; }
  95. bool empty() const { return m_instrs.empty(); }
  96. iterator begin() { return m_instrs.begin(); }
  97. iterator end() { return m_instrs.end(); }
  98. const_iterator begin() const { return m_instrs.begin(); }
  99. const_iterator end() const { return m_instrs.end(); }
  100. iterator erase(iterator pos);
  101. iterator erase(IRInstruction* inst);
  102. iterator insert(iterator pos, IRInstruction* inst);
  103. void splice(iterator pos, Block* from, iterator begin, iterator end);
  104. void push_back(IRInstruction* inst);
  105. template <class Predicate> void remove_if(Predicate p);
  106. InstructionList&& moveInstrs();
  107. // return the first instruction in the block.
  108. reference front();
  109. const_reference front() const;
  110. // return the last instruction in the block
  111. reference back();
  112. const_reference back() const;
  113. friend const Edge* nextEdge(Block*); // only for validation
  114. std::string toString() const;
  115. private:
  116. InstructionList m_instrs; // instructions in this block
  117. const unsigned m_id; // unit-assigned unique id of this block
  118. EdgeList m_preds; // Edges that point to this block
  119. Hint m_hint; // execution frequency hint
  120. };
  121. typedef smart::vector<Block*> BlockList;
  122. inline Block::reference Block::front() {
  123. assert(!m_instrs.empty());
  124. return m_instrs.front();
  125. }
  126. inline Block::const_reference Block::front() const {
  127. return const_cast<Block*>(this)->front();
  128. }
  129. inline Block::reference Block::back() {
  130. assert(!m_instrs.empty());
  131. return m_instrs.back();
  132. }
  133. inline Block::const_reference Block::back() const {
  134. return const_cast<Block*>(this)->back();
  135. }
  136. inline Block::iterator Block::erase(iterator pos) {
  137. pos->setBlock(nullptr);
  138. return m_instrs.erase(pos);
  139. }
  140. inline Block::iterator Block::erase(IRInstruction* inst) {
  141. assert(inst->block() == this);
  142. return erase(iteratorTo(inst));
  143. }
  144. inline Block::iterator Block::prepend(IRInstruction* inst) {
  145. assert(inst->marker().valid());
  146. auto it = skipHeader();
  147. return insert(it, inst);
  148. }
  149. inline Block::iterator Block::skipHeader() {
  150. auto it = begin();
  151. auto e = end();
  152. if (it != e && it->op() == DefLabel) ++it;
  153. if (it != e && it->op() == BeginCatch) ++it;
  154. return it;
  155. }
  156. inline Block::const_iterator Block::skipHeader() const {
  157. return const_cast<Block*>(this)->skipHeader();
  158. }
  159. inline Block::iterator Block::backIter() {
  160. assert(!empty());
  161. auto it = end();
  162. return --it;
  163. }
  164. inline Block::iterator Block::iteratorTo(IRInstruction* inst) {
  165. assert(inst->block() == this);
  166. return m_instrs.iterator_to(*inst);
  167. }
  168. inline Block* Block::updatePreds(Edge* edge, Block* new_to) {
  169. if (Block* old_to = edge->to()) {
  170. auto &preds = old_to->m_preds;
  171. preds.erase(preds.iterator_to(*edge));
  172. }
  173. if (new_to) {
  174. new_to->m_preds.push_front(*edge);
  175. }
  176. return new_to;
  177. }
  178. template<typename L> inline
  179. void Block::forEachSrc(unsigned i, L body) const {
  180. for (auto const& e : m_preds) {
  181. auto jmp = e.inst();
  182. assert(jmp->op() == Jmp && jmp->taken() == this);
  183. body(jmp, jmp->src(i));
  184. }
  185. }
  186. template<typename L> inline
  187. SSATmp* Block::findSrc(unsigned i, L body) {
  188. for (Edge& e : m_preds) {
  189. SSATmp* src = e.inst()->src(i);
  190. if (body(src)) return src;
  191. }
  192. return nullptr;
  193. }
  194. template <typename L> inline
  195. void Block::forEachPred(L body) {
  196. for (auto i = m_preds.begin(), e = m_preds.end(); i != e;) {
  197. auto inst = i->inst();
  198. ++i;
  199. body(inst->block());
  200. }
  201. }
  202. inline Block::iterator Block::insert(iterator pos, IRInstruction* inst) {
  203. assert(inst->marker().valid());
  204. inst->setBlock(this);
  205. return m_instrs.insert(pos, *inst);
  206. }
  207. inline
  208. void Block::splice(iterator pos, Block* from, iterator begin, iterator end) {
  209. assert(from != this);
  210. for (auto i = begin; i != end; ++i) i->setBlock(this);
  211. m_instrs.splice(pos, from->instrs(), begin, end);
  212. }
  213. inline void Block::push_back(IRInstruction* inst) {
  214. assert(inst->marker().valid());
  215. inst->setBlock(this);
  216. return m_instrs.push_back(*inst);
  217. }
  218. template <class Predicate> inline
  219. void Block::remove_if(Predicate p) {
  220. m_instrs.remove_if(p);
  221. }
  222. inline InstructionList&& Block::moveInstrs() {
  223. for (auto i = begin(); i != end(); ++i) i->setBlock(nullptr);
  224. return std::move(m_instrs);
  225. }
  226. inline bool Block::isCatch() const {
  227. // Catch blocks always start with DefLabel; BeginCatch.
  228. if (empty()) return false;
  229. auto it = skipHeader();
  230. if (it == begin()) return false;
  231. return (--it)->op() == BeginCatch;
  232. }
  233. // defined here to avoid circular dependencies
  234. inline void Edge::setTo(Block* to) {
  235. m_to = Block::updatePreds(this, to);
  236. }
  237. }}
  238. #endif