- changed OP_PARAM handling so that all registers remain allocated until the call instruction and reordered instruction emission so that the param instructions all directly precede the call instruction.

This commit is contained in:
Christoph Oelckers 2018-11-18 01:06:04 +01:00
parent b2c07e731f
commit 983c0c56b1
4 changed files with 273 additions and 209 deletions

View file

@ -634,126 +634,102 @@ static int GetLine (void)
// misc1 = vrange (arg +3), misc2 = hrange (arg+4) // misc1 = vrange (arg +3), misc2 = hrange (arg+4)
static int CreateMushroomFunc(VMFunctionBuilder &buildit, int value1, int value2) static void CreateMushroomFunc(EmitterArray &emitters, int value1, int value2)
{ // A_Mushroom { // A_Mushroom
int typereg = buildit.GetConstantAddress(PClass::FindClass("FatShot")); emitters.AddParameterPointerConst(PClass::FindClass("FatShot")); // itemtype
buildit.Emit(OP_PARAM, REGT_POINTER | REGT_KONST, typereg); // itemtype emitters.AddParameterIntConst(0); // numspawns
buildit.Emit(OP_PARAMI, 0); // numspawns emitters.AddParameterIntConst(1); // flag MSF_Classic
buildit.Emit(OP_PARAMI, 1); // flag emitters.AddParameterFloatConst(value1? DEHToDouble(value1) : 4.0); // vrange
// vrange emitters.AddParameterFloatConst(value2? DEHToDouble(value2) : 0.5); // hrange
buildit.Emit(OP_PARAM, REGT_FLOAT | REGT_KONST, buildit.GetConstantFloat(value1? DEHToDouble(value1) : 4.0));
// hrange
buildit.Emit(OP_PARAM, REGT_FLOAT | REGT_KONST, buildit.GetConstantFloat(value2? DEHToDouble(value2) : 0.5));
return 5;
} }
// misc1 = type (arg +0), misc2 = Z-pos (arg +2) // misc1 = type (arg +0), misc2 = Z-pos (arg +2)
static int CreateSpawnFunc(VMFunctionBuilder &buildit, int value1, int value2) static void CreateSpawnFunc(EmitterArray &emitters, int value1, int value2)
{ // A_SpawnItem { // A_SpawnItem
if (InfoNames[value1-1] == NULL) if (InfoNames[value1-1] == nullptr)
{ {
I_Error("No class found for dehackednum %d!\n", value1+1); I_Error("No class found for dehackednum %d!\n", value1+1);
return 0;
} }
int typereg = buildit.GetConstantAddress(InfoNames[value1-1]); emitters.AddParameterPointerConst(InfoNames[value1-1]); // itemtype
int heightreg = buildit.GetConstantFloat(value2); emitters.AddParameterFloatConst(value2); // distance
int distreg = buildit.GetConstantFloat(0); emitters.AddParameterFloatConst(0); // height
emitters.AddParameterIntConst(0); // useammo
buildit.Emit(OP_PARAM, REGT_POINTER | REGT_KONST, typereg); // itemtype emitters.AddParameterIntConst(0); // transfer_translation
buildit.Emit(OP_PARAM, REGT_FLOAT | REGT_KONST, distreg); // distance
buildit.Emit(OP_PARAM, REGT_FLOAT | REGT_KONST, heightreg); // height
buildit.Emit(OP_PARAMI, 0); // useammo
buildit.Emit(OP_PARAMI, 0); // transfer_translation
return 5;
} }
// misc1 = angle (in degrees) (arg +0 but factor in current actor angle too) // misc1 = angle (in degrees) (arg +0 but factor in current actor angle too)
static int CreateTurnFunc(VMFunctionBuilder &buildit, int value1, int value2) static void CreateTurnFunc(EmitterArray &emitters, int value1, int value2)
{ // A_Turn { // A_Turn
buildit.Emit(OP_PARAM, REGT_FLOAT | REGT_KONST, buildit.GetConstantFloat(value1)); // angle emitters.AddParameterFloatConst(value1); // angle
return 1;
} }
// misc1 = angle (in degrees) (arg +0) // misc1 = angle (in degrees) (arg +0)
static int CreateFaceFunc(VMFunctionBuilder &buildit, int value1, int value2) static void CreateFaceFunc(EmitterArray &emitters, int value1, int value2)
{ // A_FaceTarget { // A_FaceTarget
buildit.Emit(OP_PARAM, REGT_FLOAT | REGT_KONST, buildit.GetConstantFloat(value1)); // angle emitters.AddParameterFloatConst(value1); // angle
buildit.Emit(OP_PARAMI, 0); // flags emitters.AddParameterIntConst(0); // flags
buildit.Emit(OP_PARAMI, AAPTR_DEFAULT); // ptr emitters.AddParameterIntConst(AAPTR_DEFAULT); // ptr
return 3;
} }
// misc1 = damage, misc 2 = sound // misc1 = damage, misc 2 = sound
static int CreateScratchFunc(VMFunctionBuilder &buildit, int value1, int value2) static void CreateScratchFunc(EmitterArray &emitters, int value1, int value2)
{ // A_CustomMeleeAttack { // A_CustomMeleeAttack
buildit.EmitParamInt(value1); // damage emitters.AddParameterIntConst(value1); // damage
buildit.EmitParamInt(value2? SoundMap[value2 - 1] : 0); // hit sound emitters.AddParameterIntConst(value2 ? SoundMap[value2 - 1] : 0); // hit sound
buildit.Emit(OP_PARAMI, 0); // miss sound emitters.AddParameterIntConst(0); // miss sound
buildit.Emit(OP_PARAMI, NAME_None); // damage type emitters.AddParameterIntConst(NAME_None); // damage type
buildit.Emit(OP_PARAMI, true); // bleed emitters.AddParameterIntConst(true); // bleed
return 5;
} }
// misc1 = sound, misc2 = attenuation none (true) or normal (false) // misc1 = sound, misc2 = attenuation none (true) or normal (false)
static int CreatePlaySoundFunc(VMFunctionBuilder &buildit, int value1, int value2) static void CreatePlaySoundFunc(EmitterArray &emitters, int value1, int value2)
{ // A_PlaySound { // A_PlaySound
int float1 = buildit.GetConstantFloat(1); emitters.AddParameterIntConst(value1 ? SoundMap[value1 - 1] : 0); // soundid
int attenreg = buildit.GetConstantFloat(value2 ? ATTN_NONE : ATTN_NORM); emitters.AddParameterIntConst(CHAN_BODY); // channel
emitters.AddParameterFloatConst(1); // volume
buildit.EmitParamInt(SoundMap[value1-1]); // soundid emitters.AddParameterIntConst(false); // looping
buildit.Emit(OP_PARAMI, CHAN_BODY); // channel emitters.AddParameterFloatConst(value2 ? ATTN_NONE : ATTN_NORM); // attenuation
buildit.Emit(OP_PARAM, REGT_FLOAT | REGT_KONST, float1); // volume emitters.AddParameterIntConst(false); // local
buildit.Emit(OP_PARAMI, false); // looping
buildit.Emit(OP_PARAM, REGT_FLOAT | REGT_KONST, attenreg); // attenuation
buildit.Emit(OP_PARAMI, false); // local
return 6;
} }
// misc1 = state, misc2 = probability // misc1 = state, misc2 = probability
static int CreateRandomJumpFunc(VMFunctionBuilder &buildit, int value1, int value2) static void CreateRandomJumpFunc(EmitterArray &emitters, int value1, int value2)
{ // A_Jump { // A_Jump
int statereg = buildit.GetConstantAddress(FindState(value1)); emitters.AddParameterIntConst(value2); // maxchance
emitters.AddParameterPointerConst(FindState(value1)); // jumpto
buildit.EmitParamInt(value2); // maxchance
buildit.Emit(OP_PARAM, REGT_POINTER | REGT_KONST, statereg); // jumpto
return 2;
} }
// misc1 = Boom linedef type, misc2 = sector tag // misc1 = Boom linedef type, misc2 = sector tag
static int CreateLineEffectFunc(VMFunctionBuilder &buildit, int value1, int value2) static void CreateLineEffectFunc(EmitterArray &emitters, int value1, int value2)
{ // A_LineEffect { // A_LineEffect
// This is the second MBF codepointer that couldn't be translated easily. // This is the second MBF codepointer that couldn't be translated easily.
// Calling P_TranslateLineDef() here was a simple matter, as was adding an // Calling P_TranslateLineDef() here was a simple matter, as was adding an
// extra parameter to A_CallSpecial so as to replicate the LINEDONE stuff, // extra parameter to A_CallSpecial so as to replicate the LINEDONE stuff,
// but unfortunately DEHACKED lumps are processed before the map translation // but unfortunately DEHACKED lumps are processed before the map translation
// arrays are initialized so this didn't work. // arrays are initialized so this didn't work.
buildit.EmitParamInt(value1); // special emitters.AddParameterIntConst(value1); // special
buildit.EmitParamInt(value2); // tag emitters.AddParameterIntConst(value2); // tag
return 2;
} }
// No misc, but it's basically A_Explode with an added effect // No misc, but it's basically A_Explode with an added effect
static int CreateNailBombFunc(VMFunctionBuilder &buildit, int value1, int value2) static void CreateNailBombFunc(EmitterArray &emitters, int value1, int value2)
{ // A_Explode { // A_Explode
// This one does not actually have MBF-style parameters. But since // This one does not actually have MBF-style parameters. But since
// we're aliasing it to an extension of A_Explode... // we're aliasing it to an extension of A_Explode...
int typereg = buildit.GetConstantAddress(PClass::FindClass(NAME_BulletPuff)); emitters.AddParameterIntConst(-1); // damage
buildit.Emit(OP_PARAMI, -1); // damage emitters.AddParameterIntConst(-1); // distance
buildit.Emit(OP_PARAMI, -1); // distance emitters.AddParameterIntConst(1); // flags (1=XF_HURTSOURCE)
buildit.Emit(OP_PARAMI, 1); // flags (1=XF_HURTSOURCE) emitters.AddParameterIntConst(0); // alert
buildit.Emit(OP_PARAMI, 0); // alert emitters.AddParameterIntConst(0); // fulldamagedistance
buildit.Emit(OP_PARAMI, 0); // fulldamagedistance emitters.AddParameterIntConst(30); // nails
buildit.Emit(OP_PARAMI, 30); // nails emitters.AddParameterIntConst(10); // naildamage
buildit.Emit(OP_PARAMI, 10); // naildamage emitters.AddParameterPointerConst(PClass::FindClass(NAME_BulletPuff)); // itemtype
buildit.Emit(OP_PARAM, REGT_POINTER | REGT_KONST, typereg); // itemtype emitters.AddParameterIntConst(NAME_None); // damage type
buildit.Emit(OP_PARAMI, NAME_None); // damage type
return 9;
} }
// This array must be in sync with the Aliases array in DEHSUPP. // This array must be in sync with the Aliases array in DEHSUPP.
static int (*MBFCodePointerFactories[])(VMFunctionBuilder&, int, int) = static void (*MBFCodePointerFactories[])(EmitterArray&, int, int) =
{ {
// Die and Detonate are not in this list because these codepointers have // Die and Detonate are not in this list because these codepointers have
// no dehacked arguments and therefore do not need special handling. // no dehacked arguments and therefore do not need special handling.
@ -800,13 +776,15 @@ void SetDehParams(FState *state, int codepointer)
// self, stateowner, state (all are pointers) // self, stateowner, state (all are pointers)
buildit.Registers[REGT_POINTER].Get(numargs); buildit.Registers[REGT_POINTER].Get(numargs);
// Emit code to pass the standard action function parameters. // Emit code to pass the standard action function parameters.
EmitterArray emitters;
for (int i = 0; i < numargs; i++) for (int i = 0; i < numargs; i++)
{ {
buildit.Emit(OP_PARAM, REGT_POINTER, i); emitters.AddParameterPointer(i, false);
} }
// Emit code for action parameters. // Emit code for action parameters.
int argcount = MBFCodePointerFactories[codepointer](buildit, value1, value2); MBFCodePointerFactories[codepointer](emitters, value1, value2);
buildit.Emit(OP_TAIL_K, buildit.GetConstantAddress(sym->Variants[0].Implementation), numargs + argcount, 0); int count = emitters.EmitParameters(&buildit);
buildit.Emit(OP_TAIL_K, buildit.GetConstantAddress(sym->Variants[0].Implementation), count, 0);
// Attach it to the state. // Attach it to the state.
VMScriptFunction *sfunc = new VMScriptFunction; VMScriptFunction *sfunc = new VMScriptFunction;
buildit.MakeFunction(sfunc); buildit.MakeFunction(sfunc);

View file

@ -485,7 +485,7 @@ PPrototype *FxExpression::ReturnProto()
// //
//========================================================================== //==========================================================================
static int EncodeRegType(ExpEmit reg) int EncodeRegType(ExpEmit reg)
{ {
int regtype = reg.RegType; int regtype = reg.RegType;
if (reg.Fixed && reg.Target) if (reg.Fixed && reg.Target)
@ -508,36 +508,6 @@ static int EncodeRegType(ExpEmit reg)
return regtype; return regtype;
} }
//==========================================================================
//
//
//
//==========================================================================
static int EmitParameter(VMFunctionBuilder *build, FxExpression *operand, const FScriptPosition &pos, TArray<ExpEmit> *tempstrings = nullptr)
{
ExpEmit where = operand->Emit(build);
if (where.RegType == REGT_NIL)
{
pos.Message(MSG_ERROR, "Attempted to pass a non-value");
build->Emit(OP_PARAM, where.RegType, where.RegNum);
return 1;
}
else
{
build->Emit(OP_PARAM, EncodeRegType(where), where.RegNum);
if (tempstrings != nullptr && where.RegType == REGT_STRING && !where.Fixed && !where.Konst)
{
tempstrings->Push(where); // keep temp strings until after the function call.
}
else
{
where.Free(build);
}
return where.RegCount;
}
}
//========================================================================== //==========================================================================
// //
@ -5539,10 +5509,13 @@ ExpEmit FxRandom::Emit(VMFunctionBuilder *build)
if (build->FramePointer.Fixed) EmitTail = false; // do not tail call if the stack is in use 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); int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K);
build->Emit(OP_PARAM, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng)); EmitterArray emitters;
EmitParameter(build, min, ScriptPosition);
EmitParameter(build, max, ScriptPosition); emitters.AddParameterPointerConst(rng);
build->Emit(opcode, build->GetConstantAddress(callfunc), 3, 1); emitters.AddParameter(build, min);
emitters.AddParameter(build, max);
int count = emitters.EmitParameters(build);
build->Emit(opcode, build->GetConstantAddress(callfunc), count, 1);
if (EmitTail) if (EmitTail)
{ {
@ -5653,10 +5626,12 @@ ExpEmit FxRandomPick::Emit(VMFunctionBuilder *build)
assert(((PSymbolVMFunction *)sym)->Function != nullptr); assert(((PSymbolVMFunction *)sym)->Function != nullptr);
callfunc = ((PSymbolVMFunction *)sym)->Function; callfunc = ((PSymbolVMFunction *)sym)->Function;
build->Emit(OP_PARAM, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng)); EmitterArray emitters;
build->EmitParamInt(0); emitters.AddParameterPointerConst(rng);
build->EmitParamInt(choices.Size() - 1); emitters.AddParameterIntConst(0);
build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc), 3, 1); emitters.AddParameterIntConst(choices.Size() - 1);
int count = emitters.EmitParameters(build);
build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc), count, 1);
ExpEmit resultreg(build, REGT_INT); ExpEmit resultreg(build, REGT_INT);
build->Emit(OP_RESULT, 0, REGT_INT, resultreg.RegNum); build->Emit(OP_RESULT, 0, REGT_INT, resultreg.RegNum);
@ -5775,10 +5750,12 @@ ExpEmit FxFRandom::Emit(VMFunctionBuilder *build)
if (build->FramePointer.Fixed) EmitTail = false; // do not tail call if the stack is in use 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); int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K);
build->Emit(OP_PARAM, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng)); EmitterArray emitters;
EmitParameter(build, min, ScriptPosition); emitters.AddParameterPointerConst(rng);
EmitParameter(build, max, ScriptPosition); emitters.AddParameter(build, min);
build->Emit(opcode, build->GetConstantAddress(callfunc), 3, 1); emitters.AddParameter(build, max);
int count = emitters.EmitParameters(build);
build->Emit(opcode, build->GetConstantAddress(callfunc), count, 1);
if (EmitTail) if (EmitTail)
{ {
@ -5877,9 +5854,12 @@ ExpEmit FxRandom2::Emit(VMFunctionBuilder *build)
if (build->FramePointer.Fixed) EmitTail = false; // do not tail call if the stack is in use 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); int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K);
build->Emit(OP_PARAM, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng)); EmitterArray emitters;
EmitParameter(build, mask, ScriptPosition);
build->Emit(opcode, build->GetConstantAddress(callfunc), 2, 1); emitters.AddParameterPointerConst(rng);
emitters.AddParameter(build, mask);
int count = emitters.EmitParameters(build);
build->Emit(opcode, build->GetConstantAddress(callfunc), count, 1);
if (EmitTail) if (EmitTail)
{ {
@ -5960,9 +5940,12 @@ ExpEmit FxRandomSeed::Emit(VMFunctionBuilder *build)
if (build->FramePointer.Fixed) EmitTail = false; // do not tail call if the stack is in use 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); int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K);
build->Emit(OP_PARAM, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng)); EmitterArray emitters;
EmitParameter(build, seed, ScriptPosition);
build->Emit(opcode, build->GetConstantAddress(callfunc), 2, 0); emitters.AddParameterPointerConst(rng);
emitters.AddParameter(build, seed);
int count = emitters.EmitParameters(build);
build->Emit(opcode, build->GetConstantAddress(callfunc), count, 0);
ExpEmit call; ExpEmit call;
if (EmitTail) call.Final = true; if (EmitTail) call.Final = true;
@ -8642,10 +8625,13 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build)
{ {
unsigned i = 0; unsigned i = 0;
build->Emit(OP_PARAMI, abs(Special)); // pass special number EmitterArray emitters;
emitters.AddParameterIntConst(abs(Special)); // pass special number
ExpEmit selfemit(Self->Emit(build)); ExpEmit selfemit(Self->Emit(build));
build->Emit(OP_PARAM, selfemit.Konst ? REGT_POINTER | REGT_KONST : REGT_POINTER, selfemit.RegNum); // pass special number emitters.AddParameterPointer(selfemit.RegNum, selfemit.Konst);
for (; i < ArgList.Size(); ++i) for (; i < ArgList.Size(); ++i)
{ {
FxExpression *argex = ArgList[i]; FxExpression *argex = ArgList[i];
@ -8653,20 +8639,18 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build)
{ {
assert(argex->ValueType == TypeName); assert(argex->ValueType == TypeName);
assert(argex->isConstant()); assert(argex->isConstant());
build->EmitParamInt(-static_cast<FxConstant *>(argex)->GetValue().GetName()); emitters.AddParameterIntConst(-static_cast<FxConstant *>(argex)->GetValue().GetName());
} }
else else
{ {
assert(argex->ValueType->GetRegType() == REGT_INT); assert(argex->ValueType->GetRegType() == REGT_INT);
if (argex->isConstant()) if (argex->isConstant())
{ {
build->EmitParamInt(static_cast<FxConstant *>(argex)->GetValue().GetInt()); emitters.AddParameterIntConst(static_cast<FxConstant *>(argex)->GetValue().GetInt());
} }
else else
{ {
ExpEmit arg(argex->Emit(build)); emitters.AddParameter(build, argex);
build->Emit(OP_PARAM, arg.RegType, arg.RegNum);
arg.Free(build);
} }
} }
} }
@ -8681,16 +8665,18 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build)
ArgList.ShrinkToFit(); ArgList.ShrinkToFit();
if (build->FramePointer.Fixed) EmitTail = false; // do not tail call if the stack is in use 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) if (EmitTail)
{ {
build->Emit(OP_TAIL_K, build->GetConstantAddress(callfunc), 2 + i, 0); build->Emit(OP_TAIL_K, build->GetConstantAddress(callfunc), count, 0);
ExpEmit call; ExpEmit call;
call.Final = true; call.Final = true;
return call; return call;
} }
ExpEmit dest(build, REGT_INT); ExpEmit dest(build, REGT_INT);
build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc), 2 + i, 1); build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc), count, 1);
build->Emit(OP_RESULT, 0, REGT_INT, dest.RegNum); build->Emit(OP_RESULT, 0, REGT_INT, dest.RegNum);
return dest; return dest;
} }
@ -9079,8 +9065,6 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx)
ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build)
{ {
TArray<ExpEmit> tempstrings;
assert(build->Registers[REGT_POINTER].GetMostUsed() >= build->NumImplicits); assert(build->Registers[REGT_POINTER].GetMostUsed() >= build->NumImplicits);
int count = 0; int count = 0;
@ -9093,7 +9077,6 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build)
{ {
ArgList.DeleteAndClear(); ArgList.DeleteAndClear();
ArgList.ShrinkToFit(); ArgList.ShrinkToFit();
for (auto & exp : tempstrings) exp.Free(build);
return reg; return reg;
} }
} }
@ -9102,6 +9085,7 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build)
bool staticcall = ((vmfunc->VarFlags & VARF_Final) || vmfunc->VirtualIndex == ~0u || NoVirtual); bool staticcall = ((vmfunc->VarFlags & VARF_Final) || vmfunc->VirtualIndex == ~0u || NoVirtual);
count = 0; count = 0;
EmitterArray emitters;
// Emit code to pass implied parameters // Emit code to pass implied parameters
ExpEmit selfemit; ExpEmit selfemit;
if (Function->Variants[0].Flags & VARF_Method) if (Function->Variants[0].Flags & VARF_Method)
@ -9128,64 +9112,51 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build)
} }
} }
if ((selfemit.Fixed && selfemit.Target) || selfemit.RegType == REGT_STRING) emitters.AddParameter(selfemit, (selfemit.Fixed && selfemit.Target) || selfemit.RegType == REGT_STRING);
{
// Address of a local variable.
build->Emit(OP_PARAM, selfemit.RegType | REGT_ADDROF, selfemit.RegNum);
}
else
{
build->Emit(OP_PARAM, selfemit.RegType, selfemit.RegNum);
}
count += 1;
if (Function->Variants[0].Flags & VARF_Action) if (Function->Variants[0].Flags & VARF_Action)
{ {
static_assert(NAP == 3, "This code needs to be updated if NAP changes"); static_assert(NAP == 3, "This code needs to be updated if NAP changes");
if (build->NumImplicits == NAP && selfemit.RegNum == 0) // only pass this function's stateowner and stateinfo if the subfunction is run in self's context. if (build->NumImplicits == NAP && selfemit.RegNum == 0) // only pass this function's stateowner and stateinfo if the subfunction is run in self's context.
{ {
build->Emit(OP_PARAM, REGT_POINTER, 1); emitters.AddParameterPointer(1, false);
build->Emit(OP_PARAM, REGT_POINTER, 2); emitters.AddParameterPointer(2, false);
} }
else else
{ {
// pass self as stateowner, otherwise all attempts of the subfunction to retrieve a state from a name would fail. // pass self as stateowner, otherwise all attempts of the subfunction to retrieve a state from a name would fail.
build->Emit(OP_PARAM, selfemit.RegType, selfemit.RegNum); emitters.AddParameter(selfemit, (selfemit.Fixed && selfemit.Target) || selfemit.RegType == REGT_STRING);
build->Emit(OP_PARAM, REGT_POINTER | REGT_KONST, build->GetConstantAddress(nullptr)); emitters.AddParameterPointerConst(nullptr);
} }
count += 2;
} }
if (staticcall) selfemit.Free(build);
} }
else staticcall = true; else staticcall = true;
// Emit code to pass explicit parameters // Emit code to pass explicit parameters
for (unsigned i = 0; i < ArgList.Size(); ++i) for (unsigned i = 0; i < ArgList.Size(); ++i)
{ {
count += EmitParameter(build, ArgList[i], ScriptPosition, &tempstrings); emitters.AddParameter(build, ArgList[i]);
} }
// Complete the parameter list from the defaults. // Complete the parameter list from the defaults.
auto &defaults = Function->Variants[0].Implementation->DefaultArgs; auto &defaults = Function->Variants[0].Implementation->DefaultArgs;
for (unsigned i = count; i < defaults.Size(); i++) for (unsigned i = emitters.Count(); i < defaults.Size(); i++)
{ {
FxConstant *constant;
switch (defaults[i].Type) switch (defaults[i].Type)
{ {
default: default:
case REGT_INT: case REGT_INT:
constant = new FxConstant(defaults[i].i, ScriptPosition); emitters.AddParameterIntConst(defaults[i].i);
break; break;
case REGT_FLOAT: case REGT_FLOAT:
constant = new FxConstant(defaults[i].f, ScriptPosition); emitters.AddParameterFloatConst(defaults[i].f);
break; break;
case REGT_POINTER: case REGT_POINTER:
constant = new FxConstant(defaults[i].a, ScriptPosition); emitters.AddParameterPointerConst(defaults[i].a);
break; break;
case REGT_STRING: case REGT_STRING:
constant = new FxConstant(defaults[i].s(), ScriptPosition); emitters.AddParameterStringConst(defaults[i].s());
break; break;
} }
count += EmitParameter(build, constant, ScriptPosition, &tempstrings);
delete constant;
} }
count = emitters.EmitParameters(build);
ArgList.DeleteAndClear(); ArgList.DeleteAndClear();
ArgList.ShrinkToFit(); ArgList.ShrinkToFit();
@ -9200,7 +9171,6 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build)
build->Emit(OP_TAIL_K, funcaddr, count, 0); build->Emit(OP_TAIL_K, funcaddr, count, 0);
ExpEmit call; ExpEmit call;
call.Final = true; call.Final = true;
for (auto & exp : tempstrings) exp.Free(build);
return call; return call;
} }
else if (vmfunc->Proto->ReturnTypes.Size() > 0) else if (vmfunc->Proto->ReturnTypes.Size() > 0)
@ -9211,13 +9181,11 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build)
else else
{ // Call, expecting no results { // Call, expecting no results
build->Emit(OP_CALL_K, funcaddr, count, 0); build->Emit(OP_CALL_K, funcaddr, count, 0);
for (auto & exp : tempstrings) exp.Free(build);
return ExpEmit(); return ExpEmit();
} }
} }
else else
{ {
selfemit.Free(build);
ExpEmit funcreg(build, REGT_POINTER); ExpEmit funcreg(build, REGT_POINTER);
build->Emit(OP_VTBL, funcreg.RegNum, selfemit.RegNum, vmfunc->VirtualIndex); build->Emit(OP_VTBL, funcreg.RegNum, selfemit.RegNum, vmfunc->VirtualIndex);
@ -9226,7 +9194,6 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build)
build->Emit(OP_TAIL, funcreg.RegNum, count, 0); build->Emit(OP_TAIL, funcreg.RegNum, count, 0);
ExpEmit call; ExpEmit call;
call.Final = true; call.Final = true;
for (auto & exp : tempstrings) exp.Free(build);
return call; return call;
} }
else if (vmfunc->Proto->ReturnTypes.Size() > 0) else if (vmfunc->Proto->ReturnTypes.Size() > 0)
@ -9237,7 +9204,6 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build)
else else
{ // Call, expecting no results { // Call, expecting no results
build->Emit(OP_CALL, funcreg.RegNum, count, 0); build->Emit(OP_CALL, funcreg.RegNum, count, 0);
for (auto & exp : tempstrings) exp.Free(build);
return ExpEmit(); return ExpEmit();
} }
} }
@ -9247,7 +9213,6 @@ handlereturns:
// Regular call, will not write to ReturnRegs // Regular call, will not write to ReturnRegs
ExpEmit reg(build, vmfunc->Proto->ReturnTypes[0]->GetRegType(), vmfunc->Proto->ReturnTypes[0]->GetRegCount()); ExpEmit reg(build, vmfunc->Proto->ReturnTypes[0]->GetRegType(), vmfunc->Proto->ReturnTypes[0]->GetRegCount());
build->Emit(OP_RESULT, 0, EncodeRegType(reg), reg.RegNum); build->Emit(OP_RESULT, 0, EncodeRegType(reg), reg.RegNum);
for (auto & exp : tempstrings) exp.Free(build);
return reg; return reg;
} }
else else
@ -9261,7 +9226,6 @@ handlereturns:
ReturnRegs.Push(reg); ReturnRegs.Push(reg);
} }
} }
for (auto & exp : tempstrings) exp.Free(build);
return ExpEmit(); return ExpEmit();
} }
@ -10773,9 +10737,10 @@ ExpEmit FxReturnStatement::Emit(VMFunctionBuilder *build)
assert(pstr->mDestructor != nullptr); assert(pstr->mDestructor != nullptr);
ExpEmit reg(build, REGT_POINTER); ExpEmit reg(build, REGT_POINTER);
build->Emit(OP_ADDA_RK, reg.RegNum, build->FramePointer.RegNum, build->GetConstantInt(build->ConstructedStructs[i]->StackOffset)); build->Emit(OP_ADDA_RK, reg.RegNum, build->FramePointer.RegNum, build->GetConstantInt(build->ConstructedStructs[i]->StackOffset));
build->Emit(OP_PARAM, reg.RegType, reg.RegNum); EmitterArray emitters;
build->Emit(OP_CALL_K, build->GetConstantAddress(pstr->mDestructor), 1, 0); emitters.AddParameter(reg, false);
reg.Free(build); int count = emitters.EmitParameters(build);
build->Emit(OP_CALL_K, build->GetConstantAddress(pstr->mDestructor), count, 0);
} }
// If we return nothing, use a regular RET opcode. // If we return nothing, use a regular RET opcode.
@ -10970,8 +10935,9 @@ ExpEmit FxClassTypeCast::Emit(VMFunctionBuilder *build)
ExpEmit clsname = basex->Emit(build); ExpEmit clsname = basex->Emit(build);
assert(!clsname.Konst); assert(!clsname.Konst);
ExpEmit dest(build, REGT_POINTER); ExpEmit dest(build, REGT_POINTER);
build->Emit(OP_PARAM, clsname.RegType, clsname.RegNum); EmitterArray emitters;
build->Emit(OP_PARAM, REGT_POINTER | REGT_KONST, build->GetConstantAddress(const_cast<PClass *>(desttype))); emitters.AddParameter(clsname, false);
emitters.AddParameterPointerConst(const_cast<PClass *>(desttype));
// Call the BuiltinNameToClass function to convert from 'name' to class. // Call the BuiltinNameToClass function to convert from 'name' to class.
VMFunction *callfunc; VMFunction *callfunc;
@ -10981,9 +10947,9 @@ ExpEmit FxClassTypeCast::Emit(VMFunctionBuilder *build)
assert(((PSymbolVMFunction *)sym)->Function != nullptr); assert(((PSymbolVMFunction *)sym)->Function != nullptr);
callfunc = ((PSymbolVMFunction *)sym)->Function; callfunc = ((PSymbolVMFunction *)sym)->Function;
build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc), 2, 1); int count = emitters.EmitParameters(build);
build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc), count, 1);
build->Emit(OP_RESULT, 0, REGT_POINTER, dest.RegNum); build->Emit(OP_RESULT, 0, REGT_POINTER, dest.RegNum);
clsname.Free(build);
return dest; return dest;
} }
@ -11079,8 +11045,10 @@ ExpEmit FxClassPtrCast::Emit(VMFunctionBuilder *build)
{ {
ExpEmit clsname = basex->Emit(build); ExpEmit clsname = basex->Emit(build);
build->Emit(OP_PARAM, clsname.RegType, clsname.RegNum); EmitterArray emitters;
build->Emit(OP_PARAM, REGT_POINTER | REGT_KONST, build->GetConstantAddress(desttype));
emitters.AddParameter(clsname, false);
emitters.AddParameterPointerConst(desttype);
VMFunction *callfunc; VMFunction *callfunc;
PSymbol *sym = FindBuiltinFunction(NAME_BuiltinClassCast, BuiltinClassCast); PSymbol *sym = FindBuiltinFunction(NAME_BuiltinClassCast, BuiltinClassCast);
@ -11088,9 +11056,9 @@ ExpEmit FxClassPtrCast::Emit(VMFunctionBuilder *build)
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction)));
assert(((PSymbolVMFunction *)sym)->Function != nullptr); assert(((PSymbolVMFunction *)sym)->Function != nullptr);
callfunc = ((PSymbolVMFunction *)sym)->Function; callfunc = ((PSymbolVMFunction *)sym)->Function;
clsname.Free(build);
ExpEmit dest(build, REGT_POINTER); ExpEmit dest(build, REGT_POINTER);
build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc), 2, 1); int count = emitters.EmitParameters(build);
build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc), count, 1);
build->Emit(OP_RESULT, 0, REGT_POINTER, dest.RegNum); build->Emit(OP_RESULT, 0, REGT_POINTER, dest.RegNum);
return dest; return dest;
} }
@ -11465,9 +11433,10 @@ ExpEmit FxLocalVariableDeclaration::Emit(VMFunctionBuilder *build)
{ {
ExpEmit reg(build, REGT_POINTER); ExpEmit reg(build, REGT_POINTER);
build->Emit(OP_ADDA_RK, reg.RegNum, build->FramePointer.RegNum, build->GetConstantInt(StackOffset)); build->Emit(OP_ADDA_RK, reg.RegNum, build->FramePointer.RegNum, build->GetConstantInt(StackOffset));
build->Emit(OP_PARAM, reg.RegType, reg.RegNum); EmitterArray emitters;
build->Emit(OP_CALL_K, build->GetConstantAddress(pstr->mConstructor), 1, 0); emitters.AddParameter(reg, false);
reg.Free(build); int count = emitters.EmitParameters(build);
build->Emit(OP_CALL_K, build->GetConstantAddress(pstr->mConstructor), count, 0);
} }
if (pstr->mDestructor != nullptr) build->ConstructedStructs.Push(this); if (pstr->mDestructor != nullptr) build->ConstructedStructs.Push(this);
} }
@ -11491,9 +11460,10 @@ void FxLocalVariableDeclaration::Release(VMFunctionBuilder *build)
{ {
ExpEmit reg(build, REGT_POINTER); ExpEmit reg(build, REGT_POINTER);
build->Emit(OP_ADDA_RK, reg.RegNum, build->FramePointer.RegNum, build->GetConstantInt(StackOffset)); build->Emit(OP_ADDA_RK, reg.RegNum, build->FramePointer.RegNum, build->GetConstantInt(StackOffset));
build->Emit(OP_PARAM, reg.RegType, reg.RegNum); EmitterArray emitters;
build->Emit(OP_CALL_K, build->GetConstantAddress(pstr->mDestructor), 1, 0); emitters.AddParameter(reg, false);
reg.Free(build); int count = emitters.EmitParameters(build);
build->Emit(OP_CALL_K, build->GetConstantAddress(pstr->mDestructor), count, 0);
} }
build->ConstructedStructs.Delete(build->ConstructedStructs.Find(this)); build->ConstructedStructs.Delete(build->ConstructedStructs.Find(this));
} }

