From 72973fe5825b0927ab854445e0aa07d58fc75941 Mon Sep 17 00:00:00 2001 From: lizzie Date: Fri, 13 Feb 2026 11:51:34 +0100 Subject: [PATCH] [dynarmic] fix NSBU regressions (#3533) Signed-off-by: lizzie Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3533 Reviewed-by: Maufeat Reviewed-by: MaranBr Co-authored-by: lizzie Co-committed-by: lizzie --- .../dynarmic/backend/x64/a32_interface.cpp | 19 +++++----- .../dynarmic/backend/x64/a64_interface.cpp | 15 ++++---- src/dynarmic/src/dynarmic/ir/basic_block.cpp | 36 ++++++++++++------- src/dynarmic/src/dynarmic/ir/basic_block.h | 17 ++------- 4 files changed, 45 insertions(+), 42 deletions(-) diff --git a/src/dynarmic/src/dynarmic/backend/x64/a32_interface.cpp b/src/dynarmic/src/dynarmic/backend/x64/a32_interface.cpp index d56e3729ee..e540839fd5 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/a32_interface.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/a32_interface.cpp @@ -65,11 +65,10 @@ static Optimization::PolyfillOptions GenPolyfillOptions(const BlockOfCode& code) struct Jit::Impl { Impl(Jit* jit, A32::UserConfig conf) noexcept - : ir_block{LocationDescriptor(0, PSR(0), FPSCR(0), false)} - , conf(std::move(conf)) - , block_of_code(GenRunCodeCallbacks(conf.callbacks, &GetCurrentBlockThunk, this, conf), JitStateInfo{jit_state}, conf.code_cache_size, GenRCP(conf)) + : block_of_code(GenRunCodeCallbacks(conf.callbacks, &GetCurrentBlockThunk, this, conf), JitStateInfo{jit_state}, conf.code_cache_size, GenRCP(conf)) , emitter(block_of_code, conf, jit) , polyfill_options(GenPolyfillOptions(block_of_code)) + , conf(std::move(conf)) , jit_interface(jit) {} @@ -204,8 +203,7 @@ private: } A32EmitX64::BlockDescriptor GetBasicBlock(IR::LocationDescriptor descriptor) { - auto block = emitter.GetBasicBlock(descriptor); - if (block) + if (auto block = emitter.GetBasicBlock(descriptor)) return *block; constexpr size_t MINIMUM_REMAINING_CODESIZE = 1 * 1024 * 1024; @@ -215,8 +213,10 @@ private: } block_of_code.EnsureMemoryCommitted(MINIMUM_REMAINING_CODESIZE); - ir_block.Reset(descriptor); - A32::Translate(ir_block, A32::LocationDescriptor{descriptor}, conf.callbacks, {conf.arch_version, conf.define_unpredictable_behaviour, conf.hook_hint_instructions}); + // LocationDescriptor ctor() does important ops (like tflags) do not skip + auto const arch_descriptor = A32::LocationDescriptor{descriptor}; + ir_block.Reset(arch_descriptor); + A32::Translate(ir_block, arch_descriptor, conf.callbacks, {conf.arch_version, conf.define_unpredictable_behaviour, conf.hook_hint_instructions}); Optimization::Optimize(ir_block, conf, polyfill_options); return emitter.Emit(ir_block); } @@ -243,12 +243,13 @@ private: } } - IR::Block ir_block; - const A32::UserConfig conf; + IR::Block ir_block = {LocationDescriptor(0, PSR(0), FPSCR(0), false)}; A32JitState jit_state; BlockOfCode block_of_code; A32EmitX64 emitter; Optimization::PolyfillOptions polyfill_options; + // Keep it here, you don't wanna mess with the fuckery that's initializer lists + const A32::UserConfig conf; Jit* jit_interface; // Requests made during execution to invalidate the cache are queued up here. diff --git a/src/dynarmic/src/dynarmic/backend/x64/a64_interface.cpp b/src/dynarmic/src/dynarmic/backend/x64/a64_interface.cpp index d0dc736b73..44c63bdfc5 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/a64_interface.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/a64_interface.cpp @@ -62,8 +62,7 @@ static Optimization::PolyfillOptions GenPolyfillOptions(const BlockOfCode& code) struct Jit::Impl final { public: Impl(Jit* jit, UserConfig conf) - : ir_block{LocationDescriptor(0, FP::FPCR(0), false)} - , conf(conf) + : conf(conf) , block_of_code(GenRunCodeCallbacks(conf.callbacks, &GetCurrentBlockThunk, this, conf), JitStateInfo{jit_state}, conf.code_cache_size, GenRCP(conf)) , emitter(block_of_code, conf, jit) , polyfill_options(GenPolyfillOptions(block_of_code)) @@ -257,8 +256,8 @@ private: return GetBlock(A64::LocationDescriptor{GetCurrentLocation()}.SetSingleStepping(true)); } - CodePtr GetBlock(IR::LocationDescriptor current_location) { - if (auto block = emitter.GetBasicBlock(current_location)) + CodePtr GetBlock(IR::LocationDescriptor descriptor) { + if (auto block = emitter.GetBasicBlock(descriptor)) return block->entrypoint; constexpr size_t MINIMUM_REMAINING_CODESIZE = 1 * 1024 * 1024; @@ -271,8 +270,10 @@ private: // JIT Compile const auto get_code = [this](u64 vaddr) { return conf.callbacks->MemoryReadCode(vaddr); }; - ir_block.Reset(current_location); - A64::Translate(ir_block, A64::LocationDescriptor{current_location}, get_code, {conf.define_unpredictable_behaviour, conf.wall_clock_cntpct}); + // LocationDescriptor ctor() does important ops (like tflags) do not skip + auto const arch_descriptor = A64::LocationDescriptor{descriptor}; + ir_block.Reset(arch_descriptor); + A64::Translate(ir_block, arch_descriptor, get_code, {conf.define_unpredictable_behaviour, conf.wall_clock_cntpct}); Optimization::Optimize(ir_block, conf, polyfill_options); return emitter.Emit(ir_block).entrypoint; } @@ -299,7 +300,7 @@ private: } } - IR::Block ir_block; + IR::Block ir_block = {LocationDescriptor(0, FP::FPCR(0), false)}; const UserConfig conf; A64JitState jit_state; BlockOfCode block_of_code; diff --git a/src/dynarmic/src/dynarmic/ir/basic_block.cpp b/src/dynarmic/src/dynarmic/ir/basic_block.cpp index 8543bfe8d7..d210bafd35 100644 --- a/src/dynarmic/src/dynarmic/ir/basic_block.cpp +++ b/src/dynarmic/src/dynarmic/ir/basic_block.cpp @@ -22,13 +22,10 @@ namespace Dynarmic::IR { -Block::Block(const LocationDescriptor& location) - : location{location}, - end_location{location}, - cond{Cond::AL} -{ - -} +Block::Block(LocationDescriptor location) noexcept + : location{location} + , end_location{location} +{} /// Prepends a new instruction to this basic block before the insertion point, /// handling any allocations necessary to do so. @@ -60,6 +57,21 @@ Block::iterator Block::PrependNewInst(iterator insertion_point, Opcode opcode, s return instructions.insert_before(insertion_point, inst); } +void Block::Reset(LocationDescriptor location_) noexcept { + mcl::intrusive_list tmp = {}; + instructions.swap(tmp); + inlined_inst.clear(); + pooled_inst.clear(); + cond_failed.reset(); + location = location_; + end_location = location_; + cond = Cond::AL; + terminal = Term::Invalid{}; + cond_failed_cycle_count = 0; + cycle_count = 0; + ASSERT(instructions.size() == 0); +} + static std::string TerminalToString(const Terminal& terminal_variant) noexcept { struct : boost::static_visitor { std::string operator()(const Term::Invalid&) const { @@ -123,11 +135,11 @@ std::string DumpBlock(const IR::Block& block) noexcept { case Type::A32ExtReg: return A32::ExtRegToString(arg.GetA32ExtRegRef()); case Type::A64Reg: return A64::RegToString(arg.GetA64RegRef()); case Type::A64Vec: return A64::VecToString(arg.GetA64VecRef()); - case Type::CoprocInfo: return fmt::format("#"); - case Type::NZCVFlags: return fmt::format("#"); - case Type::Cond: return fmt::format("#", A32::CondToString(arg.GetCond())); - case Type::Table: return fmt::format("#"); - case Type::AccType: return fmt::format("#", u32(arg.GetAccType())); + case Type::CoprocInfo: return fmt::format("$coproc{}", arg.GetCoprocInfo()[0]); + case Type::NZCVFlags: return fmt::format("$nzcv"); + case Type::Cond: return fmt::format("$cond={}", A32::CondToString(arg.GetCond())); + case Type::Table: return fmt::format("$table"); + case Type::AccType: return fmt::format("$acc-type={}", u32(arg.GetAccType())); default: return fmt::format("", arg.GetType()); } }; diff --git a/src/dynarmic/src/dynarmic/ir/basic_block.h b/src/dynarmic/src/dynarmic/ir/basic_block.h index 24115be1ec..4044005bd0 100644 --- a/src/dynarmic/src/dynarmic/ir/basic_block.h +++ b/src/dynarmic/src/dynarmic/ir/basic_block.h @@ -43,7 +43,7 @@ public: using reverse_iterator = instruction_list_type::reverse_iterator; using const_reverse_iterator = instruction_list_type::const_reverse_iterator; - explicit Block(const LocationDescriptor& location); + Block(LocationDescriptor location) noexcept; ~Block() = default; Block(const Block&) = delete; Block& operator=(const Block&) = delete; @@ -58,6 +58,7 @@ public: return PrependNewInst(instructions.end(), opcode, args); } iterator PrependNewInst(iterator insertion_point, Opcode op, std::initializer_list args) noexcept; + void Reset(LocationDescriptor location_) noexcept; /// Gets a mutable reference to the instruction list for this basic block. inline instruction_list_type& Instructions() noexcept { @@ -140,18 +141,6 @@ public: return cycle_count; } - inline void Reset(LocationDescriptor location_) noexcept { - inlined_inst.clear(); - pooled_inst.clear(); - cond_failed.reset(); - location = location_; - terminal = Term::Invalid{}; - cond_failed_cycle_count = 0; - cycle_count = 0; - instruction_list_type tmp{}; - instructions.swap(tmp); - } - /// "Hot cache" for small blocks so we don't call global allocator boost::container::static_vector inlined_inst; /// List of instructions in this block. @@ -165,7 +154,7 @@ public: /// Description of the end location of this block LocationDescriptor end_location; /// Conditional to pass in order to execute this block - Cond cond; + Cond cond = Cond::AL; /// Terminal instruction of this block. Terminal terminal = Term::Invalid{}; /// Number of cycles this block takes to execute if the conditional fails.