mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-24 21:11:39 +00:00
- make dynamic object casts a dedicated VM instruction instead of a builtin function.
This can see some heavy use in iterators where saving several hundreds of function calls can be achieved. In these cases, using a function to do the job will become a significant time waster.
This commit is contained in:
parent
f722967abe
commit
092461ed34
6 changed files with 45 additions and 73 deletions
|
@ -4324,58 +4324,32 @@ FxExpression *FxTypeCheck::Resolve(FCompileContext& ctx)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
PPrototype *FxTypeCheck::ReturnProto()
|
||||
ExpEmit FxTypeCheck::EmitCommon(VMFunctionBuilder *build)
|
||||
{
|
||||
EmitTail = true;
|
||||
return FxExpression::ReturnProto();
|
||||
ExpEmit castee = left->Emit(build);
|
||||
ExpEmit casttype = right->Emit(build);
|
||||
castee.Free(build);
|
||||
casttype.Free(build);
|
||||
ExpEmit ares(build, REGT_POINTER);
|
||||
build->Emit(casttype.Konst ? OP_DYNCAST_K : OP_DYNCAST_R, ares.RegNum, castee.RegNum, casttype.RegNum);
|
||||
return ares;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int BuiltinTypeCheck(VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret)
|
||||
{
|
||||
assert(numparam == 2);
|
||||
PARAM_POINTER_AT(0, obj, DObject);
|
||||
PARAM_CLASS_AT(1, cls, DObject);
|
||||
ACTION_RETURN_BOOL(obj && obj->IsKindOf(cls));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
ExpEmit FxTypeCheck::Emit(VMFunctionBuilder *build)
|
||||
{
|
||||
EmitParameter(build, left, ScriptPosition);
|
||||
EmitParameter(build, right, ScriptPosition);
|
||||
ExpEmit ares = EmitCommon(build);
|
||||
ares.Free(build);
|
||||
ExpEmit bres(build, REGT_INT);
|
||||
build->Emit(OP_CASTB, bres.RegNum, ares.RegNum, CASTB_A);
|
||||
return bres;
|
||||
}
|
||||
|
||||
|
||||
PSymbol *sym = FindBuiltinFunction(NAME_BuiltinTypeCheck, BuiltinTypeCheck);
|
||||
|
||||
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction)));
|
||||
assert(((PSymbolVMFunction *)sym)->Function != nullptr);
|
||||
auto callfunc = ((PSymbolVMFunction *)sym)->Function;
|
||||
|
||||
int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K);
|
||||
build->Emit(opcode, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2, 1);
|
||||
|
||||
if (EmitTail)
|
||||
{
|
||||
ExpEmit call;
|
||||
call.Final = true;
|
||||
return call;
|
||||
}
|
||||
|
||||
ExpEmit out(build, REGT_INT);
|
||||
build->Emit(OP_RESULT, 0, REGT_INT, out.RegNum);
|
||||
return out;
|
||||
void FxTypeCheck::EmitCompare(VMFunctionBuilder *build, bool invert, TArray<size_t> &patchspots_yes, TArray<size_t> &patchspots_no)
|
||||
{
|
||||
ExpEmit ares = EmitCommon(build);
|
||||
ares.Free(build);
|
||||
build->Emit(OP_EQA_K, !invert, ares.RegNum, build->GetConstantAddress(nullptr, ATAG_OBJECT));
|
||||
patchspots_no.Push(build->Emit(OP_JMP, 0));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -4443,27 +4417,11 @@ FxExpression *FxDynamicCast::Resolve(FCompileContext& ctx)
|
|||
|
||||
ExpEmit FxDynamicCast::Emit(VMFunctionBuilder *build)
|
||||
{
|
||||
ExpEmit in = expr->Emit(build);
|
||||
ExpEmit out = in.Fixed ? ExpEmit(build, in.RegType) : in;
|
||||
ExpEmit check(build, REGT_INT);
|
||||
assert(out.RegType == REGT_POINTER);
|
||||
|
||||
if (in.Fixed) build->Emit(OP_MOVEA, out.RegNum, in.RegNum);
|
||||
build->Emit(OP_PARAM, 0, REGT_POINTER, in.RegNum);
|
||||
build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(CastType, ATAG_OBJECT));
|
||||
|
||||
PSymbol *sym = FindBuiltinFunction(NAME_BuiltinTypeCheck, BuiltinTypeCheck);
|
||||
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction)));
|
||||
assert(((PSymbolVMFunction *)sym)->Function != nullptr);
|
||||
auto callfunc = ((PSymbolVMFunction *)sym)->Function;
|
||||
|
||||
build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2, 1);
|
||||
build->Emit(OP_RESULT, 0, REGT_INT, check.RegNum);
|
||||
build->Emit(OP_EQ_K, 0, check.RegNum, build->GetConstantInt(0));
|
||||
auto patch = build->Emit(OP_JMP, 0);
|
||||
build->Emit(OP_LKP, out.RegNum, build->GetConstantAddress(nullptr, ATAG_OBJECT));
|
||||
build->BackpatchToHere(patch);
|
||||
return out;
|
||||
ExpEmit castee = expr->Emit(build);
|
||||
castee.Free(build);
|
||||
ExpEmit ares(build, REGT_POINTER);
|
||||
build->Emit(OP_DYNCAST_K, ares.RegNum, castee.RegNum, build->GetConstantAddress(CastType, ATAG_OBJECT));
|
||||
return ares;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -9586,8 +9544,7 @@ int BuiltinNameToClass(VMValue *param, TArray<VMValue> &defaultparam, int numpar
|
|||
|
||||
if (!cls->IsDescendantOf(desttype))
|
||||
{
|
||||
// Let the caller check this. The message can be enabled for diagnostic purposes.
|
||||
DPrintf(DMSG_SPAMMY, "class '%s' is not compatible with '%s'\n", clsname.GetChars(), desttype->TypeName.GetChars());
|
||||
// Let the caller check this. Making this an error with a message is only taking away options from the user.
|
||||
cls = nullptr;
|
||||
}
|
||||
ret->SetPointer(const_cast<PClass *>(cls), ATAG_OBJECT);
|
||||
|
|
|
@ -1078,9 +1078,10 @@ public:
|
|||
FxTypeCheck(FxExpression*, FxExpression*);
|
||||
~FxTypeCheck();
|
||||
FxExpression *Resolve(FCompileContext&);
|
||||
PPrototype *ReturnProto();
|
||||
|
||||
ExpEmit EmitCommon(VMFunctionBuilder *build);
|
||||
ExpEmit Emit(VMFunctionBuilder *build);
|
||||
void EmitCompare(VMFunctionBuilder *build, bool invert, TArray<size_t> &patchspots_yes, TArray<size_t> &patchspots_no);
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
|
|
|
@ -414,6 +414,18 @@ begin:
|
|||
reg.f[a+1] = reg.f[B+1];
|
||||
reg.f[a+2] = reg.f[B+2];
|
||||
NEXTOP;
|
||||
OP(DYNCAST_R) :
|
||||
ASSERTA(a); ASSERTA(B); ASSERTA(C);
|
||||
b = B;
|
||||
reg.a[a] = (reg.a[b] && ((DObject*)(reg.a[b]))->IsKindOf((PClass*)(reg.a[C]))) ? reg.a[b] : nullptr;
|
||||
reg.atag[a] = ATAG_OBJECT;
|
||||
NEXTOP;
|
||||
OP(DYNCAST_K) :
|
||||
ASSERTA(a); ASSERTA(B); ASSERTKA(C);
|
||||
b = B;
|
||||
reg.a[a] = (reg.a[b] && ((DObject*)(reg.a[b]))->IsKindOf((PClass*)(konsta[C].o))) ? reg.a[b] : nullptr;
|
||||
reg.atag[a] = ATAG_OBJECT;
|
||||
NEXTOP;
|
||||
OP(CAST):
|
||||
if (C == CAST_I2F)
|
||||
{
|
||||
|
|
|
@ -84,6 +84,8 @@ xx(MOVEV2, mov2, RFRF, NOP, 0, 0), // fA = fB (2 elements)
|
|||
xx(MOVEV3, mov3, RFRF, NOP, 0, 0), // fA = fB (3 elements)
|
||||
xx(CAST, cast, CAST, NOP, 0, 0), // xA = xB, conversion specified by C
|
||||
xx(CASTB, castb, CAST, NOP, 0, 0), // xA = !!xB, type specified by C
|
||||
xx(DYNCAST_R, dyncast, RPRPRP, NOP, 0, 0), // aA = dyn_cast<aC>(aB);
|
||||
xx(DYNCAST_K, dyncast, RPRPKP, NOP, 0, 0), // aA = dyn_cast<aKC>(aB);
|
||||
|
||||
// Control flow.
|
||||
xx(TEST, test, RII16, NOP, 0, 0), // if (dA != BC) then pc++
|
||||
|
|
|
@ -193,7 +193,7 @@ extend class Actor
|
|||
if (sv_killbossmonst)
|
||||
{
|
||||
int count; // Repeat until we have no more boss-spawned monsters.
|
||||
ThinkerIterator it = ThinkerIterator.Create();
|
||||
ThinkerIterator it = ThinkerIterator.Create("Actor");
|
||||
do // (e.g. Pain Elementals can spawn more to kill upon death.)
|
||||
{
|
||||
Actor mo;
|
||||
|
|
|
@ -388,7 +388,7 @@ class Minotaur : Actor
|
|||
// In case pain caused him to skip his fade in.
|
||||
A_SetRenderStyle(1, STYLE_Normal);
|
||||
|
||||
MinotaurFriend mf = MinotaurFriend(self);
|
||||
let mf = MinotaurFriend(self);
|
||||
if (mf)
|
||||
{
|
||||
if (mf.StartTime >= 0 && (level.maptime - mf.StartTime) >= MAULATORTICS)
|
||||
|
@ -501,7 +501,7 @@ class Minotaur : Actor
|
|||
|
||||
void A_MinotaurChase()
|
||||
{
|
||||
MinotaurFriend mf = MinotaurFriend(self);
|
||||
let mf = MinotaurFriend(self);
|
||||
if (!mf)
|
||||
{
|
||||
A_Chase();
|
||||
|
|
Loading…
Reference in a new issue