Skip to content

Commit

Permalink
Jit64: divwx - Special case dividend == 0
Browse files Browse the repository at this point in the history
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!
  • Loading branch information
Sintendo committed Mar 7, 2021
1 parent c081e3f commit c9adc60
Showing 1 changed file with 56 additions and 39 deletions.
95 changes: 56 additions & 39 deletions Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);

// Set Rd to all ones or all zeroes
if (dividend & 0x80000000)
MOV(32, Rd, Imm32(0xFFFFFFFF));
else
XOR(32, Rd, Rd);
// Check for divisor == 0
TEST(32, Rb, Rb);

if (inst.OE)
GenerateConstantOverflow(true);
FixupBranch normal_path;

const FixupBranch done = J();
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(normal_path);
SetJumpTarget(overflow);
}
else
{
// Divisor is not 0, take normal path
normal_path = J_CC(CC_NZ);
// Otherwise, proceed to overflow case
}

MOV(32, eax, Imm32(dividend));
CDQ();
IDIV(32, Rb);
MOV(32, Rd, eax);
// 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(false);
if (inst.OE)
GenerateConstantOverflow(true);

SetJumpTarget(done);
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
{
Expand Down

0 comments on commit c9adc60

Please sign in to comment.