aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlizzie <lizzie@eden-emu.dev>2026-07-07 19:53:13 +0200
committercrueter <crueter@eden-emu.dev>2026-07-07 19:53:13 +0200
commitf22fd1714ba40f1444a79a629dbe53e0744c85cd (patch)
tree17611ff47caa0246b38e1ef03d28a0d1b53199d4
parent6119e8fad2677e731e6105af6063cabe7be069f8 (diff)
[dynarmic] use LinkBlockFast for branches which are guarnateed to be unconditional (or conditionally unconditional) (#4177)
CBZ is basically ```c if (thing) { jump(A); } else { jump(B); } ``` those jumps are locally unconditional so we can add the LinkBlockFast without much repercussions for a small win in JIT opts Signed-off-by: lizzie <lizzie@eden-emu.dev> Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4177 Reviewed-by: MaranBr <maranbr@eden-emu.dev> Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
-rw-r--r--docs/dynarmic/Design.md5
-rw-r--r--src/dynarmic/src/dynarmic/frontend/A32/translate/impl/a32_branch.cpp12
-rw-r--r--src/dynarmic/src/dynarmic/frontend/A32/translate/impl/status_register_access.cpp5
-rw-r--r--src/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb16.cpp21
-rw-r--r--src/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_branch.cpp37
-rw-r--r--src/dynarmic/src/dynarmic/frontend/A64/translate/impl/a64_branch.cpp24
6 files changed, 54 insertions, 50 deletions
diff --git a/docs/dynarmic/Design.md b/docs/dynarmic/Design.md
index 020cfd65bd..b46e7e5348 100644
--- a/docs/dynarmic/Design.md
+++ b/docs/dynarmic/Design.md
@@ -311,8 +311,9 @@ dispatcher, which will return control to the host.
SetTerm(IR::Term::LinkBlockFast{next})
```
-This terminal instruction jumps to the basic block described by `next` unconditionally.
-This promises guarantees that must be held at runtime - i.e that the program wont hang,
+This terminal instruction jumps to the basic block described by `next` unconditionally. This promises guarantees that must be held at runtime - i.e that the program wont hang,
+
+This is a valid expression if contained within another block (say a `Terminal::If`) and the semantics allow it to be so.
### Terminal: PopRSBHint
diff --git a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/a32_branch.cpp b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/a32_branch.cpp
index 63b40b8c31..adef1adbec 100644
--- a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/a32_branch.cpp
+++ b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/a32_branch.cpp
@@ -17,10 +17,14 @@ bool TranslatorVisitor::arm_B(Cond cond, Imm<24> imm24) {
if (!ArmConditionPassed(cond)) {
return true;
}
-
const u32 imm32 = mcl::bit::sign_extend<26, u32>(imm24.ZeroExtend() << 2) + 8;
const auto new_location = ir.current_location.AdvancePC(imm32);
- ir.SetTerm(IR::Term::LinkBlock{new_location});
+ // pattern match => b .
+ if (imm32 == 0) {
+ ir.SetTerm(IR::Term::LinkBlock{new_location});
+ } else {
+ ir.SetTerm(IR::Term::LinkBlockFast{new_location});
+ }
return false;
}
@@ -35,7 +39,7 @@ bool TranslatorVisitor::arm_BL(Cond cond, Imm<24> imm24) {
const u32 imm32 = mcl::bit::sign_extend<26, u32>(imm24.ZeroExtend() << 2) + 8;
const auto new_location = ir.current_location.AdvancePC(imm32);
- ir.SetTerm(IR::Term::LinkBlock{new_location});
+ ir.SetTerm(IR::Term::LinkBlockFast{new_location});
return false;
}
@@ -46,7 +50,7 @@ bool TranslatorVisitor::arm_BLX_imm(bool H, Imm<24> imm24) {
const u32 imm32 = mcl::bit::sign_extend<26, u32>((imm24.ZeroExtend() << 2)) + (H ? 2 : 0) + 8;
const auto new_location = ir.current_location.AdvancePC(imm32).SetTFlag(true);
- ir.SetTerm(IR::Term::LinkBlock{new_location});
+ ir.SetTerm(IR::Term::LinkBlockFast{new_location});
return false;
}
diff --git a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/status_register_access.cpp b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/status_register_access.cpp
index 7a0640598c..bd52d3d4a9 100644
--- a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/status_register_access.cpp
+++ b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/status_register_access.cpp
@@ -56,11 +56,10 @@ bool TranslatorVisitor::arm_MSR_imm(Cond cond, unsigned mask, int rotate, Imm<8>
if (write_e) {
const bool E = (imm32 & 0x00000200) != 0;
if (E != ir.current_location.EFlag()) {
- ir.SetTerm(IR::Term::LinkBlock{ir.current_location.AdvancePC(4).SetEFlag(E)});
+ ir.SetTerm(IR::Term::LinkBlockFast{ir.current_location.AdvancePC(4).SetEFlag(E)});
return false;
}
}
-
return true;
}
@@ -112,7 +111,7 @@ bool TranslatorVisitor::arm_RFE() {
// SETEND <endian_specifier>
bool TranslatorVisitor::arm_SETEND(bool E) {
- ir.SetTerm(IR::Term::LinkBlock{ir.current_location.AdvancePC(4).SetEFlag(E)});
+ ir.SetTerm(IR::Term::LinkBlockFast{ir.current_location.AdvancePC(4).SetEFlag(E)});
return false;
}
diff --git a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb16.cpp b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb16.cpp
index 082cd30db2..e7bb36f285 100644
--- a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb16.cpp
+++ b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb16.cpp
@@ -803,7 +803,7 @@ bool TranslatorVisitor::thumb16_SETEND(bool E) {
return true;
}
- ir.SetTerm(IR::Term::LinkBlock{ir.current_location.AdvancePC(2).SetEFlag(E).AdvanceIT()});
+ ir.SetTerm(IR::Term::LinkBlockFast{ir.current_location.AdvancePC(2).SetEFlag(E).AdvanceIT()});
return false;
}
@@ -906,9 +906,8 @@ bool TranslatorVisitor::thumb16_CBZ_CBNZ(bool nonzero, Imm<1> i, Imm<5> imm5, Re
ir.SetCheckBit(ir.IsZero(rn));
const auto [cond_pass, cond_fail] = [this, imm, nonzero] {
- const auto skip = IR::Term::LinkBlock{ir.current_location.AdvancePC(2).AdvanceIT()};
- const auto branch = IR::Term::LinkBlock{ir.current_location.AdvancePC(imm + 4).AdvanceIT()};
-
+ const auto skip = IR::Term::LinkBlockFast{ir.current_location.AdvancePC(2).AdvanceIT()};
+ const auto branch = IR::Term::LinkBlockFast{ir.current_location.AdvancePC(imm + 4).AdvanceIT()};
if (nonzero) {
return std::make_pair(skip, branch);
} else {
@@ -975,10 +974,10 @@ bool TranslatorVisitor::thumb16_B_t1(Cond cond, Imm<8> imm8) {
}
const s32 imm32 = static_cast<s32>((imm8.SignExtend<u32>() << 1) + 4);
- const auto then_location = ir.current_location.AdvancePC(imm32).AdvanceIT();
- const auto else_location = ir.current_location.AdvancePC(2).AdvanceIT();
+ const auto then_ = IR::Term::LinkBlockFast{ir.current_location.AdvancePC(imm32).AdvanceIT()};
+ const auto else_ = IR::Term::LinkBlockFast{ir.current_location.AdvancePC(2).AdvanceIT()};
- ir.SetTerm(IR::Term::If{cond, IR::Term::LinkBlock{then_location}, IR::Term::LinkBlock{else_location}});
+ ir.SetTerm(IR::Term::If{cond, then_, else_});
return false;
}
@@ -990,8 +989,12 @@ bool TranslatorVisitor::thumb16_B_t2(Imm<11> imm11) {
const s32 imm32 = static_cast<s32>((imm11.SignExtend<u32>() << 1) + 4);
const auto next_location = ir.current_location.AdvancePC(imm32).AdvanceIT();
-
- ir.SetTerm(IR::Term::LinkBlock{next_location});
+ // pattern (b +#0)
+ if (imm32 == 0) {
+ ir.SetTerm(IR::Term::LinkBlock{next_location});
+ } else {
+ ir.SetTerm(IR::Term::LinkBlockFast{next_location});
+ }
return false;
}
diff --git a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_branch.cpp b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_branch.cpp
index 83734f5c70..4b19449872 100644
--- a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_branch.cpp
+++ b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_branch.cpp
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
* SPDX-License-Identifier: 0BSD
@@ -20,10 +23,8 @@ bool TranslatorVisitor::thumb32_BL_imm(Imm<1> S, Imm<10> hi, Imm<1> j1, Imm<1> j
ir.SetRegister(Reg::LR, ir.Imm32((ir.current_location.PC() + 4) | 1));
const s32 imm32 = static_cast<s32>((concatenate(S, i1, i2, hi, lo).SignExtend<u32>() << 1) + 4);
- const auto new_location = ir.current_location
- .AdvancePC(imm32)
- .AdvanceIT();
- ir.SetTerm(IR::Term::LinkBlock{new_location});
+ auto const new_location = ir.current_location.AdvancePC(imm32).AdvanceIT();
+ ir.SetTerm(IR::Term::LinkBlockFast{new_location});
return false;
}
@@ -44,11 +45,8 @@ bool TranslatorVisitor::thumb32_BLX_imm(Imm<1> S, Imm<10> hi, Imm<1> j1, Imm<1>
ir.SetRegister(Reg::LR, ir.Imm32((ir.current_location.PC() + 4) | 1));
const s32 imm32 = static_cast<s32>(concatenate(S, i1, i2, hi, lo).SignExtend<u32>() << 1);
- const auto new_location = ir.current_location
- .SetPC(ir.AlignPC(4) + imm32)
- .SetTFlag(false)
- .AdvanceIT();
- ir.SetTerm(IR::Term::LinkBlock{new_location});
+ const auto new_location = ir.current_location.SetPC(ir.AlignPC(4) + imm32).SetTFlag(false).AdvanceIT();
+ ir.SetTerm(IR::Term::LinkBlockFast{new_location});
return false;
}
@@ -61,10 +59,13 @@ bool TranslatorVisitor::thumb32_B(Imm<1> S, Imm<10> hi, Imm<1> j1, Imm<1> j2, Im
}
const s32 imm32 = static_cast<s32>((concatenate(S, i1, i2, hi, lo).SignExtend<u32>() << 1) + 4);
- const auto new_location = ir.current_location
- .AdvancePC(imm32)
- .AdvanceIT();
- ir.SetTerm(IR::Term::LinkBlock{new_location});
+ auto const new_location = ir.current_location.AdvancePC(imm32).AdvanceIT();
+ // Pattern to halt execution (b +#0)
+ if (imm32 == 0) {
+ ir.SetTerm(IR::Term::LinkBlock{new_location});
+ } else {
+ ir.SetTerm(IR::Term::LinkBlockFast{new_location});
+ }
return false;
}
@@ -75,13 +76,9 @@ bool TranslatorVisitor::thumb32_B_cond(Imm<1> S, Cond cond, Imm<6> hi, Imm<1> i1
// Note: i1 and i2 were not inverted from encoding and are opposite compared to the other B instructions.
const s32 imm32 = static_cast<s32>((concatenate(S, i2, i1, hi, lo).SignExtend<u32>() << 1) + 4);
- const auto then_location = ir.current_location
- .AdvancePC(imm32)
- .AdvanceIT();
- const auto else_location = ir.current_location
- .AdvancePC(4)
- .AdvanceIT();
- ir.SetTerm(IR::Term::If{cond, IR::Term::LinkBlock{then_location}, IR::Term::LinkBlock{else_location}});
+ const auto then_ = IR::Term::LinkBlockFast{ir.current_location.AdvancePC(imm32).AdvanceIT()};
+ const auto else_ = IR::Term::LinkBlockFast{ir.current_location.AdvancePC(4).AdvanceIT()};
+ ir.SetTerm(IR::Term::If{cond, then_, else_});
return false;
}
diff --git a/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/a64_branch.cpp b/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/a64_branch.cpp
index 36b91f13e9..a07160394c 100644
--- a/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/a64_branch.cpp
+++ b/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/a64_branch.cpp
@@ -14,8 +14,8 @@ bool TranslatorVisitor::B_cond(Imm<19> imm19, Cond cond) {
const s64 offset = concatenate(imm19, Imm<2>{0}).SignExtend<s64>();
const u64 target = ir.PC() + offset;
- const auto cond_pass = IR::Term::LinkBlock{ir.current_location->SetPC(target)};
- const auto cond_fail = IR::Term::LinkBlock{ir.current_location->AdvancePC(4)};
+ const auto cond_pass = IR::Term::LinkBlockFast{ir.current_location->SetPC(target)};
+ const auto cond_fail = IR::Term::LinkBlockFast{ir.current_location->AdvancePC(4)};
ir.SetTerm(IR::Term::If{cond, cond_pass, cond_fail});
return false;
}
@@ -26,9 +26,9 @@ bool TranslatorVisitor::B_uncond(Imm<26> imm26) {
// Pattern to halt execution (B .)
if (target == ir.PC()) {
ir.SetTerm(IR::Term::LinkBlock{ir.current_location->SetPC(target)});
- return false;
+ } else {
+ ir.SetTerm(IR::Term::LinkBlockFast{ir.current_location->SetPC(target)});
}
- ir.SetTerm(IR::Term::LinkBlockFast{ir.current_location->SetPC(target)});
return false;
}
@@ -79,8 +79,8 @@ bool TranslatorVisitor::CBZ(bool sf, Imm<19> imm19, Reg Rt) {
ir.SetCheckBit(ir.IsZero(operand1));
const u64 target = ir.PC() + offset;
- const auto cond_pass = IR::Term::LinkBlock{ir.current_location->SetPC(target)};
- const auto cond_fail = IR::Term::LinkBlock{ir.current_location->AdvancePC(4)};
+ const auto cond_pass = IR::Term::LinkBlockFast{ir.current_location->SetPC(target)};
+ const auto cond_fail = IR::Term::LinkBlockFast{ir.current_location->AdvancePC(4)};
ir.SetTerm(IR::Term::CheckBit{cond_pass, cond_fail});
return false;
}
@@ -94,8 +94,8 @@ bool TranslatorVisitor::CBNZ(bool sf, Imm<19> imm19, Reg Rt) {
ir.SetCheckBit(ir.IsZero(operand1));
const u64 target = ir.PC() + offset;
- const auto cond_pass = IR::Term::LinkBlock{ir.current_location->AdvancePC(4)};
- const auto cond_fail = IR::Term::LinkBlock{ir.current_location->SetPC(target)};
+ const auto cond_pass = IR::Term::LinkBlockFast{ir.current_location->AdvancePC(4)};
+ const auto cond_fail = IR::Term::LinkBlockFast{ir.current_location->SetPC(target)};
ir.SetTerm(IR::Term::CheckBit{cond_pass, cond_fail});
return false;
}
@@ -110,8 +110,8 @@ bool TranslatorVisitor::TBZ(Imm<1> b5, Imm<5> b40, Imm<14> imm14, Reg Rt) {
ir.SetCheckBit(ir.TestBit(operand, ir.Imm8(bit_pos)));
const u64 target = ir.PC() + offset;
- const auto cond_1 = IR::Term::LinkBlock{ir.current_location->AdvancePC(4)};
- const auto cond_0 = IR::Term::LinkBlock{ir.current_location->SetPC(target)};
+ const auto cond_1 = IR::Term::LinkBlockFast{ir.current_location->AdvancePC(4)};
+ const auto cond_0 = IR::Term::LinkBlockFast{ir.current_location->SetPC(target)};
ir.SetTerm(IR::Term::CheckBit{cond_1, cond_0});
return false;
}
@@ -126,8 +126,8 @@ bool TranslatorVisitor::TBNZ(Imm<1> b5, Imm<5> b40, Imm<14> imm14, Reg Rt) {
ir.SetCheckBit(ir.TestBit(operand, ir.Imm8(bit_pos)));
const u64 target = ir.PC() + offset;
- const auto cond_1 = IR::Term::LinkBlock{ir.current_location->SetPC(target)};
- const auto cond_0 = IR::Term::LinkBlock{ir.current_location->AdvancePC(4)};
+ const auto cond_1 = IR::Term::LinkBlockFast{ir.current_location->SetPC(target)};
+ const auto cond_0 = IR::Term::LinkBlockFast{ir.current_location->AdvancePC(4)};
ir.SetTerm(IR::Term::CheckBit{cond_1, cond_0});
return false;
}