mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-28 15:02:01 +00:00
- cleaned out a large part of unused methods from VMValue.
- keep string registers which are being used as function parameters allocated until after the function call returns. This is for allowing to pass strings by reference which would avoid some costly constructor/destructor loops in the call instruction.
This commit is contained in:
parent
0a11e38967
commit
403c5693a9
4 changed files with 29 additions and 194 deletions
|
@ -503,7 +503,7 @@ static int EncodeRegType(ExpEmit reg)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
static int EmitParameter(VMFunctionBuilder *build, FxExpression *operand, const FScriptPosition &pos)
|
||||
static int EmitParameter(VMFunctionBuilder *build, FxExpression *operand, const FScriptPosition &pos, TArray<ExpEmit> *tempstrings = nullptr)
|
||||
{
|
||||
ExpEmit where = operand->Emit(build);
|
||||
|
||||
|
@ -516,7 +516,14 @@ static int EmitParameter(VMFunctionBuilder *build, FxExpression *operand, const
|
|||
else
|
||||
{
|
||||
build->Emit(OP_PARAM, 0, EncodeRegType(where), where.RegNum);
|
||||
where.Free(build);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -6581,18 +6588,6 @@ FxClassDefaults::~FxClassDefaults()
|
|||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
PPrototype *FxClassDefaults::ReturnProto()
|
||||
{
|
||||
EmitTail = true;
|
||||
return FxExpression::ReturnProto();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
|
@ -8572,7 +8567,6 @@ FxVMFunctionCall::FxVMFunctionCall(FxExpression *self, PFunction *func, FArgumen
|
|||
Self = self;
|
||||
Function = func;
|
||||
ArgList = std::move(args);
|
||||
EmitTail = false;
|
||||
NoVirtual = novirtual;
|
||||
CallingFunction = nullptr;
|
||||
}
|
||||
|
@ -8595,6 +8589,8 @@ FxVMFunctionCall::~FxVMFunctionCall()
|
|||
|
||||
PPrototype *FxVMFunctionCall::ReturnProto()
|
||||
{
|
||||
if (hasStringArgs)
|
||||
return FxExpression::ReturnProto();
|
||||
EmitTail = true;
|
||||
return Function->Variants[0].Proto;
|
||||
}
|
||||
|
@ -8810,6 +8806,10 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx)
|
|||
}
|
||||
failed |= (x == nullptr);
|
||||
ArgList[i] = x;
|
||||
if (!failed && x->ValueType == TypeString)
|
||||
{
|
||||
hasStringArgs = true;
|
||||
}
|
||||
}
|
||||
int numargs = ArgList.Size() + implicit;
|
||||
if ((unsigned)numargs < argtypes.Size() && argtypes[numargs] != nullptr)
|
||||
|
@ -8861,6 +8861,8 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx)
|
|||
|
||||
ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build)
|
||||
{
|
||||
TArray<ExpEmit> tempstrings;
|
||||
|
||||
assert(build->Registers[REGT_POINTER].GetMostUsed() >= build->NumImplicits);
|
||||
int count = 0;
|
||||
|
||||
|
@ -8873,6 +8875,7 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build)
|
|||
{
|
||||
ArgList.DeleteAndClear();
|
||||
ArgList.ShrinkToFit();
|
||||
for (auto & exp : tempstrings) exp.Free(build);
|
||||
return reg;
|
||||
}
|
||||
}
|
||||
|
@ -8939,7 +8942,7 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build)
|
|||
// Emit code to pass explicit parameters
|
||||
for (unsigned i = 0; i < ArgList.Size(); ++i)
|
||||
{
|
||||
count += EmitParameter(build, ArgList[i], ScriptPosition);
|
||||
count += EmitParameter(build, ArgList[i], ScriptPosition, &tempstrings);
|
||||
}
|
||||
ArgList.DeleteAndClear();
|
||||
ArgList.ShrinkToFit();
|
||||
|
@ -8954,6 +8957,7 @@ 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)
|
||||
|
@ -8964,6 +8968,7 @@ 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();
|
||||
}
|
||||
}
|
||||
|
@ -8978,6 +8983,7 @@ 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)
|
||||
|
@ -8988,6 +8994,7 @@ 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();
|
||||
}
|
||||
}
|
||||
|
@ -8997,6 +9004,7 @@ 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
|
||||
|
@ -9009,8 +9017,9 @@ handlereturns:
|
|||
build->Emit(OP_RESULT, 0, EncodeRegType(reg), reg.RegNum);
|
||||
ReturnRegs.Push(reg);
|
||||
}
|
||||
return ExpEmit();
|
||||
}
|
||||
for (auto & exp : tempstrings) exp.Free(build);
|
||||
return ExpEmit();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
|
@ -407,7 +407,6 @@ class FxClassDefaults : public FxExpression
|
|||
public:
|
||||
FxClassDefaults(FxExpression *, const FScriptPosition &);
|
||||
~FxClassDefaults();
|
||||
PPrototype *ReturnProto();
|
||||
FxExpression *Resolve(FCompileContext&);
|
||||
ExpEmit Emit(VMFunctionBuilder *build);
|
||||
};
|
||||
|
@ -1704,8 +1703,9 @@ class FxVMFunctionCall : public FxExpression
|
|||
{
|
||||
friend class FxMultiAssign;
|
||||
|
||||
bool EmitTail;
|
||||
bool EmitTail = false;
|
||||
bool NoVirtual;
|
||||
bool hasStringArgs = false;
|
||||
FxExpression *Self;
|
||||
PFunction *Function;
|
||||
FArgumentList ArgList;
|
||||
|
|
|
@ -570,6 +570,7 @@ size_t VMFunctionBuilder::Emit(int opcode, int opa, int opb, int opc)
|
|||
assert(opb >= 0);
|
||||
assert(opc >= 0);
|
||||
|
||||
assert(opcode != OP_NOP);
|
||||
|
||||
// The following were just asserts, meaning this would silently create broken code if there was an overflow
|
||||
// if this happened in a release build. Not good.
|
||||
|
|
|
@ -481,181 +481,6 @@ struct VMValue
|
|||
atag = tag;
|
||||
Type = REGT_POINTER;
|
||||
}
|
||||
VMValue &operator=(const VMValue &o)
|
||||
{
|
||||
if (o.Type == REGT_STRING)
|
||||
{
|
||||
if (Type == REGT_STRING)
|
||||
{
|
||||
s() = o.s();
|
||||
}
|
||||
else
|
||||
{
|
||||
new(&s()) FString(o.s());
|
||||
Type = REGT_STRING;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Kill();
|
||||
biggest = o.biggest;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
VMValue &operator=(int v)
|
||||
{
|
||||
Kill();
|
||||
i = v;
|
||||
Type = REGT_INT;
|
||||
return *this;
|
||||
}
|
||||
VMValue &operator=(double v)
|
||||
{
|
||||
Kill();
|
||||
f = v;
|
||||
Type = REGT_FLOAT;
|
||||
return *this;
|
||||
}
|
||||
VMValue &operator=(const FString &v)
|
||||
{
|
||||
if (Type == REGT_STRING)
|
||||
{
|
||||
s() = v;
|
||||
}
|
||||
else
|
||||
{
|
||||
::new(&s()) FString(v);
|
||||
Type = REGT_STRING;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
VMValue &operator=(const char *v)
|
||||
{
|
||||
if (Type == REGT_STRING)
|
||||
{
|
||||
s() = v;
|
||||
}
|
||||
else
|
||||
{
|
||||
::new(&s()) FString(v);
|
||||
Type = REGT_STRING;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
VMValue &operator=(DObject *v)
|
||||
{
|
||||
Kill();
|
||||
a = v;
|
||||
atag = ATAG_OBJECT;
|
||||
Type = REGT_POINTER;
|
||||
return *this;
|
||||
}
|
||||
void SetPointer(void *v, VM_ATAG atag=ATAG_GENERIC)
|
||||
{
|
||||
Kill();
|
||||
a = v;
|
||||
this->atag = atag;
|
||||
Type = REGT_POINTER;
|
||||
}
|
||||
void SetNil()
|
||||
{
|
||||
Kill();
|
||||
Type = REGT_NIL;
|
||||
}
|
||||
bool operator==(const VMValue &o)
|
||||
{
|
||||
return Test(o) == 0;
|
||||
}
|
||||
bool operator!=(const VMValue &o)
|
||||
{
|
||||
return Test(o) != 0;
|
||||
}
|
||||
bool operator< (const VMValue &o)
|
||||
{
|
||||
return Test(o) < 0;
|
||||
}
|
||||
bool operator<=(const VMValue &o)
|
||||
{
|
||||
return Test(o) <= 0;
|
||||
}
|
||||
bool operator> (const VMValue &o)
|
||||
{
|
||||
return Test(o) > 0;
|
||||
}
|
||||
bool operator>=(const VMValue &o)
|
||||
{
|
||||
return Test(o) >= 0;
|
||||
}
|
||||
int Test(const VMValue &o, int inexact=false)
|
||||
{
|
||||
double diff;
|
||||
|
||||
if (Type == o.Type)
|
||||
{
|
||||
switch(Type)
|
||||
{
|
||||
case REGT_NIL:
|
||||
return 0;
|
||||
|
||||
case REGT_INT:
|
||||
return i - o.i;
|
||||
|
||||
case REGT_FLOAT:
|
||||
diff = f - o.f;
|
||||
do_double: if (inexact)
|
||||
{
|
||||
return diff < -VM_EPSILON ? -1 : diff > VM_EPSILON ? 1 : 0;
|
||||
}
|
||||
return diff < 0 ? -1 : diff > 0 ? 1 : 0;
|
||||
|
||||
case REGT_STRING:
|
||||
return inexact ? s().CompareNoCase(o.s()) : s().Compare(o.s());
|
||||
|
||||
case REGT_POINTER:
|
||||
return int((const VM_UBYTE *)a - (const VM_UBYTE *)o.a);
|
||||
}
|
||||
assert(0); // Should not get here
|
||||
return 2;
|
||||
}
|
||||
if (Type == REGT_FLOAT && o.Type == REGT_INT)
|
||||
{
|
||||
diff = f - o.i;
|
||||
goto do_double;
|
||||
}
|
||||
if (Type == REGT_INT && o.Type == REGT_FLOAT)
|
||||
{
|
||||
diff = i - o.f;
|
||||
goto do_double;
|
||||
}
|
||||
// Bad comparison
|
||||
return 2;
|
||||
}
|
||||
FString ToString()
|
||||
{
|
||||
if (Type == REGT_STRING)
|
||||
{
|
||||
return s();
|
||||
}
|
||||
else if (Type == REGT_NIL)
|
||||
{
|
||||
return "nil";
|
||||
}
|
||||
FString t;
|
||||
if (Type == REGT_INT)
|
||||
{
|
||||
t.Format ("%d", i);
|
||||
}
|
||||
else if (Type == REGT_FLOAT)
|
||||
{
|
||||
t.Format ("%.14g", f);
|
||||
}
|
||||
else if (Type == REGT_POINTER)
|
||||
{
|
||||
// FIXME
|
||||
t.Format ("Object: %p", a);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
int ToInt()
|
||||
{
|
||||
if (Type == REGT_INT)
|
||||
|
|
Loading…
Reference in a new issue