diff --git a/src/dynarmic/CMakeLists.txt b/src/dynarmic/CMakeLists.txt index 5b084d9a..fc4690f2 100644 --- a/src/dynarmic/CMakeLists.txt +++ b/src/dynarmic/CMakeLists.txt @@ -86,6 +86,7 @@ add_library(dynarmic ir/opt/dead_code_elimination_pass.cpp ir/opt/identity_removal_pass.cpp ir/opt/ir_matcher.h + ir/opt/naming_pass.cpp ir/opt/passes.h ir/opt/polyfill_pass.cpp ir/opt/verification_pass.cpp diff --git a/src/dynarmic/backend/arm64/a32_address_space.cpp b/src/dynarmic/backend/arm64/a32_address_space.cpp index 8723326b..8cf57aaa 100644 --- a/src/dynarmic/backend/arm64/a32_address_space.cpp +++ b/src/dynarmic/backend/arm64/a32_address_space.cpp @@ -165,6 +165,7 @@ IR::Block A32AddressSpace::GenerateIR(IR::LocationDescriptor descriptor) const { IR::Block ir_block = A32::Translate(A32::LocationDescriptor{descriptor}, conf.callbacks, {conf.arch_version, conf.define_unpredictable_behaviour, conf.hook_hint_instructions}); Optimization::PolyfillPass(ir_block, {}); + Optimization::NamingPass(ir_block); if (conf.HasOptimization(OptimizationFlag::GetSetElimination)) { Optimization::A32GetSetElimination(ir_block, {.convert_nzc_to_nz = true}); Optimization::DeadCodeElimination(ir_block); diff --git a/src/dynarmic/backend/arm64/a64_address_space.cpp b/src/dynarmic/backend/arm64/a64_address_space.cpp index 28016384..69146a15 100644 --- a/src/dynarmic/backend/arm64/a64_address_space.cpp +++ b/src/dynarmic/backend/arm64/a64_address_space.cpp @@ -333,6 +333,7 @@ IR::Block A64AddressSpace::GenerateIR(IR::LocationDescriptor descriptor) const { {conf.define_unpredictable_behaviour, conf.wall_clock_cntpct}); Optimization::A64CallbackConfigPass(ir_block, conf); + Optimization::NamingPass(ir_block); if (conf.HasOptimization(OptimizationFlag::GetSetElimination) && !conf.check_halt_on_memory_access) { Optimization::A64GetSetElimination(ir_block); Optimization::DeadCodeElimination(ir_block); diff --git a/src/dynarmic/backend/arm64/emit_arm64_memory.cpp b/src/dynarmic/backend/arm64/emit_arm64_memory.cpp index 544676f2..8d2e09de 100644 --- a/src/dynarmic/backend/arm64/emit_arm64_memory.cpp +++ b/src/dynarmic/backend/arm64/emit_arm64_memory.cpp @@ -491,8 +491,7 @@ std::optional ShouldFastmem(EmitContext& ctx, IR::Inst* inst return std::nullopt; } - const auto inst_offset = std::distance(ctx.block.begin(), IR::Block::iterator(inst)); - const auto marker = std::make_tuple(ctx.block.Location(), inst_offset); + const auto marker = std::make_tuple(ctx.block.Location(), inst->GetName()); if (ctx.fastmem.ShouldFastmem(marker)) { return marker; } diff --git a/src/dynarmic/backend/arm64/fastmem.h b/src/dynarmic/backend/arm64/fastmem.h index 3b98b056..74abb45a 100644 --- a/src/dynarmic/backend/arm64/fastmem.h +++ b/src/dynarmic/backend/arm64/fastmem.h @@ -17,7 +17,7 @@ namespace Dynarmic::Backend::Arm64 { -using DoNotFastmemMarker = std::tuple; +using DoNotFastmemMarker = std::tuple; struct DoNotFastmemMarkerHash { size_t operator()(const DoNotFastmemMarker& value) const { diff --git a/src/dynarmic/backend/arm64/reg_alloc.h b/src/dynarmic/backend/arm64/reg_alloc.h index a280d204..2a1ddf95 100644 --- a/src/dynarmic/backend/arm64/reg_alloc.h +++ b/src/dynarmic/backend/arm64/reg_alloc.h @@ -336,7 +336,7 @@ private: mutable std::mt19937 rand_gen; - tsl::robin_set defined_insts; + tsl::robin_set defined_insts; }; template diff --git a/src/dynarmic/backend/x64/a32_emit_x64.h b/src/dynarmic/backend/x64/a32_emit_x64.h index b037071b..4866c9ec 100644 --- a/src/dynarmic/backend/x64/a32_emit_x64.h +++ b/src/dynarmic/backend/x64/a32_emit_x64.h @@ -97,7 +97,7 @@ protected: std::string LocationDescriptorToFriendlyName(const IR::LocationDescriptor&) const override; // Fastmem information - using DoNotFastmemMarker = std::tuple; + using DoNotFastmemMarker = std::tuple; struct FastmemPatchInfo { u64 resume_rip; u64 callback; diff --git a/src/dynarmic/backend/x64/a32_interface.cpp b/src/dynarmic/backend/x64/a32_interface.cpp index e428672f..37b17a51 100644 --- a/src/dynarmic/backend/x64/a32_interface.cpp +++ b/src/dynarmic/backend/x64/a32_interface.cpp @@ -174,6 +174,7 @@ private: IR::Block ir_block = A32::Translate(A32::LocationDescriptor{descriptor}, conf.callbacks, {conf.arch_version, conf.define_unpredictable_behaviour, conf.hook_hint_instructions}); Optimization::PolyfillPass(ir_block, polyfill_options); + Optimization::NamingPass(ir_block); if (conf.HasOptimization(OptimizationFlag::GetSetElimination) && !conf.check_halt_on_memory_access) { Optimization::A32GetSetElimination(ir_block, {.convert_nz_to_nzc = true}); Optimization::DeadCodeElimination(ir_block); @@ -197,7 +198,9 @@ Jit::~Jit() = default; HaltReason Jit::Run() { ASSERT(!is_executing); is_executing = true; - SCOPE_EXIT { this->is_executing = false; }; + SCOPE_EXIT { + this->is_executing = false; + }; const HaltReason hr = impl->Execute(); @@ -209,7 +212,9 @@ HaltReason Jit::Run() { HaltReason Jit::Step() { ASSERT(!is_executing); is_executing = true; - SCOPE_EXIT { this->is_executing = false; }; + SCOPE_EXIT { + this->is_executing = false; + }; const HaltReason hr = impl->Step(); diff --git a/src/dynarmic/backend/x64/a64_emit_x64.h b/src/dynarmic/backend/x64/a64_emit_x64.h index b5e1a746..bd0e6e01 100644 --- a/src/dynarmic/backend/x64/a64_emit_x64.h +++ b/src/dynarmic/backend/x64/a64_emit_x64.h @@ -95,7 +95,7 @@ protected: std::string LocationDescriptorToFriendlyName(const IR::LocationDescriptor&) const override; // Fastmem information - using DoNotFastmemMarker = std::tuple; + using DoNotFastmemMarker = std::tuple; struct FastmemPatchInfo { u64 resume_rip; u64 callback; diff --git a/src/dynarmic/backend/x64/a64_interface.cpp b/src/dynarmic/backend/x64/a64_interface.cpp index f7f53c99..b2bfa6c8 100644 --- a/src/dynarmic/backend/x64/a64_interface.cpp +++ b/src/dynarmic/backend/x64/a64_interface.cpp @@ -72,7 +72,9 @@ public: PerformRequestedCacheInvalidation(); is_executing = true; - SCOPE_EXIT { this->is_executing = false; }; + SCOPE_EXIT { + this->is_executing = false; + }; // TODO: Check code alignment @@ -99,7 +101,9 @@ public: PerformRequestedCacheInvalidation(); is_executing = true; - SCOPE_EXIT { this->is_executing = false; }; + SCOPE_EXIT { + this->is_executing = false; + }; const HaltReason hr = block_of_code.StepCode(&jit_state, GetCurrentSingleStep()); @@ -273,6 +277,7 @@ private: {conf.define_unpredictable_behaviour, conf.wall_clock_cntpct}); Optimization::PolyfillPass(ir_block, polyfill_options); Optimization::A64CallbackConfigPass(ir_block, conf); + Optimization::NamingPass(ir_block); if (conf.HasOptimization(OptimizationFlag::GetSetElimination) && !conf.check_halt_on_memory_access) { Optimization::A64GetSetElimination(ir_block); Optimization::DeadCodeElimination(ir_block); diff --git a/src/dynarmic/backend/x64/emit_x64.cpp b/src/dynarmic/backend/x64/emit_x64.cpp index 722d793d..2d7250ca 100644 --- a/src/dynarmic/backend/x64/emit_x64.cpp +++ b/src/dynarmic/backend/x64/emit_x64.cpp @@ -35,10 +35,6 @@ EmitContext::EmitContext(RegAlloc& reg_alloc, IR::Block& block) EmitContext::~EmitContext() = default; -size_t EmitContext::GetInstOffset(IR::Inst* inst) const { - return static_cast(std::distance(block.begin(), IR::Block::iterator(inst))); -} - void EmitContext::EraseInstruction(IR::Inst* inst) { block.Instructions().erase(inst); inst->ClearArgs(); diff --git a/src/dynarmic/backend/x64/emit_x64.h b/src/dynarmic/backend/x64/emit_x64.h index c1921a9a..228398d8 100644 --- a/src/dynarmic/backend/x64/emit_x64.h +++ b/src/dynarmic/backend/x64/emit_x64.h @@ -53,7 +53,6 @@ struct EmitContext { EmitContext(RegAlloc& reg_alloc, IR::Block& block); virtual ~EmitContext(); - size_t GetInstOffset(IR::Inst* inst) const; void EraseInstruction(IR::Inst* inst); virtual FP::FPCR FPCR(bool fpcr_controlled = true) const = 0; diff --git a/src/dynarmic/backend/x64/emit_x64_memory.cpp.inc b/src/dynarmic/backend/x64/emit_x64_memory.cpp.inc index 4c807ed6..61116dbc 100644 --- a/src/dynarmic/backend/x64/emit_x64_memory.cpp.inc +++ b/src/dynarmic/backend/x64/emit_x64_memory.cpp.inc @@ -19,7 +19,7 @@ std::optional AxxEmitX64::ShouldFastmem(AxxEmitC return std::nullopt; } - const auto marker = std::make_tuple(ctx.Location(), ctx.GetInstOffset(inst)); + const auto marker = std::make_tuple(ctx.Location(), inst->GetName()); if (do_not_fastmem.count(marker) > 0) { return std::nullopt; } diff --git a/src/dynarmic/ir/basic_block.cpp b/src/dynarmic/ir/basic_block.cpp index a466c2f6..cc7eb48e 100644 --- a/src/dynarmic/ir/basic_block.cpp +++ b/src/dynarmic/ir/basic_block.cpp @@ -168,17 +168,14 @@ std::string DumpBlock(const IR::Block& block) { } ret += '\n'; - std::map inst_to_index; - size_t index = 0; - - const auto arg_to_string = [&inst_to_index](const IR::Value& arg) -> std::string { + const auto arg_to_string = [](const IR::Value& arg) -> std::string { if (arg.IsEmpty()) { return ""; } else if (!arg.IsImmediate()) { - if (const auto iter = inst_to_index.find(arg.GetInst()); iter != inst_to_index.end()) { - return fmt::format("%{}", iter->second); + if (const unsigned name = arg.GetInst()->GetName()) { + return fmt::format("%{}", name); } - return fmt::format("%", reinterpret_cast(arg.GetInst())); + return fmt::format("%", reinterpret_cast(arg.GetInst())); } switch (arg.GetType()) { case Type::U1: @@ -209,7 +206,11 @@ std::string DumpBlock(const IR::Block& block) { ret += fmt::format("[{:016x}] ", reinterpret_cast(&inst)); if (GetTypeOf(op) != Type::Void) { - ret += fmt::format("%{:<5} = ", index); + if (inst.GetName()) { + ret += fmt::format("%{:<5} = ", inst.GetName()); + } else { + ret += "noname = "; + } } else { ret += " "; // '%00000 = ' -> 1 + 5 + 3 = 9 spaces } @@ -233,7 +234,6 @@ std::string DumpBlock(const IR::Block& block) { ret += fmt::format(" (uses: {})", inst.UseCount()); ret += '\n'; - inst_to_index[&inst] = index++; } ret += "terminal = " + TerminalToString(block.GetTerminal()) + '\n'; diff --git a/src/dynarmic/ir/microinstruction.h b/src/dynarmic/ir/microinstruction.h index 7c2d9dc7..26b6b899 100644 --- a/src/dynarmic/ir/microinstruction.h +++ b/src/dynarmic/ir/microinstruction.h @@ -141,12 +141,18 @@ public: void ReplaceUsesWith(Value replacement); + // IR name (i.e. instruction number in block). This is set in the naming pass. Treat 0 as an invalid name. + // This is used for debugging and fastmem instruction identification. + void SetName(unsigned value) { name = value; } + unsigned GetName() const { return name; } + private: void Use(const Value& value); void UndoUse(const Value& value); Opcode op; - size_t use_count = 0; + unsigned use_count = 0; + unsigned name = 0; std::array args; // Linked list of pseudooperations associated with this instruction. diff --git a/src/dynarmic/ir/opt/naming_pass.cpp b/src/dynarmic/ir/opt/naming_pass.cpp new file mode 100644 index 00000000..a766bdc8 --- /dev/null +++ b/src/dynarmic/ir/opt/naming_pass.cpp @@ -0,0 +1,18 @@ +/* This file is part of the dynarmic project. + * Copyright (c) 2023 MerryMage + * SPDX-License-Identifier: 0BSD + */ + +#include "dynarmic/ir/basic_block.h" +#include "dynarmic/ir/microinstruction.h" + +namespace Dynarmic::Optimization { + +void NamingPass(IR::Block& block) { + unsigned name = 1; + for (auto& inst : block) { + inst.SetName(name++); + } +} + +} // namespace Dynarmic::Optimization diff --git a/src/dynarmic/ir/opt/passes.h b/src/dynarmic/ir/opt/passes.h index 9a77accb..703145b5 100644 --- a/src/dynarmic/ir/opt/passes.h +++ b/src/dynarmic/ir/opt/passes.h @@ -42,5 +42,6 @@ void ConstantPropagation(IR::Block& block); void DeadCodeElimination(IR::Block& block); void IdentityRemovalPass(IR::Block& block); void VerificationPass(const IR::Block& block); +void NamingPass(IR::Block& block); } // namespace Dynarmic::Optimization diff --git a/tests/A32/fuzz_thumb.cpp b/tests/A32/fuzz_thumb.cpp index 3733dbb3..f13c5ee0 100644 --- a/tests/A32/fuzz_thumb.cpp +++ b/tests/A32/fuzz_thumb.cpp @@ -176,6 +176,7 @@ static void RunInstance(size_t run_number, ThumbTestEnv& test_env, A32Unicorn