diff --git a/src/scripting/vm/jit_math.cpp b/src/scripting/vm/jit_math.cpp index d88eae471..1fadbb362 100644 --- a/src/scripting/vm/jit_math.cpp +++ b/src/scripting/vm/jit_math.cpp @@ -1219,27 +1219,7 @@ void JitCompiler::EmitLENV2() void JitCompiler::EmitEQV2_R() { EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) { - if (static_cast(A & CMP_APPROX)) I_FatalError("CMP_APPROX not implemented for EQV2_R.\n"); - - cc.ucomisd(regF[B], regF[C]); - if (check) { - cc.jp(success); - cc.jne(success); - } - else { - cc.jp(fail); - cc.jne(fail); - } - - cc.ucomisd(regF[B + 1], regF[C + 1]); - if (check) { - cc.jp(success); - cc.je(fail); - } - else { - cc.jp(fail); - cc.jne(fail); - } + EmitVectorComparison<2> (check, fail, success); }); } @@ -1406,37 +1386,7 @@ void JitCompiler::EmitLENV3() void JitCompiler::EmitEQV3_R() { EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) { - if (static_cast(A & CMP_APPROX)) I_FatalError("CMP_APPROX not implemented for EQV3_R.\n"); - - cc.ucomisd(regF[B], regF[C]); - if (check) { - cc.jp(success); - cc.jne(success); - } - else { - cc.jp(fail); - cc.jne(fail); - } - - cc.ucomisd(regF[B + 1], regF[C + 1]); - if (check) { - cc.jp(success); - cc.jne(success); - } - else { - cc.jp(fail); - cc.jne(fail); - } - - cc.ucomisd(regF[B + 2], regF[C + 2]); - if (check) { - cc.jp(success); - cc.je(fail); - } - else { - cc.jp(fail); - cc.jne(fail); - } + EmitVectorComparison<3> (check, fail, success); }); } diff --git a/src/scripting/vm/jitintern.h b/src/scripting/vm/jitintern.h index 14a6c995d..769f03891 100644 --- a/src/scripting/vm/jitintern.h +++ b/src/scripting/vm/jitintern.h @@ -72,6 +72,53 @@ private: pc++; // This instruction uses two instruction slots - skip the next one } + template + void EmitVectorComparison(bool check, asmjit::Label& fail, asmjit::Label& success) + { + bool approx = static_cast(A & CMP_APPROX); + if (!approx) + { + for (int i = 0; i < N; i++) + { + cc.ucomisd(regF[B + i], regF[C + i]); + if (check) + { + cc.jp(success); + cc.jne(success); + } + else + { + cc.jp(fail); + cc.jne(fail); + } + } + } + else + { + auto tmp = newTempXmmSd(); + + const int64_t absMaskInt = 0x7FFFFFFFFFFFFFFF; + auto absMask = cc.newDoubleConst(asmjit::kConstScopeLocal, reinterpret_cast(absMaskInt)); + auto absMaskXmm = newTempXmmPd(); + + auto epsilon = cc.newDoubleConst(asmjit::kConstScopeLocal, VM_EPSILON); + auto epsilonXmm = newTempXmmSd(); + + for (int i = 0; i < N; i++) + { + cc.movsd(tmp, regF[B + i]); + cc.subsd(tmp, regF[C + i]); + cc.movsd(absMaskXmm, absMask); + cc.andpd(tmp, absMaskXmm); + cc.movsd(epsilonXmm, epsilon); + cc.ucomisd(epsilonXmm, tmp); + + if (check) cc.ja(fail); + else cc.jna(fail); + } + } + } + static uint64_t ToMemAddress(const void *d) { return (uint64_t)(ptrdiff_t)d;