From e28e3f205e0fca53526cd1b56db0c7876a2f7792 Mon Sep 17 00:00:00 2001 From: Jordan DeLong Date: Thu, 18 Jul 2013 13:44:08 -0700 Subject: [PATCH] Allow using ExtraData-supplied immediates in native-calls.cpp Ports CreateCont* opcodes to use extra data for their compile-time constants as a test case. --- hphp/doc/ir.specification | 16 +++----- hphp/runtime/vm/jit/code-gen.cpp | 7 +++- hphp/runtime/vm/jit/code-gen.h | 3 -- hphp/runtime/vm/jit/extra-data.h | 49 +++++++++++-------------- hphp/runtime/vm/jit/hhbc-translator.cpp | 17 +++++---- hphp/runtime/vm/jit/ir.h | 44 +++++++++++++++++++++- hphp/runtime/vm/jit/linear-scan.cpp | 2 + hphp/runtime/vm/jit/native-calls.cpp | 39 +++++++++++++++----- hphp/runtime/vm/jit/native-calls.h | 19 +++++++++- 9 files changed, 132 insertions(+), 64 deletions(-) diff --git a/hphp/doc/ir.specification b/hphp/doc/ir.specification index 25fa35ccb..aba9c8d99 100755 --- a/hphp/doc/ir.specification +++ b/hphp/doc/ir.specification @@ -1518,20 +1518,14 @@ D:Obj = CreateCl S0:ConstCls S1:ConstInt S2:FramePtr S3:StkPtr object. Saves the $this and Func* from ActRec S2 into the object, and returns the object. -D:Obj = CreateContFunc S0:ConstFunc S1:ConstFunc +D:Obj = CreateContFunc - Create a continuation object from function. Arguments: + Create a continuation object for a generator function. - S0 - the "original" function - S1 - the generator function +D:Obj = CreateContMeth S0:Ctx -D:Obj = CreateContMeth S0:ConstFunc S1:ConstFunc S2:Ctx - - Create a continuation object from method. Arguments: - - S0 - the "original" method - S1 - the generator function - S2 - the m_this/m_cls field of the current frame pointer + Create a continuation object for a generator method. S0 is the + m_this/m_cls field of the current frame pointer. ContEnter S0:FramePtr S1:TCA S2:ConstInt S3:FramePtr diff --git a/hphp/runtime/vm/jit/code-gen.cpp b/hphp/runtime/vm/jit/code-gen.cpp index 4ff6df130..289466a3b 100755 --- a/hphp/runtime/vm/jit/code-gen.cpp +++ b/hphp/runtime/vm/jit/code-gen.cpp @@ -340,7 +340,7 @@ Address CodeGenerator::cgInst(IRInstruction* inst) { void CodeGenerator::cg##opcode(IRInstruction*) {} #define CALL_OPCODE(opcode) \ - void CodeGenerator::cg##opcode(IRInstruction* i) { cgCallNative(i); } + void CodeGenerator::cg##opcode(IRInstruction* i) { cgCallNative(m_as, i); } #define CALL_STK_OPCODE(opcode) \ CALL_OPCODE(opcode) \ @@ -1046,6 +1046,9 @@ void CodeGenerator::cgCallNative(Asm& a, IRInstruction* inst) { case VecKeyIS: argGroup.vectorKeyIS(src); break; + case ExtraImm: + argGroup.imm(arg.extraFunc(inst)); + break; } } @@ -5768,7 +5771,7 @@ void CodeGenerator::cgVerifyParamCls(IRInstruction* inst) { // The native call for this instruction is the slow path that does // proper subtype checking. The comparison above is just to // short-circuit the overhead when the Classes are an exact match. - ifThen(m_as, CC_NE, [&]{ cgCallNative(inst); }); + ifThen(m_as, CC_NE, [&]{ cgCallNative(m_as, inst); }); } static void emitTraceCall(CodeGenerator::Asm& as, diff --git a/hphp/runtime/vm/jit/code-gen.h b/hphp/runtime/vm/jit/code-gen.h index 09b33a0d9..41bfcb312 100644 --- a/hphp/runtime/vm/jit/code-gen.h +++ b/hphp/runtime/vm/jit/code-gen.h @@ -140,9 +140,6 @@ private: #undef O // helper functions for code generation - void cgCallNative(IRInstruction* inst) { - cgCallNative(m_as, inst); - } void cgCallNative(Asm& a, IRInstruction* inst); void doStackArgs(Asm&, ArgGroup&); void cgCallHelper(Asm&, diff --git a/hphp/runtime/vm/jit/extra-data.h b/hphp/runtime/vm/jit/extra-data.h index 87cd5bb73..c4cd5d2f5 100644 --- a/hphp/runtime/vm/jit/extra-data.h +++ b/hphp/runtime/vm/jit/extra-data.h @@ -154,30 +154,8 @@ struct FPushCufData : IRExtraData { struct ConstData : IRExtraData { template explicit ConstData(T data) - : m_dataBits(0) - { - static_assert(sizeof(T) <= sizeof m_dataBits, - "Constant data was larger than supported"); - static_assert(std::is_pod::value, - "Constant data wasn't a pod?"); - const auto toCopy = promoteIfNeeded(data); - std::memcpy(&m_dataBits, &toCopy, sizeof(toCopy)); - } - - template - struct needsPromotion { - static constexpr bool value = std::is_integral::value || - std::is_same::value || - std::is_enum::value; - }; - - template - typename std::enable_if::value, int64_t>::type - promoteIfNeeded(T t) { return t; } - - template - typename std::enable_if::value, T>::type - promoteIfNeeded(T t) { return t; } + : m_dataBits(constToBits(data)) + {} template T as() const { @@ -324,9 +302,6 @@ struct CheckDefinedClsData : IRExtraData { * Offset and stack deltas for InterpOne. */ struct InterpOneData : IRExtraData { - InterpOneData(Offset o, int64_t pop, int64_t push, Op op) - : bcOff(o), cellsPopped(pop), cellsPushed(push), opcode(op) {} - // Offset of the instruction to interpret, in the Unit indicated by // the current Marker. Offset bcOff; @@ -341,6 +316,24 @@ struct InterpOneData : IRExtraData { Op opcode; }; +/* + * Information for creating continuation objects. + * CreateCont{Func,Meth}. + */ +struct CreateContData : IRExtraData { + CreateContData(const Func* origFunc, const Func* genFunc) + : origFunc(origFunc) + , genFunc(genFunc) + {} + + std::string show() const { + return folly::to(origFunc->fullName()->data(), "()"); + } + + const Func* origFunc; + const Func* genFunc; +}; + ////////////////////////////////////////////////////////////////////// #define X(op, data) \ @@ -405,6 +398,8 @@ X(SideExitGuardLoc, SideExitGuardData); X(SideExitGuardStk, SideExitGuardData); X(CheckDefinedClsEq, CheckDefinedClsData); X(InterpOne, InterpOneData); +X(CreateContFunc, CreateContData); +X(CreateContMeth, CreateContData); #undef X diff --git a/hphp/runtime/vm/jit/hhbc-translator.cpp b/hphp/runtime/vm/jit/hhbc-translator.cpp index 37fd357e6..69a10963f 100755 --- a/hphp/runtime/vm/jit/hhbc-translator.cpp +++ b/hphp/runtime/vm/jit/hhbc-translator.cpp @@ -1152,14 +1152,12 @@ void HhbcTranslator::emitCreateCont(Id funNameStrId) { auto const cont = origFunc->isMethod() ? gen( CreateContMeth, - cns(origFunc), - cns(genFunc), + CreateContData { origFunc, genFunc }, gen(LdCtx, m_tb->fp(), cns(curFunc())) ) : gen( CreateContFunc, - cns(origFunc), - cns(genFunc) + CreateContData { origFunc, genFunc } ); ContParamMap params; @@ -3805,9 +3803,14 @@ void HhbcTranslator::emitInterpOne(Type outType, int popped) { void HhbcTranslator::emitInterpOne(Type outType, int popped, int pushed) { auto sp = spillStack(); Unit *u = curFunc()->unit(); - gen(InterpOne, outType, InterpOneData(bcOff(), popped, pushed, - u->getOpcode(bcOff())), - m_tb->fp(), sp); + + InterpOneData idata; + idata.bcOff = bcOff(); + idata.cellsPopped = popped; + idata.cellsPushed = pushed; + idata.opcode = u->getOpcode(bcOff()); + + gen(InterpOne, outType, idata, m_tb->fp(), sp); assert(m_stackDeficit == 0); } diff --git a/hphp/runtime/vm/jit/ir.h b/hphp/runtime/vm/jit/ir.h index 0b2b90eb3..c25a55bb7 100755 --- a/hphp/runtime/vm/jit/ir.h +++ b/hphp/runtime/vm/jit/ir.h @@ -475,8 +475,8 @@ O(InterpOneCF, ND, S(FramePtr) S(StkPtr) \ C(Int), T|E|N|Mem|Refs|Er) \ O(Spill, DofS(0), SUnk, Mem) \ O(Reload, DofS(0), SUnk, Mem) \ -O(CreateContFunc, D(Obj), C(Func) C(Func), E|N|PRc) \ -O(CreateContMeth, D(Obj), C(Func) C(Func) S(Ctx), E|N|PRc) \ +O(CreateContFunc, D(Obj), NA, E|N|PRc) \ +O(CreateContMeth, D(Obj), S(Ctx), E|N|PRc) \ O(ContEnter, ND, S(FramePtr) \ S(TCA) C(Int) S(FramePtr), E|Mem) \ O(ContPreNext, ND, S(Obj), E|Mem) \ @@ -840,6 +840,46 @@ inline Type typeForConst(const ArrayData* ad) { return Type::Arr; } +/* + * constToBits(T) + * + * Returns a constant value as a 8-byte word (in the shape it would + * need to be to go into a register). Takes care to ensure that + * various types are safely copied. + */ + +namespace constToBits_detail { + template + struct needs_promotion + : std::integral_constant< + bool, + std::is_integral::value || + std::is_same::value || + std::is_enum::value + > + {}; + + template + typename std::enable_if::value,uint64_t>::type + promoteIfNeeded(T t) { return t; } + + template + typename std::enable_if::value,T>::type + promoteIfNeeded(T t) { return t; } +} + +template +uintptr_t constToBits(T input) { + uintptr_t ret; + static_assert(sizeof(T) <= sizeof ret, + "Constant data was larger than supported"); + static_assert(std::is_pod::value, + "Constant data wasn't a pod?"); + const auto toCopy = constToBits_detail::promoteIfNeeded(input); + std::memcpy(&ret, &toCopy, sizeof toCopy); + return ret; +} + bool cmpOpTypesMayReenter(Opcode, Type t0, Type t1); class RawMemSlot { diff --git a/hphp/runtime/vm/jit/linear-scan.cpp b/hphp/runtime/vm/jit/linear-scan.cpp index 6afc648e2..c13ca9720 100644 --- a/hphp/runtime/vm/jit/linear-scan.cpp +++ b/hphp/runtime/vm/jit/linear-scan.cpp @@ -780,6 +780,8 @@ void LinearScan::computePreColoringHint() { m_preColoringHint.add(inst->src(arg.srcIdx), 0, reg++); m_preColoringHint.add(inst->src(arg.srcIdx), 1, reg++); break; + case ExtraImm: + break; } } return; diff --git a/hphp/runtime/vm/jit/native-calls.cpp b/hphp/runtime/vm/jit/native-calls.cpp index e9a6f2a2a..d3fa2affa 100644 --- a/hphp/runtime/vm/jit/native-calls.cpp +++ b/hphp/runtime/vm/jit/native-calls.cpp @@ -27,13 +27,28 @@ namespace HPHP { namespace JIT { namespace NativeCalls { using namespace HPHP::Transl; using namespace HPHP::Transl::TargetCache; -const SyncOptions SNone = SyncOptions::kNoSyncPoint; -const SyncOptions SSync = SyncOptions::kSyncPoint; -const SyncOptions SSyncAdj1 = SyncOptions::kSyncPointAdjustOne; +namespace { -const DestType DSSA = DestType::SSA; -const DestType DTV = DestType::TV; -const DestType DNone = DestType::None; +constexpr SyncOptions SNone = SyncOptions::kNoSyncPoint; +constexpr SyncOptions SSync = SyncOptions::kSyncPoint; +constexpr SyncOptions SSyncAdj1 = SyncOptions::kSyncPointAdjustOne; + +constexpr DestType DSSA = DestType::SSA; +constexpr DestType DTV = DestType::TV; +constexpr DestType DNone = DestType::None; + +template +Arg extra(MemberType EDType::*ptr) { + auto fun = [ptr] (IRInstruction* inst) { + auto const extra = inst->extra(); + return constToBits(extra->*ptr); + }; + return Arg(fun); +} + +} + +////////////////////////////////////////////////////////////////////// /* * The table passed to s_callMap's constructor describes helpers calls @@ -65,8 +80,9 @@ const DestType DNone = DestType::None; * {VecKeyS, idx} - Like TV, but Str values are passed as a raw * StringData*, in a single register * {VecKeyIS, idx} - Like VecKeyS, including Int + * extra(&EDStruct::member) -- extract an immediate from extra data */ -static CallMap s_callMap({ +static CallMap s_callMap { /* Opcode, Func, Dest, SyncPoint, Args */ {ConvBoolToArr, (TCA)convCellToArrHelper, DSSA, SNone, {{TV, 0}}}, @@ -175,9 +191,12 @@ static CallMap s_callMap({ /* Continuation support helpers */ {CreateContFunc, (TCA)&VMExecutionContext::createContFunc, DSSA, SNone, - {{SSA, 0}, {SSA, 1}}}, + { extra(&CreateContData::origFunc), + extra(&CreateContData::genFunc) }}, {CreateContMeth, (TCA)&VMExecutionContext::createContMeth, DSSA, SNone, - {{SSA, 0}, {SSA, 1}, {SSA, 2}}}, + { extra(&CreateContData::origFunc), + extra(&CreateContData::genFunc), + {SSA, 0} }}, /* VectorTranslator helpers */ {BaseG, {FSSA, 0}, DSSA, SSync, {{TV, 1}, {SSA, 2}}}, @@ -267,7 +286,7 @@ static CallMap s_callMap({ /* debug assert helpers */ {DbgAssertPtr, (TCA)assertTv, DNone, SNone, {{SSA, 0}}}, -}); +}; CallMap::CallMap(CallInfoList infos) { for (auto const& info : infos) { diff --git a/hphp/runtime/vm/jit/native-calls.h b/hphp/runtime/vm/jit/native-calls.h index 3443cb603..713ced76b 100644 --- a/hphp/runtime/vm/jit/native-calls.h +++ b/hphp/runtime/vm/jit/native-calls.h @@ -18,6 +18,7 @@ #define incl_HPHP_VM_TRANSL_HOPT_NATIVECALLS_H_ #include +#include #include #include "hphp/runtime/vm/jit/types.h" @@ -51,19 +52,33 @@ enum ArgType : unsigned { TV, VecKeyS, VecKeyIS, + ExtraImm, }; + +// Function that extracts the bits for an immediate value from extra +// data. +typedef std::function ExtraDataBits; + struct Arg { + Arg(ArgType type, unsigned srcIdx) : type(type), srcIdx(srcIdx) {} + + explicit Arg(ExtraDataBits&& func) + : type(ExtraImm) + , srcIdx(-1u) + , extraFunc(std::move(func)) + {} + ArgType type; unsigned srcIdx; + ExtraDataBits extraFunc; }; -typedef std::vector ArgVec; struct CallInfo { Opcode op; FuncPtr func; DestType dest; SyncOptions sync; - ArgVec args; + std::vector args; }; typedef std::initializer_list CallInfoList;