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:
MerryMage 2017-11-22 17:45:37 +00:00
parent 93cf180a44
commit 814e378249
6 changed files with 32 additions and 22 deletions

View file

@ -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);

View file

@ -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
} }
} }

View file

@ -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) {

View file

@ -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);

View file

@ -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;

View file

@ -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"),