View file

@ -654,28 +654,6 @@ size_t VMFunctionBuilder::Emit(int opcode, int opabc)
return Code.Push(op); return Code.Push(op);
} }
//==========================================================================
//
// VMFunctionBuilder :: EmitParamInt
//
// Passes a constant integer parameter, using either PARAMI and an immediate
// value or PARAM and a constant register, as appropriate.
//
//==========================================================================
size_t VMFunctionBuilder::EmitParamInt(int value)
{
// Immediates for PARAMI must fit in 24 bits.
if (((value << 8) >> 8) == value)
{
return Emit(OP_PARAMI, value);
}
else
{
return Emit(OP_PARAM, REGT_INT | REGT_KONST, GetConstantInt(value));
}
}
//========================================================================== //==========================================================================
// //
// VMFunctionBuilder :: EmitLoadInt // VMFunctionBuilder :: EmitLoadInt
@ -951,3 +929,112 @@ void FFunctionBuildList::DumpJit()
fclose(dump); fclose(dump);
} }
void EmitterArray::AddParameter(VMFunctionBuilder *build, FxExpression *operand)
{
ExpEmit where = operand->Emit(build);
if (where.RegType == REGT_NIL)
{
operand->ScriptPosition.Message(MSG_ERROR, "Attempted to pass a non-value");
}
numparams += where.RegCount;
emitters.push_back([=](VMFunctionBuilder *build) -> int
{
auto op = where;
if (op.RegType == REGT_NIL)
{
build->Emit(OP_PARAM, op.RegType, op.RegNum);
return 1;
}
else
{
build->Emit(OP_PARAM, EncodeRegType(op), op.RegNum);
op.Free(build);
return op.RegCount;
}
});
}
void EmitterArray::AddParameter(ExpEmit &emit, bool reference)
{
numparams += emit.RegCount;
emitters.push_back([=](VMFunctionBuilder *build) ->int
{
build->Emit(OP_PARAM, emit.RegType + (reference * REGT_ADDROF), emit.RegNum);
auto op = emit;
op.Free(build);
return emit.RegCount;
});
}
void EmitterArray::AddParameterPointerConst(void *konst)
{
numparams++;
emitters.push_back([=](VMFunctionBuilder *build) ->int
{
build->Emit(OP_PARAM, REGT_POINTER | REGT_KONST, build->GetConstantAddress(konst));
return 1;
});
}
void EmitterArray::AddParameterPointer(int index, bool konst)
{
numparams++;
emitters.push_back([=](VMFunctionBuilder *build) ->int
{
build->Emit(OP_PARAM, konst ? REGT_POINTER | REGT_KONST : REGT_POINTER, index);
return 1;
});
}
void EmitterArray::AddParameterFloatConst(double konst)
{
numparams++;
emitters.push_back([=](VMFunctionBuilder *build) ->int
{
build->Emit(OP_PARAM, REGT_FLOAT | REGT_KONST, build->GetConstantFloat(konst));
return 1;
});
}
void EmitterArray::AddParameterIntConst(int konst)
{
numparams++;
emitters.push_back([=](VMFunctionBuilder *build) ->int
{
// Immediates for PARAMI must fit in 24 bits.
if (((konst << 8) >> 8) == konst)
{
build->Emit(OP_PARAMI, konst);
}
else
{
build->Emit(OP_PARAM, REGT_INT | REGT_KONST, build->GetConstantInt(konst));
}
return 1;
});
}
void EmitterArray::AddParameterStringConst(const FString &konst)
{
numparams++;
emitters.push_back([=](VMFunctionBuilder *build) ->int
{
build->Emit(OP_PARAM, REGT_STRING | REGT_KONST, build->GetConstantString(konst));
return 1;
});
}
int EmitterArray::EmitParameters(VMFunctionBuilder *build)
{
int paramcount = 0;
for (auto &func : emitters)
{
paramcount += func(build);
}
assert(paramcount == numparams);
return paramcount;
}

