- fixed code generation for min/max when the first operand was a local variable or constant.

The code for constants was not optimal because the first operand of the instructions cannot be constant. This was solved by swapping it with the second choice which will always be non-constant.
The code for local variables did not allocate a new destination register and would overwrite the first parameter's variable.
This commit is contained in:
Christoph Oelckers 2017-03-09 09:36:12 +01:00
parent a632fae33f
commit 77bac4f6fa
2 changed files with 19 additions and 10 deletions

View File

@ -5281,6 +5281,12 @@ FxExpression *FxMinMax::Resolve(FCompileContext &ctx)
break;
}
}
// If the first choice is constant, swap it with the second one.
// Note that all constants have already been folded together so there can only be one constant in the list of choices.
if (choices[0]->isConstant())
{
std::swap(choices[0], choices[1]);
}
return this;
}
@ -5307,6 +5313,7 @@ ExpEmit FxMinMax::Emit(VMFunctionBuilder *build)
int opcode;
assert(choices.Size() > 0);
assert(!choices[0]->isConstant());
assert(OP_MAXF_RK == OP_MAXF_RR+1);
assert(OP_MAX_RK == OP_MAX_RR+1);
assert(OP_MIN_RK == OP_MIN_RR+1);
@ -5321,28 +5328,30 @@ ExpEmit FxMinMax::Emit(VMFunctionBuilder *build)
opcode = ValueType->GetRegType() == REGT_FLOAT ? OP_MAXF_RR : OP_MAX_RR;
}
ExpEmit bestreg;
ExpEmit firstreg = choices[0]->Emit(build);
ExpEmit destreg;
// Get first value into a register. This will also be the result register.
if (choices[0]->isConstant())
if (firstreg.Fixed)
{
bestreg = ExpEmit(build, ValueType->GetRegType());
EmitLoad(build, bestreg, static_cast<FxConstant *>(choices[0])->GetValue());
destreg = ExpEmit(build, firstreg.RegType);
firstreg.Free(build);
}
else
{
bestreg = choices[0]->Emit(build);
destreg = firstreg;
}
// Compare every choice. Better matches get copied to the bestreg.
for (i = 1; i < choices.Size(); ++i)
{
ExpEmit checkreg = choices[i]->Emit(build);
assert(checkreg.RegType == bestreg.RegType);
build->Emit(opcode + checkreg.Konst, bestreg.RegNum, bestreg.RegNum, checkreg.RegNum);
assert(checkreg.RegType == firstreg.RegType);
build->Emit(opcode + checkreg.Konst, destreg.RegNum, firstreg.RegNum, checkreg.RegNum);
firstreg = destreg;
checkreg.Free(build);
}
return bestreg;
return destreg;
}
//==========================================================================

View File

@ -276,7 +276,7 @@ void ZCCCompiler::ProcessStruct(ZCC_Struct *cnode, PSymbolTreeNode *treenode, ZC
//==========================================================================
ZCCCompiler::ZCCCompiler(ZCC_AST &ast, DObject *_outer, PSymbolTable &_symbols, PNamespace *_outnamespc, int lumpnum, const VersionInfo &ver)
: Outer(_outer), GlobalTreeNodes(&_symbols), OutNamespace(_outnamespc), AST(ast), Lump(lumpnum), mVersion(ver)
: Outer(_outer), GlobalTreeNodes(&_symbols), OutNamespace(_outnamespc), AST(ast), mVersion(ver), Lump(lumpnum)
{
FScriptPosition::ResetErrorCounter();
// Group top-level nodes by type