mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-24 13:01:47 +00:00
- 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:
parent
b2c07e731f
commit
983c0c56b1
4 changed files with 273 additions and 209 deletions
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue