From 2cafa0a96044d25f8b5248964f3dc1e319f5eb9b Mon Sep 17 00:00:00 2001 From: Sintendo Date: Wed, 5 May 2021 22:54:56 +0200 Subject: [PATCH] Jit64: divwux - Prefer three-operand IMUL By taking advantage of three-operand IMUL, we can eliminate a MOV instruction. This is a small code size win. However, due to IMUL sign extending the immediate value to 64 bits, we can only apply this when the magic number's most significant bit is zero. To ensure this can actually happen, we also minimize the magic number by checking for trailing zeroes. Example (Unsigned division by 18) Before: 41 BE E4 38 8E E3 mov r14d,0E38E38E4h 4D 0F AF F5 imul r14,r13 49 C1 EE 24 shr r14,24h After: 4D 69 F5 39 8E E3 38 imul r14,r13,38E38E39h 49 C1 EE 22 shr r14,22h --- .../Core/Core/PowerPC/Jit64/Jit_Integer.cpp | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp index 4329fc0a13..028f51a0bf 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp @@ -1271,14 +1271,29 @@ void Jit64::divwux(UGeckoInstruction inst) RCX64Reg Rd = gpr.Bind(d, RCMode::Write); RegCache::Realize(Ra, Rd); - if (d == a) + magic++; + + // Use smallest magic number and shift amount possible + while ((magic & 1) == 0 && shift > 0) { - MOV(32, R(RSCRATCH), Imm32(magic + 1)); + magic >>= 1; + shift--; + } + + // Three-operand IMUL sign extends the immediate to 64 bits, so we may only + // use it when the magic number has its most significant bit set to 0 + if ((magic & 0x80000000) == 0) + { + IMUL(64, Rd, Ra, Imm32(magic)); + } + else if (d == a) + { + MOV(32, R(RSCRATCH), Imm32(magic)); IMUL(64, Rd, R(RSCRATCH)); } else { - MOV(32, Rd, Imm32(magic + 1)); + MOV(32, Rd, Imm32(magic)); IMUL(64, Rd, Ra); } SHR(64, Rd, Imm8(shift + 32));