VCMP and VCMPE were the other way around
- This was due to a misunderstanding of what the E in VCMPE means. - The E refers to an exception being raised when a QNaN is encountered. - Added unit tests for VCMP{E}
This commit is contained in:
parent
93cf180a44
commit
814e378249
6 changed files with 32 additions and 22 deletions
|
@ -2473,12 +2473,12 @@ void EmitX64::EmitFPCompare32(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
|
||||||
auto args = reg_alloc.GetArgumentInfo(inst);
|
auto args = reg_alloc.GetArgumentInfo(inst);
|
||||||
Xbyak::Xmm reg_a = reg_alloc.UseXmm(args[0]);
|
Xbyak::Xmm reg_a = reg_alloc.UseXmm(args[0]);
|
||||||
Xbyak::Xmm reg_b = reg_alloc.UseXmm(args[1]);
|
Xbyak::Xmm reg_b = reg_alloc.UseXmm(args[1]);
|
||||||
bool quiet = args[2].GetImmediateU1();
|
bool exc_on_qnan = args[2].GetImmediateU1();
|
||||||
|
|
||||||
if (quiet) {
|
if (exc_on_qnan) {
|
||||||
code->ucomiss(reg_a, reg_b);
|
|
||||||
} else {
|
|
||||||
code->comiss(reg_a, reg_b);
|
code->comiss(reg_a, reg_b);
|
||||||
|
} else {
|
||||||
|
code->ucomiss(reg_a, reg_b);
|
||||||
}
|
}
|
||||||
|
|
||||||
SetFpscrNzcvFromFlags(code, reg_alloc);
|
SetFpscrNzcvFromFlags(code, reg_alloc);
|
||||||
|
@ -2488,12 +2488,12 @@ void EmitX64::EmitFPCompare64(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
|
||||||
auto args = reg_alloc.GetArgumentInfo(inst);
|
auto args = reg_alloc.GetArgumentInfo(inst);
|
||||||
Xbyak::Xmm reg_a = reg_alloc.UseXmm(args[0]);
|
Xbyak::Xmm reg_a = reg_alloc.UseXmm(args[0]);
|
||||||
Xbyak::Xmm reg_b = reg_alloc.UseXmm(args[1]);
|
Xbyak::Xmm reg_b = reg_alloc.UseXmm(args[1]);
|
||||||
bool quiet = args[2].GetImmediateU1();
|
bool exc_on_qnan = args[2].GetImmediateU1();
|
||||||
|
|
||||||
if (quiet) {
|
if (exc_on_qnan) {
|
||||||
code->ucomisd(reg_a, reg_b);
|
|
||||||
} else {
|
|
||||||
code->comisd(reg_a, reg_b);
|
code->comisd(reg_a, reg_b);
|
||||||
|
} else {
|
||||||
|
code->ucomisd(reg_a, reg_b);
|
||||||
}
|
}
|
||||||
|
|
||||||
SetFpscrNzcvFromFlags(code, reg_alloc);
|
SetFpscrNzcvFromFlags(code, reg_alloc);
|
||||||
|
|
|
@ -120,7 +120,7 @@ void JitState::SetFpscr(u32 FPSCR) {
|
||||||
if (Common::Bit<24>(FPSCR)) {
|
if (Common::Bit<24>(FPSCR)) {
|
||||||
// VFP Flush to Zero
|
// VFP Flush to Zero
|
||||||
//guest_MXCSR |= (1 << 15); // SSE Flush to Zero
|
//guest_MXCSR |= (1 << 15); // SSE Flush to Zero
|
||||||
guest_MXCSR |= (1 << 6); // SSE Denormals are Zero
|
//guest_MXCSR |= (1 << 6); // SSE Denormals are Zero
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -544,14 +544,14 @@ 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) {
|
void IREmitter::FPCompare32(const Value& a, const Value& b, bool exc_on_qnan, bool fpscr_controlled) {
|
||||||
ASSERT(fpscr_controlled);
|
ASSERT(fpscr_controlled);
|
||||||
Inst(Opcode::FPCompare32, {a, b, Imm1(quiet)});
|
Inst(Opcode::FPCompare32, {a, b, Imm1(exc_on_qnan)});
|
||||||
}
|
}
|
||||||
|
|
||||||
void IREmitter::FPCompare64(const Value& a, const Value& b, bool quiet, bool fpscr_controlled) {
|
void IREmitter::FPCompare64(const Value& a, const Value& b, bool exc_on_qnan, bool fpscr_controlled) {
|
||||||
ASSERT(fpscr_controlled);
|
ASSERT(fpscr_controlled);
|
||||||
Inst(Opcode::FPCompare64, {a, b, Imm1(quiet)});
|
Inst(Opcode::FPCompare64, {a, b, Imm1(exc_on_qnan)});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::FPDiv32(const Value& a, const Value& b, bool fpscr_controlled) {
|
Value IREmitter::FPDiv32(const Value& a, const Value& b, bool fpscr_controlled) {
|
||||||
|
|
|
@ -183,8 +183,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 FPCompare32(const Value& a, const Value& b, bool exc_on_qnan, bool fpscr_controlled);
|
||||||
void FPCompare64(const Value& a, const Value& b, bool quiet, bool fpscr_controlled);
|
void FPCompare64(const Value& a, const Value& b, bool exc_on_qnan, 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);
|
||||||
|
|
|
@ -488,16 +488,16 @@ bool ArmTranslatorVisitor::vfp2_VCVT_to_s32(Cond cond, bool D, size_t Vd, bool s
|
||||||
bool ArmTranslatorVisitor::vfp2_VCMP(Cond cond, bool D, size_t Vd, bool sz, bool E, bool M, size_t Vm) {
|
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 d = ToExtReg(sz, Vd, D);
|
||||||
ExtReg m = ToExtReg(sz, Vm, M);
|
ExtReg m = ToExtReg(sz, Vm, M);
|
||||||
bool quiet = E;
|
bool exc_on_qnan = E;
|
||||||
// VCMP{E}.F32 <Sd>, <Sm>
|
// VCMP{E}.F32 <Sd>, <Sm>
|
||||||
// VCMP{E}.F64 <Dd>, <Dm>
|
// VCMP{E}.F64 <Dd>, <Dm>
|
||||||
if (ConditionPassed(cond)) {
|
if (ConditionPassed(cond)) {
|
||||||
auto reg_d = ir.GetExtendedRegister(d);
|
auto reg_d = ir.GetExtendedRegister(d);
|
||||||
auto reg_m = ir.GetExtendedRegister(m);
|
auto reg_m = ir.GetExtendedRegister(m);
|
||||||
if (sz) {
|
if (sz) {
|
||||||
ir.FPCompare64(reg_d, reg_m, quiet, true);
|
ir.FPCompare64(reg_d, reg_m, exc_on_qnan, true);
|
||||||
} else {
|
} else {
|
||||||
ir.FPCompare32(reg_d, reg_m, quiet, true);
|
ir.FPCompare32(reg_d, reg_m, exc_on_qnan, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -505,7 +505,7 @@ bool ArmTranslatorVisitor::vfp2_VCMP(Cond cond, bool D, size_t Vd, bool sz, bool
|
||||||
|
|
||||||
bool ArmTranslatorVisitor::vfp2_VCMP_zero(Cond cond, bool D, size_t Vd, bool sz, bool E) {
|
bool ArmTranslatorVisitor::vfp2_VCMP_zero(Cond cond, bool D, size_t Vd, bool sz, bool E) {
|
||||||
ExtReg d = ToExtReg(sz, Vd, D);
|
ExtReg d = ToExtReg(sz, Vd, D);
|
||||||
bool quiet = E;
|
bool exc_on_qnan = E;
|
||||||
// VCMP{E}.F32 <Sd>, #0.0
|
// VCMP{E}.F32 <Sd>, #0.0
|
||||||
// VCMP{E}.F64 <Dd>, #0.0
|
// VCMP{E}.F64 <Dd>, #0.0
|
||||||
if (ConditionPassed(cond)) {
|
if (ConditionPassed(cond)) {
|
||||||
|
@ -514,9 +514,9 @@ bool ArmTranslatorVisitor::vfp2_VCMP_zero(Cond cond, bool D, size_t Vd, bool sz,
|
||||||
? ir.TransferToFP64(ir.Imm64(0))
|
? ir.TransferToFP64(ir.Imm64(0))
|
||||||
: ir.TransferToFP32(ir.Imm32(0));
|
: ir.TransferToFP32(ir.Imm32(0));
|
||||||
if (sz) {
|
if (sz) {
|
||||||
ir.FPCompare64(reg_d, zero, quiet, true);
|
ir.FPCompare64(reg_d, zero, exc_on_qnan, true);
|
||||||
} else {
|
} else {
|
||||||
ir.FPCompare32(reg_d, zero, quiet, true);
|
ir.FPCompare32(reg_d, zero, exc_on_qnan, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -535,7 +535,6 @@ TEST_CASE("VFP: VMOV", "[JitX64][vfp]") {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST_CASE("VFP: VMOV (reg), VLDR, VSTR", "[JitX64][vfp]") {
|
TEST_CASE("VFP: VMOV (reg), VLDR, VSTR", "[JitX64][vfp]") {
|
||||||
const std::array<InstructionGenerator, 4> instructions = {{
|
const std::array<InstructionGenerator, 4> instructions = {{
|
||||||
InstructionGenerator("1111000100000001000000e000000000"), // SETEND
|
InstructionGenerator("1111000100000001000000e000000000"), // SETEND
|
||||||
|
@ -549,6 +548,17 @@ TEST_CASE("VFP: VMOV (reg), VLDR, VSTR", "[JitX64][vfp]") {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("VFP: VCMP", "[JitX64][vfp]") {
|
||||||
|
const std::array<InstructionGenerator, 2> instructions = {{
|
||||||
|
InstructionGenerator("cccc11101D110100dddd101zE1M0mmmm"), // VCMP
|
||||||
|
InstructionGenerator("cccc11101D110101dddd101zE1000000"), // VCMP (zero)
|
||||||
|
}};
|
||||||
|
|
||||||
|
FuzzJitArm(5, 6, 10000, [&instructions]() -> u32 {
|
||||||
|
return instructions[RandInt<size_t>(0, instructions.size() - 1)].Generate();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE("Fuzz ARM data processing instructions", "[JitX64]") {
|
TEST_CASE("Fuzz ARM data processing instructions", "[JitX64]") {
|
||||||
const std::array<InstructionGenerator, 16> imm_instructions = {{
|
const std::array<InstructionGenerator, 16> imm_instructions = {{
|
||||||
InstructionGenerator("cccc0010101Snnnnddddrrrrvvvvvvvv"),
|
InstructionGenerator("cccc0010101Snnnnddddrrrrvvvvvvvv"),
|
||||||
|
|
Loading…
Reference in a new issue