diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp index c870682cf8..aa3df5a608 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp @@ -668,6 +668,152 @@ 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)) + { + const 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 */); + const bool final_not = (inst.SUBOP10 == 476 /* nandx */) || (inst.SUBOP10 == 124 /* norx */); + const bool is_and = (inst.SUBOP10 == 28 /* andx */) || (inst.SUBOP10 == 60 /* andcx */) || + (inst.SUBOP10 == 476 /* nandx */); + const bool is_or = (inst.SUBOP10 == 444 /* orx */) || (inst.SUBOP10 == 412 /* orcx */) || + (inst.SUBOP10 == 124 /* norx */); + const bool is_xor = (inst.SUBOP10 == 316 /* xorx */) || (inst.SUBOP10 == 284 /* eqvx */); + + // Precompute complement when possible + if (complement_b && gpr.IsImm(b) || (inst.SUBOP10 == 284 /* eqvx */)) + { + 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 (imm == 0) + { + if (a != j) + MOV(32, Ra, Rj); + needs_test = true; + } + else if (imm == 0xFFFFFFFF && !inst.Rc) + { + if (a != j) + MOV(32, Ra, Rj); + NOT(32, Ra); + } + else if (a == j) + XOR(32, Ra, Imm32(imm)); + else if (s32(imm) >= -128 && s32(imm) <= 127) + { + MOV(32, Ra, Rj); + XOR(32, Ra, Imm32(imm)); + } + else + { + MOV(32, Ra, Imm32(imm)); + XOR(32, Ra, Rj); + } + } + else if (is_and) + { + if (imm == 0) + gpr.SetImmediate32(a, final_not ? 0xFFFFFFFF : 0); + else + { + RCOpArg Rj = gpr.Use(j, RCMode::Read); + RCX64Reg Ra = gpr.Bind(a, RCMode::Write); + RegCache::Realize(Rj, Ra); + + if (imm == 0xFFFFFFFF) + { + if (a != j) + MOV(32, Ra, Rj); + if (final_not || complement_b) + NOT(32, Ra); + needs_test = true; + } + else if (complement_b) + { + if (a != j) + MOV(32, Ra, Rj); + NOT(32, Ra); + AND(32, Ra, Imm32(imm)); + } + else + { + if (a == j) + AND(32, Ra, Imm32(imm)); + else if (s32(imm) >= -128 && s32(imm) <= 127) + { + MOV(32, Ra, Rj); + AND(32, Ra, Imm32(imm)); + } + else + { + MOV(32, Ra, Imm32(imm)); + AND(32, Ra, Rj); + } + + 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 (imm == 0) + { + if (a != j) + MOV(32, Ra, Rj); + if (final_not || complement_b) + NOT(32, Ra); + needs_test = true; + } + else if (complement_b) + { + if (a != j) + MOV(32, Ra, Rj); + NOT(32, Ra); + OR(32, Ra, Imm32(imm)); + } + else + { + if (a == j) + OR(32, Ra, Imm32(imm)); + else if (s32(imm) >= -128 && s32(imm) <= 127) + { + MOV(32, Ra, Rj); + OR(32, Ra, Imm32(imm)); + } + else + { + MOV(32, Ra, Imm32(imm)); + OR(32, Ra, Rj); + } + + 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 */)) @@ -736,7 +882,7 @@ void Jit64::boolX(UGeckoInstruction inst) } else if (inst.SUBOP10 == 60) // andcx { - if (cpu_info.bBMI1 && Rb.IsSimpleReg() && !Rs.IsImm()) + if (cpu_info.bBMI1 && Rb.IsSimpleReg()) { ANDN(32, Ra, Rb.GetSimpleReg(), Rs); } @@ -811,7 +957,7 @@ void Jit64::boolX(UGeckoInstruction inst) } else if (inst.SUBOP10 == 60) // andcx { - if (cpu_info.bBMI1 && Rb.IsSimpleReg() && !Rs.IsImm()) + if (cpu_info.bBMI1 && Rb.IsSimpleReg()) { ANDN(32, Ra, Rb.GetSimpleReg(), Rs); }