From 629d329f2215c00994eb55f5c1e80cc58e39eddb Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 18 Nov 2018 07:43:03 +0100 Subject: [PATCH] - removed OP_TAIL. The amount of support code for this minor optimization was quite large and this stood in the way of streamlining the VM's calling convention, so it was preferable to remove it before moving on. --- src/d_dehacked.cpp | 3 +- src/scripting/backend/codegen.cpp | 114 ++-------------------------- src/scripting/backend/codegen.h | 9 --- src/scripting/backend/vmbuilder.cpp | 2 +- src/scripting/backend/vmdisasm.cpp | 3 +- src/scripting/vm/jit_call.cpp | 56 -------------- src/scripting/vm/jitintern.h | 3 - src/scripting/vm/vmexec.h | 39 ---------- src/scripting/vm/vmops.h | 2 - 9 files changed, 12 insertions(+), 219 deletions(-) diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index aaac4b879..9004dc555 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -784,7 +784,8 @@ void SetDehParams(FState *state, int codepointer) // Emit code for action parameters. MBFCodePointerFactories[codepointer](emitters, value1, value2); int count = emitters.EmitParameters(&buildit); - buildit.Emit(OP_TAIL_K, buildit.GetConstantAddress(sym->Variants[0].Implementation), count, 0); + buildit.Emit(OP_CALL_K, buildit.GetConstantAddress(sym->Variants[0].Implementation), count, 0); + buildit.Emit(OP_RET, RET_FINAL, REGT_NIL, 0); // Attach it to the state. VMScriptFunction *sfunc = new VMScriptFunction; buildit.MakeFunction(sfunc); diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index 26e2ccd99..74ab9a1c8 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -5449,18 +5449,6 @@ FxRandom::~FxRandom() // //========================================================================== -PPrototype *FxRandom::ReturnProto() -{ - EmitTail = true; - return FxExpression::ReturnProto(); -} - -//========================================================================== -// -// -// -//========================================================================== - FxExpression *FxRandom::Resolve(FCompileContext &ctx) { CHECKRESOLVED(); @@ -5506,23 +5494,13 @@ ExpEmit FxRandom::Emit(VMFunctionBuilder *build) assert(min && max); callfunc = ((PSymbolVMFunction *)sym)->Function; - if (build->FramePointer.Fixed) EmitTail = false; // do not tail call if the stack is in use - int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K); - EmitterArray emitters; emitters.AddParameterPointerConst(rng); emitters.AddParameter(build, min); emitters.AddParameter(build, max); int count = emitters.EmitParameters(build); - build->Emit(opcode, build->GetConstantAddress(callfunc), count, 1); - - if (EmitTail) - { - ExpEmit call; - call.Final = true; - return call; - } + build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc), count, 1); ExpEmit out(build, REGT_INT); build->Emit(OP_RESULT, 0, REGT_INT, out.RegNum); @@ -5747,22 +5725,12 @@ ExpEmit FxFRandom::Emit(VMFunctionBuilder *build) assert(min && max); callfunc = ((PSymbolVMFunction *)sym)->Function; - if (build->FramePointer.Fixed) EmitTail = false; // do not tail call if the stack is in use - int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K); - EmitterArray emitters; emitters.AddParameterPointerConst(rng); emitters.AddParameter(build, min); emitters.AddParameter(build, max); int count = emitters.EmitParameters(build); - build->Emit(opcode, build->GetConstantAddress(callfunc), count, 1); - - if (EmitTail) - { - ExpEmit call; - call.Final = true; - return call; - } + build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc), count, 1); ExpEmit out(build, REGT_FLOAT); build->Emit(OP_RESULT, 0, REGT_FLOAT, out.RegNum); @@ -5778,7 +5746,6 @@ ExpEmit FxFRandom::Emit(VMFunctionBuilder *build) FxRandom2::FxRandom2(FRandom *r, FxExpression *m, const FScriptPosition &pos, bool nowarn) : FxExpression(EFX_Random2, pos) { - EmitTail = false; rng = r; if (m) mask = new FxIntCast(m, nowarn); else mask = new FxConstant(-1, pos); @@ -5802,18 +5769,6 @@ FxRandom2::~FxRandom2() // //========================================================================== -PPrototype *FxRandom2::ReturnProto() -{ - EmitTail = true; - return FxExpression::ReturnProto(); -} - -//========================================================================== -// -// -// -//========================================================================== - FxExpression *FxRandom2::Resolve(FCompileContext &ctx) { CHECKRESOLVED(); @@ -5851,22 +5806,12 @@ ExpEmit FxRandom2::Emit(VMFunctionBuilder *build) assert(((PSymbolVMFunction *)sym)->Function != nullptr); callfunc = ((PSymbolVMFunction *)sym)->Function; - if (build->FramePointer.Fixed) EmitTail = false; // do not tail call if the stack is in use - int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K); - EmitterArray emitters; emitters.AddParameterPointerConst(rng); emitters.AddParameter(build, mask); int count = emitters.EmitParameters(build); - build->Emit(opcode, build->GetConstantAddress(callfunc), count, 1); - - if (EmitTail) - { - ExpEmit call; - call.Final = true; - return call; - } + build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc), count, 1); ExpEmit out(build, REGT_INT); build->Emit(OP_RESULT, 0, REGT_INT, out.RegNum); @@ -5881,7 +5826,6 @@ ExpEmit FxRandom2::Emit(VMFunctionBuilder *build) FxRandomSeed::FxRandomSeed(FRandom * r, FxExpression *s, const FScriptPosition &pos, bool nowarn) : FxExpression(EFX_Random, pos) { - EmitTail = false; seed = new FxIntCast(s, nowarn); rng = r; ValueType = TypeVoid; @@ -5937,18 +5881,14 @@ ExpEmit FxRandomSeed::Emit(VMFunctionBuilder *build) assert(((PSymbolVMFunction *)sym)->Function != nullptr); callfunc = ((PSymbolVMFunction *)sym)->Function; - if (build->FramePointer.Fixed) EmitTail = false; // do not tail call if the stack is in use - int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K); - EmitterArray emitters; emitters.AddParameterPointerConst(rng); emitters.AddParameter(build, seed); int count = emitters.EmitParameters(build); - build->Emit(opcode, build->GetConstantAddress(callfunc), count, 0); + build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc), count, 0); ExpEmit call; - if (EmitTail) call.Final = true; return call; } @@ -6636,7 +6576,6 @@ FxClassDefaults::FxClassDefaults(FxExpression *X, const FScriptPosition &pos) : FxExpression(EFX_ClassDefaults, pos) { obj = X; - EmitTail = false; } FxClassDefaults::~FxClassDefaults() @@ -8508,7 +8447,6 @@ FxActionSpecialCall::FxActionSpecialCall(FxExpression *self, int special, FArgum { ArgList.Push(new FxConstant(0, ScriptPosition)); } - EmitTail = false; } //========================================================================== @@ -8528,18 +8466,6 @@ FxActionSpecialCall::~FxActionSpecialCall() // //========================================================================== -PPrototype *FxActionSpecialCall::ReturnProto() -{ - EmitTail = true; - return FxExpression::ReturnProto(); -} - -//========================================================================== -// -// -// -//========================================================================== - FxExpression *FxActionSpecialCall::Resolve(FCompileContext& ctx) { CHECKRESOLVED(); @@ -8664,16 +8590,8 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build) ArgList.DeleteAndClear(); ArgList.ShrinkToFit(); - if (build->FramePointer.Fixed) EmitTail = false; // do not tail call if the stack is in use int count = emitters.EmitParameters(build); selfemit.Free(build); - if (EmitTail) - { - build->Emit(OP_TAIL_K, build->GetConstantAddress(callfunc), count, 0); - ExpEmit call; - call.Final = true; - return call; - } ExpEmit dest(build, REGT_INT); build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc), count, 1); @@ -8717,7 +8635,7 @@ PPrototype *FxVMFunctionCall::ReturnProto() { if (hasStringArgs) return FxExpression::ReturnProto(); - EmitTail = true; + return Function->Variants[0].Proto; } @@ -9068,12 +8986,10 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) assert(build->Registers[REGT_POINTER].GetMostUsed() >= build->NumImplicits); int count = 0; - if (build->FramePointer.Fixed) EmitTail = false; // do not tail call if the stack is in use - if (count == 1) { ExpEmit reg; - if (CheckEmitCast(build, EmitTail, reg)) + if (CheckEmitCast(build, false, reg)) { ArgList.DeleteAndClear(); ArgList.ShrinkToFit(); @@ -9166,14 +9082,7 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) { int funcaddr = build->GetConstantAddress(vmfunc); // Emit the call - if (EmitTail) - { // Tail call - build->Emit(OP_TAIL_K, funcaddr, count, 0); - ExpEmit call; - call.Final = true; - return call; - } - else if (vmfunc->Proto->ReturnTypes.Size() > 0) + if (vmfunc->Proto->ReturnTypes.Size() > 0) { // Call, expecting one result build->Emit(OP_CALL_K, funcaddr, count, MAX(1, AssignCount)); goto handlereturns; @@ -9189,14 +9098,7 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) ExpEmit funcreg(build, REGT_POINTER); build->Emit(OP_VTBL, funcreg.RegNum, selfemit.RegNum, vmfunc->VirtualIndex); - if (EmitTail) - { // Tail call - build->Emit(OP_TAIL, funcreg.RegNum, count, 0); - ExpEmit call; - call.Final = true; - return call; - } - else if (vmfunc->Proto->ReturnTypes.Size() > 0) + if (vmfunc->Proto->ReturnTypes.Size() > 0) { // Call, expecting one result build->Emit(OP_CALL, funcreg.RegNum, count, MAX(1, AssignCount)); goto handlereturns; diff --git a/src/scripting/backend/codegen.h b/src/scripting/backend/codegen.h index 9e93ec6f3..ba0bb4d41 100644 --- a/src/scripting/backend/codegen.h +++ b/src/scripting/backend/codegen.h @@ -404,7 +404,6 @@ public: class FxClassDefaults : public FxExpression { FxExpression *obj; - bool EmitTail; public: FxClassDefaults(FxExpression *, const FScriptPosition &); @@ -1257,7 +1256,6 @@ public: class FxRandom : public FxExpression { protected: - bool EmitTail = false; FRandom *rng; FxExpression *min, *max; @@ -1267,7 +1265,6 @@ public: FxRandom(FRandom *, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos, bool nowarn); ~FxRandom(); FxExpression *Resolve(FCompileContext&); - PPrototype *ReturnProto(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -1313,7 +1310,6 @@ public: class FxRandom2 : public FxExpression { - bool EmitTail; FRandom * rng; FxExpression *mask; @@ -1322,7 +1318,6 @@ public: FxRandom2(FRandom *, FxExpression *m, const FScriptPosition &pos, bool nowarn); ~FxRandom2(); FxExpression *Resolve(FCompileContext&); - PPrototype *ReturnProto(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -1336,7 +1331,6 @@ public: class FxRandomSeed : public FxExpression { protected: - bool EmitTail; FRandom *rng; FxExpression *seed; @@ -1583,7 +1577,6 @@ public: class FxActionSpecialCall : public FxExpression { int Special; - bool EmitTail; FxExpression *Self; FArgumentList ArgList; @@ -1592,7 +1585,6 @@ public: FxActionSpecialCall(FxExpression *self, int special, FArgumentList &args, const FScriptPosition &pos); ~FxActionSpecialCall(); FxExpression *Resolve(FCompileContext&); - PPrototype *ReturnProto(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -1752,7 +1744,6 @@ class FxVMFunctionCall : public FxExpression { friend class FxMultiAssign; - bool EmitTail = false; bool NoVirtual; bool hasStringArgs = false; FxExpression *Self; diff --git a/src/scripting/backend/vmbuilder.cpp b/src/scripting/backend/vmbuilder.cpp index 6c16e1a3a..ecd8c2d29 100644 --- a/src/scripting/backend/vmbuilder.cpp +++ b/src/scripting/backend/vmbuilder.cpp @@ -606,7 +606,7 @@ size_t VMFunctionBuilder::Emit(int opcode, int opa, int opb, int opc) emit.Free(this); } - if (opcode == OP_CALL || opcode == OP_CALL_K || opcode == OP_TAIL || opcode == OP_TAIL_K) + if (opcode == OP_CALL || opcode == OP_CALL_K) { ParamChange(-opb); } diff --git a/src/scripting/backend/vmdisasm.cpp b/src/scripting/backend/vmdisasm.cpp index 53b8891c1..ebde2ef57 100644 --- a/src/scripting/backend/vmdisasm.cpp +++ b/src/scripting/backend/vmdisasm.cpp @@ -330,7 +330,6 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction break; case OP_CALL_K: - case OP_TAIL_K: { callfunc = (VMFunction *)func->KonstA[code[i].a].o; col = printf_wrapper(out, "[%p],%d", callfunc, code[i].b); @@ -524,7 +523,7 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction { printf_wrapper(out, ",%d\n", code[++i].i24); } - else if (code[i].op == OP_CALL_K || code[i].op == OP_TAIL_K) + else if (code[i].op == OP_CALL_K) { printf_wrapper(out, " [%s]\n", callfunc->PrintableName.GetChars()); } diff --git a/src/scripting/vm/jit_call.cpp b/src/scripting/vm/jit_call.cpp index f8130437b..15dc8b56e 100644 --- a/src/scripting/vm/jit_call.cpp +++ b/src/scripting/vm/jit_call.cpp @@ -132,18 +132,6 @@ void JitCompiler::EmitCALL_K() EmitDoCall(ptr); } -void JitCompiler::EmitTAIL() -{ - EmitDoTail(regA[A]); -} - -void JitCompiler::EmitTAIL_K() -{ - auto ptr = newTempIntPtr(); - cc.mov(ptr, asmjit::imm_ptr(konsta[A].o)); - EmitDoTail(ptr); -} - void JitCompiler::EmitDoCall(asmjit::X86Gp vmfunc) { using namespace asmjit; @@ -185,50 +173,6 @@ void JitCompiler::EmitScriptCall(asmjit::X86Gp vmfunc, asmjit::X86Gp paramsptr) call->setArg(4, Imm(C)); } -void JitCompiler::EmitDoTail(asmjit::X86Gp vmfunc) -{ - // Whereas the CALL instruction uses its third operand to specify how many return values - // it expects, TAIL ignores its third operand and uses whatever was passed to this Exec call. - - // Note: this is not a true tail call, but then again, it isn't in the vmexec implementation either.. - - using namespace asmjit; - - if (NumParam < B) - I_FatalError("OP_TAIL parameter count does not match the number of preceding OP_PARAM instructions"); - - StoreInOuts(B); // Is REGT_ADDROF even allowed for (true) tail calls? - - X86Gp paramsptr = newTempIntPtr(); - cc.lea(paramsptr, x86::ptr(vmframe, offsetParams + (int)((NumParam - B) * sizeof(VMValue)))); - - auto result = newResultInt32(); - - EmitScriptTailCall(vmfunc, result, paramsptr); - - EmitPopFrame(); - cc.ret(result); - - NumParam -= B; - ParamOpcodes.Resize(ParamOpcodes.Size() - B); -} - -void JitCompiler::EmitScriptTailCall(asmjit::X86Gp vmfunc, asmjit::X86Gp result, asmjit::X86Gp paramsptr) -{ - using namespace asmjit; - - auto scriptcall = newTempIntPtr(); - cc.mov(scriptcall, x86::ptr(vmfunc, offsetof(VMScriptFunction, ScriptCall))); - - auto call = cc.call(scriptcall, FuncSignature5()); - call->setRet(0, result); - call->setArg(0, vmfunc); - call->setArg(1, paramsptr); - call->setArg(2, Imm(B)); - call->setArg(3, ret); - call->setArg(4, numret); -} - void JitCompiler::StoreInOuts(int b) { using namespace asmjit; diff --git a/src/scripting/vm/jitintern.h b/src/scripting/vm/jitintern.h index a34488054..34099158a 100644 --- a/src/scripting/vm/jitintern.h +++ b/src/scripting/vm/jitintern.h @@ -55,9 +55,6 @@ private: void EmitDoCall(asmjit::X86Gp ptr); void EmitScriptCall(asmjit::X86Gp vmfunc, asmjit::X86Gp paramsptr); - void EmitDoTail(asmjit::X86Gp ptr); - void EmitScriptTailCall(asmjit::X86Gp vmfunc, asmjit::X86Gp result, asmjit::X86Gp paramsptr); - void StoreInOuts(int b); void LoadInOuts(int b); void LoadReturns(const VMOP *retval, int numret); diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index e7735c5cb..c910d61b9 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -718,45 +718,6 @@ static int ExecScriptFunc(VMFrameStack *stack, VMReturn *ret, int numret) pc += C; // Skip RESULTs } NEXTOP; - OP(TAIL_K): - ASSERTKA(a); - ptr = konsta[a].o; - goto Do_TAILCALL; - OP(TAIL): - ASSERTA(a); - ptr = reg.a[a]; - Do_TAILCALL: - // Whereas the CALL instruction uses its third operand to specify how many return values - // it expects, TAIL ignores its third operand and uses whatever was passed to this Exec call. - assert(B <= f->NumParam); - assert(C <= MAX_RETURNS); - { - VMFunction *call = (VMFunction *)ptr; - - if (call->VarFlags & VARF_Native) - { - try - { - VMCycles[0].Unclock(); - auto r = static_cast(call)->NativeCall(reg.param + f->NumParam - B, B, ret, numret); - VMCycles[0].Clock(); - return r; - } - catch (CVMAbortException &err) - { - err.MaybePrintMessage(); - err.stacktrace.AppendFormat("Called from %s\n", call->PrintableName.GetChars()); - // PrintParameters(reg.param + f->NumParam - B, B); - throw; - } - } - else - { // FIXME: Not a true tail call - auto sfunc = static_cast(call); - return sfunc->ScriptCall(sfunc, reg.param + f->NumParam - B, B, ret, numret); - } - } - NEXTOP; OP(RET): if (B == REGT_NIL) { // No return values diff --git a/src/scripting/vm/vmops.h b/src/scripting/vm/vmops.h index afa0dbfa9..a4e623e9b 100644 --- a/src/scripting/vm/vmops.h +++ b/src/scripting/vm/vmops.h @@ -105,8 +105,6 @@ xx(CALL, call, RPI8I8, NOP, 0, 0) // Call function pkA with parameter count B a xx(CALL_K, call, KPI8I8, CALL, 1, REGT_POINTER) xx(VTBL, vtbl, RPRPI8, NOP, 0, 0) // dereferences a virtual method table. xx(SCOPE, scope, RPI8, NOP, 0, 0) // Scope check at runtime. -xx(TAIL, tail, RPI8, NOP, 0, 0) // Call+Ret in a single instruction -xx(TAIL_K, tail, KPI8, TAIL, 1, REGT_POINTER) xx(RESULT, result, __BCP, NOP, 0, 0) // Result should go in register encoded in BC (in caller, after CALL) xx(RET, ret, I8BCP, NOP, 0, 0) // Copy value from register encoded in BC to return value A, possibly returning xx(RETI, reti, I8I16, NOP, 0, 0) // Copy immediate from BC to return value A, possibly returning