View file

@ -68,7 +68,6 @@ public:
size_t Emit(int opcode, int opa, int opb, int opc); size_t Emit(int opcode, int opa, int opb, int opc);
size_t Emit(int opcode, int opa, VM_SHALF opbc); size_t Emit(int opcode, int opa, VM_SHALF opbc);
size_t Emit(int opcode, int opabc); size_t Emit(int opcode, int opabc);
size_t EmitParamInt(int value);
size_t EmitLoadInt(int regnum, int value); size_t EmitLoadInt(int regnum, int value);
size_t EmitRetInt(int retnum, bool final, int value); size_t EmitRetInt(int retnum, bool final, int value);
@ -154,4 +153,34 @@ public:
}; };
extern FFunctionBuildList FunctionBuildList; extern FFunctionBuildList FunctionBuildList;
//==========================================================================
//
// Function call parameter collector
//
//==========================================================================
extern int EncodeRegType(ExpEmit reg);
class EmitterArray
{
// std::function and TArray are not compatible so this has to use std::vector instead.
std::vector<std::function<int(VMFunctionBuilder *)>> emitters;
unsigned numparams = 0;
public:
void AddParameter(VMFunctionBuilder *build, FxExpression *operand);
void AddParameter(ExpEmit &emit, bool reference);
void AddParameterPointerConst(void *konst);
void AddParameterPointer(int index, bool konst);
void AddParameterFloatConst(double konst);
void AddParameterIntConst(int konst);
void AddParameterStringConst(const FString &konst);
int EmitParameters(VMFunctionBuilder *build);
unsigned Count() const
{
return numparams;
}
};
#endif #endif