From 541dfe68055ba970dbded60791e0a9083ab3ba59 Mon Sep 17 00:00:00 2001 From: lizzie Date: Tue, 10 Mar 2026 07:42:02 +0000 Subject: [PATCH] attempt use std::list instead --- .../backend/arm64/a32_address_space.cpp | 4 +- .../backend/arm64/a64_address_space.cpp | 4 +- .../dynarmic/backend/arm64/address_space.cpp | 6 +- .../src/dynarmic/backend/arm64/emit_arm64.cpp | 8 +- .../dynarmic/backend/arm64/emit_arm64_a32.cpp | 14 +-- .../dynarmic/backend/arm64/emit_arm64_a64.cpp | 8 +- .../backend/arm64/emit_arm64_memory.cpp | 2 +- .../src/dynarmic/backend/arm64/emit_context.h | 2 +- .../dynarmic/backend/riscv64/emit_riscv64.cpp | 2 +- .../backend/riscv64/emit_riscv64_a32.cpp | 4 +- .../src/dynarmic/backend/x64/a32_emit_x64.cpp | 21 ++-- .../src/dynarmic/backend/x64/a64_emit_x64.cpp | 12 +- .../A32/translate/conditional_state.cpp | 14 +-- .../frontend/A32/translate/translate_arm.cpp | 10 +- .../A32/translate/translate_thumb.cpp | 10 +- .../frontend/A64/translate/a64_translate.cpp | 9 +- .../frontend/A64/translate/impl/system.cpp | 2 +- src/dynarmic/src/dynarmic/ir/basic_block.cpp | 47 +++----- src/dynarmic/src/dynarmic/ir/basic_block.h | 103 ++---------------- src/dynarmic/src/dynarmic/ir/ir_emitter.h | 19 ++-- .../src/dynarmic/ir/microinstruction.h | 5 +- src/dynarmic/src/dynarmic/ir/opt_passes.cpp | 31 +++--- src/dynarmic/tests/A32/fuzz_arm.cpp | 2 +- src/dynarmic/tests/A32/fuzz_thumb.cpp | 2 +- 24 files changed, 116 insertions(+), 225 deletions(-) diff --git a/src/dynarmic/src/dynarmic/backend/arm64/a32_address_space.cpp b/src/dynarmic/src/dynarmic/backend/arm64/a32_address_space.cpp index 274e553cd8..5b26d7f113 100644 --- a/src/dynarmic/src/dynarmic/backend/arm64/a32_address_space.cpp +++ b/src/dynarmic/src/dynarmic/backend/arm64/a32_address_space.cpp @@ -405,8 +405,8 @@ EmitConfig A32AddressSpace::GetEmitConfig() { } void A32AddressSpace::RegisterNewBasicBlock(const IR::Block& block, const EmittedBlockInfo&) { - const A32::LocationDescriptor descriptor{block.Location()}; - const A32::LocationDescriptor end_location{block.EndLocation()}; + const A32::LocationDescriptor descriptor{block.location}; + const A32::LocationDescriptor end_location{block.end_location}; const auto range = boost::icl::discrete_interval::closed(descriptor.PC(), end_location.PC() - 1); block_ranges.AddRange(range, descriptor); } diff --git a/src/dynarmic/src/dynarmic/backend/arm64/a64_address_space.cpp b/src/dynarmic/src/dynarmic/backend/arm64/a64_address_space.cpp index a5a8306a6d..627db89261 100644 --- a/src/dynarmic/src/dynarmic/backend/arm64/a64_address_space.cpp +++ b/src/dynarmic/src/dynarmic/backend/arm64/a64_address_space.cpp @@ -579,8 +579,8 @@ EmitConfig A64AddressSpace::GetEmitConfig() { } void A64AddressSpace::RegisterNewBasicBlock(const IR::Block& block, const EmittedBlockInfo&) { - const A64::LocationDescriptor descriptor{block.Location()}; - const A64::LocationDescriptor end_location{block.EndLocation()}; + const A64::LocationDescriptor descriptor{block.location}; + const A64::LocationDescriptor end_location{block.end_location}; const auto range = boost::icl::discrete_interval::closed(descriptor.PC(), end_location.PC() - 1); block_ranges.AddRange(range, descriptor); } diff --git a/src/dynarmic/src/dynarmic/backend/arm64/address_space.cpp b/src/dynarmic/src/dynarmic/backend/arm64/address_space.cpp index 6b59871b0a..30a2950768 100644 --- a/src/dynarmic/src/dynarmic/backend/arm64/address_space.cpp +++ b/src/dynarmic/src/dynarmic/backend/arm64/address_space.cpp @@ -115,12 +115,12 @@ EmittedBlockInfo AddressSpace::Emit(IR::Block block) { EmittedBlockInfo block_info = EmitArm64(code, std::move(block), GetEmitConfig(), fastmem_manager); - ASSERT(block_entries.insert({block.Location(), block_info.entry_point}).second); - ASSERT(reverse_block_entries.insert({block_info.entry_point, block.Location()}).second); + ASSERT(block_entries.insert({block.location, block_info.entry_point}).second); + ASSERT(reverse_block_entries.insert({block_info.entry_point, block.location}).second); ASSERT(block_infos.insert({block_info.entry_point, block_info}).second); Link(block_info); - RelinkForDescriptor(block.Location(), block_info.entry_point); + RelinkForDescriptor(block.location, block_info.entry_point); mem.invalidate(reinterpret_cast(block_info.entry_point), block_info.size); ProtectCodeMemory(); diff --git a/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64.cpp b/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64.cpp index 104d0a452c..3aaacb0cc8 100644 --- a/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64.cpp +++ b/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64.cpp @@ -205,14 +205,14 @@ EmittedBlockInfo EmitArm64(oaknut::CodeGenerator& code, IR::Block block, const E ebi.entry_point = code.xptr(); - if (ctx.block.GetCondition() == IR::Cond::AL) { + if (ctx.block.cond == IR::Cond::AL) { ASSERT(!ctx.block.HasConditionFailedLocation()); } else { ASSERT(ctx.block.HasConditionFailedLocation()); oaknut::Label pass; - pass = conf.emit_cond(code, ctx, ctx.block.GetCondition()); - EmitAddCycles(code, ctx, ctx.block.ConditionFailedCycleCount()); + pass = conf.emit_cond(code, ctx, ctx.block.cond); + EmitAddCycles(code, ctx, ctx.block.cond_failed_cycle_count); conf.emit_condition_failed_terminal(code, ctx); code.l(pass); @@ -254,7 +254,7 @@ EmittedBlockInfo EmitArm64(oaknut::CodeGenerator& code, IR::Block block, const E reg_alloc.AssertNoMoreUses(); - EmitAddCycles(code, ctx, block.CycleCount()); + EmitAddCycles(code, ctx, block.cycle_count); conf.emit_terminal(code, ctx); code.BRK(0); diff --git a/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_a32.cpp b/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_a32.cpp index a65efb3c59..3c312de59b 100644 --- a/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_a32.cpp +++ b/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_a32.cpp @@ -153,13 +153,13 @@ void EmitA32Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::Te } void EmitA32Terminal(oaknut::CodeGenerator& code, EmitContext& ctx) { - const A32::LocationDescriptor location{ctx.block.Location()}; - EmitA32Terminal(code, ctx, ctx.block.GetTerminal(), location.SetSingleStepping(false), location.SingleStepping()); + const A32::LocationDescriptor location{ctx.block.location}; + EmitA32Terminal(code, ctx, ctx.block.terminal, location.SetSingleStepping(false), location.SingleStepping()); } void EmitA32ConditionFailedTerminal(oaknut::CodeGenerator& code, EmitContext& ctx) { - const A32::LocationDescriptor location{ctx.block.Location()}; - EmitA32Terminal(code, ctx, IR::Term::LinkBlock{ctx.block.ConditionFailedLocation()}, location.SetSingleStepping(false), location.SingleStepping()); + const A32::LocationDescriptor location{ctx.block.location}; + EmitA32Terminal(code, ctx, IR::Term::LinkBlock{ctx.block.cond_failed}, location.SetSingleStepping(false), location.SingleStepping()); } void EmitA32CheckMemoryAbort(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst, oaknut::Label& end) { @@ -172,7 +172,7 @@ void EmitA32CheckMemoryAbort(oaknut::CodeGenerator& code, EmitContext& ctx, IR:: code.LDAR(Xscratch0, Xhalt); code.TST(Xscratch0, static_cast(HaltReason::MemoryAbort)); code.B(EQ, end); - EmitSetUpperLocationDescriptor(code, ctx, current_location, ctx.block.Location()); + EmitSetUpperLocationDescriptor(code, ctx, current_location, ctx.block.location); code.MOV(Wscratch0, current_location.PC()); code.STR(Wscratch0, Xstate, offsetof(A32JitState, regs) + sizeof(u32) * 15); EmitRelocation(code, ctx, LinkTarget::ReturnFromRunCode); @@ -550,7 +550,7 @@ template<> void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const u32 upper_without_t = (A32::LocationDescriptor{ctx.block.EndLocation()}.SetSingleStepping(false).UniqueHash() >> 32) & 0xFFFFFFFE; + const u32 upper_without_t = (A32::LocationDescriptor{ctx.block.end_location}.SetSingleStepping(false).UniqueHash() >> 32) & 0xFFFFFFFE; static_assert(offsetof(A32JitState, regs) + 16 * sizeof(u32) == offsetof(A32JitState, upper_location_descriptor)); @@ -581,7 +581,7 @@ void EmitIR(oaknut::CodeGenerator& for (auto& inst : ctx.block.instructions) if (inst.GetOpcode() == IR::Opcode::A32BXWritePC) return; - EmitSetUpperLocationDescriptor(code, ctx, ctx.block.EndLocation(), ctx.block.Location()); + EmitSetUpperLocationDescriptor(code, ctx, ctx.block.end_location, ctx.block.location); } template<> diff --git a/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_a64.cpp b/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_a64.cpp index da4364c1b5..03cd594660 100644 --- a/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_a64.cpp +++ b/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_a64.cpp @@ -136,13 +136,13 @@ void EmitA64Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::Te } void EmitA64Terminal(oaknut::CodeGenerator& code, EmitContext& ctx) { - const A64::LocationDescriptor location{ctx.block.Location()}; - EmitA64Terminal(code, ctx, ctx.block.GetTerminal(), location.SetSingleStepping(false), location.SingleStepping()); + const A64::LocationDescriptor location{ctx.block.location}; + EmitA64Terminal(code, ctx, ctx.block.terminal, location.SetSingleStepping(false), location.SingleStepping()); } void EmitA64ConditionFailedTerminal(oaknut::CodeGenerator& code, EmitContext& ctx) { - const A64::LocationDescriptor location{ctx.block.Location()}; - EmitA64Terminal(code, ctx, IR::Term::LinkBlock{ctx.block.ConditionFailedLocation()}, location.SetSingleStepping(false), location.SingleStepping()); + const A64::LocationDescriptor location{ctx.block.location}; + EmitA64Terminal(code, ctx, IR::Term::LinkBlock{ctx.block.cond_failed}, location.SetSingleStepping(false), location.SingleStepping()); } void EmitA64CheckMemoryAbort(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst, oaknut::Label& end) { diff --git a/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_memory.cpp b/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_memory.cpp index 67ab61f8a3..beaa6ec005 100644 --- a/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_memory.cpp +++ b/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_memory.cpp @@ -497,7 +497,7 @@ std::optional ShouldFastmem(EmitContext& ctx, IR::Inst* inst return std::nullopt; } - const auto marker = std::make_tuple(ctx.block.Location(), inst->GetName()); + const auto marker = std::make_tuple(ctx.block.location, inst->GetName()); if (ctx.fastmem.ShouldFastmem(marker)) { return marker; } diff --git a/src/dynarmic/src/dynarmic/backend/arm64/emit_context.h b/src/dynarmic/src/dynarmic/backend/arm64/emit_context.h index 6bfc6f3cae..c4f69b3cb1 100644 --- a/src/dynarmic/src/dynarmic/backend/arm64/emit_context.h +++ b/src/dynarmic/src/dynarmic/backend/arm64/emit_context.h @@ -43,7 +43,7 @@ struct EmitContext { std::vector> deferred_emits; FP::FPCR FPCR(bool fpcr_controlled = true) const { - const FP::FPCR fpcr = conf.descriptor_to_fpcr(block.Location()); + const FP::FPCR fpcr = conf.descriptor_to_fpcr(block.location); return fpcr_controlled ? fpcr : fpcr.ASIMDStandardValue(); } }; diff --git a/src/dynarmic/src/dynarmic/backend/riscv64/emit_riscv64.cpp b/src/dynarmic/src/dynarmic/backend/riscv64/emit_riscv64.cpp index 50cbaf9526..32a26de781 100644 --- a/src/dynarmic/src/dynarmic/backend/riscv64/emit_riscv64.cpp +++ b/src/dynarmic/src/dynarmic/backend/riscv64/emit_riscv64.cpp @@ -151,7 +151,7 @@ EmittedBlockInfo EmitRV64(biscuit::Assembler& as, IR::Block block, const EmitCon reg_alloc.AssertNoMoreUses(); if (emit_conf.enable_cycle_counting) { - const size_t cycles_to_add = block.CycleCount(); + const size_t cycles_to_add = block.cycle_count; as.LD(Xscratch0, offsetof(StackLayout, cycles_remaining), sp); if (mcl::bit::sign_extend<12>(-cycles_to_add) == -cycles_to_add) { as.ADDI(Xscratch0, Xscratch0, -cycles_to_add); diff --git a/src/dynarmic/src/dynarmic/backend/riscv64/emit_riscv64_a32.cpp b/src/dynarmic/src/dynarmic/backend/riscv64/emit_riscv64_a32.cpp index 572f197955..b2aad61cc5 100644 --- a/src/dynarmic/src/dynarmic/backend/riscv64/emit_riscv64_a32.cpp +++ b/src/dynarmic/src/dynarmic/backend/riscv64/emit_riscv64_a32.cpp @@ -199,8 +199,8 @@ void EmitA32Terminal(biscuit::Assembler& as, EmitContext& ctx, IR::Term::Termina } void EmitA32Terminal(biscuit::Assembler& as, EmitContext& ctx) { - const A32::LocationDescriptor location{ctx.block.Location()}; - EmitA32Terminal(as, ctx, ctx.block.GetTerminal(), location.SetSingleStepping(false), location.SingleStepping()); + const A32::LocationDescriptor location{ctx.block.location}; + EmitA32Terminal(as, ctx, ctx.block.terminal, location.SetSingleStepping(false), location.SingleStepping()); } template<> diff --git a/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.cpp b/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.cpp index f037919eb0..7b8cd0d5c9 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.cpp @@ -64,11 +64,11 @@ A32EmitContext::A32EmitContext(const A32::UserConfig& conf, RegAlloc& reg_alloc, : EmitContext(reg_alloc, block), conf(conf) {} A32::LocationDescriptor A32EmitContext::Location() const { - return A32::LocationDescriptor{block.Location()}; + return A32::LocationDescriptor{block.location}; } A32::LocationDescriptor A32EmitContext::EndLocation() const { - return A32::LocationDescriptor{block.EndLocation()}; + return A32::LocationDescriptor{block.end_location}; } bool A32EmitContext::IsSingleStep() const { @@ -148,9 +148,9 @@ A32EmitX64::BlockDescriptor A32EmitX64::Emit(IR::Block& block) { reg_alloc.AssertNoMoreUses(); if (conf.enable_cycle_counting) { - EmitAddCycles(block.CycleCount()); + EmitAddCycles(block.cycle_count); } - EmitTerminal(block.GetTerminal(), ctx.Location().SetSingleStepping(false), ctx.IsSingleStep()); + EmitTerminal(block.terminal, ctx.Location().SetSingleStepping(false), ctx.IsSingleStep()); code.int3(); for (auto& deferred_emit : ctx.deferred_emits) { @@ -160,8 +160,8 @@ A32EmitX64::BlockDescriptor A32EmitX64::Emit(IR::Block& block) { const size_t size = size_t(code.getCurr() - entrypoint); - const A32::LocationDescriptor descriptor{block.Location()}; - const A32::LocationDescriptor end_location{block.EndLocation()}; + const A32::LocationDescriptor descriptor{block.location}; + const A32::LocationDescriptor end_location{block.end_location}; const auto range = boost::icl::discrete_interval::closed(descriptor.PC(), end_location.PC() - 1); block_ranges.AddRange(range, descriptor); @@ -183,18 +183,17 @@ void A32EmitX64::InvalidateCacheRanges(const boost::icl::interval_set& rang } void A32EmitX64::EmitCondPrelude(const A32EmitContext& ctx) { - if (ctx.block.GetCondition() == IR::Cond::AL) { + if (ctx.block.cond == IR::Cond::AL) { ASSERT(!ctx.block.HasConditionFailedLocation()); return; } - ASSERT(ctx.block.HasConditionFailedLocation()); - Xbyak::Label pass = EmitCond(ctx.block.GetCondition()); + Xbyak::Label pass = EmitCond(ctx.block.cond); if (conf.enable_cycle_counting) { - EmitAddCycles(ctx.block.ConditionFailedCycleCount()); + EmitAddCycles(ctx.block.cond_failed_cycle_count); } - EmitTerminal(IR::Term::LinkBlock{ctx.block.ConditionFailedLocation()}, ctx.Location().SetSingleStepping(false), ctx.IsSingleStep()); + EmitTerminal(IR::Term::LinkBlock{ctx.block.cond_failed}, ctx.Location().SetSingleStepping(false), ctx.IsSingleStep()); code.L(pass); } diff --git a/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp b/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp index ff82d8b05c..7edb4aba51 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp @@ -42,7 +42,7 @@ A64EmitContext::A64EmitContext(const A64::UserConfig& conf, RegAlloc& reg_alloc, : EmitContext(reg_alloc, block), conf(conf) {} A64::LocationDescriptor A64EmitContext::Location() const { - return A64::LocationDescriptor{block.Location()}; + return A64::LocationDescriptor{block.location}; } bool A64EmitContext::IsSingleStep() const { @@ -90,7 +90,7 @@ A64EmitX64::BlockDescriptor A64EmitX64::Emit(IR::Block& block) noexcept { code.align(); const auto* const entrypoint = code.getCurr(); - DEBUG_ASSERT(block.GetCondition() == IR::Cond::AL); + DEBUG_ASSERT(block.cond == IR::Cond::AL); typedef void (EmitX64::*EmitHandlerFn)(EmitContext& context, IR::Inst* inst); constexpr EmitHandlerFn opcode_handlers[] = { #define OPCODE(name, type, ...) &EmitX64::Emit##name, @@ -142,9 +142,9 @@ finish_this_inst: reg_alloc.AssertNoMoreUses(); if (conf.enable_cycle_counting) { - EmitAddCycles(block.CycleCount()); + EmitAddCycles(block.cycle_count); } - EmitTerminal(block.GetTerminal(), ctx.Location().SetSingleStepping(false), ctx.IsSingleStep()); + EmitTerminal(block.terminal, ctx.Location().SetSingleStepping(false), ctx.IsSingleStep()); code.int3(); for (auto& deferred_emit : ctx.deferred_emits) { @@ -154,8 +154,8 @@ finish_this_inst: const size_t size = size_t(code.getCurr() - entrypoint); - const A64::LocationDescriptor descriptor{block.Location()}; - const A64::LocationDescriptor end_location{block.EndLocation()}; + const A64::LocationDescriptor descriptor{block.location}; + const A64::LocationDescriptor end_location{block.end_location}; const auto range = boost::icl::discrete_interval::closed(descriptor.PC(), end_location.PC() - 1); block_ranges.AddRange(range, descriptor); diff --git a/src/dynarmic/src/dynarmic/frontend/A32/translate/conditional_state.cpp b/src/dynarmic/src/dynarmic/frontend/A32/translate/conditional_state.cpp index 8c55588a28..403c2a8a23 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/translate/conditional_state.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A32/translate/conditional_state.cpp @@ -43,12 +43,12 @@ bool IsConditionPassed(TranslatorVisitor& v, IR::Cond cond) { } if (v.cond_state == ConditionalState::Translating) { - if (v.ir.block.ConditionFailedLocation() != v.ir.current_location || cond == IR::Cond::AL) { + if (v.ir.block.cond_failed != v.ir.current_location || cond == IR::Cond::AL) { v.cond_state = ConditionalState::Trailing; } else { - if (cond == v.ir.block.GetCondition()) { - v.ir.block.SetConditionFailedLocation(v.ir.current_location.AdvancePC(static_cast(v.current_instruction_size)).AdvanceIT()); - v.ir.block.ConditionFailedCycleCount()++; + if (cond == v.ir.block.cond) { + v.ir.block.cond_failed = v.ir.current_location.AdvancePC(static_cast(v.current_instruction_size)).AdvanceIT(); + v.ir.block.cond_failed_cycle_count++; return true; } @@ -77,9 +77,9 @@ bool IsConditionPassed(TranslatorVisitor& v, IR::Cond cond) { // We'll emit one instruction, and set the block-entry conditional appropriately. v.cond_state = ConditionalState::Translating; - v.ir.block.SetCondition(cond); - v.ir.block.SetConditionFailedLocation(v.ir.current_location.AdvancePC(static_cast(v.current_instruction_size)).AdvanceIT()); - v.ir.block.ConditionFailedCycleCount() = v.ir.block.CycleCount() + 1; + v.ir.block.cond = cond; + v.ir.block.cond_failed = v.ir.current_location.AdvancePC(int(v.current_instruction_size)).AdvanceIT(); + v.ir.block.cond_failed_cycle_count = v.ir.block.cycle_count + 1; return true; } 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 5cc9ef3893..ade6ff109d 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/translate/translate_arm.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A32/translate/translate_arm.cpp @@ -61,7 +61,7 @@ void TranslateArm(IR::Block& block, LocationDescriptor descriptor, TranslateCall } visitor.ir.current_location = visitor.ir.current_location.AdvancePC(4); - block.CycleCount() += ticks_for_instruction; + block.cycle_count += ticks_for_instruction; } while (should_continue && CondCanContinue(visitor.cond_state, visitor.ir) && !single_step); if (visitor.cond_state == ConditionalState::Translating || visitor.cond_state == ConditionalState::Trailing || single_step) { @@ -74,7 +74,7 @@ void TranslateArm(IR::Block& block, LocationDescriptor descriptor, TranslateCall } } ASSERT(block.HasTerminal() && "Terminal has not been set"); - block.SetEndLocation(visitor.ir.current_location); + block.end_location = visitor.ir.current_location; } bool TranslateSingleArmInstruction(IR::Block& block, LocationDescriptor descriptor, u32 arm_instruction) { @@ -101,10 +101,8 @@ bool TranslateSingleArmInstruction(IR::Block& block, LocationDescriptor descript // TODO: Feedback resulting cond status to caller somehow. visitor.ir.current_location = visitor.ir.current_location.AdvancePC(4); - block.CycleCount() += ticks_for_instruction; - - block.SetEndLocation(visitor.ir.current_location); - + block.cycle_count += ticks_for_instruction; + block.end_location = visitor.ir.current_location; return should_continue; } 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 e0333e487d..da5031bb6b 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/translate/translate_thumb.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A32/translate/translate_thumb.cpp @@ -161,7 +161,7 @@ void TranslateThumb(IR::Block& block, LocationDescriptor descriptor, TranslateCa } visitor.ir.current_location = visitor.ir.current_location.AdvancePC(static_cast(visitor.current_instruction_size)).AdvanceIT(); - block.CycleCount() += ticks_for_instruction; + block.cycle_count += ticks_for_instruction; } while (should_continue && CondCanContinue(visitor.cond_state, visitor.ir) && !single_step); if (visitor.cond_state == ConditionalState::Translating || visitor.cond_state == ConditionalState::Trailing || single_step) { @@ -174,7 +174,7 @@ void TranslateThumb(IR::Block& block, LocationDescriptor descriptor, TranslateCa } } ASSERT(block.HasTerminal() && "Terminal has not been set"); - block.SetEndLocation(visitor.ir.current_location); + block.end_location = visitor.ir.current_location; } bool TranslateSingleThumbInstruction(IR::Block& block, LocationDescriptor descriptor, u32 thumb_instruction) { @@ -214,10 +214,8 @@ bool TranslateSingleThumbInstruction(IR::Block& block, LocationDescriptor descri const s32 advance_pc = is_thumb_16 ? 2 : 4; visitor.ir.current_location = visitor.ir.current_location.AdvancePC(advance_pc); - block.CycleCount() += ticks_for_instruction; - - block.SetEndLocation(visitor.ir.current_location); - + block.cycle_count += ticks_for_instruction; + block.end_location = visitor.ir.current_location; return should_continue; } 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 6778d13890..b940a563f8 100644 --- a/src/dynarmic/src/dynarmic/frontend/A64/translate/a64_translate.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A64/translate/a64_translate.cpp @@ -30,14 +30,14 @@ void Translate(IR::Block& block, LocationDescriptor descriptor, MemoryReadCodeFu should_continue = visitor.RaiseException(Exception::NoExecuteFault); } visitor.ir.current_location = visitor.ir.current_location->AdvancePC(4); - block.CycleCount()++; + block.cycle_count++; } while (should_continue && !single_step); 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); + block.end_location = *visitor.ir.current_location; } bool TranslateSingleInstruction(IR::Block& block, LocationDescriptor descriptor, u32 instruction) { @@ -48,10 +48,9 @@ bool TranslateSingleInstruction(IR::Block& block, LocationDescriptor descriptor, should_continue = decoder.get().call(visitor, instruction); visitor.ir.current_location = visitor.ir.current_location->AdvancePC(4); - block.CycleCount()++; - - block.SetEndLocation(*visitor.ir.current_location); + block.cycle_count++; + block.end_location = *visitor.ir.current_location; return should_continue; } diff --git a/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/system.cpp b/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/system.cpp index c60fdc3ae0..61d5c065f4 100644 --- a/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/system.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/system.cpp @@ -130,7 +130,7 @@ bool TranslatorVisitor::MRS(Imm<1> o0, Imm<3> op1, Imm<4> CRn, Imm<4> CRm, Imm<3 case SystemRegisterEncoding::CNTPCT_EL0: // HACK: Ensure that this is the first instruction in the block it's emitted in, so the cycle count is most up-to-date. if (!ir.block.instructions.empty() && !options.wall_clock_cntpct) { - ir.block.CycleCount()--; + ir.block.cycle_count--; ir.SetTerm(IR::Term::LinkBlock{*ir.current_location}); return false; } diff --git a/src/dynarmic/src/dynarmic/ir/basic_block.cpp b/src/dynarmic/src/dynarmic/ir/basic_block.cpp index ac0f03d76a..7e79b6862b 100644 --- a/src/dynarmic/src/dynarmic/ir/basic_block.cpp +++ b/src/dynarmic/src/dynarmic/ir/basic_block.cpp @@ -23,46 +23,35 @@ namespace Dynarmic::IR { Block::Block(LocationDescriptor location) noexcept - : location{location} + : cond_failed(0) + , location{location} , end_location{location} {} /// Prepends a new instruction to this basic block before the insertion point, /// handling any allocations necessary to do so. /// @param insertion_point Where to insert the new instruction. -/// @param op Opcode representing the instruction to add. -/// @param args A sequence of Value instances used as arguments for the instruction. +/// @param op Opcode representing the instruction to add. +/// @param args A sequence of Value instances used as arguments for the instruction. /// @returns Iterator to the newly created instruction. -Block::iterator Block::PrependNewInst(iterator insertion_point, Opcode opcode, std::initializer_list args) noexcept { +Block::iterator Block::PrependNewInst(Block::const_iterator insertion_point, Opcode opcode, std::initializer_list args) noexcept { // First try using the "inline" buffer, otherwise fallback to a slower slab-like allocation scheme // purpouse is to avoid many calls to new/delete which invoke malloc which invokes mmap // just pool it!!! - reason why there is an inline buffer is because many small blocks are created // with few instructions due to subpar optimisations on other passes... plus branch-heavy code will // hugely benefit from the coherency of faster allocations... - IR::Inst* inst; - if (inlined_inst.size() < inlined_inst.max_size()) { - inlined_inst.emplace_back(opcode); - inst = &inlined_inst[inlined_inst.size() - 1]; - } else { - if (pooled_inst.empty() || pooled_inst.back().size() == pooled_inst.back().max_size()) - pooled_inst.emplace_back(); - pooled_inst.back().emplace_back(opcode); - inst = &pooled_inst.back()[pooled_inst.back().size() - 1]; - } - DEBUG_ASSERT(args.size() == inst->NumArgs()); - std::for_each(args.begin(), args.end(), [&inst, index = size_t(0)](const auto& arg) mutable { - inst->SetArg(index, arg); + auto it = instructions.insert(insertion_point, Inst(opcode)); + DEBUG_ASSERT(args.size() == it->NumArgs()); + std::for_each(args.begin(), args.end(), [&it, index = size_t(0)](const auto& arg) mutable { + it->SetArg(index, arg); index++; }); - return instructions.insert_before(insertion_point, inst); + return it; } void Block::Reset(LocationDescriptor location_) noexcept { - mcl::intrusive_list tmp = {}; - instructions.swap(tmp); - inlined_inst.clear(); - pooled_inst.clear(); - cond_failed.reset(); + instructions.clear(); + cond_failed = LocationDescriptor(0); location = location_; end_location = location_; cond = Cond::AL; @@ -106,11 +95,11 @@ static std::string TerminalToString(const Terminal& terminal_variant) noexcept { } std::string DumpBlock(const IR::Block& block) noexcept { - std::string ret = fmt::format("Block: location={}-{}\n", block.Location(), block.EndLocation()) - + fmt::format("cycles={}", block.CycleCount()) - + fmt::format(", entry_cond={}", A64::CondToString(block.GetCondition())); - if (block.GetCondition() != Cond::AL) - ret += fmt::format(", cond_fail={}", block.ConditionFailedLocation()); + std::string ret = fmt::format("Block: location={}-{}\n", block.location, block.end_location) + + fmt::format("cycles={}", block.cycle_count) + + fmt::format(", entry_cond={}", A64::CondToString(block.cond)); + if (block.cond != Cond::AL) + ret += fmt::format(", cond_fail={}", block.cond_failed); ret += '\n'; const auto arg_to_string = [](const IR::Value& arg) -> std::string { @@ -173,7 +162,7 @@ std::string DumpBlock(const IR::Block& block) noexcept { ret += fmt::format(" (uses: {})", inst.UseCount()) + '\n'; } - ret += "terminal = " + TerminalToString(block.GetTerminal()) + '\n'; + ret += "terminal = " + TerminalToString(block.terminal) + '\n'; return ret; } diff --git a/src/dynarmic/src/dynarmic/ir/basic_block.h b/src/dynarmic/src/dynarmic/ir/basic_block.h index 4044005bd0..1bb27a03e4 100644 --- a/src/dynarmic/src/dynarmic/ir/basic_block.h +++ b/src/dynarmic/src/dynarmic/ir/basic_block.h @@ -12,11 +12,11 @@ #include #include #include +#include #include #include #include -#include #include "dynarmic/common/common_types.h" #include "dynarmic/ir/location_descriptor.h" @@ -33,15 +33,12 @@ enum class Opcode; /// Note that this is a linear IR and not a pure tree-based IR: i.e.: there is an ordering to /// the microinstructions. This only matters before chaining is done in order to correctly /// order memory accesses. -class alignas(4096) Block final { +class Block final { public: - //using instruction_list_type = dense_list; - using instruction_list_type = mcl::intrusive_list; - using size_type = instruction_list_type::size_type; + using instruction_list_type = std::list; using iterator = instruction_list_type::iterator; using const_iterator = instruction_list_type::const_iterator; using reverse_iterator = instruction_list_type::reverse_iterator; - using const_reverse_iterator = instruction_list_type::const_reverse_iterator; Block(LocationDescriptor location) noexcept; ~Block() = default; @@ -50,105 +47,23 @@ public: Block(Block&&) = default; Block& operator=(Block&&) = default; - /// Appends a new instruction to the end of this basic block, - /// handling any allocations necessary to do so. - /// @param op Opcode representing the instruction to add. - /// @param args A sequence of Value instances used as arguments for the instruction. - inline iterator AppendNewInst(const Opcode opcode, const std::initializer_list args) noexcept { - return PrependNewInst(instructions.end(), opcode, args); - } - iterator PrependNewInst(iterator insertion_point, Opcode op, std::initializer_list args) noexcept; + [[nodiscard]] iterator PrependNewInst(const_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 { - return instructions; - } - /// Gets an immutable reference to the instruction list for this basic block. - inline const instruction_list_type& Instructions() const noexcept { - return instructions; - } - - /// Gets the starting location for this basic block. - inline LocationDescriptor Location() const noexcept { - return location; - } - /// Gets the end location for this basic block. - inline LocationDescriptor EndLocation() const noexcept { - return end_location; - } - /// Sets the end location for this basic block. - inline void SetEndLocation(const LocationDescriptor& descriptor) noexcept { - end_location = descriptor; - } - - /// Gets the condition required to pass in order to execute this block. - inline Cond GetCondition() const noexcept { - return cond; - } - /// Sets the condition required to pass in order to execute this block. - inline void SetCondition(Cond condition) noexcept { - cond = condition; - } - - /// Gets the location of the block to execute if the predicated condition fails. - inline LocationDescriptor ConditionFailedLocation() const noexcept { - return *cond_failed; - } - /// Sets the location of the block to execute if the predicated condition fails. - inline void SetConditionFailedLocation(LocationDescriptor fail_location) noexcept { - cond_failed = fail_location; - } /// Determines whether or not a predicated condition failure block is present. - inline bool HasConditionFailedLocation() const noexcept { - return cond_failed.has_value(); - } - - /// Gets a mutable reference to the condition failed cycle count. - inline size_t& ConditionFailedCycleCount() noexcept { - return cond_failed_cycle_count; - } - /// Gets an immutable reference to the condition failed cycle count. - inline const size_t& ConditionFailedCycleCount() const noexcept { - return cond_failed_cycle_count; + [[nodiscard]] inline bool HasConditionFailedLocation() const noexcept { + return cond_failed.Value() > 0; } - /// Gets the terminal instruction for this basic block. - inline Terminal GetTerminal() const noexcept { - return terminal; - } - /// Sets the terminal instruction for this basic block. - inline void SetTerminal(Terminal term) noexcept { - ASSERT(!HasTerminal() && "Terminal has already been set."); - terminal = std::move(term); - } - /// Replaces the terminal instruction for this basic block. - inline void ReplaceTerminal(Terminal term) noexcept { - ASSERT(HasTerminal() && "Terminal has not been set."); - terminal = std::move(term); - } /// Determines whether or not this basic block has a terminal instruction. - inline bool HasTerminal() const noexcept { + [[nodiscard]] inline bool HasTerminal() const noexcept { return terminal.which() != 0; } - /// Gets a mutable reference to the cycle count for this basic block. - inline size_t& CycleCount() noexcept { - return cycle_count; - } - /// Gets an immutable reference to the cycle count for this basic block. - inline const size_t& CycleCount() const noexcept { - return cycle_count; - } - - /// "Hot cache" for small blocks so we don't call global allocator - boost::container::static_vector inlined_inst; /// List of instructions in this block. instruction_list_type instructions; - /// "Long/far" memory pool - boost::container::stable_vector> pooled_inst; /// Block to execute next if `cond` did not pass. - std::optional cond_failed = {}; + LocationDescriptor cond_failed; /// Description of the starting location of this block LocationDescriptor location; /// Description of the end location of this block @@ -162,7 +77,7 @@ public: /// Number of cycles this block takes to execute. size_t cycle_count = 0; }; -static_assert(sizeof(Block) == 4096); +//static_assert(sizeof(Block) == 120); /// Returns a string representation of the contents of block. Intended for debugging. std::string DumpBlock(const IR::Block& block) noexcept; diff --git a/src/dynarmic/src/dynarmic/ir/ir_emitter.h b/src/dynarmic/src/dynarmic/ir/ir_emitter.h index 2b5c7d5cdd..0d051ba7cc 100644 --- a/src/dynarmic/src/dynarmic/ir/ir_emitter.h +++ b/src/dynarmic/src/dynarmic/ir/ir_emitter.h @@ -70,7 +70,10 @@ enum class MemOp { /// The user of this class updates `current_location` as appropriate. class IREmitter { public: - explicit IREmitter(Block& block) : block(block), insertion_point(block.instructions.end()) {} + explicit IREmitter(Block& block) noexcept + : block(block) + , insertion_point(block.instructions.end()) + {} Block& block; @@ -2944,22 +2947,14 @@ public: } void SetTerm(const Terminal& terminal) { - block.SetTerminal(terminal); - } - - void SetInsertionPointBefore(IR::Inst* new_insertion_point) { - insertion_point = IR::Block::iterator{*new_insertion_point}; + ASSERT(!block.HasTerminal() && "Terminal has already been set."); + block.terminal = std::move(terminal); } void SetInsertionPointBefore(IR::Block::iterator new_insertion_point) { insertion_point = new_insertion_point; } - void SetInsertionPointAfter(IR::Inst* new_insertion_point) { - insertion_point = IR::Block::iterator{*new_insertion_point}; - ++insertion_point; - } - void SetInsertionPointAfter(IR::Block::iterator new_insertion_point) { insertion_point = new_insertion_point; ++insertion_point; @@ -2970,7 +2965,9 @@ protected: template T Inst(Opcode op, Args... args) { + auto const offset = std::distance(block.instructions.begin(), insertion_point); auto iter = block.PrependNewInst(insertion_point, op, {Value(args)...}); + insertion_point = std::next(block.instructions.begin(), offset + 1); return T(Value(&*iter)); } }; diff --git a/src/dynarmic/src/dynarmic/ir/microinstruction.h b/src/dynarmic/src/dynarmic/ir/microinstruction.h index 1700eb110b..c3e3cb4382 100644 --- a/src/dynarmic/src/dynarmic/ir/microinstruction.h +++ b/src/dynarmic/src/dynarmic/ir/microinstruction.h @@ -10,9 +10,7 @@ #include -#include #include "dynarmic/common/common_types.h" - #include "dynarmic/ir/value.h" #include "dynarmic/ir/opcodes.h" @@ -25,8 +23,7 @@ constexpr size_t max_arg_count = 4; /// A representation of a microinstruction. A single ARM/Thumb instruction may be /// converted into zero or more microinstructions. -//class Inst final { -class Inst final : public mcl::intrusive_list_node { +class Inst final { public: explicit Inst(Opcode op) : op(op) {} diff --git a/src/dynarmic/src/dynarmic/ir/opt_passes.cpp b/src/dynarmic/src/dynarmic/ir/opt_passes.cpp index f22e8aaa69..a0da0d0c81 100644 --- a/src/dynarmic/src/dynarmic/ir/opt_passes.cpp +++ b/src/dynarmic/src/dynarmic/ir/opt_passes.cpp @@ -86,12 +86,10 @@ static void ConstantMemoryReads(IR::Block& block, A32::UserCallbacks* cb) { } static void FlagsPass(IR::Block& block) { - using Iterator = typename std::reverse_iterator; - struct FlagInfo { bool set_not_required = false; bool has_value_request = false; - Iterator value_request = {}; + IR::Block::reverse_iterator value_request = {}; }; struct ValuelessFlagInfo { bool set_not_required = false; @@ -102,7 +100,7 @@ static void FlagsPass(IR::Block& block) { FlagInfo c_flag; FlagInfo ge; - auto do_set = [&](FlagInfo& info, IR::Value value, Iterator inst) { + auto do_set = [&](FlagInfo& info, IR::Value value, IR::Block::reverse_iterator inst) { if (info.has_value_request) { info.value_request->ReplaceUsesWith(value); } @@ -114,14 +112,14 @@ static void FlagsPass(IR::Block& block) { info.set_not_required = true; }; - auto do_set_valueless = [&](ValuelessFlagInfo& info, Iterator inst) { + auto do_set_valueless = [](ValuelessFlagInfo& info, IR::Block::reverse_iterator inst) { if (info.set_not_required) { inst->Invalidate(); } info.set_not_required = true; }; - auto do_get = [](FlagInfo& info, Iterator inst) { + auto do_get = [](FlagInfo& info, IR::Block::reverse_iterator inst) { if (info.has_value_request) { info.value_request->ReplaceUsesWith(IR::Value{&*inst}); } @@ -129,7 +127,7 @@ static void FlagsPass(IR::Block& block) { info.value_request = inst; }; - A32::IREmitter ir{block, A32::LocationDescriptor{block.Location()}, {}}; + A32::IREmitter ir{block, A32::LocationDescriptor{block.location}, {}}; for (auto inst = block.instructions.rbegin(); inst != block.instructions.rend(); ++inst) { auto const opcode = inst->GetOpcode(); @@ -316,7 +314,7 @@ static void RegisterPass(IR::Block& block) { }; // Location and version don't matter here. - A32::IREmitter ir{block, A32::LocationDescriptor{block.Location()}, {}}; + A32::IREmitter ir{block, A32::LocationDescriptor{block.location}, {}}; for (auto inst = block.instructions.begin(); inst != block.instructions.end(); ++inst) { auto const opcode = inst->GetOpcode(); @@ -448,7 +446,8 @@ static void A64CallbackConfigPass(IR::Block& block, const A64::UserConfig& conf) return; } - for (auto& inst : block.instructions) { + for (auto it = block.instructions.begin(); it != block.instructions.end(); it++) { + auto& inst = *it; if (inst.GetOpcode() != IR::Opcode::A64DataCacheOperationRaised) { continue; } @@ -457,7 +456,7 @@ static void A64CallbackConfigPass(IR::Block& block, const A64::UserConfig& conf) if (op == A64::DataCacheOperation::ZeroByVA) { A64::IREmitter ir{block}; ir.current_location = A64::LocationDescriptor{IR::LocationDescriptor{inst.GetArg(0).GetU64()}}; - ir.SetInsertionPointBefore(&inst); + ir.SetInsertionPointBefore(it); size_t bytes = 4 << static_cast(conf.dczid_el0 & 0b1111); IR::U64 addr{inst.GetArg(2)}; @@ -522,7 +521,7 @@ static void A64GetSetElimination(IR::Block& block) { const auto do_set = [&block](RegisterInfo& info, IR::Value value, Iterator set_inst, TrackingType tracking_type) { if (info.set_instruction_present) { info.last_set_instruction->Invalidate(); - block.Instructions().erase(info.last_set_instruction); + block.instructions.erase(info.last_set_instruction); } info.register_value = value; info.tracking_type = tracking_type; @@ -541,7 +540,7 @@ static void A64GetSetElimination(IR::Block& block) { ReplaceUsesWith(*get_inst, true, u32(info.register_value.GetImmediateAsU64())); } else { A64::IREmitter ir{block}; - ir.SetInsertionPointBefore(&*get_inst); + ir.SetInsertionPointBefore(get_inst); get_inst->ReplaceUsesWith(ir.LeastSignificantWord(IR::U64{info.register_value})); } } else { @@ -1210,7 +1209,7 @@ static void IdentityRemovalPass(IR::Block& block) { } if (it->GetOpcode() == IR::Opcode::Identity || it->GetOpcode() == IR::Opcode::Void) { to_invalidate.push_back(&*it); - it = block.Instructions().erase(it); + it = block.instructions.erase(it); } else { ++it; } @@ -1370,9 +1369,9 @@ static void PolyfillPass(IR::Block& block, const PolyfillOptions& polyfill) { IR::IREmitter ir{block}; - for (auto& inst : block.instructions) { - ir.SetInsertionPointBefore(&inst); - + for (auto it = block.instructions.begin(); it != block.instructions.end(); it++) { + auto& inst = *it; + ir.SetInsertionPointBefore(it); switch (inst.GetOpcode()) { case IR::Opcode::SHA256MessageSchedule0: if (polyfill.sha256) { diff --git a/src/dynarmic/tests/A32/fuzz_arm.cpp b/src/dynarmic/tests/A32/fuzz_arm.cpp index fd17b3bd01..fdd9ce4e5d 100644 --- a/src/dynarmic/tests/A32/fuzz_arm.cpp +++ b/src/dynarmic/tests/A32/fuzz_arm.cpp @@ -83,7 +83,7 @@ bool ShouldTestInst(u32 instruction, u32 pc, bool is_thumb, bool is_last_inst, A return false; } - if (AnyLocationDescriptorForTerminalHas(block.GetTerminal(), [&](IR::LocationDescriptor ld) { return A32::LocationDescriptor{ld}.PC() <= pc; })) { + if (AnyLocationDescriptorForTerminalHas(block.terminal, [&](IR::LocationDescriptor ld) { return A32::LocationDescriptor{ld}.PC() <= pc; })) { return false; } diff --git a/src/dynarmic/tests/A32/fuzz_thumb.cpp b/src/dynarmic/tests/A32/fuzz_thumb.cpp index 3a561a18d9..da533e6a62 100644 --- a/src/dynarmic/tests/A32/fuzz_thumb.cpp +++ b/src/dynarmic/tests/A32/fuzz_thumb.cpp @@ -183,7 +183,7 @@ static void RunInstance(size_t run_number, ThumbTestEnv& test_env, A32Unicorn