From 50d991780fe9b1b6efbf4097c06c90b3b84dbdb6 Mon Sep 17 00:00:00 2001 From: Sintendo <3380580+Sintendo@users.noreply.github.com> Date: Fri, 27 Dec 2024 09:47:54 +0100 Subject: [PATCH 01/12] JitBase: Add HasConstantCarry helper --- Source/Core/Core/PowerPC/JitCommon/JitBase.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Source/Core/Core/PowerPC/JitCommon/JitBase.h b/Source/Core/Core/PowerPC/JitCommon/JitBase.h index fa2fdd167f..50c840a2b9 100644 --- a/Source/Core/Core/PowerPC/JitCommon/JitBase.h +++ b/Source/Core/Core/PowerPC/JitCommon/JitBase.h @@ -178,6 +178,14 @@ protected: void CleanUpAfterStackFault(); bool CanMergeNextInstructions(int count) const; + bool HasConstantCarry() const + { +#ifdef _M_ARM_64 + return js.carryFlag == CarryFlag::ConstantTrue || js.carryFlag == CarryFlag::ConstantFalse; +#else + return false; +#endif + } bool ShouldHandleFPExceptionForInstruction(const PPCAnalyst::CodeOp* op); From 5cc9bde1c1e800770569a8b047265f939d97df0f Mon Sep 17 00:00:00 2001 From: Sintendo <3380580+Sintendo@users.noreply.github.com> Date: Fri, 27 Dec 2024 09:48:58 +0100 Subject: [PATCH 02/12] JitBase: Improve const-correctness --- Source/Core/Core/PowerPC/JitCommon/JitBase.cpp | 4 ++-- Source/Core/Core/PowerPC/JitCommon/JitBase.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Source/Core/Core/PowerPC/JitCommon/JitBase.cpp b/Source/Core/Core/PowerPC/JitCommon/JitBase.cpp index 033ca756cd..d2de2895a7 100644 --- a/Source/Core/Core/PowerPC/JitCommon/JitBase.cpp +++ b/Source/Core/Core/PowerPC/JitCommon/JitBase.cpp @@ -110,7 +110,7 @@ JitBase::~JitBase() CPUThreadConfigCallback::RemoveConfigChangedCallback(m_registered_config_callback_id); } -bool JitBase::DoesConfigNeedRefresh() +bool JitBase::DoesConfigNeedRefresh() const { return std::ranges::any_of(JIT_SETTINGS, [this](const auto& pair) { return this->*pair.first != Config::Get(*pair.second); @@ -276,7 +276,7 @@ bool JitBase::CanMergeNextInstructions(int count) const return true; } -bool JitBase::ShouldHandleFPExceptionForInstruction(const PPCAnalyst::CodeOp* op) +bool JitBase::ShouldHandleFPExceptionForInstruction(const PPCAnalyst::CodeOp* op) const { if (jo.fp_exceptions) return (op->opinfo->flags & FL_FLOAT_EXCEPTION) != 0; diff --git a/Source/Core/Core/PowerPC/JitCommon/JitBase.h b/Source/Core/Core/PowerPC/JitCommon/JitBase.h index 50c840a2b9..4ac81c4049 100644 --- a/Source/Core/Core/PowerPC/JitCommon/JitBase.h +++ b/Source/Core/Core/PowerPC/JitCommon/JitBase.h @@ -167,7 +167,7 @@ protected: static const std::array*>, 23> JIT_SETTINGS; - bool DoesConfigNeedRefresh(); + bool DoesConfigNeedRefresh() const; void RefreshConfig(); void InitFastmemArena(); @@ -187,7 +187,7 @@ protected: #endif } - bool ShouldHandleFPExceptionForInstruction(const PPCAnalyst::CodeOp* op); + bool ShouldHandleFPExceptionForInstruction(const PPCAnalyst::CodeOp* op) const; public: explicit JitBase(Core::System& system); From e54bfd660567f6fd20e3d30b9072339ab56047b5 Mon Sep 17 00:00:00 2001 From: Sintendo <3380580+Sintendo@users.noreply.github.com> Date: Sat, 28 Dec 2024 18:12:13 +0100 Subject: [PATCH 03/12] JitArm64_Integer: Refactor subfex --- .../PowerPC/JitArm64/JitArm64_Integer.cpp | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp index 76f771abe5..41ad4290d0 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp @@ -1216,40 +1216,44 @@ void JitArm64::subfex(UGeckoInstruction inst) if (gpr.IsImm(a) && (mex || gpr.IsImm(b))) { - u32 i = gpr.GetImm(a), j = mex ? -1 : gpr.GetImm(b); - - gpr.BindToRegister(d, false); + const u32 i = gpr.GetImm(a); + const u32 j = mex ? -1 : gpr.GetImm(b); + const u32 imm = ~i + j; + const bool is_all_ones = imm == 0xFFFFFFFF; switch (js.carryFlag) { case CarryFlag::InPPCState: { + gpr.BindToRegister(d, false); + ARM64Reg RD = gpr.R(d); auto WA = gpr.GetScopedReg(); LDRB(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(xer_ca)); - ADDI2R(gpr.R(d), WA, ~i + j, gpr.R(d)); + ADDI2R(RD, WA, imm, RD); break; } case CarryFlag::InHostCarry: { - auto WA = gpr.GetScopedReg(); - MOVI2R(WA, ~i + j); - ADC(gpr.R(d), WA, ARM64Reg::WZR); + gpr.BindToRegister(d, false); + ARM64Reg RD = gpr.R(d); + MOVI2R(RD, imm); + ADC(RD, RD, ARM64Reg::WZR); break; } case CarryFlag::ConstantTrue: { - gpr.SetImmediate(d, ~i + j + 1); + gpr.SetImmediate(d, imm + 1); break; } case CarryFlag::ConstantFalse: { - gpr.SetImmediate(d, ~i + j); + gpr.SetImmediate(d, imm); break; } } const bool must_have_carry = Interpreter::Helper_Carry(~i, j); - const bool might_have_carry = (~i + j) == 0xFFFFFFFF; + const bool might_have_carry = is_all_ones; if (must_have_carry) { From 18dd3f69f15f8659f74a7b69627db924b9d169df Mon Sep 17 00:00:00 2001 From: Sintendo <3380580+Sintendo@users.noreply.github.com> Date: Sat, 28 Dec 2024 18:15:44 +0100 Subject: [PATCH 04/12] JitArm64_Integer: subfex - Optimize InPPCState case for 0 When the immediate is zero, we can load the carry flag from memory directly to the destination register. Before: 0x394bd3b8 ldrb w24, [x29, #0x2f4] 0x2a1803f9 mov w25, w24 After: 0x394bd3b9 ldrb w25, [x29, #0x2f4] --- .../Core/PowerPC/JitArm64/JitArm64_Integer.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp index 41ad4290d0..3b6aef8788 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp @@ -1219,6 +1219,7 @@ void JitArm64::subfex(UGeckoInstruction inst) const u32 i = gpr.GetImm(a); const u32 j = mex ? -1 : gpr.GetImm(b); const u32 imm = ~i + j; + const bool is_zero = imm == 0; const bool is_all_ones = imm == 0xFFFFFFFF; switch (js.carryFlag) @@ -1227,9 +1228,16 @@ void JitArm64::subfex(UGeckoInstruction inst) { gpr.BindToRegister(d, false); ARM64Reg RD = gpr.R(d); - auto WA = gpr.GetScopedReg(); - LDRB(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(xer_ca)); - ADDI2R(RD, WA, imm, RD); + if (is_zero) + { + LDRB(IndexType::Unsigned, RD, PPC_REG, PPCSTATE_OFF(xer_ca)); + } + else + { + auto WA = gpr.GetScopedReg(); + LDRB(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(xer_ca)); + ADDI2R(RD, WA, imm, RD); + } break; } case CarryFlag::InHostCarry: From fa13457abbf4bf194b4c5b8b0d5ff86fc2862ae7 Mon Sep 17 00:00:00 2001 From: Sintendo <3380580+Sintendo@users.noreply.github.com> Date: Sat, 28 Dec 2024 20:18:09 +0100 Subject: [PATCH 05/12] JitArm64_Integer: subfex - Optimize InHostCarry case for -1 The result is either -1 or 0 depending on the state of the carry flag. This can be done with a csetm instruction. Before: 0x1280001a mov w26, #-0x1 ; =-1 0x1a1f035a adc w26, w26, wzr After: 0x5a9f23fa csetm w26, lo --- .../Core/PowerPC/JitArm64/JitArm64_Integer.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp index 3b6aef8788..ed59599cff 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp @@ -1244,8 +1244,18 @@ void JitArm64::subfex(UGeckoInstruction inst) { gpr.BindToRegister(d, false); ARM64Reg RD = gpr.R(d); - MOVI2R(RD, imm); - ADC(RD, RD, ARM64Reg::WZR); + if (is_all_ones) + { + // RD = -1 + carry = carry ? 0 : -1 + // CSETM sets the destination to -1 if the condition is true, 0 + // otherwise. Hence, the condition must be carry clear. + CSETM(RD, CC_CC); + } + else + { + MOVI2R(RD, imm); + ADC(RD, RD, ARM64Reg::WZR); + } break; } case CarryFlag::ConstantTrue: From 7410bc20257ab3f1a56b3808817ec6a2ade96c16 Mon Sep 17 00:00:00 2001 From: Sintendo <3380580+Sintendo@users.noreply.github.com> Date: Sat, 28 Dec 2024 20:57:55 +0100 Subject: [PATCH 06/12] JitArm64_Integer: subfzex - Constant folding When both the input register and the carry flag are constants, the result can be precomputed. Before: 0x52800016 mov w22, #0x0 ; =0 0x2a3603f6 mvn w22, w22 After: --- .../PowerPC/JitArm64/JitArm64_Integer.cpp | 70 +++++++++++-------- 1 file changed, 40 insertions(+), 30 deletions(-) diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp index ed59599cff..b2193faf36 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp @@ -1359,39 +1359,49 @@ void JitArm64::subfzex(UGeckoInstruction inst) int a = inst.RA, d = inst.RD; - gpr.BindToRegister(d, d == a); + if (gpr.IsImm(a) && HasConstantCarry()) + { + const u32 imm = ~gpr.GetImm(a); + const u32 carry = js.carryFlag == CarryFlag::ConstantTrue; + gpr.SetImmediate(d, imm + carry); + ComputeCarry(Interpreter::Helper_Carry(imm, carry)); + } + else + { + gpr.BindToRegister(d, d == a); - switch (js.carryFlag) - { - case CarryFlag::InPPCState: - { + switch (js.carryFlag) { - auto WA = gpr.GetScopedReg(); - LDRB(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(xer_ca)); - MVN(gpr.R(d), gpr.R(a)); - CARRY_IF_NEEDED(ADD, ADDS, gpr.R(d), gpr.R(d), WA); + case CarryFlag::InPPCState: + { + { + auto WA = gpr.GetScopedReg(); + LDRB(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(xer_ca)); + MVN(gpr.R(d), gpr.R(a)); + CARRY_IF_NEEDED(ADD, ADDS, gpr.R(d), gpr.R(d), WA); + } + ComputeCarry(); + break; + } + case CarryFlag::InHostCarry: + { + CARRY_IF_NEEDED(SBC, SBCS, gpr.R(d), ARM64Reg::WZR, gpr.R(a)); + ComputeCarry(); + break; + } + case CarryFlag::ConstantTrue: + { + CARRY_IF_NEEDED(NEG, NEGS, gpr.R(d), gpr.R(a)); + ComputeCarry(); + break; + } + case CarryFlag::ConstantFalse: + { + MVN(gpr.R(d), gpr.R(a)); + ComputeCarry(false); + break; + } } - ComputeCarry(); - break; - } - case CarryFlag::InHostCarry: - { - CARRY_IF_NEEDED(SBC, SBCS, gpr.R(d), ARM64Reg::WZR, gpr.R(a)); - ComputeCarry(); - break; - } - case CarryFlag::ConstantTrue: - { - CARRY_IF_NEEDED(NEG, NEGS, gpr.R(d), gpr.R(a)); - ComputeCarry(); - break; - } - case CarryFlag::ConstantFalse: - { - MVN(gpr.R(d), gpr.R(a)); - ComputeCarry(false); - break; - } } if (inst.Rc) From ad7dba541353d532f0299f6442e8ca59a9040695 Mon Sep 17 00:00:00 2001 From: Sintendo <3380580+Sintendo@users.noreply.github.com> Date: Sat, 28 Dec 2024 21:41:48 +0100 Subject: [PATCH 07/12] JitArm64_Integer: addex - Optimize InPPCState case for 0 Same optimization we did for subfex. Skip loading the carry flag into a temporary register first when we're dealing with zero. Before: 0x394bd3b8 ldrb w24, [x29, #0x2f4] 0x2a1803f9 mov w25, w24 After: 0x394bd3b9 ldrb w25, [x29, #0x2f4] --- .../PowerPC/JitArm64/JitArm64_Integer.cpp | 31 +++++++++++++------ 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp index b2193faf36..eb742ac1dd 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp @@ -1468,40 +1468,51 @@ void JitArm64::addex(UGeckoInstruction inst) if (gpr.IsImm(a) && (mex || gpr.IsImm(b))) { - u32 i = gpr.GetImm(a), j = mex ? -1 : gpr.GetImm(b); - - gpr.BindToRegister(d, false); + const u32 i = gpr.GetImm(a), j = mex ? -1 : gpr.GetImm(b); + const u32 imm = i + j; + const bool is_zero = imm == 0; + const bool is_all_ones = imm == 0xFFFFFFFF; switch (js.carryFlag) { case CarryFlag::InPPCState: { - auto WA = gpr.GetScopedReg(); - LDRB(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(xer_ca)); - ADDI2R(gpr.R(d), WA, i + j, gpr.R(d)); + gpr.BindToRegister(d, false); + ARM64Reg RD = gpr.R(d); + if (is_zero) + { + LDRB(IndexType::Unsigned, RD, PPC_REG, PPCSTATE_OFF(xer_ca)); + } + else + { + auto WA = gpr.GetScopedReg(); + LDRB(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(xer_ca)); + ADDI2R(RD, WA, imm, RD); + } break; } case CarryFlag::InHostCarry: { + gpr.BindToRegister(d, false); ARM64Reg RD = gpr.R(d); - MOVI2R(RD, i + j); + MOVI2R(RD, imm); ADC(RD, RD, ARM64Reg::WZR); break; } case CarryFlag::ConstantTrue: { - gpr.SetImmediate(d, i + j + 1); + gpr.SetImmediate(d, imm + 1); break; } case CarryFlag::ConstantFalse: { - gpr.SetImmediate(d, i + j); + gpr.SetImmediate(d, imm); break; } } const bool must_have_carry = Interpreter::Helper_Carry(i, j); - const bool might_have_carry = (i + j) == 0xFFFFFFFF; + const bool might_have_carry = is_all_ones; if (must_have_carry) { From d2bfa157dc9ed038ab298c92b52dc09fda782bb5 Mon Sep 17 00:00:00 2001 From: Sintendo <3380580+Sintendo@users.noreply.github.com> Date: Sat, 28 Dec 2024 21:53:28 +0100 Subject: [PATCH 08/12] JitArm64_Integer: addex - Optimize InHostCarry for 0 Similar to what we did for subfex, but for 0. Before: 0x5280001b mov w27, #0x0 ; =0 0x1a1f037b adc w27, w27, wzr After: 0x1a9f37fb cset w27, hs --- .../Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp index eb742ac1dd..54c86ba1f1 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp @@ -1495,8 +1495,16 @@ void JitArm64::addex(UGeckoInstruction inst) { gpr.BindToRegister(d, false); ARM64Reg RD = gpr.R(d); - MOVI2R(RD, imm); - ADC(RD, RD, ARM64Reg::WZR); + if (is_zero) + { + // RD = 0 + carry = carry ? 1 : 0 + CSET(RD, CC_CS); + } + else + { + MOVI2R(RD, imm); + ADC(RD, RD, ARM64Reg::WZR); + } break; } case CarryFlag::ConstantTrue: From a4ba13b4c98f668e69523448960a230c031fea37 Mon Sep 17 00:00:00 2001 From: Sintendo <3380580+Sintendo@users.noreply.github.com> Date: Sat, 28 Dec 2024 22:12:46 +0100 Subject: [PATCH 09/12] JitArm64_Integer: addex - Optimize InHostCarry for -1 Same thing we did for subfex. Before: 0x1280001a mov w26, #-0x1 ; =-1 0x1a1f035a adc w26, w26, wzr After: 0x5a9f23fa csetm w26, lo --- Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp index 54c86ba1f1..a6820fdfd2 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp @@ -1500,6 +1500,13 @@ void JitArm64::addex(UGeckoInstruction inst) // RD = 0 + carry = carry ? 1 : 0 CSET(RD, CC_CS); } + else if (is_all_ones) + { + // RD = -1 + carry = carry ? 0 : -1 + // Note that CSETM sets the destination to -1 if the condition is true, + // and 0 otherwise. Hence, the condition must be carry clear. + CSETM(RD, CC_CC); + } else { MOVI2R(RD, imm); From 14641b06fc001e4ecd828b6b3e6d66422b2da8e4 Mon Sep 17 00:00:00 2001 From: Sintendo <3380580+Sintendo@users.noreply.github.com> Date: Sat, 28 Dec 2024 23:07:33 +0100 Subject: [PATCH 10/12] JitArm64_Integer: addzex - Optimize ConstantFalse and ConstantTrue When the input register and carry flags are known, we can always precompute the result. We still materialize the immediate when the condition register needs to be updated, but this seems to be a general problem. I might look into that one day, but for now this'll do. - ConstantFalse Before: 0x52800119 mov w25, #0x8 ; =8 0x2a1903fa mov w26, w25 After: N/A - ConstantTrue Before: 0x52800119 mov w25, #0x8 ; =8 0x1100073a add w26, w25, #0x1 After: N/A --- .../PowerPC/JitArm64/JitArm64_Integer.cpp | 97 ++++++++++++------- 1 file changed, 62 insertions(+), 35 deletions(-) diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp index a6820fdfd2..c3ebc252e4 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp @@ -10,6 +10,7 @@ #include "Common/BitUtils.h" #include "Common/CommonTypes.h" #include "Common/MathUtil.h" +#include "Common/Unreachable.h" #include "Core/Core.h" #include "Core/CoreTiming.h" @@ -1128,47 +1129,73 @@ void JitArm64::addzex(UGeckoInstruction inst) int a = inst.RA, d = inst.RD; - switch (js.carryFlag) + if (gpr.IsImm(a) && HasConstantCarry()) { - case CarryFlag::InPPCState: - { - const bool allocate_reg = d == a; - gpr.BindToRegister(d, allocate_reg); + const u32 imm = gpr.GetImm(a); + const bool is_all_ones = imm == 0xFFFFFFFF; + switch (js.carryFlag) { - auto WA = allocate_reg ? gpr.GetScopedReg() : Arm64GPRCache::ScopedARM64Reg(gpr.R(d)); - LDRB(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(xer_ca)); - CARRY_IF_NEEDED(ADD, ADDS, gpr.R(d), gpr.R(a), WA); - } - - ComputeCarry(); - break; - } - case CarryFlag::InHostCarry: - { - gpr.BindToRegister(d, d == a); - CARRY_IF_NEEDED(ADC, ADCS, gpr.R(d), gpr.R(a), ARM64Reg::WZR); - ComputeCarry(); - break; - } - case CarryFlag::ConstantTrue: - { - gpr.BindToRegister(d, d == a); - CARRY_IF_NEEDED(ADD, ADDS, gpr.R(d), gpr.R(a), 1); - ComputeCarry(); - break; - } - case CarryFlag::ConstantFalse: - { - if (d != a) + case CarryFlag::ConstantTrue: { - gpr.BindToRegister(d, false); - MOV(gpr.R(d), gpr.R(a)); + gpr.SetImmediate(d, imm + 1); + ComputeCarry(is_all_ones); + break; + } + case CarryFlag::ConstantFalse: + { + gpr.SetImmediate(d, imm); + ComputeCarry(false); + break; + } + default: + Common::Unreachable(); } - - ComputeCarry(false); - break; } + else + { + switch (js.carryFlag) + { + case CarryFlag::InPPCState: + { + const bool allocate_reg = d == a; + gpr.BindToRegister(d, allocate_reg); + + { + auto WA = allocate_reg ? gpr.GetScopedReg() : Arm64GPRCache::ScopedARM64Reg(gpr.R(d)); + LDRB(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(xer_ca)); + CARRY_IF_NEEDED(ADD, ADDS, gpr.R(d), gpr.R(a), WA); + } + + ComputeCarry(); + break; + } + case CarryFlag::InHostCarry: + { + gpr.BindToRegister(d, d == a); + CARRY_IF_NEEDED(ADC, ADCS, gpr.R(d), gpr.R(a), ARM64Reg::WZR); + ComputeCarry(); + break; + } + case CarryFlag::ConstantTrue: + { + gpr.BindToRegister(d, d == a); + CARRY_IF_NEEDED(ADD, ADDS, gpr.R(d), gpr.R(a), 1); + ComputeCarry(); + break; + } + case CarryFlag::ConstantFalse: + { + if (d != a) + { + gpr.BindToRegister(d, false); + MOV(gpr.R(d), gpr.R(a)); + } + + ComputeCarry(false); + break; + } + } } if (inst.Rc) From c817b4779daf6b58a25bfb194a156e3215177574 Mon Sep 17 00:00:00 2001 From: Sintendo <3380580+Sintendo@users.noreply.github.com> Date: Sat, 28 Dec 2024 23:20:17 +0100 Subject: [PATCH 11/12] JitArm64_Integer: addzex - Optimize InPPCState case for 0 Before: 0x52800019 mov w25, #0x0 ; =0 0x394bd3b8 ldrb w24, [x29, #0x2f4] 0x2b180339 adds w25, w25, w24 After: 0x394bd3b9 ldrb w25, [x29, #0x2f4] --- Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp index c3ebc252e4..0b21cc2d9d 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp @@ -1129,13 +1129,21 @@ void JitArm64::addzex(UGeckoInstruction inst) int a = inst.RA, d = inst.RD; - if (gpr.IsImm(a) && HasConstantCarry()) + if (gpr.IsImm(a) && + (HasConstantCarry() || (js.carryFlag == CarryFlag::InPPCState && gpr.GetImm(a) == 0))) { const u32 imm = gpr.GetImm(a); const bool is_all_ones = imm == 0xFFFFFFFF; switch (js.carryFlag) { + case CarryFlag::InPPCState: + { + gpr.BindToRegister(d, false); + LDRB(IndexType::Unsigned, gpr.R(d), PPC_REG, PPCSTATE_OFF(xer_ca)); + ComputeCarry(false); + break; + } case CarryFlag::ConstantTrue: { gpr.SetImmediate(d, imm + 1); From d81bfe94ebda073938fb71b148dd7d613719fca0 Mon Sep 17 00:00:00 2001 From: Sintendo <3380580+Sintendo@users.noreply.github.com> Date: Sat, 28 Dec 2024 23:26:55 +0100 Subject: [PATCH 12/12] JitArm64_Integer: addzex - Optimize InHostCarry case for 0 Before: 0x5280000d mov w13, #0x0 ; =0 0x1a1f01ae adc w14, w13, wzr After: 0x1a9f37ee cset w14, hs --- .../Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp index 0b21cc2d9d..4d92714fd9 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp @@ -10,7 +10,6 @@ #include "Common/BitUtils.h" #include "Common/CommonTypes.h" #include "Common/MathUtil.h" -#include "Common/Unreachable.h" #include "Core/Core.h" #include "Core/CoreTiming.h" @@ -1129,8 +1128,7 @@ void JitArm64::addzex(UGeckoInstruction inst) int a = inst.RA, d = inst.RD; - if (gpr.IsImm(a) && - (HasConstantCarry() || (js.carryFlag == CarryFlag::InPPCState && gpr.GetImm(a) == 0))) + if (gpr.IsImm(a) && (gpr.GetImm(a) == 0 || HasConstantCarry())) { const u32 imm = gpr.GetImm(a); const bool is_all_ones = imm == 0xFFFFFFFF; @@ -1144,6 +1142,13 @@ void JitArm64::addzex(UGeckoInstruction inst) ComputeCarry(false); break; } + case CarryFlag::InHostCarry: + { + gpr.BindToRegister(d, false); + CSET(gpr.R(d), CCFlags::CC_CS); + ComputeCarry(false); + break; + } case CarryFlag::ConstantTrue: { gpr.SetImmediate(d, imm + 1); @@ -1156,8 +1161,6 @@ void JitArm64::addzex(UGeckoInstruction inst) ComputeCarry(false); break; } - default: - Common::Unreachable(); } } else