- implemented CMP_APPROX for OP_EQF_*, making ~== work for doubles

This commit is contained in:
Jonathan Russell 2018-08-17 19:08:19 +01:00
parent 079391e5ac
commit d137b3c94e
1 changed files with 61 additions and 14 deletions

View File

@ -1166,12 +1166,34 @@ JitFuncPtr JitCompile(VMScriptFunction *sfunc)
case OP_EQF_R: // if ((fB == fkC) != (A & 1)) then pc++ case OP_EQF_R: // if ((fB == fkC) != (A & 1)) then pc++
{ {
auto compLambda = [&](X86Gp& result) { auto compLambda = [&](X86Gp& result) {
auto tmp = cc.newInt32(); bool approx = static_cast<bool>(A & CMP_APPROX);
cc.ucomisd(regF[B], regF[C]); if (!approx) {
cc.sete(result); auto tmp = cc.newInt32();
cc.setnp(tmp); cc.ucomisd(regF[B], regF[C]);
cc.and_(result, tmp); cc.sete(result);
cc.and_(result, 1); cc.setnp(tmp);
cc.and_(result, tmp);
cc.and_(result, 1);
}
else {
auto tmp = cc.newXmmSd();
int64_t absMaskInt = 0x7FFFFFFFFFFFFFFF;
auto absMask = cc.newDoubleConst(kConstScopeLocal, reinterpret_cast<const double&>(absMaskInt));
auto absMaskXmm = cc.newXmmPd();
auto epsilon = cc.newDoubleConst(kConstScopeLocal, VM_EPSILON);
auto epsilonXmm = cc.newXmmSd();
cc.movsd(tmp, regF[B]);
cc.subsd(tmp, regF[C]);
cc.movsd(absMaskXmm, absMask);
cc.andpd(tmp, absMaskXmm);
cc.movsd(epsilonXmm, epsilon);
cc.ucomisd(epsilonXmm, tmp);
cc.seta(result);
cc.and_(result, 1);
}
}; };
emitComparisonOpcode(cc, labels, pc, i, compLambda); emitComparisonOpcode(cc, labels, pc, i, compLambda);
@ -1180,15 +1202,40 @@ JitFuncPtr JitCompile(VMScriptFunction *sfunc)
case OP_EQF_K: case OP_EQF_K:
{ {
auto compLambda = [&](X86Gp& result) { auto compLambda = [&](X86Gp& result) {
auto konstTmp = cc.newIntPtr(); bool approx = static_cast<bool>(A & CMP_APPROX);
auto parityTmp = cc.newInt32(); if (!approx) {
cc.mov(konstTmp, reinterpret_cast<ptrdiff_t>(&(konstf[C]))); auto konstTmp = cc.newIntPtr();
auto parityTmp = cc.newInt32();
cc.mov(konstTmp, reinterpret_cast<ptrdiff_t>(&(konstf[C])));
cc.ucomisd(regF[B], x86::qword_ptr(konstTmp)); cc.ucomisd(regF[B], x86::qword_ptr(konstTmp));
cc.sete(result); cc.sete(result);
cc.setnp(parityTmp); cc.setnp(parityTmp);
cc.and_(result, parityTmp); cc.and_(result, parityTmp);
cc.and_(result, 1); cc.and_(result, 1);
}
else {
auto konstTmp = cc.newIntPtr();
auto subTmp = cc.newXmmSd();
int64_t absMaskInt = 0x7FFFFFFFFFFFFFFF;
auto absMask = cc.newDoubleConst(kConstScopeLocal, reinterpret_cast<const double&>(absMaskInt));
auto absMaskXmm = cc.newXmmPd();
auto epsilon = cc.newDoubleConst(kConstScopeLocal, VM_EPSILON);
auto epsilonXmm = cc.newXmmSd();
cc.mov(konstTmp, reinterpret_cast<ptrdiff_t>(&(konstf[C])));
cc.movsd(subTmp, regF[B]);
cc.subsd(subTmp, x86::qword_ptr(konstTmp));
cc.movsd(absMaskXmm, absMask);
cc.andpd(subTmp, absMaskXmm);
cc.movsd(epsilonXmm, epsilon);
cc.ucomisd(epsilonXmm, subTmp);
cc.seta(result);
cc.and_(result, 1);
}
}; };
emitComparisonOpcode(cc, labels, pc, i, compLambda); emitComparisonOpcode(cc, labels, pc, i, compLambda);