- 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)
static int CreateMushroomFunc(VMFunctionBuilder &buildit, int value1, int value2)
static void CreateMushroomFunc(EmitterArray &emitters, int value1, int value2)
{ // A_Mushroom
int typereg = buildit.GetConstantAddress(PClass::FindClass("FatShot"));
buildit.Emit(OP_PARAM, REGT_POINTER | REGT_KONST, typereg); // itemtype
buildit.Emit(OP_PARAMI, 0); // numspawns
buildit.Emit(OP_PARAMI, 1); // flag
// vrange
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;
emitters.AddParameterPointerConst(PClass::FindClass("FatShot")); // itemtype
emitters.AddParameterIntConst(0); // numspawns
emitters.AddParameterIntConst(1); // flag MSF_Classic
emitters.AddParameterFloatConst(value1? DEHToDouble(value1) : 4.0); // vrange
emitters.AddParameterFloatConst(value2? DEHToDouble(value2) : 0.5); // hrange
}
// 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
if (InfoNames[value1-1] == NULL)
if (InfoNames[value1-1] == nullptr)
{
I_Error("No class found for dehackednum %d!\n", value1+1);
return 0;
}
int typereg = buildit.GetConstantAddress(InfoNames[value1-1]);
int heightreg = buildit.GetConstantFloat(value2);
int distreg = buildit.GetConstantFloat(0);
buildit.Emit(OP_PARAM, REGT_POINTER | REGT_KONST, typereg); // itemtype
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;
emitters.AddParameterPointerConst(InfoNames[value1-1]); // itemtype
emitters.AddParameterFloatConst(value2); // distance
emitters.AddParameterFloatConst(0); // height
emitters.AddParameterIntConst(0); // useammo
emitters.AddParameterIntConst(0); // transfer_translation
}
// 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
buildit.Emit(OP_PARAM, REGT_FLOAT | REGT_KONST, buildit.GetConstantFloat(value1)); // angle
return 1;
emitters.AddParameterFloatConst(value1); // angle
}
// 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
buildit.Emit(OP_PARAM, REGT_FLOAT | REGT_KONST, buildit.GetConstantFloat(value1)); // angle
buildit.Emit(OP_PARAMI, 0); // flags
buildit.Emit(OP_PARAMI, AAPTR_DEFAULT); // ptr
return 3;
emitters.AddParameterFloatConst(value1); // angle
emitters.AddParameterIntConst(0); // flags
emitters.AddParameterIntConst(AAPTR_DEFAULT); // ptr
}
// 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
buildit.EmitParamInt(value1); // damage
buildit.EmitParamInt(value2? SoundMap[value2 - 1] : 0); // hit sound
buildit.Emit(OP_PARAMI, 0); // miss sound
buildit.Emit(OP_PARAMI, NAME_None); // damage type
buildit.Emit(OP_PARAMI, true); // bleed
return 5;
emitters.AddParameterIntConst(value1); // damage
emitters.AddParameterIntConst(value2 ? SoundMap[value2 - 1] : 0); // hit sound
emitters.AddParameterIntConst(0); // miss sound
emitters.AddParameterIntConst(NAME_None); // damage type
emitters.AddParameterIntConst(true); // bleed
}
// 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
int float1 = buildit.GetConstantFloat(1);
int attenreg = buildit.GetConstantFloat(value2 ? ATTN_NONE : ATTN_NORM);
buildit.EmitParamInt(SoundMap[value1-1]); // soundid
buildit.Emit(OP_PARAMI, CHAN_BODY); // channel
buildit.Emit(OP_PARAM, REGT_FLOAT | REGT_KONST, float1); // volume
buildit.Emit(OP_PARAMI, false); // looping
buildit.Emit(OP_PARAM, REGT_FLOAT | REGT_KONST, attenreg); // attenuation
buildit.Emit(OP_PARAMI, false); // local
return 6;
emitters.AddParameterIntConst(value1 ? SoundMap[value1 - 1] : 0); // soundid
emitters.AddParameterIntConst(CHAN_BODY); // channel
emitters.AddParameterFloatConst(1); // volume
emitters.AddParameterIntConst(false); // looping
emitters.AddParameterFloatConst(value2 ? ATTN_NONE : ATTN_NORM); // attenuation
emitters.AddParameterIntConst(false); // local
}
// misc1 = state, misc2 = probability
static int CreateRandomJumpFunc(VMFunctionBuilder &buildit, int value1, int value2)
static void CreateRandomJumpFunc(EmitterArray &emitters, int value1, int value2)
{ // A_Jump
int statereg = buildit.GetConstantAddress(FindState(value1));
buildit.EmitParamInt(value2); // maxchance
buildit.Emit(OP_PARAM, REGT_POINTER | REGT_KONST, statereg); // jumpto
return 2;
emitters.AddParameterIntConst(value2); // maxchance
emitters.AddParameterPointerConst(FindState(value1)); // jumpto
}
// 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
// This is the second MBF codepointer that couldn't be translated easily.
// Calling P_TranslateLineDef() here was a simple matter, as was adding an
// extra parameter to A_CallSpecial so as to replicate the LINEDONE stuff,
// but unfortunately DEHACKED lumps are processed before the map translation
// arrays are initialized so this didn't work.
buildit.EmitParamInt(value1); // special
buildit.EmitParamInt(value2); // tag
return 2;
emitters.AddParameterIntConst(value1); // special
emitters.AddParameterIntConst(value2); // tag
}
// 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
// This one does not actually have MBF-style parameters. But since
// we're aliasing it to an extension of A_Explode...
int typereg = buildit.GetConstantAddress(PClass::FindClass(NAME_BulletPuff));
buildit.Emit(OP_PARAMI, -1); // damage
buildit.Emit(OP_PARAMI, -1); // distance
buildit.Emit(OP_PARAMI, 1); // flags (1=XF_HURTSOURCE)
buildit.Emit(OP_PARAMI, 0); // alert
buildit.Emit(OP_PARAMI, 0); // fulldamagedistance
buildit.Emit(OP_PARAMI, 30); // nails
buildit.Emit(OP_PARAMI, 10); // naildamage
buildit.Emit(OP_PARAM, REGT_POINTER | REGT_KONST, typereg); // itemtype
buildit.Emit(OP_PARAMI, NAME_None); // damage type
return 9;
emitters.AddParameterIntConst(-1); // damage
emitters.AddParameterIntConst(-1); // distance
emitters.AddParameterIntConst(1); // flags (1=XF_HURTSOURCE)
emitters.AddParameterIntConst(0); // alert
emitters.AddParameterIntConst(0); // fulldamagedistance
emitters.AddParameterIntConst(30); // nails
emitters.AddParameterIntConst(10); // naildamage
emitters.AddParameterPointerConst(PClass::FindClass(NAME_BulletPuff)); // itemtype
emitters.AddParameterIntConst(NAME_None); // damage type
}
// 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
// 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)
buildit.Registers[REGT_POINTER].Get(numargs);
// Emit code to pass the standard action function parameters.
EmitterArray emitters;
for (int i = 0; i < numargs; i++)
{
buildit.Emit(OP_PARAM, REGT_POINTER, i);
emitters.AddParameterPointer(i, false);
}
// Emit code for action parameters.
int argcount = MBFCodePointerFactories[codepointer](buildit, value1, value2);
buildit.Emit(OP_TAIL_K, buildit.GetConstantAddress(sym->Variants[0].Implementation), numargs + argcount, 0);
MBFCodePointerFactories[codepointer](emitters, value1, value2);
int count = emitters.EmitParameters(&buildit);
buildit.Emit(OP_TAIL_K, buildit.GetConstantAddress(sym->Variants[0].Implementation), count, 0);
// Attach it to the state.
VMScriptFunction *sfunc = new VMScriptFunction;
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;
if (reg.Fixed && reg.Target)
@ -508,36 +508,6 @@ static int EncodeRegType(ExpEmit reg)
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
int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K);
build->Emit(OP_PARAM, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng));
EmitParameter(build, min, ScriptPosition);
EmitParameter(build, max, ScriptPosition);
build->Emit(opcode, build->GetConstantAddress(callfunc), 3, 1);
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)
{
@ -5653,10 +5626,12 @@ ExpEmit FxRandomPick::Emit(VMFunctionBuilder *build)
assert(((PSymbolVMFunction *)sym)->Function != nullptr);
callfunc = ((PSymbolVMFunction *)sym)->Function;
build->Emit(OP_PARAM, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng));
build->EmitParamInt(0);
build->EmitParamInt(choices.Size() - 1);
build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc), 3, 1);
EmitterArray emitters;
emitters.AddParameterPointerConst(rng);
emitters.AddParameterIntConst(0);
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);
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
int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K);
build->Emit(OP_PARAM, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng));
EmitParameter(build, min, ScriptPosition);
EmitParameter(build, max, ScriptPosition);
build->Emit(opcode, build->GetConstantAddress(callfunc), 3, 1);
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)
{
@ -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
int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K);
build->Emit(OP_PARAM, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng));
EmitParameter(build, mask, ScriptPosition);
build->Emit(opcode, build->GetConstantAddress(callfunc), 2, 1);
EmitterArray emitters;
emitters.AddParameterPointerConst(rng);
emitters.AddParameter(build, mask);
int count = emitters.EmitParameters(build);
build->Emit(opcode, build->GetConstantAddress(callfunc), count, 1);
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
int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K);
build->Emit(OP_PARAM, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng));
EmitParameter(build, seed, ScriptPosition);
build->Emit(opcode, build->GetConstantAddress(callfunc), 2, 0);
EmitterArray emitters;
emitters.AddParameterPointerConst(rng);
emitters.AddParameter(build, seed);
int count = emitters.EmitParameters(build);
build->Emit(opcode, build->GetConstantAddress(callfunc), count, 0);
ExpEmit call;
if (EmitTail) call.Final = true;
@ -8642,10 +8625,13 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build)
{
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));
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)
{
FxExpression *argex = ArgList[i];
@ -8653,20 +8639,18 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build)
{
assert(argex->ValueType == TypeName);
assert(argex->isConstant());
build->EmitParamInt(-static_cast<FxConstant *>(argex)->GetValue().GetName());
emitters.AddParameterIntConst(-static_cast<FxConstant *>(argex)->GetValue().GetName());
}
else
{
assert(argex->ValueType->GetRegType() == REGT_INT);
if (argex->isConstant())
{
build->EmitParamInt(static_cast<FxConstant *>(argex)->GetValue().GetInt());
emitters.AddParameterIntConst(static_cast<FxConstant *>(argex)->GetValue().GetInt());
}
else
{
ExpEmit arg(argex->Emit(build));
build->Emit(OP_PARAM, arg.RegType, arg.RegNum);
arg.Free(build);
emitters.AddParameter(build, argex);
}
}
}
@ -8681,16 +8665,18 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build)
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), 2 + i, 0);
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), 2 + i, 1);
build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc), count, 1);
build->Emit(OP_RESULT, 0, REGT_INT, dest.RegNum);
return dest;
}
@ -9079,8 +9065,6 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx)
ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build)
{
TArray<ExpEmit> tempstrings;
assert(build->Registers[REGT_POINTER].GetMostUsed() >= build->NumImplicits);
int count = 0;
@ -9093,7 +9077,6 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build)
{
ArgList.DeleteAndClear();
ArgList.ShrinkToFit();
for (auto & exp : tempstrings) exp.Free(build);
return reg;
}
}
@ -9102,6 +9085,7 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build)
bool staticcall = ((vmfunc->VarFlags & VARF_Final) || vmfunc->VirtualIndex == ~0u || NoVirtual);
count = 0;
EmitterArray emitters;
// Emit code to pass implied parameters
ExpEmit selfemit;
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)
{
// 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;
emitters.AddParameter(selfemit, (selfemit.Fixed && selfemit.Target) || selfemit.RegType == REGT_STRING);
if (Function->Variants[0].Flags & VARF_Action)
{
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.
{
build->Emit(OP_PARAM, REGT_POINTER, 1);
build->Emit(OP_PARAM, REGT_POINTER, 2);
emitters.AddParameterPointer(1, false);
emitters.AddParameterPointer(2, false);
}
else
{
// 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);
build->Emit(OP_PARAM, REGT_POINTER | REGT_KONST, build->GetConstantAddress(nullptr));
emitters.AddParameter(selfemit, (selfemit.Fixed && selfemit.Target) || selfemit.RegType == REGT_STRING);
emitters.AddParameterPointerConst(nullptr);
}
count += 2;
}
if (staticcall) selfemit.Free(build);
}
else staticcall = true;
// Emit code to pass explicit parameters
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.
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)
{
default:
case REGT_INT:
constant = new FxConstant(defaults[i].i, ScriptPosition);
emitters.AddParameterIntConst(defaults[i].i);
break;
case REGT_FLOAT:
constant = new FxConstant(defaults[i].f, ScriptPosition);
emitters.AddParameterFloatConst(defaults[i].f);
break;
case REGT_POINTER:
constant = new FxConstant(defaults[i].a, ScriptPosition);
emitters.AddParameterPointerConst(defaults[i].a);
break;
case REGT_STRING:
constant = new FxConstant(defaults[i].s(), ScriptPosition);
emitters.AddParameterStringConst(defaults[i].s());
break;
}
count += EmitParameter(build, constant, ScriptPosition, &tempstrings);
delete constant;
}
count = emitters.EmitParameters(build);
ArgList.DeleteAndClear();
ArgList.ShrinkToFit();
@ -9200,7 +9171,6 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build)
build->Emit(OP_TAIL_K, funcaddr, count, 0);
ExpEmit call;
call.Final = true;
for (auto & exp : tempstrings) exp.Free(build);
return call;
}
else if (vmfunc->Proto->ReturnTypes.Size() > 0)
@ -9211,13 +9181,11 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build)
else
{ // Call, expecting no results
build->Emit(OP_CALL_K, funcaddr, count, 0);
for (auto & exp : tempstrings) exp.Free(build);
return ExpEmit();
}
}
else
{
selfemit.Free(build);
ExpEmit funcreg(build, REGT_POINTER);
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);
ExpEmit call;
call.Final = true;
for (auto & exp : tempstrings) exp.Free(build);
return call;
}
else if (vmfunc->Proto->ReturnTypes.Size() > 0)
@ -9237,7 +9204,6 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build)
else
{ // Call, expecting no results
build->Emit(OP_CALL, funcreg.RegNum, count, 0);
for (auto & exp : tempstrings) exp.Free(build);
return ExpEmit();
}
}
@ -9247,7 +9213,6 @@ handlereturns:
// Regular call, will not write to ReturnRegs
ExpEmit reg(build, vmfunc->Proto->ReturnTypes[0]->GetRegType(), vmfunc->Proto->ReturnTypes[0]->GetRegCount());
build->Emit(OP_RESULT, 0, EncodeRegType(reg), reg.RegNum);
for (auto & exp : tempstrings) exp.Free(build);
return reg;
}
else
@ -9261,7 +9226,6 @@ handlereturns:
ReturnRegs.Push(reg);
}
}
for (auto & exp : tempstrings) exp.Free(build);
return ExpEmit();
}
@ -10773,9 +10737,10 @@ ExpEmit FxReturnStatement::Emit(VMFunctionBuilder *build)
assert(pstr->mDestructor != nullptr);
ExpEmit reg(build, REGT_POINTER);
build->Emit(OP_ADDA_RK, reg.RegNum, build->FramePointer.RegNum, build->GetConstantInt(build->ConstructedStructs[i]->StackOffset));
build->Emit(OP_PARAM, reg.RegType, reg.RegNum);
build->Emit(OP_CALL_K, build->GetConstantAddress(pstr->mDestructor), 1, 0);
reg.Free(build);
EmitterArray emitters;
emitters.AddParameter(reg, false);
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.
@ -10970,8 +10935,9 @@ ExpEmit FxClassTypeCast::Emit(VMFunctionBuilder *build)
ExpEmit clsname = basex->Emit(build);
assert(!clsname.Konst);
ExpEmit dest(build, REGT_POINTER);
build->Emit(OP_PARAM, clsname.RegType, clsname.RegNum);
build->Emit(OP_PARAM, REGT_POINTER | REGT_KONST, build->GetConstantAddress(const_cast<PClass *>(desttype)));
EmitterArray emitters;
emitters.AddParameter(clsname, false);
emitters.AddParameterPointerConst(const_cast<PClass *>(desttype));
// Call the BuiltinNameToClass function to convert from 'name' to class.
VMFunction *callfunc;
@ -10981,9 +10947,9 @@ ExpEmit FxClassTypeCast::Emit(VMFunctionBuilder *build)
assert(((PSymbolVMFunction *)sym)->Function != nullptr);
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);
clsname.Free(build);
return dest;
}
@ -11079,8 +11045,10 @@ ExpEmit FxClassPtrCast::Emit(VMFunctionBuilder *build)
{
ExpEmit clsname = basex->Emit(build);
build->Emit(OP_PARAM, clsname.RegType, clsname.RegNum);
build->Emit(OP_PARAM, REGT_POINTER | REGT_KONST, build->GetConstantAddress(desttype));
EmitterArray emitters;
emitters.AddParameter(clsname, false);
emitters.AddParameterPointerConst(desttype);
VMFunction *callfunc;
PSymbol *sym = FindBuiltinFunction(NAME_BuiltinClassCast, BuiltinClassCast);
@ -11088,9 +11056,9 @@ ExpEmit FxClassPtrCast::Emit(VMFunctionBuilder *build)
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction)));
assert(((PSymbolVMFunction *)sym)->Function != nullptr);
callfunc = ((PSymbolVMFunction *)sym)->Function;
clsname.Free(build);
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);
return dest;
}
@ -11465,9 +11433,10 @@ ExpEmit FxLocalVariableDeclaration::Emit(VMFunctionBuilder *build)
{
ExpEmit reg(build, REGT_POINTER);
build->Emit(OP_ADDA_RK, reg.RegNum, build->FramePointer.RegNum, build->GetConstantInt(StackOffset));
build->Emit(OP_PARAM, reg.RegType, reg.RegNum);
build->Emit(OP_CALL_K, build->GetConstantAddress(pstr->mConstructor), 1, 0);
reg.Free(build);
EmitterArray emitters;
emitters.AddParameter(reg, false);
int count = emitters.EmitParameters(build);
build->Emit(OP_CALL_K, build->GetConstantAddress(pstr->mConstructor), count, 0);
}
if (pstr->mDestructor != nullptr) build->ConstructedStructs.Push(this);
}
@ -11491,9 +11460,10 @@ void FxLocalVariableDeclaration::Release(VMFunctionBuilder *build)
{
ExpEmit reg(build, REGT_POINTER);
build->Emit(OP_ADDA_RK, reg.RegNum, build->FramePointer.RegNum, build->GetConstantInt(StackOffset));
build->Emit(OP_PARAM, reg.RegType, reg.RegNum);
build->Emit(OP_CALL_K, build->GetConstantAddress(pstr->mDestructor), 1, 0);
reg.Free(build);
EmitterArray emitters;
emitters.AddParameter(reg, false);
int count = emitters.EmitParameters(build);
build->Emit(OP_CALL_K, build->GetConstantAddress(pstr->mDestructor), count, 0);
}
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);
}
//==========================================================================
//
// 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
@ -951,3 +929,112 @@ void FFunctionBuildList::DumpJit()
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, VM_SHALF opbc);
size_t Emit(int opcode, int opabc);
size_t EmitParamInt(int value);
size_t EmitLoadInt(int regnum, int value);
size_t EmitRetInt(int retnum, bool final, int value);
@ -154,4 +153,34 @@ public:
};
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