mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-11 15:22:16 +00:00
- branch optimization.
This commit is contained in:
parent
17d9a152e7
commit
77192fa9dd
4 changed files with 166 additions and 97 deletions
|
@ -288,6 +288,45 @@ ExpEmit FxExpression::Emit (VMFunctionBuilder *build)
|
|||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FxExpression::EmitCompare(VMFunctionBuilder *build, bool invert, TArray<size_t> &patchspots_yes, TArray<size_t> &patchspots_no)
|
||||
{
|
||||
ExpEmit op = Emit(build);
|
||||
ExpEmit i;
|
||||
assert(op.RegType != REGT_NIL && op.RegCount == 1 && !op.Konst);
|
||||
switch (op.RegType)
|
||||
{
|
||||
case REGT_INT:
|
||||
build->Emit(OP_EQ_K, !invert, op.RegNum, build->GetConstantInt(0));
|
||||
break;
|
||||
|
||||
case REGT_FLOAT:
|
||||
build->Emit(OP_EQF_K, !invert, op.RegNum, build->GetConstantFloat(0));
|
||||
break;
|
||||
|
||||
case REGT_POINTER:
|
||||
build->Emit(OP_EQA_K, !invert, op.RegNum, build->GetConstantAddress(0, ATAG_GENERIC));
|
||||
break;
|
||||
|
||||
case REGT_STRING:
|
||||
i = ExpEmit(build, REGT_INT);
|
||||
build->Emit(OP_LENS, i.RegNum, op.RegNum);
|
||||
build->Emit(OP_EQ_K, !invert, i.RegNum, build->GetConstantInt(0));
|
||||
i.Free(build);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
patchspots_no.Push(build->Emit(OP_JMP, 0));
|
||||
op.Free(build);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
|
@ -757,7 +796,6 @@ ExpEmit FxBoolCast::Emit(VMFunctionBuilder *build)
|
|||
{
|
||||
ExpEmit to(build, REGT_INT);
|
||||
from.Free(build);
|
||||
// Preload result with 0.
|
||||
build->Emit(OP_CASTB, to.RegNum, from.RegNum, from.RegType == REGT_INT ? CASTB_I : from.RegType == REGT_FLOAT ? CASTB_F : CASTB_A);
|
||||
return to;
|
||||
}
|
||||
|
@ -773,6 +811,17 @@ ExpEmit FxBoolCast::Emit(VMFunctionBuilder *build)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void FxBoolCast::EmitCompare(VMFunctionBuilder *build, bool invert, TArray<size_t> &patchspots_yes, TArray<size_t> &patchspots_no)
|
||||
{
|
||||
basex->EmitCompare(build, invert, patchspots_yes, patchspots_no);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FxIntCast::FxIntCast(FxExpression *x, bool nowarn, bool explicitly)
|
||||
: FxExpression(EFX_IntCast, x->ScriptPosition)
|
||||
{
|
||||
|
@ -1872,6 +1921,17 @@ ExpEmit FxUnaryNotBoolean::Emit(VMFunctionBuilder *build)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void FxUnaryNotBoolean::EmitCompare(VMFunctionBuilder *build, bool invert, TArray<size_t> &patchspots_yes, TArray<size_t> &patchspots_no)
|
||||
{
|
||||
Operand->EmitCompare(build, !invert, patchspots_yes, patchspots_no);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FxSizeAlign::FxSizeAlign(FxExpression *operand, int which)
|
||||
: FxExpression(EFX_SizeAlign, operand->ScriptPosition)
|
||||
{
|
||||
|
@ -3124,7 +3184,7 @@ FxExpression *FxCompareRel::Resolve(FCompileContext& ctx)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
ExpEmit FxCompareRel::Emit(VMFunctionBuilder *build)
|
||||
ExpEmit FxCompareRel::EmitCommon(VMFunctionBuilder *build, bool forcompare, bool invert)
|
||||
{
|
||||
ExpEmit op1 = left->Emit(build);
|
||||
ExpEmit op2 = right->Emit(build);
|
||||
|
@ -3154,11 +3214,15 @@ ExpEmit FxCompareRel::Emit(VMFunctionBuilder *build)
|
|||
{
|
||||
op2.Free(build);
|
||||
}
|
||||
if (invert) a ^= CMP_CHECK;
|
||||
|
||||
build->Emit(OP_LI, to.RegNum, 0, 0);
|
||||
if (!forcompare) build->Emit(OP_LI, to.RegNum, 0, 0);
|
||||
build->Emit(OP_CMPS, a, op1.RegNum, op2.RegNum);
|
||||
if (!forcompare)
|
||||
{
|
||||
build->Emit(OP_JMP, 1);
|
||||
build->Emit(OP_LI, to.RegNum, 1);
|
||||
}
|
||||
return to;
|
||||
}
|
||||
else
|
||||
|
@ -3197,16 +3261,32 @@ ExpEmit FxCompareRel::Emit(VMFunctionBuilder *build)
|
|||
{
|
||||
op1.Free(build);
|
||||
}
|
||||
if (invert) check ^= 1;
|
||||
|
||||
// See FxBoolCast for comments, since it's the same thing.
|
||||
build->Emit(OP_LI, to.RegNum, 0, 0);
|
||||
if (!forcompare) build->Emit(OP_LI, to.RegNum, 0, 0);
|
||||
build->Emit(instr, check, op1.RegNum, op2.RegNum);
|
||||
if (!forcompare)
|
||||
{
|
||||
build->Emit(OP_JMP, 1);
|
||||
build->Emit(OP_LI, to.RegNum, 1);
|
||||
}
|
||||
return to;
|
||||
}
|
||||
}
|
||||
|
||||
ExpEmit FxCompareRel::Emit(VMFunctionBuilder *build)
|
||||
{
|
||||
return EmitCommon(build, false, false);
|
||||
}
|
||||
|
||||
void FxCompareRel::EmitCompare(VMFunctionBuilder *build, bool invert, TArray<size_t> &patchspots_yes, TArray<size_t> &patchspots_no)
|
||||
{
|
||||
ExpEmit emit = EmitCommon(build, true, invert);
|
||||
emit.Free(build);
|
||||
patchspots_no.Push(build->Emit(OP_JMP, 0));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
|
@ -3404,7 +3484,7 @@ error:
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
ExpEmit FxCompareEq::Emit(VMFunctionBuilder *build)
|
||||
ExpEmit FxCompareEq::EmitCommon(VMFunctionBuilder *build, bool forcompare, bool invert)
|
||||
{
|
||||
ExpEmit op1 = left->Emit(build);
|
||||
ExpEmit op2 = right->Emit(build);
|
||||
|
@ -3420,11 +3500,15 @@ ExpEmit FxCompareEq::Emit(VMFunctionBuilder *build)
|
|||
|
||||
if (op1.Konst) a |= CMP_BK;
|
||||
if (op2.Konst) a |= CMP_CK;
|
||||
if (invert) a ^= CMP_CHECK;
|
||||
|
||||
build->Emit(OP_LI, to.RegNum, 0, 0);
|
||||
if (!forcompare) build->Emit(OP_LI, to.RegNum, 0, 0);
|
||||
build->Emit(OP_CMPS, a, op1.RegNum, op2.RegNum);
|
||||
if (!forcompare)
|
||||
{
|
||||
build->Emit(OP_JMP, 1);
|
||||
build->Emit(OP_LI, to.RegNum, 1);
|
||||
}
|
||||
op1.Free(build);
|
||||
op2.Free(build);
|
||||
return to;
|
||||
|
@ -3457,14 +3541,29 @@ ExpEmit FxCompareEq::Emit(VMFunctionBuilder *build)
|
|||
}
|
||||
|
||||
// See FxUnaryNotBoolean for comments, since it's the same thing.
|
||||
build->Emit(OP_LI, to.RegNum, 0, 0);
|
||||
build->Emit(instr, Operator == TK_ApproxEq ? CMP_APPROX : ((Operator != TK_Eq) ? CMP_CHECK : 0), op1.RegNum, op2.RegNum);
|
||||
if (!forcompare) build->Emit(OP_LI, to.RegNum, 0, 0);
|
||||
build->Emit(instr, int(invert) ^ (Operator == TK_ApproxEq ? CMP_APPROX : ((Operator != TK_Eq) ? CMP_CHECK : 0)), op1.RegNum, op2.RegNum);
|
||||
if (!forcompare)
|
||||
{
|
||||
build->Emit(OP_JMP, 1);
|
||||
build->Emit(OP_LI, to.RegNum, 1);
|
||||
}
|
||||
return to;
|
||||
}
|
||||
}
|
||||
|
||||
ExpEmit FxCompareEq::Emit(VMFunctionBuilder *build)
|
||||
{
|
||||
return EmitCommon(build, false, false);
|
||||
}
|
||||
|
||||
void FxCompareEq::EmitCompare(VMFunctionBuilder *build, bool invert, TArray<size_t> &patchspots_yes, TArray<size_t> &patchspots_no)
|
||||
{
|
||||
ExpEmit emit = EmitCommon(build, true, invert);
|
||||
emit.Free(build);
|
||||
patchspots_no.Push(build->Emit(OP_JMP, 0));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
|
@ -4447,21 +4546,17 @@ FxExpression *FxConditional::Resolve(FCompileContext& ctx)
|
|||
|
||||
ExpEmit FxConditional::Emit(VMFunctionBuilder *build)
|
||||
{
|
||||
size_t truejump, falsejump;
|
||||
ExpEmit out;
|
||||
size_t truejump;
|
||||
ExpEmit out, falseout;
|
||||
|
||||
// The true and false expressions ought to be assigned to the
|
||||
// same temporary instead of being copied to it. Oh well; good enough
|
||||
// for now.
|
||||
ExpEmit cond = condition->Emit(build);
|
||||
assert(cond.RegType == REGT_INT && !cond.Konst);
|
||||
TArray<size_t> yes, no;
|
||||
condition->EmitCompare(build, false, yes, no);
|
||||
|
||||
// Test condition.
|
||||
build->Emit(OP_EQ_K, 1, cond.RegNum, build->GetConstantInt(0));
|
||||
falsejump = build->Emit(OP_JMP, 0);
|
||||
cond.Free(build);
|
||||
build->BackpatchListToHere(yes);
|
||||
|
||||
// Evaluate true expression.
|
||||
if (truex->isConstant() && truex->ValueType->GetRegType() == REGT_INT)
|
||||
{
|
||||
out = ExpEmit(build, REGT_INT);
|
||||
|
@ -4501,7 +4596,7 @@ ExpEmit FxConditional::Emit(VMFunctionBuilder *build)
|
|||
truejump = build->Emit(OP_JMP, 0);
|
||||
|
||||
// Evaluate false expression.
|
||||
build->BackpatchToHere(falsejump);
|
||||
build->BackpatchListToHere(no);
|
||||
if (falsex->isConstant() && falsex->ValueType->GetRegType() == REGT_INT)
|
||||
{
|
||||
build->EmitLoadInt(out.RegNum, static_cast<FxConstant *>(falsex)->GetValue().GetInt());
|
||||
|
@ -8858,68 +8953,28 @@ FxExpression *FxIfStatement::Resolve(FCompileContext &ctx)
|
|||
ExpEmit FxIfStatement::Emit(VMFunctionBuilder *build)
|
||||
{
|
||||
ExpEmit v;
|
||||
size_t jumpspot;
|
||||
FxExpression *path1, *path2;
|
||||
int condcheck;
|
||||
size_t jumpspot = ~0u;
|
||||
|
||||
// This is pretty much copied from FxConditional, except we don't
|
||||
// keep any results.
|
||||
ExpEmit cond = Condition->Emit(build);
|
||||
assert(cond.RegType != REGT_STRING && !cond.Konst);
|
||||
TArray<size_t> yes, no;
|
||||
Condition->EmitCompare(build, false, yes, no);
|
||||
|
||||
if (WhenTrue != nullptr)
|
||||
{
|
||||
path1 = WhenTrue;
|
||||
path2 = WhenFalse;
|
||||
condcheck = 1;
|
||||
build->BackpatchListToHere(yes);
|
||||
WhenTrue->Emit(build);
|
||||
}
|
||||
if (WhenFalse != nullptr)
|
||||
{
|
||||
if (!WhenTrue->CheckReturn()) jumpspot = build->Emit(OP_JMP, 0); // no need to emit a jump if the block returns.
|
||||
build->BackpatchListToHere(no);
|
||||
WhenFalse->Emit(build);
|
||||
if (jumpspot != ~0u) build->BackpatchToHere(jumpspot);
|
||||
if (WhenTrue == nullptr) build->BackpatchListToHere(yes);
|
||||
}
|
||||
else
|
||||
{
|
||||
// When there is only a false path, reverse the condition so we can
|
||||
// treat it as a true path.
|
||||
assert(WhenFalse != nullptr);
|
||||
path1 = WhenFalse;
|
||||
path2 = nullptr;
|
||||
condcheck = 0;
|
||||
build->BackpatchListToHere(no);
|
||||
}
|
||||
|
||||
// Test condition.
|
||||
|
||||
switch (cond.RegType)
|
||||
{
|
||||
default:
|
||||
case REGT_INT:
|
||||
build->Emit(OP_EQ_K, condcheck, cond.RegNum, build->GetConstantInt(0));
|
||||
break;
|
||||
|
||||
case REGT_FLOAT:
|
||||
build->Emit(OP_EQF_K, condcheck, cond.RegNum, build->GetConstantFloat(0));
|
||||
break;
|
||||
|
||||
case REGT_POINTER:
|
||||
build->Emit(OP_EQA_K, condcheck, cond.RegNum, build->GetConstantAddress(nullptr, ATAG_GENERIC));
|
||||
break;
|
||||
}
|
||||
jumpspot = build->Emit(OP_JMP, 0);
|
||||
cond.Free(build);
|
||||
|
||||
// Evaluate first path
|
||||
v = path1->Emit(build);
|
||||
v.Free(build);
|
||||
if (path2 != nullptr)
|
||||
{
|
||||
size_t path1jump;
|
||||
|
||||
// if the branch ends with a return we do not need a terminating jmp.
|
||||
if (!path1->CheckReturn()) path1jump = build->Emit(OP_JMP, 0);
|
||||
else path1jump = 0xffffffff;
|
||||
// Evaluate second path
|
||||
build->BackpatchToHere(jumpspot);
|
||||
v = path2->Emit(build);
|
||||
v.Free(build);
|
||||
jumpspot = path1jump;
|
||||
}
|
||||
if (jumpspot != 0xffffffff) build->BackpatchToHere(jumpspot);
|
||||
return ExpEmit();
|
||||
}
|
||||
|
||||
|
@ -9027,19 +9082,17 @@ ExpEmit FxWhileLoop::Emit(VMFunctionBuilder *build)
|
|||
assert(Condition->ValueType == TypeBool);
|
||||
|
||||
size_t loopstart, loopend;
|
||||
size_t jumpspot;
|
||||
TArray<size_t> yes, no;
|
||||
|
||||
// Evaluate the condition and execute/break out of the loop.
|
||||
loopstart = build->GetAddress();
|
||||
if (!Condition->isConstant())
|
||||
{
|
||||
ExpEmit cond = Condition->Emit(build);
|
||||
build->Emit(OP_TEST, cond.RegNum, 0);
|
||||
jumpspot = build->Emit(OP_JMP, 0);
|
||||
cond.Free(build);
|
||||
Condition->EmitCompare(build, false, yes, no);
|
||||
}
|
||||
else assert(static_cast<FxConstant *>(Condition)->GetValue().GetBool() == true);
|
||||
|
||||
build->BackpatchListToHere(yes);
|
||||
// Execute the loop's content.
|
||||
if (Code != nullptr)
|
||||
{
|
||||
|
@ -9049,13 +9102,8 @@ ExpEmit FxWhileLoop::Emit(VMFunctionBuilder *build)
|
|||
|
||||
// Loop back.
|
||||
build->Backpatch(build->Emit(OP_JMP, 0), loopstart);
|
||||
build->BackpatchListToHere(no);
|
||||
loopend = build->GetAddress();
|
||||
|
||||
if (!Condition->isConstant())
|
||||
{
|
||||
build->Backpatch(jumpspot, loopend);
|
||||
}
|
||||
|
||||
Backpatch(build, loopstart, loopend);
|
||||
return ExpEmit();
|
||||
}
|
||||
|
@ -9132,17 +9180,16 @@ ExpEmit FxDoWhileLoop::Emit(VMFunctionBuilder *build)
|
|||
loopstart = build->GetAddress();
|
||||
if (!Condition->isConstant())
|
||||
{
|
||||
ExpEmit cond = Condition->Emit(build);
|
||||
build->Emit(OP_TEST, cond.RegNum, 1);
|
||||
cond.Free(build);
|
||||
build->Backpatch(build->Emit(OP_JMP, 0), codestart);
|
||||
TArray<size_t> yes, no;
|
||||
Condition->EmitCompare(build, true, yes, no);
|
||||
build->BackpatchList(no, codestart);
|
||||
build->BackpatchListToHere(yes);
|
||||
}
|
||||
else if (static_cast<FxConstant *>(Condition)->GetValue().GetBool() == true)
|
||||
{ // Always looping
|
||||
build->Backpatch(build->Emit(OP_JMP, 0), codestart);
|
||||
}
|
||||
loopend = build->GetAddress();
|
||||
|
||||
Backpatch(build, loopstart, loopend);
|
||||
|
||||
return ExpEmit();
|
||||
|
|
|
@ -328,6 +328,7 @@ public:
|
|||
bool IsObject() const { return ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && !ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer)) && ValueType != TypeNullPtr && static_cast<PPointer*>(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PClass)); }
|
||||
|
||||
virtual ExpEmit Emit(VMFunctionBuilder *build);
|
||||
virtual void EmitCompare(VMFunctionBuilder *build, bool invert, TArray<size_t> &patchspots_yes, TArray<size_t> &patchspots_no);
|
||||
|
||||
FScriptPosition ScriptPosition;
|
||||
PType *ValueType = nullptr;
|
||||
|
@ -565,6 +566,7 @@ public:
|
|||
FxExpression *Resolve(FCompileContext&);
|
||||
|
||||
ExpEmit Emit(VMFunctionBuilder *build);
|
||||
void EmitCompare(VMFunctionBuilder *build, bool invert, TArray<size_t> &patchspots_yes, TArray<size_t> &patchspots_no);
|
||||
};
|
||||
|
||||
class FxIntCast : public FxExpression
|
||||
|
@ -734,6 +736,7 @@ public:
|
|||
~FxUnaryNotBoolean();
|
||||
FxExpression *Resolve(FCompileContext&);
|
||||
ExpEmit Emit(VMFunctionBuilder *build);
|
||||
void EmitCompare(VMFunctionBuilder *build, bool invert, TArray<size_t> &patchspots_yes, TArray<size_t> &patchspots_no);
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
|
@ -934,7 +937,9 @@ public:
|
|||
|
||||
FxCompareRel(int, FxExpression*, FxExpression*);
|
||||
FxExpression *Resolve(FCompileContext&);
|
||||
ExpEmit EmitCommon(VMFunctionBuilder *build, bool forcompare, bool invert);
|
||||
ExpEmit Emit(VMFunctionBuilder *build);
|
||||
void EmitCompare(VMFunctionBuilder *build, bool invert, TArray<size_t> &patchspots_yes, TArray<size_t> &patchspots_no);
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
|
@ -949,7 +954,9 @@ public:
|
|||
|
||||
FxCompareEq(int, FxExpression*, FxExpression*);
|
||||
FxExpression *Resolve(FCompileContext&);
|
||||
ExpEmit EmitCommon(VMFunctionBuilder *build, bool forcompare, bool invert);
|
||||
ExpEmit Emit(VMFunctionBuilder *build);
|
||||
void EmitCompare(VMFunctionBuilder *build, bool invert, TArray<size_t> &patchspots_yes, TArray<size_t> &patchspots_no);
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
|
|
|
@ -734,6 +734,13 @@ void VMFunctionBuilder::Backpatch(size_t loc, size_t target)
|
|||
Code[loc].i24 = offset;
|
||||
}
|
||||
|
||||
void VMFunctionBuilder::BackpatchList(TArray<size_t> &locs, size_t target)
|
||||
{
|
||||
for (auto loc : locs)
|
||||
Backpatch(loc, target);
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// VMFunctionBuilder :: BackpatchToHere
|
||||
|
@ -748,6 +755,12 @@ void VMFunctionBuilder::BackpatchToHere(size_t loc)
|
|||
Backpatch(loc, Code.Size());
|
||||
}
|
||||
|
||||
void VMFunctionBuilder::BackpatchListToHere(TArray<size_t> &locs)
|
||||
{
|
||||
for (auto loc : locs)
|
||||
Backpatch(loc, Code.Size());
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FFunctionBuildList
|
||||
|
|
|
@ -69,6 +69,8 @@ public:
|
|||
|
||||
void Backpatch(size_t addr, size_t target);
|
||||
void BackpatchToHere(size_t addr);
|
||||
void BackpatchList(TArray<size_t> &addrs, size_t target);
|
||||
void BackpatchListToHere(TArray<size_t> &addrs);
|
||||
|
||||
// Write out complete constant tables.
|
||||
void FillIntConstants(int *konst);
|
||||
|
|
Loading…
Reference in a new issue