From d9953eb3bddc2881a40564ad0cd5aeb70b97af0f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 18 Nov 2016 12:23:58 +0100 Subject: [PATCH] - cleaned up FxCompareRel::Resolve. Also added unsigned integer support to it and FxMulDiv (these, aside from the float cast, are the only two operations where this is important.) --- src/scripting/codegeneration/codegen.cpp | 90 +++++++++++++++++++----- src/scripting/codegeneration/codegen.h | 9 ++- 2 files changed, 80 insertions(+), 19 deletions(-) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 418fc4a5f..c18548bdc 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -2922,9 +2922,18 @@ ExpEmit FxMulDiv::Emit(VMFunctionBuilder *build) { assert(ValueType->GetRegType() == REGT_INT); assert(op1.RegType == REGT_INT && op2.RegType == REGT_INT); - build->Emit(Operator == '/' ? (op1.Konst ? OP_DIV_KR : op2.Konst ? OP_DIV_RK : OP_DIV_RR) - : (op1.Konst ? OP_MOD_KR : op2.Konst ? OP_MOD_RK : OP_MOD_RR), - to.RegNum, op1.RegNum, op2.RegNum); + if (ValueType == TypeUInt32) + { + build->Emit(Operator == '/' ? (op1.Konst ? OP_DIVU_KR : op2.Konst ? OP_DIVU_RK : OP_DIVU_RR) + : (op1.Konst ? OP_MODU_KR : op2.Konst ? OP_MODU_RK : OP_MODU_RR), + to.RegNum, op1.RegNum, op2.RegNum); + } + else + { + build->Emit(Operator == '/' ? (op1.Konst ? OP_DIV_KR : op2.Konst ? OP_DIV_RK : OP_DIV_RR) + : (op1.Konst ? OP_MOD_KR : op2.Konst ? OP_MOD_RK : OP_MOD_RR), + to.RegNum, op1.RegNum, op2.RegNum); + } return to; } } @@ -3024,16 +3033,51 @@ FxCompareRel::FxCompareRel(int o, FxExpression *l, FxExpression *r) FxExpression *FxCompareRel::Resolve(FCompileContext& ctx) { CHECKRESOLVED(); - if (!ResolveLR(ctx, true)) - return nullptr; - if (!IsNumeric()) + RESOLVE(left, ctx); + RESOLVE(right, ctx); + if (!left || !right) { - ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); delete this; return nullptr; } - else if (left->isConstant() && right->isConstant()) + + if (left->ValueType == TypeString || right->ValueType == TypeString) + { + if (left->ValueType != TypeString) + { + left = new FxStringCast(left); + left = left->Resolve(ctx); + if (left == nullptr) + { + delete this; + return nullptr; + } + } + if (right->ValueType != TypeString) + { + right = new FxStringCast(right); + right = right->Resolve(ctx); + if (right == nullptr) + { + delete this; + return nullptr; + } + } + ValueType == TypeString; + } + else if (left->IsNumeric() && right->IsNumeric()) + { + Promote(ctx); + } + else + { + ScriptPosition.Message(MSG_ERROR, "Incompatible operands for relative comparison"); + delete this; + return nullptr; + } + + if (left->isConstant() && right->isConstant()) { int v; @@ -3056,20 +3100,29 @@ FxExpression *FxCompareRel::Resolve(FCompileContext& ctx) Operator == TK_Geq? v1 >= v2 : Operator == TK_Leq? v1 <= v2 : 0; } - else + else if (ValueType == TypeUInt32) { - int v1 = static_cast(left)->GetValue().GetInt(); - int v2 = static_cast(right)->GetValue().GetInt(); + int v1 = static_cast(left)->GetValue().GetUInt(); + int v2 = static_cast(right)->GetValue().GetUInt(); v = Operator == '<'? v1 < v2 : Operator == '>'? v1 > v2 : Operator == TK_Geq? v1 >= v2 : Operator == TK_Leq? v1 <= v2 : 0; } + else + { + int v1 = static_cast(left)->GetValue().GetInt(); + int v2 = static_cast(right)->GetValue().GetInt(); + v = Operator == '<' ? v1 < v2 : + Operator == '>' ? v1 > v2 : + Operator == TK_Geq ? v1 >= v2 : + Operator == TK_Leq ? v1 <= v2 : 0; + } FxExpression *e = new FxConstant(v, ScriptPosition); delete this; return e; } - Promote(ctx); + CompareType = ValueType; // needs to be preserved for detection of unsigned compare. ValueType = TypeBool; return this; } @@ -3124,10 +3177,10 @@ ExpEmit FxCompareRel::Emit(VMFunctionBuilder *build) assert(Operator == '<' || Operator == '>' || Operator == TK_Geq || Operator == TK_Leq); static const VM_UBYTE InstrMap[][4] = { - { OP_LT_RR, OP_LTF_RR, 0 }, // < - { OP_LE_RR, OP_LEF_RR, 1 }, // > - { OP_LT_RR, OP_LTF_RR, 1 }, // >= - { OP_LE_RR, OP_LEF_RR, 0 } // <= + { OP_LT_RR, OP_LTF_RR, OP_LTU_RR, 0 }, // < + { OP_LE_RR, OP_LEF_RR, OP_LEU_RR, 1 }, // > + { OP_LT_RR, OP_LTF_RR, OP_LTU_RR, 1 }, // >= + { OP_LE_RR, OP_LEF_RR, OP_LEU_RR, 0 } // <= }; int instr, check; ExpEmit to(build, REGT_INT); @@ -3135,8 +3188,9 @@ ExpEmit FxCompareRel::Emit(VMFunctionBuilder *build) Operator == '>' ? 1 : Operator == TK_Geq ? 2 : 3; - instr = InstrMap[index][op1.RegType == REGT_INT ? 0 : 1]; - check = InstrMap[index][2]; + int mode = op1.RegType == REGT_FLOAT ? 1 : CompareType == TypeUInt32 ? 2 : 0; + instr = InstrMap[index][mode]; + check = InstrMap[index][3]; if (op2.Konst) { instr += 1; diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/codegeneration/codegen.h index 0ec3491bb..5f7791e3e 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/codegeneration/codegen.h @@ -169,10 +169,16 @@ struct ExpVal return regtype == REGT_INT ? Int : regtype == REGT_FLOAT ? int(Float) : 0; } + unsigned GetUInt() const + { + int regtype = Type->GetRegType(); + return regtype == REGT_INT ? unsigned(Int) : regtype == REGT_FLOAT ? unsigned(Float) : 0; + } + double GetFloat() const { int regtype = Type->GetRegType(); - return regtype == REGT_INT ? double(Int) : regtype == REGT_FLOAT ? Float : 0; + return regtype == REGT_INT ? (Type == TypeUInt32? double(unsigned(Int)) : double(Int)) : regtype == REGT_FLOAT ? Float : 0; } void *GetPointer() const @@ -864,6 +870,7 @@ public: class FxCompareRel : public FxBinary { + PType *CompareType; public: FxCompareRel(int, FxExpression*, FxExpression*);