From 77bac4f6fa58dcfab6cdcad6ffab9087f4637389 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 9 Mar 2017 09:36:12 +0100 Subject: [PATCH] - 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. --- src/scripting/backend/codegen.cpp | 27 ++++++++++++++++++--------- src/scripting/zscript/zcc_compile.cpp | 2 +- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index 56bf71080..dc904b804 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -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(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; } //========================================================================== diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 6be8a0038..222c20a26 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -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