2018-09-13 00:29:04 +00:00
|
|
|
|
|
|
|
#include "jitintern.h"
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// String instructions.
|
|
|
|
|
|
|
|
void JitCompiler::EmitCONCAT()
|
|
|
|
{
|
2018-09-13 19:31:06 +00:00
|
|
|
auto rc = CheckRegS(C, A);
|
2018-09-17 10:00:25 +00:00
|
|
|
auto call = CreateCall<void, FString*, FString*, FString*>([](FString* to, FString* first, FString* second) {
|
2018-09-13 19:31:06 +00:00
|
|
|
*to = *first + *second;
|
2018-09-17 10:00:25 +00:00
|
|
|
});
|
2018-09-13 19:31:06 +00:00
|
|
|
call->setArg(0, regS[A]);
|
|
|
|
call->setArg(1, regS[B]);
|
|
|
|
call->setArg(2, rc);
|
2018-09-13 00:29:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void JitCompiler::EmitLENS()
|
|
|
|
{
|
2018-09-17 10:00:25 +00:00
|
|
|
auto call = CreateCall<int, FString*>([](FString* str) -> int {
|
2018-09-13 19:31:06 +00:00
|
|
|
return static_cast<int>(str->Len());
|
2018-09-17 10:00:25 +00:00
|
|
|
});
|
2018-09-13 19:31:06 +00:00
|
|
|
call->setRet(0, regD[A]);
|
|
|
|
call->setArg(0, regS[B]);
|
2018-09-13 00:29:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void JitCompiler::EmitCMPS()
|
|
|
|
{
|
2018-09-13 19:31:06 +00:00
|
|
|
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);
|
|
|
|
};
|
|
|
|
|
2018-09-17 10:00:25 +00:00
|
|
|
auto call = static_cast<bool>(A & CMP_APPROX) ?
|
|
|
|
CreateCall<int, FString*, FString*>(compareNoCaseLambda) :
|
|
|
|
CreateCall<int, FString*, FString*>(compareLambda);
|
2018-09-13 19:31:06 +00:00
|
|
|
|
|
|
|
auto result = cc.newInt32();
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
});
|
2018-09-13 00:29:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// 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()
|
|
|
|
{
|
|
|
|
auto tmp0 = cc.newInt32();
|
|
|
|
auto tmp1 = cc.newInt32();
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
auto tmp0 = cc.newInt32();
|
|
|
|
auto tmp1 = cc.newInt32();
|
|
|
|
auto konstTmp = cc.newIntPtr();
|
|
|
|
cc.mov(tmp0, regD[B]);
|
|
|
|
cc.cdq(tmp1, tmp0);
|
|
|
|
cc.mov(konstTmp, ToMemAddress(&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()
|
|
|
|
{
|
|
|
|
auto tmp0 = cc.newInt32();
|
|
|
|
auto tmp1 = cc.newInt32();
|
|
|
|
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()
|
|
|
|
{
|
|
|
|
auto tmp0 = cc.newInt32();
|
|
|
|
auto tmp1 = cc.newInt32();
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
auto tmp0 = cc.newInt32();
|
|
|
|
auto tmp1 = cc.newInt32();
|
|
|
|
auto konstTmp = cc.newIntPtr();
|
|
|
|
cc.mov(tmp0, regD[B]);
|
|
|
|
cc.mov(tmp1, 0);
|
|
|
|
cc.mov(konstTmp, ToMemAddress(&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()
|
|
|
|
{
|
|
|
|
auto tmp0 = cc.newInt32();
|
|
|
|
auto tmp1 = cc.newInt32();
|
|
|
|
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()
|
|
|
|
{
|
|
|
|
auto tmp0 = cc.newInt32();
|
|
|
|
auto tmp1 = cc.newInt32();
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
auto tmp0 = cc.newInt32();
|
|
|
|
auto tmp1 = cc.newInt32();
|
|
|
|
auto konstTmp = cc.newIntPtr();
|
|
|
|
cc.mov(tmp0, regD[B]);
|
|
|
|
cc.cdq(tmp1, tmp0);
|
|
|
|
cc.mov(konstTmp, ToMemAddress(&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()
|
|
|
|
{
|
|
|
|
auto tmp0 = cc.newInt32();
|
|
|
|
auto tmp1 = cc.newInt32();
|
|
|
|
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()
|
|
|
|
{
|
|
|
|
auto tmp0 = cc.newInt32();
|
|
|
|
auto tmp1 = cc.newInt32();
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
auto tmp0 = cc.newInt32();
|
|
|
|
auto tmp1 = cc.newInt32();
|
|
|
|
auto konstTmp = cc.newIntPtr();
|
|
|
|
cc.mov(tmp0, regD[B]);
|
|
|
|
cc.mov(tmp1, 0);
|
|
|
|
cc.mov(konstTmp, ToMemAddress(&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()
|
|
|
|
{
|
|
|
|
auto tmp0 = cc.newInt32();
|
|
|
|
auto tmp1 = cc.newInt32();
|
|
|
|
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()
|
|
|
|
{
|
|
|
|
auto tmp0 = cc.newXmmSs();
|
|
|
|
auto tmp1 = cc.newXmmSs();
|
|
|
|
cc.movd(tmp0, regD[B]);
|
|
|
|
cc.movd(tmp1, regD[C]);
|
|
|
|
cc.pminsd(tmp0, tmp1);
|
|
|
|
cc.movd(regD[A], tmp0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void JitCompiler::EmitMIN_RK()
|
|
|
|
{
|
|
|
|
auto tmp0 = cc.newXmmSs();
|
|
|
|
auto tmp1 = cc.newXmmSs();
|
|
|
|
auto konstTmp = cc.newIntPtr();
|
|
|
|
cc.mov(konstTmp, ToMemAddress(&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()
|
|
|
|
{
|
|
|
|
auto tmp0 = cc.newXmmSs();
|
|
|
|
auto tmp1 = cc.newXmmSs();
|
|
|
|
cc.movd(tmp0, regD[B]);
|
|
|
|
cc.movd(tmp1, regD[C]);
|
|
|
|
cc.pmaxsd(tmp0, tmp1);
|
|
|
|
cc.movd(regD[A], tmp0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void JitCompiler::EmitMAX_RK()
|
|
|
|
{
|
|
|
|
auto tmp0 = cc.newXmmSs();
|
|
|
|
auto tmp1 = cc.newXmmSs();
|
|
|
|
auto konstTmp = cc.newIntPtr();
|
|
|
|
cc.mov(konstTmp, ToMemAddress(&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);
|
|
|
|
auto tmp = cc.newInt32();
|
|
|
|
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) {
|
|
|
|
auto tmp = cc.newIntPtr();
|
|
|
|
cc.mov(tmp, ToMemAddress(&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) {
|
|
|
|
auto tmp = cc.newIntPtr();
|
|
|
|
cc.mov(tmp, ToMemAddress(&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) {
|
|
|
|
auto tmp = cc.newIntPtr();
|
|
|
|
cc.mov(tmp, ToMemAddress(&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) {
|
|
|
|
auto tmp = cc.newIntPtr();
|
|
|
|
cc.mov(tmp, ToMemAddress(&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()
|
|
|
|
{
|
|
|
|
auto tmp = cc.newIntPtr();
|
|
|
|
if (A != B)
|
|
|
|
cc.movsd(regF[A], regF[B]);
|
|
|
|
cc.mov(tmp, ToMemAddress(&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()
|
|
|
|
{
|
|
|
|
auto tmp = cc.newIntPtr();
|
|
|
|
if (A != B)
|
|
|
|
cc.movsd(regF[A], regF[B]);
|
|
|
|
cc.mov(tmp, ToMemAddress(&konstf[C]));
|
|
|
|
cc.subsd(regF[A], asmjit::x86::qword_ptr(tmp));
|
|
|
|
}
|
|
|
|
|
|
|
|
void JitCompiler::EmitSUBF_KR()
|
|
|
|
{
|
|
|
|
auto rc = CheckRegF(C, A);
|
|
|
|
auto tmp = cc.newIntPtr();
|
|
|
|
cc.mov(tmp, ToMemAddress(&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()
|
|
|
|
{
|
|
|
|
auto tmp = cc.newIntPtr();
|
|
|
|
if (A != B)
|
|
|
|
cc.movsd(regF[A], regF[B]);
|
|
|
|
cc.mov(tmp, ToMemAddress(&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
|
|
|
|
{
|
|
|
|
auto tmp = cc.newIntPtr();
|
|
|
|
cc.movsd(regF[A], regF[B]);
|
|
|
|
cc.mov(tmp, ToMemAddress(&konstf[C]));
|
|
|
|
cc.divsd(regF[A], asmjit::x86::qword_ptr(tmp));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void JitCompiler::EmitDIVF_KR()
|
|
|
|
{
|
|
|
|
auto rc = CheckRegF(C, A);
|
|
|
|
auto tmp = cc.newIntPtr();
|
|
|
|
cc.mov(tmp, ToMemAddress(&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-09-17 10:00:25 +00:00
|
|
|
auto call = CreateCall<double, double, double>([](double a, double b) -> double
|
2018-09-13 00:29:04 +00:00
|
|
|
{
|
|
|
|
return a - floor(a / b) * b;
|
2018-09-17 10:00:25 +00:00
|
|
|
});
|
2018-09-13 00:29:04 +00:00
|
|
|
call->setRet(0, regF[A]);
|
|
|
|
call->setArg(0, regF[B]);
|
|
|
|
call->setArg(1, regF[C]);
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
auto tmp = cc.newXmm();
|
2018-09-17 10:00:25 +00:00
|
|
|
cc.movsd(tmp, asmjit::x86::ptr(ToMemAddress(&konstf[C])));
|
2018-09-13 00:29:04 +00:00
|
|
|
|
2018-09-17 10:00:25 +00:00
|
|
|
auto call = CreateCall<double, double, double>([](double a, double b) -> double {
|
2018-09-13 00:29:04 +00:00
|
|
|
return a - floor(a / b) * b;
|
2018-09-17 10:00:25 +00:00
|
|
|
});
|
2018-09-13 00:29:04 +00:00
|
|
|
call->setRet(0, regF[A]);
|
|
|
|
call->setArg(0, regF[B]);
|
|
|
|
call->setArg(1, tmp);
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
auto tmp = cc.newXmm();
|
|
|
|
cc.movsd(tmp, x86::ptr(ToMemAddress(&konstf[B])));
|
|
|
|
|
2018-09-17 10:00:25 +00:00
|
|
|
auto call = CreateCall<double, double, double>([](double a, double b) -> double {
|
2018-09-13 00:29:04 +00:00
|
|
|
return a - floor(a / b) * b;
|
2018-09-17 10:00:25 +00:00
|
|
|
});
|
2018-09-13 00:29:04 +00:00
|
|
|
call->setRet(0, regF[A]);
|
|
|
|
call->setArg(0, tmp);
|
|
|
|
call->setArg(1, regF[C]);
|
|
|
|
}
|
|
|
|
|
|
|
|
void JitCompiler::EmitPOWF_RR()
|
|
|
|
{
|
2018-09-17 10:00:25 +00:00
|
|
|
auto call = CreateCall<double, double, double>(g_pow);
|
2018-09-13 00:29:04 +00:00
|
|
|
call->setRet(0, regF[A]);
|
|
|
|
call->setArg(0, regF[B]);
|
|
|
|
call->setArg(1, regF[C]);
|
|
|
|
}
|
|
|
|
|
|
|
|
void JitCompiler::EmitPOWF_RK()
|
|
|
|
{
|
|
|
|
auto tmp = cc.newIntPtr();
|
|
|
|
auto tmp2 = cc.newXmm();
|
|
|
|
cc.mov(tmp, ToMemAddress(&konstf[C]));
|
|
|
|
cc.movsd(tmp2, asmjit::x86::qword_ptr(tmp));
|
|
|
|
|
2018-09-17 10:00:25 +00:00
|
|
|
auto call = CreateCall<double, double, double>(g_pow);
|
2018-09-13 00:29:04 +00:00
|
|
|
call->setRet(0, regF[A]);
|
|
|
|
call->setArg(0, regF[B]);
|
|
|
|
call->setArg(1, tmp2);
|
|
|
|
}
|
|
|
|
|
|
|
|
void JitCompiler::EmitPOWF_KR()
|
|
|
|
{
|
|
|
|
auto tmp = cc.newIntPtr();
|
|
|
|
auto tmp2 = cc.newXmm();
|
|
|
|
cc.mov(tmp, ToMemAddress(&konstf[B]));
|
|
|
|
cc.movsd(tmp2, asmjit::x86::qword_ptr(tmp));
|
|
|
|
|
2018-09-17 10:00:25 +00:00
|
|
|
auto call = CreateCall<double, double, double>(g_pow);
|
2018-09-13 00:29:04 +00:00
|
|
|
call->setRet(0, regF[A]);
|
|
|
|
call->setArg(0, tmp2);
|
|
|
|
call->setArg(1, regF[C]);
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
auto tmp = cc.newIntPtr();
|
|
|
|
cc.mov(tmp, ToMemAddress(&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);
|
|
|
|
auto tmp = cc.newIntPtr();
|
|
|
|
cc.mov(tmp, ToMemAddress(&konstf[C]));
|
|
|
|
cc.movsd(regF[A], asmjit::x86::qword_ptr(tmp));
|
|
|
|
cc.maxsd(regF[A], rb);
|
|
|
|
}
|
|
|
|
|
|
|
|
void JitCompiler::EmitATAN2()
|
|
|
|
{
|
2018-09-17 10:00:25 +00:00
|
|
|
auto call = CreateCall<double, double, double>(g_atan2);
|
2018-09-13 00:29:04 +00:00
|
|
|
call->setRet(0, regF[A]);
|
|
|
|
call->setArg(0, regF[B]);
|
|
|
|
call->setArg(1, regF[C]);
|
|
|
|
|
|
|
|
static const double constant = 180 / M_PI;
|
|
|
|
auto tmp = cc.newIntPtr();
|
|
|
|
cc.mov(tmp, ToMemAddress(&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);
|
|
|
|
auto maskXmm = cc.newXmmSd();
|
|
|
|
cc.movsd(maskXmm, mask);
|
|
|
|
if (A != B)
|
|
|
|
cc.movsd(regF[A], regF[B]);
|
|
|
|
cc.xorpd(regF[A], maskXmm);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
auto v = cc.newXmm();
|
|
|
|
cc.movsd(v, regF[B]);
|
|
|
|
|
|
|
|
if (C == FLOP_TAN_DEG)
|
|
|
|
{
|
|
|
|
static const double constant = M_PI / 180;
|
|
|
|
auto tmp = cc.newIntPtr();
|
|
|
|
cc.mov(tmp, ToMemAddress(&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-09-17 10:00:25 +00:00
|
|
|
auto call = CreateCall<double, double>(func);
|
2018-09-13 00:29:04 +00:00
|
|
|
call->setRet(0, regF[A]);
|
|
|
|
call->setArg(0, v);
|
|
|
|
|
|
|
|
if (C == FLOP_ACOS_DEG || C == FLOP_ASIN_DEG || C == FLOP_ATAN_DEG)
|
|
|
|
{
|
|
|
|
static const double constant = 180 / M_PI;
|
|
|
|
auto tmp = cc.newIntPtr();
|
|
|
|
cc.mov(tmp, ToMemAddress(&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
|
|
|
|
{
|
|
|
|
auto tmp = cc.newXmmSd();
|
|
|
|
|
|
|
|
const int64_t absMaskInt = 0x7FFFFFFFFFFFFFFF;
|
|
|
|
auto absMask = cc.newDoubleConst(asmjit::kConstScopeLocal, reinterpret_cast<const double&>(absMaskInt));
|
|
|
|
auto absMaskXmm = cc.newXmmPd();
|
|
|
|
|
|
|
|
auto epsilon = cc.newDoubleConst(asmjit::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);
|
|
|
|
|
|
|
|
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) {
|
|
|
|
auto konstTmp = cc.newIntPtr();
|
|
|
|
cc.mov(konstTmp, ToMemAddress(&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 {
|
|
|
|
auto konstTmp = cc.newIntPtr();
|
|
|
|
auto subTmp = cc.newXmmSd();
|
|
|
|
|
|
|
|
const 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, ToMemAddress(&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");
|
|
|
|
|
|
|
|
auto constTmp = cc.newIntPtr();
|
|
|
|
auto xmmTmp = cc.newXmmSd();
|
|
|
|
cc.mov(constTmp, ToMemAddress(&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");
|
|
|
|
|
|
|
|
auto tmp = cc.newIntPtr();
|
|
|
|
cc.mov(tmp, ToMemAddress(&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");
|
|
|
|
|
|
|
|
auto constTmp = cc.newIntPtr();
|
|
|
|
auto xmmTmp = cc.newXmmSd();
|
|
|
|
cc.mov(constTmp, ToMemAddress(&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");
|
|
|
|
|
|
|
|
auto tmp = cc.newIntPtr();
|
|
|
|
cc.mov(tmp, ToMemAddress(&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);
|
|
|
|
auto maskXmm = cc.newXmmSd();
|
|
|
|
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);
|
|
|
|
auto tmp = cc.newXmmSd();
|
|
|
|
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()
|
|
|
|
{
|
|
|
|
auto tmp = cc.newIntPtr();
|
|
|
|
cc.movsd(regF[A], regF[B]);
|
|
|
|
cc.movsd(regF[A + 1], regF[B + 1]);
|
|
|
|
cc.mov(tmp, ToMemAddress(&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()
|
|
|
|
{
|
|
|
|
auto tmp = cc.newIntPtr();
|
|
|
|
cc.movsd(regF[A], regF[B]);
|
|
|
|
cc.movsd(regF[A + 1], regF[B + 1]);
|
|
|
|
cc.mov(tmp, ToMemAddress(&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);
|
|
|
|
auto tmp = cc.newXmmSd();
|
|
|
|
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);
|
|
|
|
auto maskXmm = cc.newXmmSd();
|
|
|
|
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);
|
|
|
|
auto tmp = cc.newXmmSd();
|
|
|
|
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()
|
|
|
|
{
|
|
|
|
auto tmp = cc.newXmmSd();
|
|
|
|
|
|
|
|
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()
|
|
|
|
{
|
|
|
|
auto tmp = cc.newIntPtr();
|
|
|
|
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, ToMemAddress(&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()
|
|
|
|
{
|
|
|
|
auto tmp = cc.newIntPtr();
|
|
|
|
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, ToMemAddress(&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);
|
|
|
|
auto tmp = cc.newXmmSd();
|
|
|
|
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()
|
|
|
|
{
|
|
|
|
auto tmp = cc.newIntPtr();
|
|
|
|
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);
|
|
|
|
|
|
|
|
auto tmpptr = cc.newIntPtr();
|
|
|
|
cc.mov(tmpptr, regD[C]);
|
|
|
|
cc.add(tmp, tmpptr);
|
|
|
|
|
|
|
|
cc.bind(label);
|
|
|
|
cc.mov(regA[A], tmp);
|
|
|
|
}
|
|
|
|
|
|
|
|
void JitCompiler::EmitADDA_RK()
|
|
|
|
{
|
|
|
|
auto tmp = cc.newIntPtr();
|
|
|
|
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()
|
|
|
|
{
|
|
|
|
auto tmp = cc.newIntPtr();
|
|
|
|
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) {
|
|
|
|
auto tmp = cc.newIntPtr();
|
|
|
|
cc.mov(tmp, ToMemAddress(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-09-17 10:00:25 +00:00
|
|
|
auto call = CreateCall<double, double>(g_sqrt);
|
2018-09-13 00:29:04 +00:00
|
|
|
call->setRet(0, a);
|
|
|
|
call->setArg(0, b);
|
|
|
|
}
|