Jit64: divwx - Eliminate XOR for constant dividend

We normally check for division by zero to know if we should set the
destination register to zero with a XOR. However, when the divisor and
destination registers are the same the explicit zeroing can be omitted.
In addition, some of the surrounding branching can be simplified as
well.

Before:
45 85 FF             test        r15d,r15d
75 05                jne         normal_path
45 33 FF             xor         r15d,r15d
EB 0C                jmp         done
normal_path:
B8 5A 00 00 00       mov         eax,5Ah
99                   cdq
41 F7 FF             idiv        eax,r15d
44 8B F8             mov         r15d,eax
done:

After:
45 85 FF             test        r15d,r15d
74 0C                je          done
B8 5A 00 00 00       mov         eax,5Ah
99                   cdq
41 F7 FF             idiv        eax,r15d
44 8B F8             mov         r15d,eax
done:
This commit is contained in:
Sintendo 2021-04-24 21:31:39 +02:00
parent abc4c8f601
commit 47e16133e5
1 changed files with 36 additions and 25 deletions

View File

@ -1375,38 +1375,49 @@ void Jit64::divwx(UGeckoInstruction inst)
// Check for divisor == 0
TEST(32, Rb, Rb);
FixupBranch normal_path;
FixupBranch done;
if (dividend == 0x80000000)
if (d == b && (dividend & 0x80000000) == 0 && !inst.OE)
{
// 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);
// Divisor is 0, skip to the end
// No need to explicitly set destination to 0 due to overlapping registers
done = J_CC(CC_Z);
// Otherwise, proceed to normal path
}
else
{
// Divisor is not 0, take normal path
normal_path = J_CC(CC_NZ);
// Otherwise, proceed to overflow case
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 if (d != b)
XOR(32, Rd, Rd);
if (inst.OE)
GenerateConstantOverflow(true);
done = J();
SetJumpTarget(normal_path);
}
// 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);