/hphp/runtime/vm/jit/ir-unit-inl.h
C Header | 285 lines | 165 code | 49 blank | 71 comment | 9 complexity | e34651def950030ac749be9edaacae86 MD5 | raw file
- /*
- +----------------------------------------------------------------------+
- | HipHop for PHP |
- +----------------------------------------------------------------------+
- | Copyright (c) 2010-2014 Facebook, Inc. (http://www.facebook.com) |
- +----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | http://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
- +----------------------------------------------------------------------+
- */
- #include "hphp/runtime/vm/jit/extra-data.h"
- #include "hphp/runtime/vm/jit/ir-instruction.h"
- #include "hphp/runtime/vm/jit/ssa-tmp.h"
- #include "hphp/runtime/vm/jit/type.h"
- #include "hphp/util/trace.h"
- #include <folly/ScopeGuard.h>
- #include <type_traits>
- #include <utility>
- namespace HPHP { namespace jit {
- ///////////////////////////////////////////////////////////////////////////////
- namespace irunit_detail {
- ///////////////////////////////////////////////////////////////////////////////
- template<class Ret, class Func>
- struct InstructionBuilder {
- explicit InstructionBuilder(const Func& func) : func(func) {}
- /*
- * Create an IRInstruction, and then recursively chew on the Args list to
- * populate its fields. Every instruction must have at least an Opcode and a
- * BCMarker.
- *
- * The IRInstruction is stack allocated, and should not escape the lambda, so
- * we fill it with 0xc0 in debug builds after we're done.
- */
- template<class... Args>
- Ret go(Opcode op, BCMarker marker, Args&&... args) {
- std::aligned_storage<sizeof(IRInstruction)>::type buffer;
- void* const vpBuffer = &buffer;
- SCOPE_EXIT { if (debug) memset(&buffer, 0xc0, sizeof(buffer)); };
- Edge edges[2];
- new (vpBuffer) IRInstruction(op, marker, hasEdges(op) ? edges : nullptr);
- auto const inst = static_cast<IRInstruction*>(vpBuffer);
- SCOPE_EXIT { inst->clearExtra(); };
- return go2(inst, std::forward<Args>(args)...);
- }
- /////////////////////////////////////////////////////////////////////////////
- private:
- /*
- * Main loop: call setter() on the head of the list and repeat, until there's
- * no overload for the Head type; then fall through to the base case.
- */
- template<class Head, class... Tail>
- Ret go2(IRInstruction* inst, const Head& x, Tail&&... xs) {
- setter(inst, x);
- return go2(inst, std::forward<Tail>(xs)...);
- }
- /*
- * Base case: no SSATmps.
- */
- Ret go2(IRInstruction* inst) { return stop(inst); }
- /*
- * Base case: variadic list of SSATmp*'s.
- */
- template<class... SSAs>
- Ret go2(IRInstruction* inst, SSATmp* t1, SSAs... ts) {
- SSATmp* ssas[] = { t1, ts... };
- auto const nSrcs = 1 + sizeof...(ts);
- for (unsigned i = 0; debug && i < nSrcs; ++i) assertx(ssas[i]);
- inst->initializeSrcs(nSrcs, ssas);
- return stop(inst);
- }
- /*
- * Base case: (size, SSATmp**) array of srcs.
- */
- Ret go2(IRInstruction* inst, std::pair<size_t,SSATmp**> ssas) {
- inst->initializeSrcs(ssas.first, ssas.second);
- return stop(inst);
- }
- /*
- * Call the lambda on the initialized IRInstruction.
- */
- Ret stop(IRInstruction* inst) {
- assertx(checkOperandTypes(inst));
- return func(inst);
- }
- /////////////////////////////////////////////////////////////////////////////
- // Overloaded setters.
- /*
- * Setters for type param.
- */
- void setter(IRInstruction* inst, Type t) {
- inst->setTypeParam(t);
- }
- void setter(IRInstruction* inst, folly::Optional<Type> t) {
- if (t.hasValue()) {
- inst->setTypeParam(t.value());
- }
- }
- /*
- * Setter for exit label.
- */
- void setter(IRInstruction* inst, Block* target) {
- assertx(!target || inst->hasEdges());
- inst->setTaken(target);
- }
- /*
- * Setter for IRExtraData classes.
- */
- template<typename T>
- typename std::enable_if<std::is_base_of<IRExtraData,T>::value, void>::type
- setter(IRInstruction* inst, const T& extra) {
- /*
- * Taking the address of this temporary seems scary, but actually
- * it is safe: `extra' was forwarded in all the way from the
- * makeInstruction call, but then we bound a const reference to it
- * at go2() when it was the head of the varargs list, so it must
- * last until the end of the full-expression that called that
- * go2().
- *
- * This is long enough for it to outlast our call to func,
- * although the transient IRInstruction actually will outlive it.
- * We null out the extra data in go() before ~IRInstruction runs,
- * though.
- */
- assert_opcode_extra_same<T>(inst->op());
- const IRExtraData* dataPtr = &extra;
- inst->setExtra(const_cast<IRExtraData*>(dataPtr));
- }
- private:
- const Func& func;
- };
- ///////////////////////////////////////////////////////////////////////////////
- }
- template<class Func, class... Args>
- typename std::result_of<Func(IRInstruction*)>::type
- makeInstruction(Func func, Args&&... args) {
- typedef typename std::result_of<Func(IRInstruction*)>::type Ret;
- return irunit_detail::InstructionBuilder<Ret,Func>(func).go(args...);
- }
- ///////////////////////////////////////////////////////////////////////////////
- template<class... Args>
- IRInstruction* IRUnit::gen(Args&&... args) {
- return makeInstruction(
- [this] (IRInstruction* inst) { return clone(inst); },
- std::forward<Args>(args)...
- );
- }
- template<class... Args>
- IRInstruction* IRUnit::gen(SSATmp* dst, Args&&... args) {
- return makeInstruction(
- [this, dst] (IRInstruction* inst) { return clone(inst, dst); },
- std::forward<Args>(args)...
- );
- }
- template<class... Args>
- void IRUnit::replace(IRInstruction* old, Opcode op, Args... args) {
- makeInstruction(
- [&] (IRInstruction* replacement) { old->become(*this, replacement); },
- op,
- old->marker(),
- std::forward<Args>(args)...
- );
- }
- template<class... Args>
- SSATmp* IRUnit::newSSATmp(Args&&... args) {
- m_ssaTmps.push_back(
- new (m_arena) SSATmp(m_ssaTmps.size(), std::forward<Args>(args)...)
- );
- return m_ssaTmps.back();
- }
- inline IRInstruction* IRUnit::clone(const IRInstruction* old,
- SSATmp* dst /* = nullptr */) {
- auto inst = new (m_arena) IRInstruction(
- m_arena, old, IRInstruction::Id(m_nextInstId++));
- if (dst) {
- dst->setInstruction(inst);
- inst->setDst(dst);
- } else if (inst->hasDst()) {
- dst = newSSATmp(inst);
- inst->setDst(dst);
- }
- FTRACE_MOD(Trace::hhir, 5, "cloned {}\n", *old);
- return inst;
- }
- ///////////////////////////////////////////////////////////////////////////////
- inline Arena& IRUnit::arena() {
- return m_arena;
- }
- inline const TransContext& IRUnit::context() const {
- return m_context;
- }
- inline Block* IRUnit::entry() const {
- return m_entry;
- }
- inline uint32_t IRUnit::bcOff() const {
- return m_context.initBcOffset;
- }
- inline SrcKey IRUnit::initSrcKey() const {
- return m_context.srcKey();
- }
- inline uint32_t IRUnit::numTmps() const {
- return m_ssaTmps.size();
- }
- inline uint32_t IRUnit::numBlocks() const {
- return m_nextBlockId;
- }
- inline uint32_t IRUnit::numInsts() const {
- return m_nextInstId;
- }
- inline uint32_t IRUnit::numIds(const SSATmp*) const {
- return numTmps();
- }
- inline uint32_t IRUnit::numIds(const Block*) const {
- return numBlocks();
- }
- inline uint32_t IRUnit::numIds(const IRInstruction*) const {
- return numInsts();
- }
- inline SSATmp* IRUnit::findSSATmp(uint32_t id) const {
- assert(id < m_ssaTmps.size());
- return m_ssaTmps[id];
- }
- inline SSATmp* IRUnit::mainFP() const {
- assertx(!entry()->empty() && entry()->begin()->is(DefFP));
- return entry()->begin()->dst();
- }
- ///////////////////////////////////////////////////////////////////////////////
- template<typename T> SSATmp* IRUnit::cns(T val) {
- return cns(Type::cns(val));
- }
- ///////////////////////////////////////////////////////////////////////////////
- }}