From 26f70657bcebe612444cf738e22a23f40e90718c Mon Sep 17 00:00:00 2001 From: Sintendo Date: Mon, 25 Jan 2021 22:16:41 +0100 Subject: [PATCH 01/12] 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 */)) From 3677a5035c56072a179fb0f424452b5d8b84ebb7 Mon Sep 17 00:00:00 2001 From: Sintendo Date: Thu, 28 Jan 2021 23:06:00 +0100 Subject: [PATCH 02/12] Jit64: boolX - Precompute complement for eqvx In the case of eqvx, the final complement can always be baked directly into the immediate value. Before: 45 8B EF mov r13d,r15d 41 F7 D5 not r13d 41 83 F5 04 xor r13d,4 After: 45 8B EF mov r13d,r15d 41 83 F5 FB xor r13d,0FFFFFFFBh --- Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp index 53a55ccf31..6fadcebb48 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp @@ -668,8 +668,7 @@ void Jit64::boolX(UGeckoInstruction inst) 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 final_not = (inst.SUBOP10 == 476 /* nandx */) || (inst.SUBOP10 == 124 /* norx */); 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 */) || @@ -677,7 +676,7 @@ void Jit64::boolX(UGeckoInstruction inst) bool is_xor = (inst.SUBOP10 == 316 /* xorx */) || (inst.SUBOP10 == 284 /* eqvx */); // Precompute complement when possible - if (complement_b && gpr.IsImm(b)) + if (complement_b && gpr.IsImm(b) || (inst.SUBOP10 == 284 /* eqvx */)) { imm = ~imm; complement_b = false; @@ -692,12 +691,6 @@ void Jit64::boolX(UGeckoInstruction inst) 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) { From c9011e9d2c1a8bc8a1121d220e7a0d0b33c71e15 Mon Sep 17 00:00:00 2001 From: Sintendo Date: Mon, 25 Jan 2021 22:59:14 +0100 Subject: [PATCH 03/12] Jit64: boolX - Special case xor with 0 No computation necessary, but we may need a MOV. Before: 8B FE mov edi,esi 83 F7 00 xor edi,0 After: 8B FE mov edi,esi --- Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp index 6fadcebb48..b4cb6cee39 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp @@ -687,10 +687,18 @@ void Jit64::boolX(UGeckoInstruction inst) 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 (imm == 0) + { + if (a != j) + MOV(32, Ra, Rj); + needs_test = true; + } + else + { + if (a != j) + MOV(32, Ra, Rj); + XOR(32, Ra, Imm32(imm)); + } } else if (is_and) { From c3775588dfd65ae09e1a174fdba35d7179ccfc59 Mon Sep 17 00:00:00 2001 From: Sintendo Date: Mon, 25 Jan 2021 23:25:38 +0100 Subject: [PATCH 04/12] Jit64: boolX - Special case xor with 0xFFFFFFFF Ever so slightly shorter. When the condition register needs updating, we still prefer xor over not+test. Before: 45 8B F5 mov r14d,r13d 41 83 F6 FF xor r14d,0FFFFFFFFh After: 45 8B F5 mov r14d,r13d 41 F7 D6 not r14d --- Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp index b4cb6cee39..2997748790 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp @@ -693,6 +693,12 @@ void Jit64::boolX(UGeckoInstruction inst) 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) From 845d7cd51f731f1eedd25f89fa41823a7f03b9f9 Mon Sep 17 00:00:00 2001 From: Sintendo Date: Mon, 25 Jan 2021 23:44:54 +0100 Subject: [PATCH 05/12] Jit64: boolX - Optimize xor for size XOR allows for a more compact representation for constants that can be represented by a signed 8-bit integer, while MOV does not. By letting MOV handle the larger constants we can occasionally save a byte. Before: 44 89 F7 mov edi,r14d 81 F7 A0 52 57 01 xor edi,15752A0h After: BF A0 52 57 01 mov edi,15752A0h 41 33 FE xor edi,r14d --- Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp index 2997748790..d32c0031b6 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp @@ -699,11 +699,17 @@ void Jit64::boolX(UGeckoInstruction inst) 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 { - if (a != j) - MOV(32, Ra, Rj); - XOR(32, Ra, Imm32(imm)); + MOV(32, Ra, Imm32(imm)); + XOR(32, Ra, Rj); } } else if (is_and) From 131163d33b0f9014bc3d190f0defab1a70184b0f Mon Sep 17 00:00:00 2001 From: Sintendo Date: Mon, 25 Jan 2021 23:54:35 +0100 Subject: [PATCH 06/12] Jit64: boolX - Remove andcx immediate checks All cases involving immediate values are now guaranteed to be handled elsewhere, making these checks redundant. --- Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp index d32c0031b6..5c33e3e8b6 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp @@ -835,7 +835,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); } @@ -910,7 +910,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); } From 34dbfd92db681bb5ec826df65260e65a79d6593d Mon Sep 17 00:00:00 2001 From: Sintendo Date: Tue, 26 Jan 2021 22:16:00 +0100 Subject: [PATCH 07/12] Jit64: boolX - Special case and with 0 Bitwise and with zero is always zero. Before: 45 8B F8 mov r15d,r8d 41 83 E7 00 and r15d,0 After: Nothing, register a is set to constant 0. --- .../Core/Core/PowerPC/Jit64/Jit_Integer.cpp | 42 +++++++++++-------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp index 5c33e3e8b6..def501d988 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp @@ -714,27 +714,33 @@ void Jit64::boolX(UGeckoInstruction inst) } 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)); - } + if (imm == 0) + gpr.SetImmediate32(a, final_not ? 0xFFFFFFFF : 0); else { - if (a != j) - MOV(32, Ra, Rj); - AND(32, Ra, Imm32(imm)); - } + RCOpArg Rj = gpr.Use(j, RCMode::Read); + RCX64Reg Ra = gpr.Bind(a, RCMode::Write); + RegCache::Realize(Rj, Ra); - if (final_not) { - NOT(32, Ra); - needs_test = true; + 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) From b760a56a9abd4fdda2f2809f0ad8e7d861c7a2a8 Mon Sep 17 00:00:00 2001 From: Sintendo Date: Tue, 26 Jan 2021 22:34:03 +0100 Subject: [PATCH 08/12] Jit64: boolX - Special case and with 0xFFFFFFFF Bitwise and with all ones doesn't accomplish much. Before: 41 8B F5 mov esi,r13d 83 E6 FF and esi,0FFFFFFFFh After: 41 8B F5 mov esi,r13d --- .../Core/Core/PowerPC/Jit64/Jit_Integer.cpp | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp index def501d988..7b16d335f0 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp @@ -722,7 +722,15 @@ void Jit64::boolX(UGeckoInstruction inst) RCX64Reg Ra = gpr.Bind(a, RCMode::Write); RegCache::Realize(Rj, Ra); - if (complement_b) + 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); @@ -734,12 +742,12 @@ void Jit64::boolX(UGeckoInstruction inst) if (a != j) MOV(32, Ra, Rj); AND(32, Ra, Imm32(imm)); - } - if (final_not) - { - NOT(32, Ra); - needs_test = true; + if (final_not) + { + NOT(32, Ra); + needs_test = true; + } } } } From 356172bc98760f77f2202a2e057fcdce1a0c0533 Mon Sep 17 00:00:00 2001 From: Sintendo Date: Tue, 26 Jan 2021 22:56:05 +0100 Subject: [PATCH 09/12] Jit64: boolX - Optimize and for size AND allows for a more compact representation for constants that can be represented by a signed 8-bit integer, while MOV does not. By letting MOV handle the larger constants we can occasionally save a byte. Before: 41 8B FE mov edi,r14d 81 E7 FF FE FF FF and edi,0FFFFFEFFh After: BF FF FE FF FF mov edi,0FFFFFEFFh 41 23 FE and edi,r14d --- Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp index 7b16d335f0..7bca28fd4b 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp @@ -739,9 +739,18 @@ void Jit64::boolX(UGeckoInstruction inst) } else { - if (a != j) + 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)); + AND(32, Ra, Imm32(imm)); + } + else + { + MOV(32, Ra, Imm32(imm)); + AND(32, Ra, Rj); + } if (final_not) { From 62f80a008cff4eb3c417b91b7d28a4b3602208fd Mon Sep 17 00:00:00 2001 From: Sintendo Date: Tue, 26 Jan 2021 23:25:19 +0100 Subject: [PATCH 10/12] Jit64: boolX - Special case or with 0 Bitwise or with zero is just a fancy MOV, really. - Example 1 Before: 41 BA 00 00 00 00 mov r10d,0 45 0B D1 or r10d,r9d After: 45 8B D1 mov r10d,r9d - Example 2 Before: 41 83 CA 00 or r10d,0 After: Nothing! --- .../Core/Core/PowerPC/Jit64/Jit_Integer.cpp | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp index 7bca28fd4b..b2a76be60e 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp @@ -766,7 +766,15 @@ void Jit64::boolX(UGeckoInstruction inst) RCX64Reg Ra = gpr.Bind(a, RCMode::Write); RegCache::Realize(Rj, Ra); - if (complement_b) + 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); @@ -778,11 +786,12 @@ void Jit64::boolX(UGeckoInstruction inst) if (a != j) MOV(32, Ra, Rj); OR(32, Ra, Imm32(imm)); - } - if (final_not) { - NOT(32, Ra); - needs_test = true; + if (final_not) + { + NOT(32, Ra); + needs_test = true; + } } } else From 2d3c7fca8d26f434b14a79d26884a7825ddc8547 Mon Sep 17 00:00:00 2001 From: Sintendo Date: Tue, 26 Jan 2021 23:37:22 +0100 Subject: [PATCH 11/12] Jit64: boolX - Optimize or for size OR allows for a more compact representation for constants that can be represented by a signed 8-bit integer, while MOV does not. By letting MOV handle the larger constants we can occasionally save a byte. Before: 45 8B F5 mov r14d,r13d 41 81 CE 00 80 01 00 or r14d,18000h After: 41 BE 00 80 01 00 mov r14d,18000h 45 0B F5 or r14d,r13d --- Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp index b2a76be60e..19d090c7c1 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp @@ -783,9 +783,18 @@ void Jit64::boolX(UGeckoInstruction inst) } else { - if (a != j) + 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)); + OR(32, Ra, Imm32(imm)); + } + else + { + MOV(32, Ra, Imm32(imm)); + OR(32, Ra, Rj); + } if (final_not) { From ecbf6fff74ab9574c0945181917d122e1ae1c4c6 Mon Sep 17 00:00:00 2001 From: Sintendo Date: Thu, 28 Jan 2021 23:49:56 +0100 Subject: [PATCH 12/12] Jit64: boolX - Mark locals as const --- Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp index 19d090c7c1..71aa2513c0 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp @@ -664,16 +664,16 @@ void Jit64::boolX(UGeckoInstruction inst) } else if (gpr.IsImm(s) || gpr.IsImm(b)) { - auto [i, j] = gpr.IsImm(s) ? std::pair(s, b) : std::pair(b, s); + 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 */); - bool final_not = (inst.SUBOP10 == 476 /* nandx */) || (inst.SUBOP10 == 124 /* norx */); - 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 */); + 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 */))