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!
This commit is contained in:
parent
c081e3f2b3
commit
c9adc60d73
|
@ -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
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue