Implement VCMP
This commit is contained in:
parent
f2fe376fc6
commit
e166965f3e
9 changed files with 131 additions and 2 deletions
|
@ -1762,6 +1762,70 @@ void EmitX64::EmitFPSub64(IR::Block& block, IR::Inst* inst) {
|
||||||
FPThreeOp64(code, reg_alloc, block, inst, &Xbyak::CodeGenerator::subsd);
|
FPThreeOp64(code, reg_alloc, block, inst, &Xbyak::CodeGenerator::subsd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void SetFpscrNzcvFromLahf(JitState* jit_state, u8 lahf) {
|
||||||
|
switch (lahf) {
|
||||||
|
case 0b01000111:
|
||||||
|
jit_state->FPSCR_nzcv = 0x30000000;
|
||||||
|
return;
|
||||||
|
case 0b00000010:
|
||||||
|
jit_state->FPSCR_nzcv = 0x20000000;
|
||||||
|
return;
|
||||||
|
case 0b00000011:
|
||||||
|
jit_state->FPSCR_nzcv = 0x80000000;
|
||||||
|
return;
|
||||||
|
case 0b01000010:
|
||||||
|
jit_state->FPSCR_nzcv = 0x60000000;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ASSERT_MSG(false, "<internal error>");
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmitX64::EmitFPCompare32(IR::Block& block, IR::Inst* inst) {
|
||||||
|
IR::Value a = inst->GetArg(0);
|
||||||
|
IR::Value b = inst->GetArg(1);
|
||||||
|
bool quiet = inst->GetArg(2).GetU1();
|
||||||
|
|
||||||
|
Xbyak::Xmm reg_a = reg_alloc.UseXmm(a);
|
||||||
|
Xbyak::Xmm reg_b = reg_alloc.UseXmm(b);
|
||||||
|
|
||||||
|
if (quiet) {
|
||||||
|
code->ucomiss(reg_a, reg_b);
|
||||||
|
} else {
|
||||||
|
code->comiss(reg_a, reg_b);
|
||||||
|
}
|
||||||
|
|
||||||
|
reg_alloc.EndOfAllocScope();
|
||||||
|
reg_alloc.HostCall();
|
||||||
|
|
||||||
|
code->lahf();
|
||||||
|
code->mov(code->ABI_PARAM1, code->r15);
|
||||||
|
code->mov(code->ABI_PARAM2.cvt8(), code->ah);
|
||||||
|
code->CallFunction(&SetFpscrNzcvFromLahf);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmitX64::EmitFPCompare64(IR::Block& block, IR::Inst* inst) {
|
||||||
|
IR::Value a = inst->GetArg(0);
|
||||||
|
IR::Value b = inst->GetArg(1);
|
||||||
|
bool quiet = inst->GetArg(2).GetU1();
|
||||||
|
|
||||||
|
Xbyak::Xmm reg_a = reg_alloc.UseXmm(a);
|
||||||
|
Xbyak::Xmm reg_b = reg_alloc.UseXmm(b);
|
||||||
|
|
||||||
|
if (quiet) {
|
||||||
|
code->ucomisd(reg_a, reg_b);
|
||||||
|
} else {
|
||||||
|
code->comisd(reg_a, reg_b);
|
||||||
|
}
|
||||||
|
|
||||||
|
reg_alloc.EndOfAllocScope();
|
||||||
|
reg_alloc.HostCall();
|
||||||
|
|
||||||
|
code->lahf();
|
||||||
|
code->mov(code->ABI_PARAM1, code->r15);
|
||||||
|
code->mov(code->ABI_PARAM2.cvt8(), code->ah);
|
||||||
|
code->CallFunction(&SetFpscrNzcvFromLahf);
|
||||||
|
}
|
||||||
|
|
||||||
void EmitX64::EmitFPSingleToDouble(IR::Block& block, IR::Inst* inst) {
|
void EmitX64::EmitFPSingleToDouble(IR::Block& block, IR::Inst* inst) {
|
||||||
IR::Value a = inst->GetArg(0);
|
IR::Value a = inst->GetArg(0);
|
||||||
|
|
||||||
|
|
|
@ -58,8 +58,8 @@ boost::optional<const VFP2Matcher<V>&> DecodeVFP2(u32 instruction) {
|
||||||
INST(&V::vfp2_VCVT_to_float, "VCVT (to float)", "cccc11101D111000dddd101zs1M0mmmm"),
|
INST(&V::vfp2_VCVT_to_float, "VCVT (to float)", "cccc11101D111000dddd101zs1M0mmmm"),
|
||||||
INST(&V::vfp2_VCVT_to_u32, "VCVT (to u32)", "cccc11101D111100dddd101zr1M0mmmm"),
|
INST(&V::vfp2_VCVT_to_u32, "VCVT (to u32)", "cccc11101D111100dddd101zr1M0mmmm"),
|
||||||
INST(&V::vfp2_VCVT_to_s32, "VCVT (to s32)", "cccc11101D111101dddd101zr1M0mmmm"),
|
INST(&V::vfp2_VCVT_to_s32, "VCVT (to s32)", "cccc11101D111101dddd101zr1M0mmmm"),
|
||||||
// VCMP
|
INST(&V::vfp2_VCMP, "VCMP", "cccc11101D110100dddd101zE1M0mmmm"),
|
||||||
// VCMPE
|
INST(&V::vfp2_VCMP_zero, "VCMP (with zero)", "cccc11101D110101dddd101zE1000000"),
|
||||||
|
|
||||||
// Floating-point system register access
|
// Floating-point system register access
|
||||||
INST(&V::vfp2_VMSR, "VMSR", "cccc111011100001tttt101000010000"),
|
INST(&V::vfp2_VMSR, "VMSR", "cccc111011100001tttt101000010000"),
|
||||||
|
|
|
@ -949,6 +949,14 @@ public:
|
||||||
return fmt::format("vcvt{}{}.s32.{} {}, {}", round_towards_zero ? "" : "r", CondToString(cond), sz ? "f64" : "f32", FPRegStr(false, Vd, D), FPRegStr(sz, Vm, M));
|
return fmt::format("vcvt{}{}.s32.{} {}, {}", round_towards_zero ? "" : "r", CondToString(cond), sz ? "f64" : "f32", FPRegStr(false, Vd, D), FPRegStr(sz, Vm, M));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string vfp2_VCMP(Cond cond, bool D, size_t Vd, bool sz, bool E, bool M, size_t Vm) {
|
||||||
|
return fmt::format("vcmp{}{}.{} {}, {}", E ? "e" : "", CondToString(cond), sz ? "f64" : "f32", FPRegStr(sz, Vd, D), FPRegStr(sz, Vm, M));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string vfp2_VCMP_zero(Cond cond, bool D, size_t Vd, bool sz, bool E) {
|
||||||
|
return fmt::format("vcmp{}{}.{} {}, #0.0", E ? "e" : "", CondToString(cond), sz ? "f64" : "f32", FPRegStr(sz, Vd, D));
|
||||||
|
}
|
||||||
|
|
||||||
std::string vfp2_VMSR(Cond cond, Reg t) {
|
std::string vfp2_VMSR(Cond cond, Reg t) {
|
||||||
return fmt::format("vmsr{} fpscr, {}", CondToString(cond), t);
|
return fmt::format("vmsr{} fpscr, {}", CondToString(cond), t);
|
||||||
}
|
}
|
||||||
|
|
|
@ -414,6 +414,16 @@ Value IREmitter::FPAdd64(const Value& a, const Value& b, bool fpscr_controlled)
|
||||||
return Inst(Opcode::FPAdd64, {a, b});
|
return Inst(Opcode::FPAdd64, {a, b});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IREmitter::FPCompare32(const Value& a, const Value& b, bool quiet, bool fpscr_controlled) {
|
||||||
|
ASSERT(fpscr_controlled);
|
||||||
|
Inst(Opcode::FPCompare32, {a, b, Imm1(quiet)});
|
||||||
|
}
|
||||||
|
|
||||||
|
void IREmitter::FPCompare64(const Value& a, const Value& b, bool quiet, bool fpscr_controlled) {
|
||||||
|
ASSERT(fpscr_controlled);
|
||||||
|
Inst(Opcode::FPCompare64, {a, b, Imm1(quiet)});
|
||||||
|
}
|
||||||
|
|
||||||
Value IREmitter::FPDiv32(const Value& a, const Value& b, bool fpscr_controlled) {
|
Value IREmitter::FPDiv32(const Value& a, const Value& b, bool fpscr_controlled) {
|
||||||
ASSERT(fpscr_controlled);
|
ASSERT(fpscr_controlled);
|
||||||
return Inst(Opcode::FPDiv32, {a, b});
|
return Inst(Opcode::FPDiv32, {a, b});
|
||||||
|
|
|
@ -145,6 +145,8 @@ public:
|
||||||
Value FPAbs64(const Value& a);
|
Value FPAbs64(const Value& a);
|
||||||
Value FPAdd32(const Value& a, const Value& b, bool fpscr_controlled);
|
Value FPAdd32(const Value& a, const Value& b, bool fpscr_controlled);
|
||||||
Value FPAdd64(const Value& a, const Value& b, bool fpscr_controlled);
|
Value FPAdd64(const Value& a, const Value& b, bool fpscr_controlled);
|
||||||
|
void FPCompare32(const Value& a, const Value& b, bool quiet, bool fpscr_controlled);
|
||||||
|
void FPCompare64(const Value& a, const Value& b, bool quiet, bool fpscr_controlled);
|
||||||
Value FPDiv32(const Value& a, const Value& b, bool fpscr_controlled);
|
Value FPDiv32(const Value& a, const Value& b, bool fpscr_controlled);
|
||||||
Value FPDiv64(const Value& a, const Value& b, bool fpscr_controlled);
|
Value FPDiv64(const Value& a, const Value& b, bool fpscr_controlled);
|
||||||
Value FPMul32(const Value& a, const Value& b, bool fpscr_controlled);
|
Value FPMul32(const Value& a, const Value& b, bool fpscr_controlled);
|
||||||
|
|
|
@ -156,6 +156,8 @@ bool Inst::ReadsFromFPSCR() const {
|
||||||
case Opcode::FPAbs64:
|
case Opcode::FPAbs64:
|
||||||
case Opcode::FPAdd32:
|
case Opcode::FPAdd32:
|
||||||
case Opcode::FPAdd64:
|
case Opcode::FPAdd64:
|
||||||
|
case Opcode::FPCompare32:
|
||||||
|
case Opcode::FPCompare64:
|
||||||
case Opcode::FPDiv32:
|
case Opcode::FPDiv32:
|
||||||
case Opcode::FPDiv64:
|
case Opcode::FPDiv64:
|
||||||
case Opcode::FPMul32:
|
case Opcode::FPMul32:
|
||||||
|
@ -181,6 +183,8 @@ bool Inst::WritesToFPSCR() const {
|
||||||
case Opcode::FPAbs64:
|
case Opcode::FPAbs64:
|
||||||
case Opcode::FPAdd32:
|
case Opcode::FPAdd32:
|
||||||
case Opcode::FPAdd64:
|
case Opcode::FPAdd64:
|
||||||
|
case Opcode::FPCompare32:
|
||||||
|
case Opcode::FPCompare64:
|
||||||
case Opcode::FPDiv32:
|
case Opcode::FPDiv32:
|
||||||
case Opcode::FPDiv64:
|
case Opcode::FPDiv64:
|
||||||
case Opcode::FPMul32:
|
case Opcode::FPMul32:
|
||||||
|
|
|
@ -95,6 +95,8 @@ OPCODE(FPAbs32, T::F32, T::F32
|
||||||
OPCODE(FPAbs64, T::F64, T::F64 )
|
OPCODE(FPAbs64, T::F64, T::F64 )
|
||||||
OPCODE(FPAdd32, T::F32, T::F32, T::F32 )
|
OPCODE(FPAdd32, T::F32, T::F32, T::F32 )
|
||||||
OPCODE(FPAdd64, T::F64, T::F64, T::F64 )
|
OPCODE(FPAdd64, T::F64, T::F64, T::F64 )
|
||||||
|
OPCODE(FPCompare32, T::Void, T::F32, T::F32, T::U1 )
|
||||||
|
OPCODE(FPCompare64, T::Void, T::F64, T::F64, T::U1 )
|
||||||
OPCODE(FPDiv32, T::F32, T::F32, T::F32 )
|
OPCODE(FPDiv32, T::F32, T::F32, T::F32 )
|
||||||
OPCODE(FPDiv64, T::F64, T::F64, T::F64 )
|
OPCODE(FPDiv64, T::F64, T::F64, T::F64 )
|
||||||
OPCODE(FPMul32, T::F32, T::F32, T::F32 )
|
OPCODE(FPMul32, T::F32, T::F32, T::F32 )
|
||||||
|
|
|
@ -365,6 +365,8 @@ struct ArmTranslatorVisitor final {
|
||||||
bool vfp2_VCVT_to_float(Cond cond, bool D, size_t Vd, bool sz, bool is_signed, bool M, size_t Vm);
|
bool vfp2_VCVT_to_float(Cond cond, bool D, size_t Vd, bool sz, bool is_signed, bool M, size_t Vm);
|
||||||
bool vfp2_VCVT_to_u32(Cond cond, bool D, size_t Vd, bool sz, bool round_towards_zero, bool M, size_t Vm);
|
bool vfp2_VCVT_to_u32(Cond cond, bool D, size_t Vd, bool sz, bool round_towards_zero, bool M, size_t Vm);
|
||||||
bool vfp2_VCVT_to_s32(Cond cond, bool D, size_t Vd, bool sz, bool round_towards_zero, bool M, size_t Vm);
|
bool vfp2_VCVT_to_s32(Cond cond, bool D, size_t Vd, bool sz, bool round_towards_zero, bool M, size_t Vm);
|
||||||
|
bool vfp2_VCMP(Cond cond, bool D, size_t Vd, bool sz, bool E, bool M, size_t Vm);
|
||||||
|
bool vfp2_VCMP_zero(Cond cond, bool D, size_t Vd, bool sz, bool E);
|
||||||
|
|
||||||
// Floating-point system register access
|
// Floating-point system register access
|
||||||
bool vfp2_VMSR(Cond cond, Reg t);
|
bool vfp2_VMSR(Cond cond, Reg t);
|
||||||
|
|
|
@ -425,6 +425,43 @@ bool ArmTranslatorVisitor::vfp2_VCVT_to_s32(Cond cond, bool D, size_t Vd, bool s
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ArmTranslatorVisitor::vfp2_VCMP(Cond cond, bool D, size_t Vd, bool sz, bool E, bool M, size_t Vm) {
|
||||||
|
ExtReg d = ToExtReg(sz, Vd, D);
|
||||||
|
ExtReg m = ToExtReg(sz, Vm, M);
|
||||||
|
bool quiet = E;
|
||||||
|
// VCMP{E}.F32 <Sd>, <Sm>
|
||||||
|
// VCMP{E}.F64 <Dd>, <Dm>
|
||||||
|
if (ConditionPassed(cond)) {
|
||||||
|
auto a = ir.GetExtendedRegister(d);
|
||||||
|
auto b = ir.GetExtendedRegister(m);
|
||||||
|
if (sz) {
|
||||||
|
ir.FPCompare64(a, b, quiet, true);
|
||||||
|
} else {
|
||||||
|
ir.FPCompare32(a, b, quiet, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ArmTranslatorVisitor::vfp2_VCMP_zero(Cond cond, bool D, size_t Vd, bool sz, bool E) {
|
||||||
|
ExtReg d = ToExtReg(sz, Vd, D);
|
||||||
|
bool quiet = E;
|
||||||
|
// VCMP{E}.F32 <Sd>, #0.0
|
||||||
|
// VCMP{E}.F64 <Dd>, #0.0
|
||||||
|
if (ConditionPassed(cond)) {
|
||||||
|
auto a = ir.GetExtendedRegister(d);
|
||||||
|
auto b = sz
|
||||||
|
? ir.TransferToFP64(ir.Imm64(0))
|
||||||
|
: ir.TransferToFP32(ir.Imm32(0));
|
||||||
|
if (sz) {
|
||||||
|
ir.FPCompare64(a, b, quiet, true);
|
||||||
|
} else {
|
||||||
|
ir.FPCompare32(a, b, quiet, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool ArmTranslatorVisitor::vfp2_VMSR(Cond cond, Reg t) {
|
bool ArmTranslatorVisitor::vfp2_VMSR(Cond cond, Reg t) {
|
||||||
if (t == Reg::PC)
|
if (t == Reg::PC)
|
||||||
return UnpredictableInstruction();
|
return UnpredictableInstruction();
|
||||||
|
|
Loading…
Reference in a new issue