diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index 3e591d257..ca46e1ec7 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -5214,12 +5214,13 @@ FxMinMax::FxMinMax(TArray &expr, FName type, const FScriptPositio FxExpression *FxMinMax::Resolve(FCompileContext &ctx) { unsigned int i; - int intcount, floatcount; + int intcount, floatcount, uintcount; CHECKRESOLVED(); // Determine if float or int - intcount = floatcount = 0; + uintcount = intcount = floatcount = 0; + for (i = 0; i < choices.Size(); ++i) { RESOLVE(choices[i], ctx); @@ -5232,6 +5233,9 @@ FxExpression *FxMinMax::Resolve(FCompileContext &ctx) else if (choices[i]->IsInteger()) { intcount++; + auto type = choices[i]->ValueType; + if (type == TypeUInt32 || type == TypeUInt16 || type == TypeUInt8 || type == TypeBool) uintcount++; + else if (choices[i]->isConstant() && static_cast(choices[i])->GetValue().GetInt() > 0) uintcount++; } else { @@ -5258,7 +5262,7 @@ FxExpression *FxMinMax::Resolve(FCompileContext &ctx) } else { - ValueType = TypeSInt32; + ValueType = uintcount == intcount? TypeUInt32 : TypeSInt32; } // If at least two arguments are constants, they can be solved now. @@ -5364,18 +5368,20 @@ ExpEmit FxMinMax::Emit(VMFunctionBuilder *build) 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); - assert(OP_MIN_RK == OP_MIN_RR+1); + static_assert(OP_MAXF_RK == OP_MAXF_RR+1, "maxf opcodes not continuous"); + static_assert(OP_MAX_RK == OP_MAX_RR+1, "max opcodes not continuous"); + static_assert(OP_MINF_RK == OP_MINF_RR+1, "minf opcodes not continuous"); + static_assert(OP_MIN_RK == OP_MIN_RR+1, "min opcodes not continuous"); + static_assert(OP_MAXU_RK == OP_MAXU_RR + 1, "maxu opcodes not continuous"); + static_assert(OP_MINU_RK == OP_MINU_RR + 1, "minu opcodes not continuous"); if (Type == NAME_Min) { - opcode = ValueType->GetRegType() == REGT_FLOAT ? OP_MINF_RR : OP_MIN_RR; + opcode = ValueType->GetRegType() == REGT_FLOAT ? OP_MINF_RR : ValueType == TypeUInt32? OP_MINU_RR : OP_MIN_RR; } else { - opcode = ValueType->GetRegType() == REGT_FLOAT ? OP_MAXF_RR : OP_MAX_RR; + opcode = ValueType->GetRegType() == REGT_FLOAT ? OP_MAXF_RR : ValueType == TypeUInt32 ? OP_MAXU_RR : OP_MAX_RR; } ExpEmit firstreg = choices[0]->Emit(build); diff --git a/src/scripting/vm/jit_math.cpp b/src/scripting/vm/jit_math.cpp index 225ef8173..e929ddd84 100644 --- a/src/scripting/vm/jit_math.cpp +++ b/src/scripting/vm/jit_math.cpp @@ -483,6 +483,44 @@ void JitCompiler::EmitMAX_RK() cc.cmovg(regD[A], rc); } +void JitCompiler::EmitMINU_RR() +{ + auto rc = CheckRegD(C, A); + if (A != B) + cc.mov(regD[A], regD[B]); + cc.cmp(rc, regD[A]); + cc.cmovb(regD[A], rc); +} + +void JitCompiler::EmitMINU_RK() +{ + auto rc = newTempInt32(); + if (A != B) + cc.mov(regD[A], regD[B]); + cc.mov(rc, asmjit::imm(konstd[C])); + cc.cmp(rc, regD[A]); + cc.cmovb(regD[A], rc); +} + +void JitCompiler::EmitMAXU_RR() +{ + auto rc = CheckRegD(C, A); + if (A != B) + cc.mov(regD[A], regD[B]); + cc.cmp(rc, regD[A]); + cc.cmova(regD[A], rc); +} + +void JitCompiler::EmitMAXU_RK() +{ + auto rc = newTempInt32(); + if (A != B) + cc.mov(regD[A], regD[B]); + cc.mov(rc, asmjit::imm(konstd[C])); + cc.cmp(rc, regD[A]); + cc.cmova(regD[A], rc); +} + void JitCompiler::EmitABS() { auto srcB = CheckRegD(B, A); diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index 2a67daaec..59fbc7afc 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -1163,6 +1163,23 @@ static int ExecScriptFunc(VMFrameStack *stack, VMReturn *ret, int numret) reg.d[a] = reg.d[B] > konstd[C] ? reg.d[B] : konstd[C]; NEXTOP; + OP(MINU_RR) : + ASSERTD(a); ASSERTD(B); ASSERTD(C); + reg.d[a] = (unsigned)reg.d[B] < (unsigned)reg.d[C] ? reg.d[B] : reg.d[C]; + NEXTOP; + OP(MINU_RK) : + ASSERTD(a); ASSERTD(B); ASSERTKD(C); + reg.d[a] = (unsigned)reg.d[B] < (unsigned)konstd[C] ? reg.d[B] : konstd[C]; + NEXTOP; + OP(MAXU_RR) : + ASSERTD(a); ASSERTD(B); ASSERTD(C); + reg.d[a] = (unsigned)reg.d[B] > (unsigned)reg.d[C] ? reg.d[B] : reg.d[C]; + NEXTOP; + OP(MAXU_RK) : + ASSERTD(a); ASSERTD(B); ASSERTKD(C); + reg.d[a] = (unsigned)reg.d[B] > (unsigned)konstd[C] ? reg.d[B] : konstd[C]; + NEXTOP; + OP(ABS): ASSERTD(a); ASSERTD(B); reg.d[a] = abs(reg.d[B]); diff --git a/src/scripting/vm/vmops.h b/src/scripting/vm/vmops.h index a4e623e9b..0f181519e 100644 --- a/src/scripting/vm/vmops.h +++ b/src/scripting/vm/vmops.h @@ -169,6 +169,10 @@ xx(MIN_RR, min, RIRIRI, NOP, 0, 0) // dA = min(dB,dkC) xx(MIN_RK, min, RIRIKI, MIN_RR, 4, REGT_INT) xx(MAX_RR, max, RIRIRI, NOP, 0, 0) // dA = max(dB,dkC) xx(MAX_RK, max, RIRIKI, MAX_RR, 4, REGT_INT) +xx(MINU_RR, minu, RIRIRI, NOP, 0, 0) // dA = min(dB,dkC) unsigned +xx(MINU_RK, minu, RIRIKI, MIN_RR, 4, REGT_INT) +xx(MAXU_RR, maxu, RIRIRI, NOP, 0, 0) // dA = max(dB,dkC) unsigned +xx(MAXU_RK, maxu, RIRIKI, MAX_RR, 4, REGT_INT) xx(ABS, abs, RIRI, NOP, 0, 0) // dA = abs(dB) xx(NEG, neg, RIRI, NOP, 0, 0) // dA = -dB xx(NOT, not, RIRI, NOP, 0, 0) // dA = ~dB