From 26f70657bcebe612444cf738e22a23f40e90718c Mon Sep 17 00:00:00 2001 From: Sintendo Date: Mon, 25 Jan 2021 22:16:41 +0100 Subject: [PATCH] Jit64: boolX - Precompute complement of b PowerPC instructions andcx and orcx complement the value of register b before performing their respective bitwise operation. If this register happens to contain a known value, we can precompute the complement, allowing us to generate simpler code. - andcx Before: BF 00 01 00 00 mov edi,100h F7 D7 not edi 41 23 FE and edi,r14d After: 41 8B FE mov edi,r14d 81 E7 FF FE FF FF and edi,0FFFFFEFFh - orc Before: 41 BE 04 00 00 00 mov r14d,4 41 F7 D6 not r14d 45 0B F5 or r14d,r13d After: 45 8B F5 mov r14d,r13d 41 83 CE FB or r14d,0FFFFFFFBh --- .../Core/Core/PowerPC/Jit64/Jit_Integer.cpp | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp index 35df5a06a5..53a55ccf31 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp @@ -662,6 +662,98 @@ void Jit64::boolX(UGeckoInstruction inst) else if (inst.SUBOP10 == 284) // eqvx gpr.SetImmediate32(a, ~(rs_offset ^ rb_offset)); } + else if (gpr.IsImm(s) || gpr.IsImm(b)) + { + auto [i, j] = gpr.IsImm(s) ? std::pair(s, b) : std::pair(b, s); + u32 imm = gpr.Imm32(i); + + bool complement_b = (inst.SUBOP10 == 60 /* andcx */) || (inst.SUBOP10 == 412 /* orcx */); + bool final_not = (inst.SUBOP10 == 476 /* nandx */) || (inst.SUBOP10 == 124 /* norx */) || + (inst.SUBOP10 == 284 /* eqvx */); + bool is_and = (inst.SUBOP10 == 28 /* andx */) || (inst.SUBOP10 == 60 /* andcx */) || + (inst.SUBOP10 == 476 /* nandx */); + bool is_or = (inst.SUBOP10 == 444 /* orx */) || (inst.SUBOP10 == 412 /* orcx */) || + (inst.SUBOP10 == 124 /* norx */); + bool is_xor = (inst.SUBOP10 == 316 /* xorx */) || (inst.SUBOP10 == 284 /* eqvx */); + + // Precompute complement when possible + if (complement_b && gpr.IsImm(b)) + { + imm = ~imm; + complement_b = false; + } + + if (is_xor) + { + RCOpArg Rj = gpr.Use(j, RCMode::Read); + RCX64Reg Ra = gpr.Bind(a, RCMode::Write); + RegCache::Realize(Rj, Ra); + + if (a != j) + MOV(32, Ra, Rj); + XOR(32, Ra, Imm32(imm)); + + if (final_not) + { + NOT(32, Ra); + needs_test = true; + } + } + else if (is_and) + { + RCOpArg Rj = gpr.Use(j, RCMode::Read); + RCX64Reg Ra = gpr.Bind(a, RCMode::Write); + RegCache::Realize(Rj, Ra); + + if (complement_b) + { + if (a != j) + MOV(32, Ra, Rj); + NOT(32, Ra); + AND(32, Ra, Imm32(imm)); + } + else + { + if (a != j) + MOV(32, Ra, Rj); + AND(32, Ra, Imm32(imm)); + } + + if (final_not) { + NOT(32, Ra); + needs_test = true; + } + } + else if (is_or) + { + RCOpArg Rj = gpr.Use(j, RCMode::Read); + RCX64Reg Ra = gpr.Bind(a, RCMode::Write); + RegCache::Realize(Rj, Ra); + + if (complement_b) + { + if (a != j) + MOV(32, Ra, Rj); + NOT(32, Ra); + OR(32, Ra, Imm32(imm)); + } + else + { + if (a != j) + MOV(32, Ra, Rj); + OR(32, Ra, Imm32(imm)); + } + + if (final_not) { + NOT(32, Ra); + needs_test = true; + } + } + else + { + PanicAlertFmt("WTF!"); + } + } else if (s == b) { if ((inst.SUBOP10 == 28 /* andx */) || (inst.SUBOP10 == 444 /* orx */))