From 710bbe0b0d86e985d42c085680191050cb58162a Mon Sep 17 00:00:00 2001 From: lizzie Date: Sun, 8 Feb 2026 20:57:24 +0000 Subject: [PATCH] [dynarmic] reuse IR::Block memory instead of creating new block each time Signed-off-by: lizzie --- .../dynarmic/backend/x64/a32_interface.cpp | 23 +++++++++++-------- .../dynarmic/backend/x64/a64_interface.cpp | 20 ++++++++-------- .../frontend/A32/translate/a32_translate.cpp | 8 +++---- .../frontend/A32/translate/a32_translate.h | 2 +- .../frontend/A32/translate/translate_arm.cpp | 9 +------- .../A32/translate/translate_thumb.cpp | 10 ++------ .../frontend/A64/translate/a64_translate.cpp | 8 +------ .../frontend/A64/translate/a64_translate.h | 2 +- src/dynarmic/src/dynarmic/ir/basic_block.h | 12 ++++++++++ 9 files changed, 46 insertions(+), 48 deletions(-) diff --git a/src/dynarmic/src/dynarmic/backend/x64/a32_interface.cpp b/src/dynarmic/src/dynarmic/backend/x64/a32_interface.cpp index fbfdf24521..91a93779b6 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/a32_interface.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/a32_interface.cpp @@ -25,6 +25,7 @@ #include "dynarmic/backend/x64/devirtualize.h" #include "dynarmic/backend/x64/jitstate_info.h" #include "dynarmic/common/atomic.h" +#include "dynarmic/frontend/A32/a32_location_descriptor.h" #include "dynarmic/frontend/A32/translate/a32_translate.h" #include "dynarmic/interface/A32/a32.h" #include "dynarmic/ir/basic_block.h" @@ -63,12 +64,14 @@ static Optimization::PolyfillOptions GenPolyfillOptions(const BlockOfCode& code) } struct Jit::Impl { - Impl(Jit* jit, A32::UserConfig 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) {} + 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)) + , emitter(block_of_code, conf, jit) + , polyfill_options(GenPolyfillOptions(block_of_code)) + , jit_interface(jit) + {} ~Impl() = default; @@ -212,7 +215,8 @@ private: } block_of_code.EnsureMemoryCommitted(MINIMUM_REMAINING_CODESIZE); - IR::Block ir_block = A32::Translate(A32::LocationDescriptor{descriptor}, conf.callbacks, {conf.arch_version, conf.define_unpredictable_behaviour, conf.hook_hint_instructions}); + ir_block.Reset(descriptor); + A32::Translate(ir_block, A32::LocationDescriptor{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); } @@ -239,13 +243,12 @@ private: } } + IR::Block ir_block; + const A32::UserConfig conf; A32JitState jit_state; BlockOfCode block_of_code; A32EmitX64 emitter; Optimization::PolyfillOptions polyfill_options; - - 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 0fe738e212..a17037ee87 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/a64_interface.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/a64_interface.cpp @@ -12,6 +12,7 @@ #include #include "dynarmic/common/assert.h" +#include "dynarmic/common/fp/fpcr.h" #include "dynarmic/common/llvm_disassemble.h" #include #include @@ -61,10 +62,12 @@ static Optimization::PolyfillOptions GenPolyfillOptions(const BlockOfCode& code) struct Jit::Impl final { public: Impl(Jit* jit, UserConfig 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)) { + : ir_block{LocationDescriptor(0, FP::FPCR(0), false)} + , 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)) + { ASSERT(conf.page_table_address_space_bits >= 12 && conf.page_table_address_space_bits <= 64); } @@ -268,8 +271,8 @@ private: // JIT Compile const auto get_code = [this](u64 vaddr) { return conf.callbacks->MemoryReadCode(vaddr); }; - IR::Block ir_block = A64::Translate(A64::LocationDescriptor{current_location}, get_code, - {conf.define_unpredictable_behaviour, conf.wall_clock_cntpct}); + ir_block.Reset(current_location); + A64::Translate(ir_block, A64::LocationDescriptor{current_location}, get_code, {conf.define_unpredictable_behaviour, conf.wall_clock_cntpct}); Optimization::Optimize(ir_block, conf, polyfill_options); return emitter.Emit(ir_block).entrypoint; } @@ -296,14 +299,13 @@ private: } } - bool is_executing = false; - + IR::Block ir_block; const UserConfig conf; A64JitState jit_state; BlockOfCode block_of_code; A64EmitX64 emitter; Optimization::PolyfillOptions polyfill_options; - + bool is_executing = false; bool invalidate_entire_cache = false; boost::icl::interval_set invalid_cache_ranges; std::mutex invalidation_mutex; diff --git a/src/dynarmic/src/dynarmic/frontend/A32/translate/a32_translate.cpp b/src/dynarmic/src/dynarmic/frontend/A32/translate/a32_translate.cpp index 2e69927ace..ea9046d27a 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/translate/a32_translate.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A32/translate/a32_translate.cpp @@ -10,11 +10,11 @@ namespace Dynarmic::A32 { -IR::Block TranslateArm(LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options); -IR::Block TranslateThumb(LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options); +void TranslateArm(IR::Block& block, LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options); +void TranslateThumb(IR::Block& block, LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options); -IR::Block Translate(LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options) { - return (descriptor.TFlag() ? TranslateThumb : TranslateArm)(descriptor, tcb, options); +void Translate(IR::Block& block, LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options) { + return (descriptor.TFlag() ? TranslateThumb : TranslateArm)(block, descriptor, tcb, options); } bool TranslateSingleArmInstruction(IR::Block& block, LocationDescriptor descriptor, u32 instruction); diff --git a/src/dynarmic/src/dynarmic/frontend/A32/translate/a32_translate.h b/src/dynarmic/src/dynarmic/frontend/A32/translate/a32_translate.h index df0b86e9ff..78cf81a7b6 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/translate/a32_translate.h +++ b/src/dynarmic/src/dynarmic/frontend/A32/translate/a32_translate.h @@ -41,7 +41,7 @@ struct TranslationOptions { * @param options Configures how certain instructions are translated. * @return A translated basic block in the intermediate representation. */ -IR::Block Translate(LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options); +void Translate(IR::Block& block, LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options); /** * This function translates a single provided instruction into our intermediate representation. diff --git a/src/dynarmic/src/dynarmic/frontend/A32/translate/translate_arm.cpp b/src/dynarmic/src/dynarmic/frontend/A32/translate/translate_arm.cpp index 614c1d2792..7c440eae32 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/translate/translate_arm.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A32/translate/translate_arm.cpp @@ -22,12 +22,9 @@ namespace Dynarmic::A32 { -IR::Block TranslateArm(LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options) { +void TranslateArm(IR::Block& block, LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options) { const bool single_step = descriptor.SingleStepping(); - - IR::Block block{descriptor}; TranslatorVisitor visitor{block, descriptor, options}; - bool should_continue = true; do { const u32 arm_pc = visitor.ir.current_location.PC(); @@ -76,12 +73,8 @@ IR::Block TranslateArm(LocationDescriptor descriptor, TranslateCallbacks* tcb, c } } } - ASSERT(block.HasTerminal() && "Terminal has not been set"); - block.SetEndLocation(visitor.ir.current_location); - - return block; } bool TranslateSingleArmInstruction(IR::Block& block, LocationDescriptor descriptor, u32 arm_instruction) { diff --git a/src/dynarmic/src/dynarmic/frontend/A32/translate/translate_thumb.cpp b/src/dynarmic/src/dynarmic/frontend/A32/translate/translate_thumb.cpp index 23935ba601..53539362c7 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/translate/translate_thumb.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A32/translate/translate_thumb.cpp @@ -24,6 +24,7 @@ #include "dynarmic/frontend/A32/translate/translate_callbacks.h" #include "dynarmic/frontend/imm.h" #include "dynarmic/interface/A32/config.h" +#include "dynarmic/ir/basic_block.h" namespace Dynarmic::A32 { namespace { @@ -103,12 +104,9 @@ inline bool MaybeVFPOrASIMDInstruction(u32 thumb_instruction) noexcept { } // namespace -IR::Block TranslateThumb(LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options) { +void TranslateThumb(IR::Block& block, LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options) { const bool single_step = descriptor.SingleStepping(); - - IR::Block block{descriptor}; TranslatorVisitor visitor{block, descriptor, options}; - bool should_continue = true; do { const u32 arm_pc = visitor.ir.current_location.PC(); @@ -175,12 +173,8 @@ IR::Block TranslateThumb(LocationDescriptor descriptor, TranslateCallbacks* tcb, } } } - ASSERT(block.HasTerminal() && "Terminal has not been set"); - block.SetEndLocation(visitor.ir.current_location); - - return block; } bool TranslateSingleThumbInstruction(IR::Block& block, LocationDescriptor descriptor, u32 thumb_instruction) { diff --git a/src/dynarmic/src/dynarmic/frontend/A64/translate/a64_translate.cpp b/src/dynarmic/src/dynarmic/frontend/A64/translate/a64_translate.cpp index 8a907acad6..dec7a92f28 100644 --- a/src/dynarmic/src/dynarmic/frontend/A64/translate/a64_translate.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A64/translate/a64_translate.cpp @@ -16,10 +16,8 @@ namespace Dynarmic::A64 { -IR::Block Translate(LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code, TranslationOptions options) { +void Translate(IR::Block& block, LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code, TranslationOptions options) { const bool single_step = descriptor.SingleStepping(); - - IR::Block block{descriptor}; TranslatorVisitor visitor{block, descriptor, std::move(options)}; bool should_continue = true; @@ -43,12 +41,8 @@ IR::Block Translate(LocationDescriptor descriptor, MemoryReadCodeFuncType memory if (single_step && should_continue) { visitor.ir.SetTerm(IR::Term::LinkBlock{*visitor.ir.current_location}); } - ASSERT(block.HasTerminal() && "Terminal has not been set"); - block.SetEndLocation(*visitor.ir.current_location); - - return block; } bool TranslateSingleInstruction(IR::Block& block, LocationDescriptor descriptor, u32 instruction) { diff --git a/src/dynarmic/src/dynarmic/frontend/A64/translate/a64_translate.h b/src/dynarmic/src/dynarmic/frontend/A64/translate/a64_translate.h index be55fb3970..6dd1024c1f 100644 --- a/src/dynarmic/src/dynarmic/frontend/A64/translate/a64_translate.h +++ b/src/dynarmic/src/dynarmic/frontend/A64/translate/a64_translate.h @@ -47,7 +47,7 @@ struct TranslationOptions { * @param options Configures how certain instructions are translated. * @return A translated basic block in the intermediate representation. */ -IR::Block Translate(LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code, TranslationOptions options); +void Translate(IR::Block& block, LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code, TranslationOptions options); /** * This function translates a single provided instruction into our intermediate representation. diff --git a/src/dynarmic/src/dynarmic/ir/basic_block.h b/src/dynarmic/src/dynarmic/ir/basic_block.h index 4fb28592e7..24115be1ec 100644 --- a/src/dynarmic/src/dynarmic/ir/basic_block.h +++ b/src/dynarmic/src/dynarmic/ir/basic_block.h @@ -140,6 +140,18 @@ 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.