PageRenderTime 24ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/hphp/runtime/vm/jit/ir-unit-inl.h

https://gitlab.com/Blueprint-Marketing/hhvm
C Header | 285 lines | 165 code | 49 blank | 71 comment | 9 complexity | e34651def950030ac749be9edaacae86 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. #include "hphp/runtime/vm/jit/extra-data.h"
  17. #include "hphp/runtime/vm/jit/ir-instruction.h"
  18. #include "hphp/runtime/vm/jit/ssa-tmp.h"
  19. #include "hphp/runtime/vm/jit/type.h"
  20. #include "hphp/util/trace.h"
  21. #include <folly/ScopeGuard.h>
  22. #include <type_traits>
  23. #include <utility>
  24. namespace HPHP { namespace jit {
  25. ///////////////////////////////////////////////////////////////////////////////
  26. namespace irunit_detail {
  27. ///////////////////////////////////////////////////////////////////////////////
  28. template<class Ret, class Func>
  29. struct InstructionBuilder {
  30. explicit InstructionBuilder(const Func& func) : func(func) {}
  31. /*
  32. * Create an IRInstruction, and then recursively chew on the Args list to
  33. * populate its fields. Every instruction must have at least an Opcode and a
  34. * BCMarker.
  35. *
  36. * The IRInstruction is stack allocated, and should not escape the lambda, so
  37. * we fill it with 0xc0 in debug builds after we're done.
  38. */
  39. template<class... Args>
  40. Ret go(Opcode op, BCMarker marker, Args&&... args) {
  41. std::aligned_storage<sizeof(IRInstruction)>::type buffer;
  42. void* const vpBuffer = &buffer;
  43. SCOPE_EXIT { if (debug) memset(&buffer, 0xc0, sizeof(buffer)); };
  44. Edge edges[2];
  45. new (vpBuffer) IRInstruction(op, marker, hasEdges(op) ? edges : nullptr);
  46. auto const inst = static_cast<IRInstruction*>(vpBuffer);
  47. SCOPE_EXIT { inst->clearExtra(); };
  48. return go2(inst, std::forward<Args>(args)...);
  49. }
  50. /////////////////////////////////////////////////////////////////////////////
  51. private:
  52. /*
  53. * Main loop: call setter() on the head of the list and repeat, until there's
  54. * no overload for the Head type; then fall through to the base case.
  55. */
  56. template<class Head, class... Tail>
  57. Ret go2(IRInstruction* inst, const Head& x, Tail&&... xs) {
  58. setter(inst, x);
  59. return go2(inst, std::forward<Tail>(xs)...);
  60. }
  61. /*
  62. * Base case: no SSATmps.
  63. */
  64. Ret go2(IRInstruction* inst) { return stop(inst); }
  65. /*
  66. * Base case: variadic list of SSATmp*'s.
  67. */
  68. template<class... SSAs>
  69. Ret go2(IRInstruction* inst, SSATmp* t1, SSAs... ts) {
  70. SSATmp* ssas[] = { t1, ts... };
  71. auto const nSrcs = 1 + sizeof...(ts);
  72. for (unsigned i = 0; debug && i < nSrcs; ++i) assertx(ssas[i]);
  73. inst->initializeSrcs(nSrcs, ssas);
  74. return stop(inst);
  75. }
  76. /*
  77. * Base case: (size, SSATmp**) array of srcs.
  78. */
  79. Ret go2(IRInstruction* inst, std::pair<size_t,SSATmp**> ssas) {
  80. inst->initializeSrcs(ssas.first, ssas.second);
  81. return stop(inst);
  82. }
  83. /*
  84. * Call the lambda on the initialized IRInstruction.
  85. */
  86. Ret stop(IRInstruction* inst) {
  87. assertx(checkOperandTypes(inst));
  88. return func(inst);
  89. }
  90. /////////////////////////////////////////////////////////////////////////////
  91. // Overloaded setters.
  92. /*
  93. * Setters for type param.
  94. */
  95. void setter(IRInstruction* inst, Type t) {
  96. inst->setTypeParam(t);
  97. }
  98. void setter(IRInstruction* inst, folly::Optional<Type> t) {
  99. if (t.hasValue()) {
  100. inst->setTypeParam(t.value());
  101. }
  102. }
  103. /*
  104. * Setter for exit label.
  105. */
  106. void setter(IRInstruction* inst, Block* target) {
  107. assertx(!target || inst->hasEdges());
  108. inst->setTaken(target);
  109. }
  110. /*
  111. * Setter for IRExtraData classes.
  112. */
  113. template<typename T>
  114. typename std::enable_if<std::is_base_of<IRExtraData,T>::value, void>::type
  115. setter(IRInstruction* inst, const T& extra) {
  116. /*
  117. * Taking the address of this temporary seems scary, but actually
  118. * it is safe: `extra' was forwarded in all the way from the
  119. * makeInstruction call, but then we bound a const reference to it
  120. * at go2() when it was the head of the varargs list, so it must
  121. * last until the end of the full-expression that called that
  122. * go2().
  123. *
  124. * This is long enough for it to outlast our call to func,
  125. * although the transient IRInstruction actually will outlive it.
  126. * We null out the extra data in go() before ~IRInstruction runs,
  127. * though.
  128. */
  129. assert_opcode_extra_same<T>(inst->op());
  130. const IRExtraData* dataPtr = &extra;
  131. inst->setExtra(const_cast<IRExtraData*>(dataPtr));
  132. }
  133. private:
  134. const Func& func;
  135. };
  136. ///////////////////////////////////////////////////////////////////////////////
  137. }
  138. template<class Func, class... Args>
  139. typename std::result_of<Func(IRInstruction*)>::type
  140. makeInstruction(Func func, Args&&... args) {
  141. typedef typename std::result_of<Func(IRInstruction*)>::type Ret;
  142. return irunit_detail::InstructionBuilder<Ret,Func>(func).go(args...);
  143. }
  144. ///////////////////////////////////////////////////////////////////////////////
  145. template<class... Args>
  146. IRInstruction* IRUnit::gen(Args&&... args) {
  147. return makeInstruction(
  148. [this] (IRInstruction* inst) { return clone(inst); },
  149. std::forward<Args>(args)...
  150. );
  151. }
  152. template<class... Args>
  153. IRInstruction* IRUnit::gen(SSATmp* dst, Args&&... args) {
  154. return makeInstruction(
  155. [this, dst] (IRInstruction* inst) { return clone(inst, dst); },
  156. std::forward<Args>(args)...
  157. );
  158. }
  159. template<class... Args>
  160. void IRUnit::replace(IRInstruction* old, Opcode op, Args... args) {
  161. makeInstruction(
  162. [&] (IRInstruction* replacement) { old->become(*this, replacement); },
  163. op,
  164. old->marker(),
  165. std::forward<Args>(args)...
  166. );
  167. }
  168. template<class... Args>
  169. SSATmp* IRUnit::newSSATmp(Args&&... args) {
  170. m_ssaTmps.push_back(
  171. new (m_arena) SSATmp(m_ssaTmps.size(), std::forward<Args>(args)...)
  172. );
  173. return m_ssaTmps.back();
  174. }
  175. inline IRInstruction* IRUnit::clone(const IRInstruction* old,
  176. SSATmp* dst /* = nullptr */) {
  177. auto inst = new (m_arena) IRInstruction(
  178. m_arena, old, IRInstruction::Id(m_nextInstId++));
  179. if (dst) {
  180. dst->setInstruction(inst);
  181. inst->setDst(dst);
  182. } else if (inst->hasDst()) {
  183. dst = newSSATmp(inst);
  184. inst->setDst(dst);
  185. }
  186. FTRACE_MOD(Trace::hhir, 5, "cloned {}\n", *old);
  187. return inst;
  188. }
  189. ///////////////////////////////////////////////////////////////////////////////
  190. inline Arena& IRUnit::arena() {
  191. return m_arena;
  192. }
  193. inline const TransContext& IRUnit::context() const {
  194. return m_context;
  195. }
  196. inline Block* IRUnit::entry() const {
  197. return m_entry;
  198. }
  199. inline uint32_t IRUnit::bcOff() const {
  200. return m_context.initBcOffset;
  201. }
  202. inline SrcKey IRUnit::initSrcKey() const {
  203. return m_context.srcKey();
  204. }
  205. inline uint32_t IRUnit::numTmps() const {
  206. return m_ssaTmps.size();
  207. }
  208. inline uint32_t IRUnit::numBlocks() const {
  209. return m_nextBlockId;
  210. }
  211. inline uint32_t IRUnit::numInsts() const {
  212. return m_nextInstId;
  213. }
  214. inline uint32_t IRUnit::numIds(const SSATmp*) const {
  215. return numTmps();
  216. }
  217. inline uint32_t IRUnit::numIds(const Block*) const {
  218. return numBlocks();
  219. }
  220. inline uint32_t IRUnit::numIds(const IRInstruction*) const {
  221. return numInsts();
  222. }
  223. inline SSATmp* IRUnit::findSSATmp(uint32_t id) const {
  224. assert(id < m_ssaTmps.size());
  225. return m_ssaTmps[id];
  226. }
  227. inline SSATmp* IRUnit::mainFP() const {
  228. assertx(!entry()->empty() && entry()->begin()->is(DefFP));
  229. return entry()->begin()->dst();
  230. }
  231. ///////////////////////////////////////////////////////////////////////////////
  232. template<typename T> SSATmp* IRUnit::cns(T val) {
  233. return cns(Type::cns(val));
  234. }
  235. ///////////////////////////////////////////////////////////////////////////////
  236. }}