- added an optimization to FxBoolCast that it doesn't force the source value to a 0/1 integer if not explicitly needed. When doing comparisons we do not care about actual values, we only want to know if it is 0 or not.

- added the above for the 'if' condition. It works for integers, floats and pointers and will save 3 instructions if the condition is a non-boolean that can be implicitly casted to bool.
This commit is contained in:
Christoph Oelckers 2016-10-23 15:30:58 +02:00
parent 5b952b116a
commit da56e5908d
2 changed files with 49 additions and 26 deletions

View File

@ -434,11 +434,12 @@ ExpEmit FxConstant::Emit(VMFunctionBuilder *build)
//
//==========================================================================
FxBoolCast::FxBoolCast(FxExpression *x)
FxBoolCast::FxBoolCast(FxExpression *x, bool needvalue)
: FxExpression(EFX_BoolCast, x->ScriptPosition)
{
basex = x;
ValueType = TypeBool;
NeedValue = needvalue;
}
//==========================================================================
@ -499,31 +500,37 @@ ExpEmit FxBoolCast::Emit(VMFunctionBuilder *build)
ExpEmit from = basex->Emit(build);
assert(!from.Konst);
assert(basex->ValueType->GetRegType() == REGT_INT || basex->ValueType->GetRegType() == REGT_FLOAT || basex->ValueType->GetRegType() == REGT_POINTER);
ExpEmit to(build, REGT_INT);
from.Free(build);
// Preload result with 0.
build->Emit(OP_LI, to.RegNum, 0);
// Check source against 0.
if (from.RegType == REGT_INT)
if (NeedValue)
{
build->Emit(OP_EQ_R, 1, from.RegNum, to.RegNum);
}
else if (from.RegType == REGT_FLOAT)
{
build->Emit(OP_EQF_K, 1, from.RegNum, build->GetConstantFloat(0.));
}
else if (from.RegType == REGT_POINTER)
{
build->Emit(OP_EQA_K, 1, from.RegNum, build->GetConstantAddress(nullptr, ATAG_GENERIC));
}
build->Emit(OP_JMP, 1);
ExpEmit to(build, REGT_INT);
from.Free(build);
// Preload result with 0.
build->Emit(OP_LI, to.RegNum, 0);
// Reload result with 1 if the comparison fell through.
build->Emit(OP_LI, to.RegNum, 1);
// Check source against 0.
if (from.RegType == REGT_INT)
{
build->Emit(OP_EQ_R, 1, from.RegNum, to.RegNum);
}
else if (from.RegType == REGT_FLOAT)
{
build->Emit(OP_EQF_K, 1, from.RegNum, build->GetConstantFloat(0.));
}
else if (from.RegType == REGT_POINTER)
{
build->Emit(OP_EQA_K, 1, from.RegNum, build->GetConstantAddress(nullptr, ATAG_GENERIC));
}
build->Emit(OP_JMP, 1);
return to;
// Reload result with 1 if the comparison fell through.
build->Emit(OP_LI, to.RegNum, 1);
return to;
}
else
{
return from;
}
}
//==========================================================================
@ -5871,7 +5878,7 @@ FxExpression *FxIfStatement::Resolve(FCompileContext &ctx)
if (Condition->ValueType != TypeBool)
{
Condition = new FxBoolCast(Condition);
Condition = new FxBoolCast(Condition, false);
SAFE_RESOLVE(Condition, ctx);
}
@ -5914,7 +5921,7 @@ ExpEmit FxIfStatement::Emit(VMFunctionBuilder *build)
// This is pretty much copied from FxConditional, except we don't
// keep any results.
ExpEmit cond = Condition->Emit(build);
assert(cond.RegType == REGT_INT && !cond.Konst);
assert(cond.RegType != REGT_STRING && !cond.Konst);
if (WhenTrue != NULL)
{
@ -5933,7 +5940,22 @@ ExpEmit FxIfStatement::Emit(VMFunctionBuilder *build)
}
// Test condition.
build->Emit(OP_EQ_K, condcheck, cond.RegNum, build->GetConstantInt(0));
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);

View File

@ -457,10 +457,11 @@ public:
class FxBoolCast : public FxExpression
{
FxExpression *basex;
bool NeedValue;
public:
FxBoolCast(FxExpression *x);
FxBoolCast(FxExpression *x, bool needvalue = true);
~FxBoolCast();
FxExpression *Resolve(FCompileContext&);