From c9adc60d730812c1cb09bcce9bf7b4ace91883c3 Mon Sep 17 00:00:00 2001 From: Sintendo Date: Sat, 27 Feb 2021 20:51:38 +0100 Subject: [PATCH] Jit64: divwx - Special case dividend == 0 Zero divided by any number is still zero. For whatever reason, this case shows up frequently too. Before: B8 00 00 00 00 mov eax,0 85 F6 test esi,esi 74 0C je overflow 3D 00 00 00 80 cmp eax,80000000h 75 0C jne normal_path 83 FE FF cmp esi,0FFFFFFFFh 75 07 jne normal_path overflow: C1 F8 1F sar eax,1Fh 8B F8 mov edi,eax EB 05 jmp done normal_path: 99 cdq F7 FE idiv eax,esi 8B F8 mov edi,eax done: After: Nothing! --- .../Core/Core/PowerPC/Jit64/Jit_Integer.cpp | 107 ++++++++++-------- 1 file changed, 62 insertions(+), 45 deletions(-) diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp index fd6feace7d..88e139abb2 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp @@ -1345,57 +1345,74 @@ void Jit64::divwx(UGeckoInstruction inst) // Constant dividend const u32 dividend = gpr.Imm32(a); - RCX64Reg Rb = gpr.Bind(b, RCMode::Read); - RCX64Reg Rd = gpr.Bind(d, RCMode::Write); - // no register choice - RCX64Reg eax = gpr.Scratch(EAX); - RCX64Reg edx = gpr.Scratch(EDX); - RegCache::Realize(Rb, Rd, eax, edx); - - // Check for divisor == 0 - TEST(32, Rb, Rb); - - FixupBranch normal_path; - - if (dividend == 0x80000000) + if (dividend == 0) { - // Divisor is 0, proceed to overflow case - const FixupBranch overflow = J_CC(CC_Z); - // Otherwise, check for divisor == -1 - CMP(32, Rb, Imm32(0xFFFFFFFF)); - normal_path = J_CC(CC_NE); + if (inst.OE) + { + RCOpArg Rb = gpr.Use(b, RCMode::Read); + RegCache::Realize(Rb); - SetJumpTarget(overflow); + CMP_or_TEST(32, Rb, Imm32(0)); + GenerateOverflow(CC_NZ); + } + + // Zero divided by anything is always zero + gpr.SetImmediate32(d, 0); } else { - // Divisor is not 0, take normal path - normal_path = J_CC(CC_NZ); - // Otherwise, proceed to overflow case + RCX64Reg Rb = gpr.Bind(b, RCMode::Read); + RCX64Reg Rd = gpr.Bind(d, RCMode::Write); + // no register choice + RCX64Reg eax = gpr.Scratch(EAX); + RCX64Reg edx = gpr.Scratch(EDX); + RegCache::Realize(Rb, Rd, eax, edx); + + // Check for divisor == 0 + TEST(32, Rb, Rb); + + FixupBranch normal_path; + + if (dividend == 0x80000000) + { + // Divisor is 0, proceed to overflow case + const FixupBranch overflow = J_CC(CC_Z); + // Otherwise, check for divisor == -1 + CMP(32, Rb, Imm32(0xFFFFFFFF)); + normal_path = J_CC(CC_NE); + + SetJumpTarget(overflow); + } + else + { + // Divisor is not 0, take normal path + normal_path = J_CC(CC_NZ); + // Otherwise, proceed to overflow case + } + + // Set Rd to all ones or all zeroes + if (dividend & 0x80000000) + MOV(32, Rd, Imm32(0xFFFFFFFF)); + else + XOR(32, Rd, Rd); + + if (inst.OE) + GenerateConstantOverflow(true); + + const FixupBranch done = J(); + + SetJumpTarget(normal_path); + + MOV(32, eax, Imm32(dividend)); + CDQ(); + IDIV(32, Rb); + MOV(32, Rd, eax); + + if (inst.OE) + GenerateConstantOverflow(false); + + SetJumpTarget(done); } - - // Set Rd to all ones or all zeroes - if (dividend & 0x80000000) - MOV(32, Rd, Imm32(0xFFFFFFFF)); - else - XOR(32, Rd, Rd); - - if (inst.OE) - GenerateConstantOverflow(true); - - const FixupBranch done = J(); - - SetJumpTarget(normal_path); - - MOV(32, eax, Imm32(dividend)); - CDQ(); - IDIV(32, Rb); - MOV(32, Rd, eax); - - if (inst.OE) - GenerateConstantOverflow(false); - - SetJumpTarget(done); } else {