qzdoom/src/scripting/vm/jit_math.cpp

1542 lines
34 KiB
C++
Raw Normal View History

#include "jitintern.h"
/////////////////////////////////////////////////////////////////////////////
// String instructions.
void JitCompiler::EmitCONCAT()
{
auto rc = CheckRegS(C, A);
auto call = CreateCall<void, FString*, FString*, FString*>([](FString* to, FString* first, FString* second) {
*to = *first + *second;
});
call->setArg(0, regS[A]);
call->setArg(1, regS[B]);
call->setArg(2, rc);
}
void JitCompiler::EmitLENS()
{
2018-10-07 07:02:28 +00:00
auto result = newResultInt32();
auto call = CreateCall<int, FString*>([](FString* str) -> int {
return static_cast<int>(str->Len());
});
call->setRet(0, result);
call->setArg(0, regS[B]);
cc.mov(regD[A], result);
}
void JitCompiler::EmitCMPS()
{
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
auto compareNoCaseLambda = [](FString* first, FString* second) -> int {
return first->CompareNoCase(*second);
};
auto compareLambda = [](FString* first, FString* second) -> int {
return first->Compare(*second);
};
auto call = static_cast<bool>(A & CMP_APPROX) ?
CreateCall<int, FString*, FString*>(compareNoCaseLambda) :
CreateCall<int, FString*, FString*>(compareLambda);
2018-10-07 07:02:28 +00:00
auto result = newResultInt32();
call->setRet(0, result);
if (static_cast<bool>(A & CMP_BK)) call->setArg(0, asmjit::imm_ptr(&konsts[B]));
else call->setArg(0, regS[B]);
if (static_cast<bool>(A & CMP_CK)) call->setArg(1, asmjit::imm_ptr(&konsts[C]));
else call->setArg(1, regS[C]);
int method = A & CMP_METHOD_MASK;
if (method == CMP_EQ) {
cc.test(result, result);
if (check) cc.jz(fail);
else cc.jnz(fail);
}
else if (method == CMP_LT) {
cc.cmp(result, 0);
if (check) cc.jl(fail);
else cc.jnl(fail);
}
else {
cc.cmp(result, 0);
if (check) cc.jle(fail);
else cc.jnle(fail);
}
});
}
/////////////////////////////////////////////////////////////////////////////
// Integer math.
void JitCompiler::EmitSLL_RR()
{
auto rc = CheckRegD(C, A);
if (A != B)
cc.mov(regD[A], regD[B]);
cc.shl(regD[A], rc);
}
void JitCompiler::EmitSLL_RI()
{
if (A != B)
cc.mov(regD[A], regD[B]);
cc.shl(regD[A], C);
}
void JitCompiler::EmitSLL_KR()
{
auto rc = CheckRegD(C, A);
cc.mov(regD[A], konstd[B]);
cc.shl(regD[A], rc);
}
void JitCompiler::EmitSRL_RR()
{
auto rc = CheckRegD(C, A);
if (A != B)
cc.mov(regD[A], regD[B]);
cc.shr(regD[A], rc);
}
void JitCompiler::EmitSRL_RI()
{
if (A != B)
cc.mov(regD[A], regD[B]);
cc.shr(regD[A], C);
}
void JitCompiler::EmitSRL_KR()
{
auto rc = CheckRegD(C, A);
cc.mov(regD[A], konstd[B]);
cc.shr(regD[A], rc);
}
void JitCompiler::EmitSRA_RR()
{
auto rc = CheckRegD(C, A);
if (A != B)
cc.mov(regD[A], regD[B]);
cc.sar(regD[A], rc);
}
void JitCompiler::EmitSRA_RI()
{
if (A != B)
cc.mov(regD[A], regD[B]);
cc.sar(regD[A], C);
}
void JitCompiler::EmitSRA_KR()
{
auto rc = CheckRegD(C, A);
cc.mov(regD[A], konstd[B]);
cc.sar(regD[A], rc);
}
void JitCompiler::EmitADD_RR()
{
auto rc = CheckRegD(C, A);
if (A != B)
cc.mov(regD[A], regD[B]);
cc.add(regD[A], rc);
}
void JitCompiler::EmitADD_RK()
{
if (A != B)
cc.mov(regD[A], regD[B]);
cc.add(regD[A], konstd[C]);
}
void JitCompiler::EmitADDI()
{
if (A != B)
cc.mov(regD[A], regD[B]);
cc.add(regD[A], Cs);
}
void JitCompiler::EmitSUB_RR()
{
auto rc = CheckRegD(C, A);
if (A != B)
cc.mov(regD[A], regD[B]);
cc.sub(regD[A], rc);
}
void JitCompiler::EmitSUB_RK()
{
if (A != B)
cc.mov(regD[A], regD[B]);
cc.sub(regD[A], konstd[C]);
}
void JitCompiler::EmitSUB_KR()
{
auto rc = CheckRegD(C, A);
cc.mov(regD[A], konstd[B]);
cc.sub(regD[A], rc);
}
void JitCompiler::EmitMUL_RR()
{
auto rc = CheckRegD(C, A);
if (A != B)
cc.mov(regD[A], regD[B]);
cc.imul(regD[A], rc);
}
void JitCompiler::EmitMUL_RK()
{
if (A != B)
cc.mov(regD[A], regD[B]);
cc.imul(regD[A], konstd[C]);
}
void JitCompiler::EmitDIV_RR()
{
2018-10-07 07:02:28 +00:00
auto tmp0 = newTempInt32();
auto tmp1 = newTempInt32();
auto label = cc.newLabel();
cc.test(regD[C], regD[C]);
cc.jne(label);
EmitThrowException(X_DIVISION_BY_ZERO);
cc.bind(label);
cc.mov(tmp0, regD[B]);
cc.cdq(tmp1, tmp0);
cc.idiv(tmp1, tmp0, regD[C]);
cc.mov(regD[A], tmp0);
}
void JitCompiler::EmitDIV_RK()
{
if (konstd[C] != 0)
{
2018-10-07 07:02:28 +00:00
auto tmp0 = newTempInt32();
auto tmp1 = newTempInt32();
auto konstTmp = newTempIntPtr();
cc.mov(tmp0, regD[B]);
cc.cdq(tmp1, tmp0);
cc.mov(konstTmp, asmjit::imm_ptr(&konstd[C]));
cc.idiv(tmp1, tmp0, asmjit::x86::ptr(konstTmp));
cc.mov(regD[A], tmp0);
}
else EmitThrowException(X_DIVISION_BY_ZERO);
}
void JitCompiler::EmitDIV_KR()
{
2018-10-07 07:02:28 +00:00
auto tmp0 = newTempInt32();
auto tmp1 = newTempInt32();
auto label = cc.newLabel();
cc.test(regD[C], regD[C]);
cc.jne(label);
EmitThrowException(X_DIVISION_BY_ZERO);
cc.bind(label);
cc.mov(tmp0, konstd[B]);
cc.cdq(tmp1, tmp0);
cc.idiv(tmp1, tmp0, regD[C]);
cc.mov(regD[A], tmp0);
}
void JitCompiler::EmitDIVU_RR()
{
2018-10-07 07:02:28 +00:00
auto tmp0 = newTempInt32();
auto tmp1 = newTempInt32();
auto label = cc.newLabel();
cc.test(regD[C], regD[C]);
cc.jne(label);
EmitThrowException(X_DIVISION_BY_ZERO);
cc.bind(label);
cc.mov(tmp0, regD[B]);
cc.mov(tmp1, 0);
cc.div(tmp1, tmp0, regD[C]);
cc.mov(regD[A], tmp0);
}
void JitCompiler::EmitDIVU_RK()
{
if (konstd[C] != 0)
{
2018-10-07 07:02:28 +00:00
auto tmp0 = newTempInt32();
auto tmp1 = newTempInt32();
auto konstTmp = newTempIntPtr();
cc.mov(tmp0, regD[B]);
cc.mov(tmp1, 0);
cc.mov(konstTmp, asmjit::imm_ptr(&konstd[C]));
cc.div(tmp1, tmp0, asmjit::x86::ptr(konstTmp));
cc.mov(regD[A], tmp0);
}
else EmitThrowException(X_DIVISION_BY_ZERO);
}
void JitCompiler::EmitDIVU_KR()
{
2018-10-07 07:02:28 +00:00
auto tmp0 = newTempInt32();
auto tmp1 = newTempInt32();
auto label = cc.newLabel();
cc.test(regD[C], regD[C]);
cc.jne(label);
EmitThrowException(X_DIVISION_BY_ZERO);
cc.bind(label);
cc.mov(tmp0, konstd[B]);
cc.mov(tmp1, 0);
cc.div(tmp1, tmp0, regD[C]);
cc.mov(regD[A], tmp0);
}
void JitCompiler::EmitMOD_RR()
{
2018-10-07 07:02:28 +00:00
auto tmp0 = newTempInt32();
auto tmp1 = newTempInt32();
auto label = cc.newLabel();
cc.test(regD[C], regD[C]);
cc.jne(label);
EmitThrowException(X_DIVISION_BY_ZERO);
cc.bind(label);
cc.mov(tmp0, regD[B]);
cc.cdq(tmp1, tmp0);
cc.idiv(tmp1, tmp0, regD[C]);
cc.mov(regD[A], tmp1);
}
void JitCompiler::EmitMOD_RK()
{
if (konstd[C] != 0)
{
2018-10-07 07:02:28 +00:00
auto tmp0 = newTempInt32();
auto tmp1 = newTempInt32();
auto konstTmp = newTempIntPtr();
cc.mov(tmp0, regD[B]);
cc.cdq(tmp1, tmp0);
cc.mov(konstTmp, asmjit::imm_ptr(&konstd[C]));
cc.idiv(tmp1, tmp0, asmjit::x86::ptr(konstTmp));
cc.mov(regD[A], tmp1);
}
else EmitThrowException(X_DIVISION_BY_ZERO);
}
void JitCompiler::EmitMOD_KR()
{
2018-10-07 07:02:28 +00:00
auto tmp0 = newTempInt32();
auto tmp1 = newTempInt32();
auto label = cc.newLabel();
cc.test(regD[C], regD[C]);
cc.jne(label);
EmitThrowException(X_DIVISION_BY_ZERO);
cc.bind(label);
cc.mov(tmp0, konstd[B]);
cc.cdq(tmp1, tmp0);
cc.idiv(tmp1, tmp0, regD[C]);
cc.mov(regD[A], tmp1);
}
void JitCompiler::EmitMODU_RR()
{
2018-10-07 07:02:28 +00:00
auto tmp0 = newTempInt32();
auto tmp1 = newTempInt32();
auto label = cc.newLabel();
cc.test(regD[C], regD[C]);
cc.jne(label);
EmitThrowException(X_DIVISION_BY_ZERO);
cc.bind(label);
cc.mov(tmp0, regD[B]);
cc.mov(tmp1, 0);
cc.div(tmp1, tmp0, regD[C]);
cc.mov(regD[A], tmp1);
}
void JitCompiler::EmitMODU_RK()
{
if (konstd[C] != 0)
{
2018-10-07 07:02:28 +00:00
auto tmp0 = newTempInt32();
auto tmp1 = newTempInt32();
auto konstTmp = newTempIntPtr();
cc.mov(tmp0, regD[B]);
cc.mov(tmp1, 0);
cc.mov(konstTmp, asmjit::imm_ptr(&konstd[C]));
cc.div(tmp1, tmp0, asmjit::x86::ptr(konstTmp));
cc.mov(regD[A], tmp1);
}
else EmitThrowException(X_DIVISION_BY_ZERO);
}
void JitCompiler::EmitMODU_KR()
{
2018-10-07 07:02:28 +00:00
auto tmp0 = newTempInt32();
auto tmp1 = newTempInt32();
auto label = cc.newLabel();
cc.test(regD[C], regD[C]);
cc.jne(label);
EmitThrowException(X_DIVISION_BY_ZERO);
cc.bind(label);
cc.mov(tmp0, konstd[B]);
cc.mov(tmp1, 0);
cc.div(tmp1, tmp0, regD[C]);
cc.mov(regD[A], tmp1);
}
void JitCompiler::EmitAND_RR()
{
auto rc = CheckRegD(C, A);
if (A != B)
cc.mov(regD[A], regD[B]);
cc.and_(regD[A], rc);
}
void JitCompiler::EmitAND_RK()
{
if (A != B)
cc.mov(regD[A], regD[B]);
cc.and_(regD[A], konstd[C]);
}
void JitCompiler::EmitOR_RR()
{
auto rc = CheckRegD(C, A);
if (A != B)
cc.mov(regD[A], regD[B]);
cc.or_(regD[A], rc);
}
void JitCompiler::EmitOR_RK()
{
if (A != B)
cc.mov(regD[A], regD[B]);
cc.or_(regD[A], konstd[C]);
}
void JitCompiler::EmitXOR_RR()
{
auto rc = CheckRegD(C, A);
if (A != B)
cc.mov(regD[A], regD[B]);
cc.xor_(regD[A], rc);
}
void JitCompiler::EmitXOR_RK()
{
if (A != B)
cc.mov(regD[A], regD[B]);
cc.xor_(regD[A], konstd[C]);
}
void JitCompiler::EmitMIN_RR()
{
2018-10-07 07:02:28 +00:00
auto tmp0 = newTempXmmSs();
auto tmp1 = newTempXmmSs();
cc.movd(tmp0, regD[B]);
cc.movd(tmp1, regD[C]);
cc.pminsd(tmp0, tmp1);
cc.movd(regD[A], tmp0);
}
void JitCompiler::EmitMIN_RK()
{
2018-10-07 07:02:28 +00:00
auto tmp0 = newTempXmmSs();
auto tmp1 = newTempXmmSs();
auto konstTmp = newTempIntPtr();
cc.mov(konstTmp, asmjit::imm_ptr(&konstd[C]));
cc.movd(tmp0, regD[B]);
cc.movss(tmp1, asmjit::x86::dword_ptr(konstTmp));
cc.pminsd(tmp0, tmp1);
cc.movd(regD[A], tmp0);
}
void JitCompiler::EmitMAX_RR()
{
2018-10-07 07:02:28 +00:00
auto tmp0 = newTempXmmSs();
auto tmp1 = newTempXmmSs();
cc.movd(tmp0, regD[B]);
cc.movd(tmp1, regD[C]);
cc.pmaxsd(tmp0, tmp1);
cc.movd(regD[A], tmp0);
}
void JitCompiler::EmitMAX_RK()
{
2018-10-07 07:02:28 +00:00
auto tmp0 = newTempXmmSs();
auto tmp1 = newTempXmmSs();
auto konstTmp = newTempIntPtr();
cc.mov(konstTmp, asmjit::imm_ptr(&konstd[C]));
cc.movd(tmp0, regD[B]);
cc.movss(tmp1, asmjit::x86::dword_ptr(konstTmp));
cc.pmaxsd(tmp0, tmp1);
cc.movd(regD[A], tmp0);
}
void JitCompiler::EmitABS()
{
auto srcB = CheckRegD(B, A);
2018-10-07 07:02:28 +00:00
auto tmp = newTempInt32();
cc.mov(tmp, regD[B]);
cc.sar(tmp, 31);
cc.mov(regD[A], tmp);
cc.xor_(regD[A], srcB);
cc.sub(regD[A], tmp);
}
void JitCompiler::EmitNEG()
{
auto srcB = CheckRegD(B, A);
cc.xor_(regD[A], regD[A]);
cc.sub(regD[A], srcB);
}
void JitCompiler::EmitNOT()
{
if (A != B)
cc.mov(regD[A], regD[B]);
cc.not_(regD[A]);
}
void JitCompiler::EmitEQ_R()
{
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
cc.cmp(regD[B], regD[C]);
if (check) cc.je(fail);
else cc.jne(fail);
});
}
void JitCompiler::EmitEQ_K()
{
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
cc.cmp(regD[B], konstd[C]);
if (check) cc.je(fail);
else cc.jne(fail);
});
}
void JitCompiler::EmitLT_RR()
{
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
cc.cmp(regD[B], regD[C]);
if (check) cc.jl(fail);
else cc.jnl(fail);
});
}
void JitCompiler::EmitLT_RK()
{
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
cc.cmp(regD[B], konstd[C]);
if (check) cc.jl(fail);
else cc.jnl(fail);
});
}
void JitCompiler::EmitLT_KR()
{
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
2018-10-07 07:02:28 +00:00
auto tmp = newTempIntPtr();
cc.mov(tmp, asmjit::imm_ptr(&konstd[B]));
cc.cmp(asmjit::x86::ptr(tmp), regD[C]);
if (check) cc.jl(fail);
else cc.jnl(fail);
});
}
void JitCompiler::EmitLE_RR()
{
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
cc.cmp(regD[B], regD[C]);
if (check) cc.jle(fail);
else cc.jnle(fail);
});
}
void JitCompiler::EmitLE_RK()
{
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
cc.cmp(regD[B], konstd[C]);
if (check) cc.jle(fail);
else cc.jnle(fail);
});
}
void JitCompiler::EmitLE_KR()
{
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
2018-10-07 07:02:28 +00:00
auto tmp = newTempIntPtr();
cc.mov(tmp, asmjit::imm_ptr(&konstd[B]));
cc.cmp(asmjit::x86::ptr(tmp), regD[C]);
if (check) cc.jle(fail);
else cc.jnle(fail);
});
}
void JitCompiler::EmitLTU_RR()
{
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
cc.cmp(regD[B], regD[C]);
if (check) cc.jb(fail);
else cc.jnb(fail);
});
}
void JitCompiler::EmitLTU_RK()
{
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
cc.cmp(regD[B], konstd[C]);
if (check) cc.jb(fail);
else cc.jnb(fail);
});
}
void JitCompiler::EmitLTU_KR()
{
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
2018-10-07 07:02:28 +00:00
auto tmp = newTempIntPtr();
cc.mov(tmp, asmjit::imm_ptr(&konstd[B]));
cc.cmp(asmjit::x86::ptr(tmp), regD[C]);
if (check) cc.jb(fail);
else cc.jnb(fail);
});
}
void JitCompiler::EmitLEU_RR()
{
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
cc.cmp(regD[B], regD[C]);
if (check) cc.jbe(fail);
else cc.jnbe(fail);
});
}
void JitCompiler::EmitLEU_RK()
{
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
cc.cmp(regD[B], konstd[C]);
if (check) cc.jbe(fail);
else cc.jnbe(fail);
});
}
void JitCompiler::EmitLEU_KR()
{
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
2018-10-07 07:02:28 +00:00
auto tmp = newTempIntPtr();
cc.mov(tmp, asmjit::imm_ptr(&konstd[B]));
cc.cmp(asmjit::x86::ptr(tmp), regD[C]);
if (check) cc.jbe(fail);
else cc.jnbe(fail);
});
}
/////////////////////////////////////////////////////////////////////////////
// Double-precision floating point math.
void JitCompiler::EmitADDF_RR()
{
auto rc = CheckRegF(C, A);
if (A != B)
cc.movsd(regF[A], regF[B]);
cc.addsd(regF[A], rc);
}
void JitCompiler::EmitADDF_RK()
{
2018-10-07 07:02:28 +00:00
auto tmp = newTempIntPtr();
if (A != B)
cc.movsd(regF[A], regF[B]);
cc.mov(tmp, asmjit::imm_ptr(&konstf[C]));
cc.addsd(regF[A], asmjit::x86::qword_ptr(tmp));
}
void JitCompiler::EmitSUBF_RR()
{
auto rc = CheckRegF(C, A);
if (A != B)
cc.movsd(regF[A], regF[B]);
cc.subsd(regF[A], rc);
}
void JitCompiler::EmitSUBF_RK()
{
2018-10-07 07:02:28 +00:00
auto tmp = newTempIntPtr();
if (A != B)
cc.movsd(regF[A], regF[B]);
cc.mov(tmp, asmjit::imm_ptr(&konstf[C]));
cc.subsd(regF[A], asmjit::x86::qword_ptr(tmp));
}
void JitCompiler::EmitSUBF_KR()
{
auto rc = CheckRegF(C, A);
2018-10-07 07:02:28 +00:00
auto tmp = newTempIntPtr();
cc.mov(tmp, asmjit::imm_ptr(&konstf[B]));
cc.movsd(regF[A], asmjit::x86::qword_ptr(tmp));
cc.subsd(regF[A], rc);
}
void JitCompiler::EmitMULF_RR()
{
auto rc = CheckRegF(C, A);
if (A != B)
cc.movsd(regF[A], regF[B]);
cc.mulsd(regF[A], rc);
}
void JitCompiler::EmitMULF_RK()
{
2018-10-07 07:02:28 +00:00
auto tmp = newTempIntPtr();
if (A != B)
cc.movsd(regF[A], regF[B]);
cc.mov(tmp, asmjit::imm_ptr(&konstf[C]));
cc.mulsd(regF[A], asmjit::x86::qword_ptr(tmp));
}
void JitCompiler::EmitDIVF_RR()
{
auto label = cc.newLabel();
cc.ptest(regF[C], regF[C]);
cc.jne(label);
EmitThrowException(X_DIVISION_BY_ZERO);
cc.bind(label);
auto rc = CheckRegF(C, A);
cc.movsd(regF[A], regF[B]);
cc.divsd(regF[A], rc);
}
void JitCompiler::EmitDIVF_RK()
{
if (konstf[C] == 0.)
{
EmitThrowException(X_DIVISION_BY_ZERO);
}
else
{
2018-10-07 07:02:28 +00:00
auto tmp = newTempIntPtr();
cc.movsd(regF[A], regF[B]);
cc.mov(tmp, asmjit::imm_ptr(&konstf[C]));
cc.divsd(regF[A], asmjit::x86::qword_ptr(tmp));
}
}
void JitCompiler::EmitDIVF_KR()
{
auto rc = CheckRegF(C, A);
2018-10-07 07:02:28 +00:00
auto tmp = newTempIntPtr();
cc.mov(tmp, asmjit::imm_ptr(&konstf[B]));
cc.movsd(regF[A], asmjit::x86::qword_ptr(tmp));
cc.divsd(regF[A], rc);
}
void JitCompiler::EmitMODF_RR()
{
auto label = cc.newLabel();
cc.ptest(regF[C], regF[C]);
cc.jne(label);
EmitThrowException(X_DIVISION_BY_ZERO);
cc.bind(label);
2018-10-07 07:02:28 +00:00
auto result = newResultXmmSd();
auto call = CreateCall<double, double, double>([](double a, double b) -> double
{
return a - floor(a / b) * b;
});
call->setRet(0, result);
call->setArg(0, regF[B]);
call->setArg(1, regF[C]);
cc.movsd(regF[A], result);
}
void JitCompiler::EmitMODF_RK()
{
auto label = cc.newLabel();
cc.ptest(regF[C], regF[C]);
cc.jne(label);
EmitThrowException(X_DIVISION_BY_ZERO);
cc.bind(label);
2018-10-07 07:02:28 +00:00
auto tmp = newTempXmmSd();
cc.movsd(tmp, asmjit::x86::ptr(ToMemAddress(&konstf[C])));
2018-10-07 07:02:28 +00:00
auto result = newResultXmmSd();
auto call = CreateCall<double, double, double>([](double a, double b) -> double {
return a - floor(a / b) * b;
});
call->setRet(0, result);
call->setArg(0, regF[B]);
call->setArg(1, tmp);
cc.movsd(regF[A], result);
}
void JitCompiler::EmitMODF_KR()
{
using namespace asmjit;
auto label = cc.newLabel();
cc.ptest(regF[C], regF[C]);
cc.jne(label);
EmitThrowException(X_DIVISION_BY_ZERO);
cc.bind(label);
2018-10-07 07:02:28 +00:00
auto tmp = newTempXmmSd();
cc.movsd(tmp, x86::ptr(ToMemAddress(&konstf[B])));
2018-10-07 07:02:28 +00:00
auto result = newResultXmmSd();
auto call = CreateCall<double, double, double>([](double a, double b) -> double {
return a - floor(a / b) * b;
});
call->setRet(0, result);
call->setArg(0, tmp);
call->setArg(1, regF[C]);
cc.movsd(regF[A], result);
}
void JitCompiler::EmitPOWF_RR()
{
2018-10-07 07:02:28 +00:00
auto result = newResultXmmSd();
auto call = CreateCall<double, double, double>(g_pow);
call->setRet(0, result);
call->setArg(0, regF[B]);
call->setArg(1, regF[C]);
cc.movsd(regF[A], result);
}
void JitCompiler::EmitPOWF_RK()
{
2018-10-07 07:02:28 +00:00
auto tmp = newTempIntPtr();
auto tmp2 = newTempXmmSd();
cc.mov(tmp, asmjit::imm_ptr(&konstf[C]));
cc.movsd(tmp2, asmjit::x86::qword_ptr(tmp));
2018-10-07 07:02:28 +00:00
auto result = newResultXmmSd();
auto call = CreateCall<double, double, double>(g_pow);
call->setRet(0, result);
call->setArg(0, regF[B]);
call->setArg(1, tmp2);
cc.movsd(regF[A], result);
}
void JitCompiler::EmitPOWF_KR()
{
2018-10-07 07:02:28 +00:00
auto tmp = newTempIntPtr();
auto tmp2 = newTempXmmSd();
cc.mov(tmp, asmjit::imm_ptr(&konstf[B]));
cc.movsd(tmp2, asmjit::x86::qword_ptr(tmp));
2018-10-07 07:02:28 +00:00
auto result = newResultXmmSd();
auto call = CreateCall<double, double, double>(g_pow);
call->setRet(0, result);
call->setArg(0, tmp2);
call->setArg(1, regF[C]);
cc.movsd(regF[A], result);
}
void JitCompiler::EmitMINF_RR()
{
auto rc = CheckRegF(C, A);
if (A != B)
cc.movsd(regF[A], regF[B]);
cc.minsd(regF[A], rc);
}
void JitCompiler::EmitMINF_RK()
{
auto rb = CheckRegF(B, A);
2018-10-07 07:02:28 +00:00
auto tmp = newTempIntPtr();
cc.mov(tmp, asmjit::imm_ptr(&konstf[C]));
cc.movsd(regF[A], asmjit::x86::qword_ptr(tmp));
cc.minsd(regF[A], rb);
}
void JitCompiler::EmitMAXF_RR()
{
auto rc = CheckRegF(C, A);
if (A != B)
cc.movsd(regF[A], regF[B]);
cc.maxsd(regF[A], rc);
}
void JitCompiler::EmitMAXF_RK()
{
auto rb = CheckRegF(B, A);
2018-10-07 07:02:28 +00:00
auto tmp = newTempIntPtr();
cc.mov(tmp, asmjit::imm_ptr(&konstf[C]));
cc.movsd(regF[A], asmjit::x86::qword_ptr(tmp));
cc.maxsd(regF[A], rb);
}
void JitCompiler::EmitATAN2()
{
2018-10-07 07:02:28 +00:00
auto result = newResultXmmSd();
auto call = CreateCall<double, double, double>(g_atan2);
call->setRet(0, result);
call->setArg(0, regF[B]);
call->setArg(1, regF[C]);
cc.movsd(regF[A], result);
static const double constant = 180 / M_PI;
2018-10-07 07:02:28 +00:00
auto tmp = newTempIntPtr();
cc.mov(tmp, asmjit::imm_ptr(&constant));
cc.mulsd(regF[A], asmjit::x86::qword_ptr(tmp));
}
void JitCompiler::EmitFLOP()
{
if (C == FLOP_NEG)
{
auto mask = cc.newDoubleConst(asmjit::kConstScopeLocal, -0.0);
2018-10-07 07:02:28 +00:00
auto maskXmm = newTempXmmSd();
cc.movsd(maskXmm, mask);
if (A != B)
cc.movsd(regF[A], regF[B]);
cc.xorpd(regF[A], maskXmm);
}
else
{
2018-10-07 07:02:28 +00:00
auto v = newTempXmmSd();
cc.movsd(v, regF[B]);
if (C == FLOP_TAN_DEG)
{
static const double constant = M_PI / 180;
2018-10-07 07:02:28 +00:00
auto tmp = newTempIntPtr();
cc.mov(tmp, asmjit::imm_ptr(&constant));
cc.mulsd(v, asmjit::x86::qword_ptr(tmp));
}
typedef double(*FuncPtr)(double);
FuncPtr func = nullptr;
switch (C)
{
default: I_FatalError("Unknown OP_FLOP subfunction");
case FLOP_ABS: func = fabs; break;
case FLOP_EXP: func = g_exp; break;
case FLOP_LOG: func = g_log; break;
case FLOP_LOG10: func = g_log10; break;
case FLOP_SQRT: func = g_sqrt; break;
case FLOP_CEIL: func = ceil; break;
case FLOP_FLOOR: func = floor; break;
case FLOP_ACOS: func = g_acos; break;
case FLOP_ASIN: func = g_asin; break;
case FLOP_ATAN: func = g_atan; break;
case FLOP_COS: func = g_cos; break;
case FLOP_SIN: func = g_sin; break;
case FLOP_TAN: func = g_tan; break;
case FLOP_ACOS_DEG: func = g_acos; break;
case FLOP_ASIN_DEG: func = g_asin; break;
case FLOP_ATAN_DEG: func = g_atan; break;
case FLOP_COS_DEG: func = g_cosdeg; break;
case FLOP_SIN_DEG: func = g_sindeg; break;
case FLOP_TAN_DEG: func = g_tan; break;
case FLOP_COSH: func = g_cosh; break;
case FLOP_SINH: func = g_sinh; break;
case FLOP_TANH: func = g_tanh; break;
}
2018-10-07 07:02:28 +00:00
auto result = newResultXmmSd();
auto call = CreateCall<double, double>(func);
call->setRet(0, result);
call->setArg(0, v);
cc.movsd(regF[A], result);
if (C == FLOP_ACOS_DEG || C == FLOP_ASIN_DEG || C == FLOP_ATAN_DEG)
{
static const double constant = 180 / M_PI;
2018-10-07 07:02:28 +00:00
auto tmp = newTempIntPtr();
cc.mov(tmp, asmjit::imm_ptr(&constant));
cc.mulsd(regF[A], asmjit::x86::qword_ptr(tmp));
}
}
}
void JitCompiler::EmitEQF_R()
{
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
bool approx = static_cast<bool>(A & CMP_APPROX);
if (!approx)
{
cc.ucomisd(regF[B], regF[C]);
if (check) {
cc.jp(success);
cc.je(fail);
}
else {
cc.jp(fail);
cc.jne(fail);
}
}
else
{
2018-10-07 07:02:28 +00:00
auto tmp = newTempXmmSd();
const int64_t absMaskInt = 0x7FFFFFFFFFFFFFFF;
auto absMask = cc.newDoubleConst(asmjit::kConstScopeLocal, reinterpret_cast<const double&>(absMaskInt));
2018-10-07 07:02:28 +00:00
auto absMaskXmm = newTempXmmPd();
auto epsilon = cc.newDoubleConst(asmjit::kConstScopeLocal, VM_EPSILON);
2018-10-07 07:02:28 +00:00
auto epsilonXmm = newTempXmmSd();
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);
if (check) cc.ja(fail);
else cc.jna(fail);
}
});
}
void JitCompiler::EmitEQF_K()
{
using namespace asmjit;
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
bool approx = static_cast<bool>(A & CMP_APPROX);
if (!approx) {
2018-10-07 07:02:28 +00:00
auto konstTmp = newTempIntPtr();
cc.mov(konstTmp, asmjit::imm_ptr(&konstf[C]));
cc.ucomisd(regF[B], x86::qword_ptr(konstTmp));
if (check) {
cc.jp(success);
cc.je(fail);
}
else {
cc.jp(fail);
cc.jne(fail);
}
}
else {
2018-10-07 07:02:28 +00:00
auto konstTmp = newTempIntPtr();
auto subTmp = newTempXmmSd();
const int64_t absMaskInt = 0x7FFFFFFFFFFFFFFF;
auto absMask = cc.newDoubleConst(kConstScopeLocal, reinterpret_cast<const double&>(absMaskInt));
2018-10-07 07:02:28 +00:00
auto absMaskXmm = newTempXmmPd();
auto epsilon = cc.newDoubleConst(kConstScopeLocal, VM_EPSILON);
2018-10-07 07:02:28 +00:00
auto epsilonXmm = newTempXmmSd();
cc.mov(konstTmp, asmjit::imm_ptr(&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);
if (check) cc.ja(fail);
else cc.jna(fail);
}
});
}
void JitCompiler::EmitLTF_RR()
{
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
if (static_cast<bool>(A & CMP_APPROX)) I_FatalError("CMP_APPROX not implemented for LTF_RR.\n");
cc.ucomisd(regF[C], regF[B]);
if (check) cc.ja(fail);
else cc.jna(fail);
});
}
void JitCompiler::EmitLTF_RK()
{
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
if (static_cast<bool>(A & CMP_APPROX)) I_FatalError("CMP_APPROX not implemented for LTF_RK.\n");
2018-10-07 07:02:28 +00:00
auto constTmp = newTempIntPtr();
auto xmmTmp = newTempXmmSd();
cc.mov(constTmp, asmjit::imm_ptr(&konstf[C]));
cc.movsd(xmmTmp, asmjit::x86::qword_ptr(constTmp));
cc.ucomisd(xmmTmp, regF[B]);
if (check) cc.ja(fail);
else cc.jna(fail);
});
}
void JitCompiler::EmitLTF_KR()
{
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
if (static_cast<bool>(A & CMP_APPROX)) I_FatalError("CMP_APPROX not implemented for LTF_KR.\n");
2018-10-07 07:02:28 +00:00
auto tmp = newTempIntPtr();
cc.mov(tmp, asmjit::imm_ptr(&konstf[B]));
cc.ucomisd(regF[C], asmjit::x86::qword_ptr(tmp));
if (check) cc.ja(fail);
else cc.jna(fail);
});
}
void JitCompiler::EmitLEF_RR()
{
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
if (static_cast<bool>(A & CMP_APPROX)) I_FatalError("CMP_APPROX not implemented for LEF_RR.\n");
cc.ucomisd(regF[C], regF[B]);
if (check) cc.jae(fail);
else cc.jnae(fail);
});
}
void JitCompiler::EmitLEF_RK()
{
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
if (static_cast<bool>(A & CMP_APPROX)) I_FatalError("CMP_APPROX not implemented for LEF_RK.\n");
2018-10-07 07:02:28 +00:00
auto constTmp = newTempIntPtr();
auto xmmTmp = newTempXmmSd();
cc.mov(constTmp, asmjit::imm_ptr(&konstf[C]));
cc.movsd(xmmTmp, asmjit::x86::qword_ptr(constTmp));
cc.ucomisd(xmmTmp, regF[B]);
if (check) cc.jae(fail);
else cc.jnae(fail);
});
}
void JitCompiler::EmitLEF_KR()
{
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
if (static_cast<bool>(A & CMP_APPROX)) I_FatalError("CMP_APPROX not implemented for LEF_KR.\n");
2018-10-07 07:02:28 +00:00
auto tmp = newTempIntPtr();
cc.mov(tmp, asmjit::imm_ptr(&konstf[B]));
cc.ucomisd(regF[C], asmjit::x86::qword_ptr(tmp));
if (check) cc.jae(fail);
else cc.jnae(fail);
});
}
/////////////////////////////////////////////////////////////////////////////
// Vector math. (2D)
void JitCompiler::EmitNEGV2()
{
auto mask = cc.newDoubleConst(asmjit::kConstScopeLocal, -0.0);
2018-10-07 07:02:28 +00:00
auto maskXmm = newTempXmmSd();
cc.movsd(maskXmm, mask);
cc.movsd(regF[A], regF[B]);
cc.xorpd(regF[A], maskXmm);
cc.movsd(regF[A + 1], regF[B + 1]);
cc.xorpd(regF[A + 1], maskXmm);
}
void JitCompiler::EmitADDV2_RR()
{
auto rc0 = CheckRegF(C, A);
auto rc1 = CheckRegF(C + 1, A + 1);
cc.movsd(regF[A], regF[B]);
cc.movsd(regF[A + 1], regF[B + 1]);
cc.addsd(regF[A], rc0);
cc.addsd(regF[A + 1], rc1);
}
void JitCompiler::EmitSUBV2_RR()
{
auto rc0 = CheckRegF(C, A);
auto rc1 = CheckRegF(C + 1, A + 1);
cc.movsd(regF[A], regF[B]);
cc.movsd(regF[A + 1], regF[B + 1]);
cc.subsd(regF[A], rc0);
cc.subsd(regF[A + 1], rc1);
}
void JitCompiler::EmitDOTV2_RR()
{
auto rc0 = CheckRegF(C, A);
auto rc1 = CheckRegF(C + 1, A);
2018-10-07 07:02:28 +00:00
auto tmp = newTempXmmSd();
cc.movsd(regF[A], regF[B]);
cc.mulsd(regF[A], rc0);
cc.movsd(tmp, regF[B + 1]);
cc.mulsd(tmp, rc1);
cc.addsd(regF[A], tmp);
}
void JitCompiler::EmitMULVF2_RR()
{
auto rc = CheckRegF(C, A, A + 1);
cc.movsd(regF[A], regF[B]);
cc.movsd(regF[A + 1], regF[B + 1]);
cc.mulsd(regF[A], rc);
cc.mulsd(regF[A + 1], rc);
}
void JitCompiler::EmitMULVF2_RK()
{
2018-10-07 07:02:28 +00:00
auto tmp = newTempIntPtr();
cc.movsd(regF[A], regF[B]);
cc.movsd(regF[A + 1], regF[B + 1]);
cc.mov(tmp, asmjit::imm_ptr(&konstf[C]));
cc.mulsd(regF[A], asmjit::x86::qword_ptr(tmp));
cc.mulsd(regF[A + 1], asmjit::x86::qword_ptr(tmp));
}
void JitCompiler::EmitDIVVF2_RR()
{
auto rc = CheckRegF(C, A, A + 1);
cc.movsd(regF[A], regF[B]);
cc.movsd(regF[A + 1], regF[B + 1]);
cc.divsd(regF[A], rc);
cc.divsd(regF[A + 1], rc);
}
void JitCompiler::EmitDIVVF2_RK()
{
2018-10-07 07:02:28 +00:00
auto tmp = newTempIntPtr();
cc.movsd(regF[A], regF[B]);
cc.movsd(regF[A + 1], regF[B + 1]);
cc.mov(tmp, asmjit::imm_ptr(&konstf[C]));
cc.divsd(regF[A], asmjit::x86::qword_ptr(tmp));
cc.divsd(regF[A + 1], asmjit::x86::qword_ptr(tmp));
}
void JitCompiler::EmitLENV2()
{
auto rb0 = CheckRegF(B, A);
auto rb1 = CheckRegF(B + 1, A);
2018-10-07 07:02:28 +00:00
auto tmp = newTempXmmSd();
cc.movsd(regF[A], regF[B]);
cc.mulsd(regF[A], rb0);
cc.movsd(tmp, rb1);
cc.mulsd(tmp, rb1);
cc.addsd(regF[A], tmp);
CallSqrt(regF[A], regF[A]);
}
void JitCompiler::EmitEQV2_R()
{
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
if (static_cast<bool>(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);
}
});
}
void JitCompiler::EmitEQV2_K()
{
I_FatalError("EQV2_K is not used.");
}
/////////////////////////////////////////////////////////////////////////////
// Vector math. (3D)
void JitCompiler::EmitNEGV3()
{
auto mask = cc.newDoubleConst(asmjit::kConstScopeLocal, -0.0);
2018-10-07 07:02:28 +00:00
auto maskXmm = newTempXmmSd();
cc.movsd(maskXmm, mask);
cc.movsd(regF[A], regF[B]);
cc.xorpd(regF[A], maskXmm);
cc.movsd(regF[A + 1], regF[B + 1]);
cc.xorpd(regF[A + 1], maskXmm);
cc.movsd(regF[A + 2], regF[B + 2]);
cc.xorpd(regF[A + 2], maskXmm);
}
void JitCompiler::EmitADDV3_RR()
{
auto rc0 = CheckRegF(C, A);
auto rc1 = CheckRegF(C + 1, A + 1);
auto rc2 = CheckRegF(C + 2, A + 2);
cc.movsd(regF[A], regF[B]);
cc.movsd(regF[A + 1], regF[B + 1]);
cc.movsd(regF[A + 2], regF[B + 2]);
cc.addsd(regF[A], rc0);
cc.addsd(regF[A + 1], rc1);
cc.addsd(regF[A + 2], rc2);
}
void JitCompiler::EmitSUBV3_RR()
{
auto rc0 = CheckRegF(C, A);
auto rc1 = CheckRegF(C + 1, A + 1);
auto rc2 = CheckRegF(C + 2, A + 2);
cc.movsd(regF[A], regF[B]);
cc.movsd(regF[A + 1], regF[B + 1]);
cc.movsd(regF[A + 2], regF[B + 2]);
cc.subsd(regF[A], rc0);
cc.subsd(regF[A + 1], rc1);
cc.subsd(regF[A + 2], rc2);
}
void JitCompiler::EmitDOTV3_RR()
{
auto rb1 = CheckRegF(B + 1, A);
auto rb2 = CheckRegF(B + 2, A);
auto rc0 = CheckRegF(C, A);
auto rc1 = CheckRegF(C + 1, A);
auto rc2 = CheckRegF(C + 2, A);
2018-10-07 07:02:28 +00:00
auto tmp = newTempXmmSd();
cc.movsd(regF[A], regF[B]);
cc.mulsd(regF[A], rc0);
cc.movsd(tmp, rb1);
cc.mulsd(tmp, rc1);
cc.addsd(regF[A], tmp);
cc.movsd(tmp, rb2);
cc.mulsd(tmp, rc2);
cc.addsd(regF[A], tmp);
}
void JitCompiler::EmitCROSSV_RR()
{
2018-10-07 07:02:28 +00:00
auto tmp = newTempXmmSd();
auto a0 = CheckRegF(B, A);
auto a1 = CheckRegF(B + 1, A + 1);
auto a2 = CheckRegF(B + 2, A + 2);
auto b0 = CheckRegF(C, A);
auto b1 = CheckRegF(C + 1, A + 1);
auto b2 = CheckRegF(C + 2, A + 2);
// r0 = a1b2 - a2b1
cc.movsd(regF[A], a1);
cc.mulsd(regF[A], b2);
cc.movsd(tmp, a2);
cc.mulsd(tmp, b1);
cc.subsd(regF[A], tmp);
// r1 = a2b0 - a0b2
cc.movsd(regF[A + 1], a2);
cc.mulsd(regF[A + 1], b0);
cc.movsd(tmp, a0);
cc.mulsd(tmp, b2);
cc.subsd(regF[A + 1], tmp);
// r2 = a0b1 - a1b0
cc.movsd(regF[A + 2], a0);
cc.mulsd(regF[A + 2], b1);
cc.movsd(tmp, a1);
cc.mulsd(tmp, b0);
cc.subsd(regF[A + 2], tmp);
}
void JitCompiler::EmitMULVF3_RR()
{
auto rc = CheckRegF(C, A, A + 1, A + 2);
cc.movsd(regF[A], regF[B]);
cc.movsd(regF[A + 1], regF[B + 1]);
cc.movsd(regF[A + 2], regF[B + 2]);
cc.mulsd(regF[A], rc);
cc.mulsd(regF[A + 1], rc);
cc.mulsd(regF[A + 2], rc);
}
void JitCompiler::EmitMULVF3_RK()
{
2018-10-07 07:02:28 +00:00
auto tmp = newTempIntPtr();
cc.movsd(regF[A], regF[B]);
cc.movsd(regF[A + 1], regF[B + 1]);
cc.movsd(regF[A + 2], regF[B + 2]);
cc.mov(tmp, asmjit::imm_ptr(&konstf[C]));
cc.mulsd(regF[A], asmjit::x86::qword_ptr(tmp));
cc.mulsd(regF[A + 1], asmjit::x86::qword_ptr(tmp));
cc.mulsd(regF[A + 2], asmjit::x86::qword_ptr(tmp));
}
void JitCompiler::EmitDIVVF3_RR()
{
auto rc = CheckRegF(C, A, A + 1, A + 2);
cc.movsd(regF[A], regF[B]);
cc.movsd(regF[A + 1], regF[B + 1]);
cc.movsd(regF[A + 2], regF[B + 2]);
cc.divsd(regF[A], rc);
cc.divsd(regF[A + 1], rc);
cc.divsd(regF[A + 2], rc);
}
void JitCompiler::EmitDIVVF3_RK()
{
2018-10-07 07:02:28 +00:00
auto tmp = newTempIntPtr();
cc.movsd(regF[A], regF[B]);
cc.movsd(regF[A + 1], regF[B + 1]);
cc.movsd(regF[A + 2], regF[B + 2]);
cc.mov(tmp, asmjit::imm_ptr(&konstf[C]));
cc.divsd(regF[A], asmjit::x86::qword_ptr(tmp));
cc.divsd(regF[A + 1], asmjit::x86::qword_ptr(tmp));
cc.divsd(regF[A + 2], asmjit::x86::qword_ptr(tmp));
}
void JitCompiler::EmitLENV3()
{
auto rb1 = CheckRegF(B + 1, A);
auto rb2 = CheckRegF(B + 2, A);
2018-10-07 07:02:28 +00:00
auto tmp = newTempXmmSd();
cc.movsd(regF[A], regF[B]);
cc.mulsd(regF[A], regF[B]);
cc.movsd(tmp, rb1);
cc.mulsd(tmp, rb1);
cc.addsd(regF[A], tmp);
cc.movsd(tmp, rb2);
cc.mulsd(tmp, rb2);
cc.addsd(regF[A], tmp);
CallSqrt(regF[A], regF[A]);
}
void JitCompiler::EmitEQV3_R()
{
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
if (static_cast<bool>(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);
}
});
}
void JitCompiler::EmitEQV3_K()
{
I_FatalError("EQV3_K is not used.");
}
/////////////////////////////////////////////////////////////////////////////
// Pointer math.
void JitCompiler::EmitADDA_RR()
{
2018-10-07 07:02:28 +00:00
auto tmp = newTempIntPtr();
auto label = cc.newLabel();
cc.mov(tmp, regA[B]);
// Check if zero, the first operand is zero, if it is, don't add.
cc.cmp(tmp, 0);
cc.je(label);
2018-10-07 07:02:28 +00:00
auto tmpptr = newTempIntPtr();
cc.mov(tmpptr, regD[C]);
cc.add(tmp, tmpptr);
cc.bind(label);
cc.mov(regA[A], tmp);
}
void JitCompiler::EmitADDA_RK()
{
2018-10-07 07:02:28 +00:00
auto tmp = newTempIntPtr();
auto label = cc.newLabel();
cc.mov(tmp, regA[B]);
// Check if zero, the first operand is zero, if it is, don't add.
cc.cmp(tmp, 0);
cc.je(label);
cc.add(tmp, konstd[C]);
cc.bind(label);
cc.mov(regA[A], tmp);
}
void JitCompiler::EmitSUBA()
{
2018-10-07 07:02:28 +00:00
auto tmp = newTempIntPtr();
cc.mov(tmp, regA[B]);
cc.sub(tmp, regD[C]);
cc.mov(regA[A], tmp);
}
void JitCompiler::EmitEQA_R()
{
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
cc.cmp(regA[B], regA[C]);
if (check) cc.je(fail);
else cc.jne(fail);
});
}
void JitCompiler::EmitEQA_K()
{
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
2018-10-07 07:02:28 +00:00
auto tmp = newTempIntPtr();
cc.mov(tmp, asmjit::imm_ptr(konsta[C].v));
cc.cmp(regA[B], tmp);
if (check) cc.je(fail);
else cc.jne(fail);
});
}
void JitCompiler::CallSqrt(const asmjit::X86Xmm &a, const asmjit::X86Xmm &b)
{
2018-10-07 07:02:28 +00:00
auto result = newResultXmmSd();
auto call = CreateCall<double, double>(g_sqrt);
call->setRet(0, result);
call->setArg(0, b);
cc.movsd(a, result);
}