diff --git a/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64.cpp b/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64.cpp index 0a65cd5aa8..104d0a452c 100644 --- a/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64.cpp +++ b/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -218,7 +218,7 @@ EmittedBlockInfo EmitArm64(oaknut::CodeGenerator& code, IR::Block block, const E code.l(pass); } - for (auto iter = block.begin(); iter != block.end(); ++iter) { + for (auto iter = block.instructions.begin(); iter != block.instructions.end(); ++iter) { IR::Inst* inst = &*iter; switch (inst->GetOpcode()) { 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 d3ba664ce4..2868d3b830 100644 --- a/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_a32.cpp +++ b/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_a32.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -582,11 +582,9 @@ void EmitIR(oaknut::CodeGenerator& code, EmitContext& template<> void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst*) { - for (auto& inst : ctx.block) { - if (inst.GetOpcode() == IR::Opcode::A32BXWritePC) { + for (auto& inst : ctx.block.instructions) + if (inst.GetOpcode() == IR::Opcode::A32BXWritePC) return; - } - } EmitSetUpperLocationDescriptor(code, ctx, ctx.block.EndLocation(), ctx.block.Location()); } 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 75c898a1cd..67ab61f8a3 100644 --- a/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_memory.cpp +++ b/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_memory.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. diff --git a/src/dynarmic/src/dynarmic/backend/arm64/reg_alloc.cpp b/src/dynarmic/src/dynarmic/backend/arm64/reg_alloc.cpp index 5e0cb79de2..3bd5ed90e4 100644 --- a/src/dynarmic/src/dynarmic/backend/arm64/reg_alloc.cpp +++ b/src/dynarmic/src/dynarmic/backend/arm64/reg_alloc.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -193,7 +193,6 @@ void RegAlloc::PrepareForCall(std::optional arg0, void RegAlloc::DefineAsExisting(IR::Inst* inst, Argument& arg) { defined_insts.insert(inst); - ASSERT(!ValueLocation(inst)); if (arg.value.IsImmediate()) { @@ -208,7 +207,6 @@ void RegAlloc::DefineAsExisting(IR::Inst* inst, Argument& arg) { void RegAlloc::DefineAsRegister(IR::Inst* inst, oaknut::Reg reg) { defined_insts.insert(inst); - ASSERT(!ValueLocation(inst)); auto& info = reg.is_vector() ? fprs[reg.index()] : gprs[reg.index()]; ASSERT(info.IsCompletelyEmpty()); @@ -375,7 +373,6 @@ int RegAlloc::RealizeReadImpl(const IR::Value& value) { template int RegAlloc::RealizeWriteImpl(const IR::Inst* value) { defined_insts.insert(value); - ASSERT(!ValueLocation(value)); if constexpr (kind == HostLoc::Kind::Gpr) { @@ -400,7 +397,6 @@ int RegAlloc::RealizeWriteImpl(const IR::Inst* value) { template int RegAlloc::RealizeReadWriteImpl(const IR::Value& read_value, const IR::Inst* write_value) { defined_insts.insert(write_value); - // TODO: Move elimination const int write_loc = RealizeWriteImpl(write_value); @@ -464,7 +460,6 @@ void RegAlloc::SpillFpr(int index) { void RegAlloc::ReadWriteFlags(Argument& read, IR::Inst* write) { defined_insts.insert(write); - const auto current_location = ValueLocation(read.value.GetInst()); ASSERT(current_location); diff --git a/src/dynarmic/src/dynarmic/backend/arm64/reg_alloc.h b/src/dynarmic/src/dynarmic/backend/arm64/reg_alloc.h index 099be4ec10..a8395a068d 100644 --- a/src/dynarmic/src/dynarmic/backend/arm64/reg_alloc.h +++ b/src/dynarmic/src/dynarmic/backend/arm64/reg_alloc.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -302,17 +302,12 @@ public: private: friend struct Argument; - template - friend struct RAReg; + template friend struct RAReg; - template - int GenerateImmediate(const IR::Value& value); - template - int RealizeReadImpl(const IR::Value& value); - template - int RealizeWriteImpl(const IR::Inst* value); - template - int RealizeReadWriteImpl(const IR::Value& read_value, const IR::Inst* write_value); + template int GenerateImmediate(const IR::Value& value); + template int RealizeReadImpl(const IR::Value& value); + template int RealizeWriteImpl(const IR::Inst* value); + template int RealizeReadWriteImpl(const IR::Value& read_value, const IR::Inst* write_value); int AllocateRegister(const std::array& regs, const std::vector& order) const; void SpillGpr(int index); @@ -337,7 +332,6 @@ private: std::array spills; mutable std::mt19937 rand_gen; - ankerl::unordered_dense::set defined_insts; }; diff --git a/src/dynarmic/src/dynarmic/backend/block_range_information.cpp b/src/dynarmic/src/dynarmic/backend/block_range_information.cpp index 0e5904ae1c..aa951d7708 100644 --- a/src/dynarmic/src/dynarmic/backend/block_range_information.cpp +++ b/src/dynarmic/src/dynarmic/backend/block_range_information.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -15,26 +15,24 @@ namespace Dynarmic::Backend { -template -void BlockRangeInformation::AddRange(boost::icl::discrete_interval range, IR::LocationDescriptor location) { - block_ranges.add(std::make_pair(range, std::set{location})); +template +void BlockRangeInformation

::AddRange(boost::icl::discrete_interval

range, IR::LocationDescriptor location) { + block_ranges.add(std::make_pair(range, ankerl::unordered_dense::set{location})); } -template -void BlockRangeInformation::ClearCache() { +template +void BlockRangeInformation

::ClearCache() { block_ranges.clear(); } -template -ankerl::unordered_dense::set BlockRangeInformation::InvalidateRanges(const boost::icl::interval_set& ranges) { +template +ankerl::unordered_dense::set BlockRangeInformation

::InvalidateRanges(const boost::icl::interval_set

& ranges) { ankerl::unordered_dense::set erase_locations; for (auto invalidate_interval : ranges) { auto pair = block_ranges.equal_range(invalidate_interval); - for (auto it = pair.first; it != pair.second; ++it) { - for (const auto& descriptor : it->second) { + for (auto it = pair.first; it != pair.second; ++it) + for (const auto& descriptor : it->second) erase_locations.insert(descriptor); - } - } } // TODO: EFFICIENCY: Remove ranges that are to be erased. return erase_locations; diff --git a/src/dynarmic/src/dynarmic/backend/block_range_information.h b/src/dynarmic/src/dynarmic/backend/block_range_information.h index e39bf992e4..2af1a1120b 100644 --- a/src/dynarmic/src/dynarmic/backend/block_range_information.h +++ b/src/dynarmic/src/dynarmic/backend/block_range_information.h @@ -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) 2018 MerryMage * SPDX-License-Identifier: 0BSD @@ -15,15 +18,13 @@ namespace Dynarmic::Backend { -template +template class BlockRangeInformation { public: - void AddRange(boost::icl::discrete_interval range, IR::LocationDescriptor location); + void AddRange(boost::icl::discrete_interval

range, IR::LocationDescriptor location); void ClearCache(); - ankerl::unordered_dense::set InvalidateRanges(const boost::icl::interval_set& ranges); - -private: - boost::icl::interval_map> block_ranges; + ankerl::unordered_dense::set InvalidateRanges(const boost::icl::interval_set

& ranges); + boost::icl::interval_map> block_ranges; }; } // namespace Dynarmic::Backend diff --git a/src/dynarmic/src/dynarmic/backend/riscv64/emit_riscv64.cpp b/src/dynarmic/src/dynarmic/backend/riscv64/emit_riscv64.cpp index bc94fda91a..50cbaf9526 100644 --- a/src/dynarmic/src/dynarmic/backend/riscv64/emit_riscv64.cpp +++ b/src/dynarmic/src/dynarmic/backend/riscv64/emit_riscv64.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -122,7 +122,7 @@ EmittedBlockInfo EmitRV64(biscuit::Assembler& as, IR::Block block, const EmitCon ebi.entry_point = reinterpret_cast(as.GetCursorPointer()); - for (auto iter = block.begin(); iter != block.end(); ++iter) { + for (auto iter = block.instructions.begin(); iter != block.instructions.end(); ++iter) { IR::Inst* inst = &*iter; switch (inst->GetOpcode()) { 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 94f73d65c1..a4c62e129b 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -123,7 +123,7 @@ A32EmitX64::BlockDescriptor A32EmitX64::Emit(IR::Block& block) { EmitCondPrelude(ctx); - for (auto iter = block.begin(); iter != block.end(); ++iter) [[likely]] { + for (auto iter = block.instructions.begin(); iter != block.instructions.end(); ++iter) [[likely]] { auto* inst = &*iter; // Call the relevant Emit* member function. switch (inst->GetOpcode()) { @@ -727,11 +727,9 @@ void A32EmitX64::EmitA32BXWritePC(A32EmitContext& ctx, IR::Inst* inst) { } void A32EmitX64::EmitA32UpdateUpperLocationDescriptor(A32EmitContext& ctx, IR::Inst*) { - for (auto& inst : ctx.block) { - if (inst.GetOpcode() == IR::Opcode::A32BXWritePC) { + for (auto& inst : ctx.block.instructions) + if (inst.GetOpcode() == IR::Opcode::A32BXWritePC) return; - } - } EmitSetUpperLocationDescriptor(ctx.EndLocation(), ctx.Location()); } 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 39bbf6880a..03d0e13562 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -116,7 +116,7 @@ A64EmitX64::BlockDescriptor A64EmitX64::Emit(IR::Block& block) noexcept { #undef A64OPC }; - for (auto& inst : block) { + for (auto& inst : block.instructions) { auto const opcode = inst.GetOpcode(); // Call the relevant Emit* member function. switch (opcode) { diff --git a/src/dynarmic/src/dynarmic/backend/x64/emit_x64.cpp b/src/dynarmic/src/dynarmic/backend/x64/emit_x64.cpp index 05394d237d..072b790fd4 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/emit_x64.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/emit_x64.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -38,11 +38,6 @@ EmitContext::EmitContext(RegAlloc& reg_alloc, IR::Block& block) EmitContext::~EmitContext() = default; -void EmitContext::EraseInstruction(IR::Inst* inst) { - block.Instructions().erase(inst); - inst->ClearArgs(); -} - EmitX64::EmitX64(BlockOfCode& code) : code(code) { exception_handler.Register(code); diff --git a/src/dynarmic/src/dynarmic/backend/x64/emit_x64.h b/src/dynarmic/src/dynarmic/backend/x64/emit_x64.h index b3614f224e..c63004ee6f 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/emit_x64.h +++ b/src/dynarmic/src/dynarmic/backend/x64/emit_x64.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -56,11 +56,7 @@ using HalfVectorArray = std::array static void EmitVectorOperation(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, Function fn) { 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 66ff795ef0..8c55588a28 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/translate/conditional_state.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A32/translate/conditional_state.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -26,7 +26,7 @@ bool CondCanContinue(const ConditionalState cond_state, const A32::IREmitter& ir return true; // TODO: This is more conservative than necessary. - return std::all_of(ir.block.begin(), ir.block.end(), [](const IR::Inst& inst) { + return std::all_of(ir.block.instructions.begin(), ir.block.instructions.end(), [](const IR::Inst& inst) { return !WritesToCPSR(inst.GetOpcode()); }); } @@ -66,7 +66,7 @@ bool IsConditionPassed(TranslatorVisitor& v, IR::Cond cond) { // non-AL cond - if (!v.ir.block.empty()) { + if (!v.ir.block.instructions.empty()) { // We've already emitted instructions. Quit for now, we'll make a new block here later. v.cond_state = ConditionalState::Break; v.ir.SetTerm(IR::Term::LinkBlockFast{v.ir.current_location}); 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 9c35a8f364..7c4b8a1ac6 100644 --- a/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/system.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/system.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) 2018 MerryMage * SPDX-License-Identifier: 0BSD @@ -126,7 +129,7 @@ bool TranslatorVisitor::MRS(Imm<1> o0, Imm<3> op1, Imm<4> CRn, Imm<4> CRm, Imm<3 return true; 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.empty() && !options.wall_clock_cntpct) { + if (!ir.block.instructions.empty() && !options.wall_clock_cntpct) { ir.block.CycleCount()--; 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 ae9e0b103b..8543bfe8d7 100644 --- a/src/dynarmic/src/dynarmic/ir/basic_block.cpp +++ b/src/dynarmic/src/dynarmic/ir/basic_block.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -100,57 +100,39 @@ 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) { + if (block.GetCondition() != Cond::AL) ret += fmt::format(", cond_fail={}", block.ConditionFailedLocation()); - } ret += '\n'; const auto arg_to_string = [](const IR::Value& arg) -> std::string { if (arg.IsEmpty()) { return ""; } else if (!arg.IsImmediate()) { - if (const unsigned name = arg.GetInst()->GetName()) { + if (auto const name = arg.GetInst()->GetName()) return fmt::format("%{}", name); - } - return fmt::format("%", reinterpret_cast(arg.GetInst())); + return fmt::format("%", u64(arg.GetInst())); } switch (arg.GetType()) { - case Type::U1: - return fmt::format("#{}", arg.GetU1() ? '1' : '0'); - case Type::U8: - return fmt::format("#{}", arg.GetU8()); - case Type::U16: - return fmt::format("#{:#x}", arg.GetU16()); - case Type::U32: - return fmt::format("#{:#x}", arg.GetU32()); - case Type::U64: - return fmt::format("#{:#x}", arg.GetU64()); - case Type::U128: - return fmt::format("#"); - case Type::A32Reg: - return A32::RegToString(arg.GetA32RegRef()); - 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())); - default: - return fmt::format("", arg.GetType()); + case Type::U1: return fmt::format("#{}", arg.GetU1() ? '1' : '0'); + case Type::U8: return fmt::format("#{}", arg.GetU8()); + case Type::U16: return fmt::format("#{:#x}", arg.GetU16()); + case Type::U32: return fmt::format("#{:#x}", arg.GetU32()); + case Type::U64: return fmt::format("#{:#x}", arg.GetU64()); + case Type::U128: return fmt::format("#"); + case Type::A32Reg: return A32::RegToString(arg.GetA32RegRef()); + 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())); + default: return fmt::format("", arg.GetType()); } }; - for (const auto& inst : block) { + for (const auto& inst : block.instructions) { const Opcode op = inst.GetOpcode(); ret += fmt::format("[{:016x}] ", reinterpret_cast(&inst)); @@ -180,13 +162,9 @@ std::string DumpBlock(const IR::Block& block) noexcept { } } - ret += fmt::format(" (uses: {})", inst.UseCount()); - - ret += '\n'; + ret += fmt::format(" (uses: {})", inst.UseCount()) + '\n'; } - ret += "terminal = " + TerminalToString(block.GetTerminal()) + '\n'; - return ret; } diff --git a/src/dynarmic/src/dynarmic/ir/basic_block.h b/src/dynarmic/src/dynarmic/ir/basic_block.h index dd978da68d..4fb28592e7 100644 --- a/src/dynarmic/src/dynarmic/ir/basic_block.h +++ b/src/dynarmic/src/dynarmic/ir/basic_block.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -23,7 +23,6 @@ #include "dynarmic/ir/microinstruction.h" #include "dynarmic/ir/terminal.h" #include "dynarmic/ir/value.h" -#include "dynarmic/ir/dense_list.h" namespace Dynarmic::IR { @@ -34,7 +33,7 @@ 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 Block final { +class alignas(4096) Block final { public: //using instruction_list_type = dense_list; using instruction_list_type = mcl::intrusive_list; @@ -51,37 +50,12 @@ public: Block(Block&&) = default; Block& operator=(Block&&) = default; - bool empty() const { return instructions.empty(); } - size_type size() const { return instructions.size(); } - - Inst& front() { return instructions.front(); } - const Inst& front() const { return instructions.front(); } - - Inst& back() { return instructions.back(); } - const Inst& back() const { return instructions.back(); } - - iterator begin() { return instructions.begin(); } - const_iterator begin() const { return instructions.begin(); } - iterator end() { return instructions.end(); } - const_iterator end() const { return instructions.end(); } - - reverse_iterator rbegin() { return instructions.rbegin(); } - const_reverse_iterator rbegin() const { return instructions.rbegin(); } - reverse_iterator rend() { return instructions.rend(); } - const_reverse_iterator rend() const { return instructions.rend(); } - - const_iterator cbegin() const { return instructions.cbegin(); } - const_iterator cend() const { return instructions.cend(); } - - const_reverse_iterator crbegin() const { return instructions.crbegin(); } - const_reverse_iterator crend() const { return instructions.crend(); } - /// 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 void AppendNewInst(const Opcode opcode, const std::initializer_list args) noexcept { - PrependNewInst(end(), opcode, args); + 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; @@ -165,9 +139,9 @@ public: inline const size_t& CycleCount() const noexcept { return cycle_count; } -private: + /// "Hot cache" for small blocks so we don't call global allocator - boost::container::static_vector inlined_inst; + boost::container::static_vector inlined_inst; /// List of instructions in this block. instruction_list_type instructions; /// "Long/far" memory pool @@ -187,7 +161,7 @@ private: /// Number of cycles this block takes to execute. size_t cycle_count = 0; }; -static_assert(sizeof(Block) == 2048); +static_assert(sizeof(Block) == 4096); /// 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/dense_list.h b/src/dynarmic/src/dynarmic/ir/dense_list.h deleted file mode 100644 index 895992170d..0000000000 --- a/src/dynarmic/src/dynarmic/ir/dense_list.h +++ /dev/null @@ -1,61 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include -#include -#include - -namespace Dynarmic { - template struct dense_list { - using difference_type = std::ptrdiff_t; - using size_type = std::size_t; - using value_type = T; - using pointer = value_type*; - using const_pointer = const value_type*; - using reference = value_type&; - using const_reference = const value_type&; - using iterator = typename std::deque::iterator; - using const_iterator = typename std::deque::const_iterator; - using reverse_iterator = typename std::reverse_iterator; - using const_reverse_iterator = typename std::reverse_iterator; - - inline bool empty() const noexcept { return list.empty(); } - inline size_type size() const noexcept { return list.size(); } - - inline value_type& front() noexcept { return list.front(); } - inline const value_type& front() const noexcept { return list.front(); } - - inline value_type& back() noexcept { return list.back(); } - inline const value_type& back() const noexcept { return list.back(); } - - inline iterator begin() noexcept { return list.begin(); } - inline const_iterator begin() const noexcept { return list.begin(); } - inline iterator end() noexcept { return list.end(); } - inline const_iterator end() const noexcept { return list.end(); } - - inline reverse_iterator rbegin() noexcept { return list.rbegin(); } - inline const_reverse_iterator rbegin() const noexcept { return list.rbegin(); } - inline reverse_iterator rend() noexcept { return list.rend(); } - inline const_reverse_iterator rend() const noexcept { return list.rend(); } - - inline const_iterator cbegin() const noexcept { return list.cbegin(); } - inline const_iterator cend() const noexcept { return list.cend(); } - - inline const_reverse_iterator crbegin() const noexcept { return list.crbegin(); } - inline const_reverse_iterator crend() const noexcept { return list.crend(); } - - inline iterator insert_before(iterator it, value_type& value) noexcept { - if (it == list.begin()) { - list.push_front(value); - return list.begin(); - } - auto const index = std::distance(list.begin(), it - 1); - list.insert(it - 1, value); - return list.begin() + index; - } - - std::deque list; - }; -} diff --git a/src/dynarmic/src/dynarmic/ir/ir_emitter.h b/src/dynarmic/src/dynarmic/ir/ir_emitter.h index 3d65a7b797..2b5c7d5cdd 100644 --- a/src/dynarmic/src/dynarmic/ir/ir_emitter.h +++ b/src/dynarmic/src/dynarmic/ir/ir_emitter.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -65,15 +65,12 @@ enum class MemOp { PREFETCH, }; -/** - * Convenience class to construct a basic block of the intermediate representation. - * `block` is the resulting block. - * The user of this class updates `current_location` as appropriate. - */ +/// @brief Convenience class to construct a basic block of the intermediate representation. +/// `block` is the resulting block. +/// The user of this class updates `current_location` as appropriate. class IREmitter { public: - explicit IREmitter(Block& block) - : block(block), insertion_point(block.end()) {} + explicit IREmitter(Block& block) : block(block), insertion_point(block.instructions.end()) {} Block& block; diff --git a/src/dynarmic/src/dynarmic/ir/opt_passes.cpp b/src/dynarmic/src/dynarmic/ir/opt_passes.cpp index c82c815cea..4929ed5e04 100644 --- a/src/dynarmic/src/dynarmic/ir/opt_passes.cpp +++ b/src/dynarmic/src/dynarmic/ir/opt_passes.cpp @@ -33,7 +33,7 @@ namespace Dynarmic::Optimization { static void ConstantMemoryReads(IR::Block& block, A32::UserCallbacks* cb) { - for (auto& inst : block) { + for (auto& inst : block.instructions) { switch (inst.GetOpcode()) { case IR::Opcode::A32ReadMemory8: case IR::Opcode::A64ReadMemory8: { @@ -131,7 +131,7 @@ static void FlagsPass(IR::Block& block) { A32::IREmitter ir{block, A32::LocationDescriptor{block.Location()}, {}}; - for (auto inst = block.rbegin(); inst != block.rend(); ++inst) { + for (auto inst = block.instructions.rbegin(); inst != block.instructions.rend(); ++inst) { auto const opcode = inst->GetOpcode(); switch (opcode) { case IR::Opcode::A32GetCFlag: { @@ -318,7 +318,7 @@ static void RegisterPass(IR::Block& block) { // Location and version don't matter here. A32::IREmitter ir{block, A32::LocationDescriptor{block.Location()}, {}}; - for (auto inst = block.begin(); inst != block.end(); ++inst) { + for (auto inst = block.instructions.begin(); inst != block.instructions.end(); ++inst) { auto const opcode = inst->GetOpcode(); switch (opcode) { case IR::Opcode::A32GetRegister: { @@ -448,7 +448,7 @@ static void A64CallbackConfigPass(IR::Block& block, const A64::UserConfig& conf) return; } - for (auto& inst : block) { + for (auto& inst : block.instructions) { if (inst.GetOpcode() != IR::Opcode::A64DataCacheOperationRaised) { continue; } @@ -541,7 +541,7 @@ static void A64GetSetElimination(IR::Block& block) { do_nothing(); }; - for (auto inst = block.begin(); inst != block.end(); ++inst) { + for (auto inst = block.instructions.begin(); inst != block.instructions.end(); ++inst) { auto const opcode = inst->GetOpcode(); switch (opcode) { case IR::Opcode::A64GetW: { @@ -1041,7 +1041,7 @@ static void FoldZeroExtendXToLong(IR::Inst& inst) { } static void ConstantPropagation(IR::Block& block) { - for (auto& inst : block) { + for (auto& inst : block.instructions) { auto const opcode = inst.GetOpcode(); switch (opcode) { case Op::LeastSignificantWord: @@ -1221,25 +1221,20 @@ static void ConstantPropagation(IR::Block& block) { static void DeadCodeElimination(IR::Block& block) { // We iterate over the instructions in reverse order. // This is because removing an instruction reduces the number of uses for earlier instructions. - for (auto it = block.rbegin(); it != block.rend(); ++it) + for (auto it = block.instructions.rbegin(); it != block.instructions.rend(); ++it) if (!it->HasUses() && !MayHaveSideEffects(it->GetOpcode())) it->Invalidate(); } static void IdentityRemovalPass(IR::Block& block) { - boost::container::small_vector to_invalidate; - for (auto it = block.begin(); it != block.end();) { - const size_t num_args = it->NumArgs(); - for (size_t i = 0; i < num_args; ++i) { - IR::Value arg = it->GetArg(i); - if (arg.IsIdentity()) { - do { - arg = arg.GetInst()->GetArg(0); - } while (arg.IsIdentity()); + boost::container::small_vector to_invalidate; + for (auto it = block.instructions.begin(); it != block.instructions.end();) { + auto const num_args = it->NumArgs(); + for (size_t i = 0; i < num_args; ++i) + if (IR::Value arg = it->GetArg(i); arg.IsIdentity()) { + do arg = arg.GetInst()->GetArg(0); while (arg.IsIdentity()); it->SetArg(i, arg); } - } - if (it->GetOpcode() == IR::Opcode::Identity || it->GetOpcode() == IR::Opcode::Void) { to_invalidate.push_back(&*it); it = block.Instructions().erase(it); @@ -1253,7 +1248,7 @@ static void IdentityRemovalPass(IR::Block& block) { static void NamingPass(IR::Block& block) { u32 name = 1; - for (auto& inst : block) + for (auto& inst : block.instructions) inst.SetName(name++); } @@ -1402,7 +1397,7 @@ static void PolyfillPass(IR::Block& block, const PolyfillOptions& polyfill) { IR::IREmitter ir{block}; - for (auto& inst : block) { + for (auto& inst : block.instructions) { ir.SetInsertionPointBefore(&inst); switch (inst.GetOpcode()) { @@ -1458,7 +1453,7 @@ static void PolyfillPass(IR::Block& block, const PolyfillOptions& polyfill) { } static void VerificationPass(const IR::Block& block) { - for (auto const& inst : block) { + for (auto const& inst : block.instructions) { for (size_t i = 0; i < inst.NumArgs(); i++) { const IR::Type t1 = inst.GetArg(i).GetType(); const IR::Type t2 = IR::GetArgTypeOf(inst.GetOpcode(), i); @@ -1466,7 +1461,7 @@ static void VerificationPass(const IR::Block& block) { } } ankerl::unordered_dense::map actual_uses; - for (auto const& inst : block) { + for (auto const& inst : block.instructions) { for (size_t i = 0; i < inst.NumArgs(); i++) if (IR::Value const arg = inst.GetArg(i); !arg.IsImmediate()) actual_uses[arg.GetInst()]++; diff --git a/src/dynarmic/tests/A32/fuzz_arm.cpp b/src/dynarmic/tests/A32/fuzz_arm.cpp index 4edc9d5bcc..b0693415bb 100644 --- a/src/dynarmic/tests/A32/fuzz_arm.cpp +++ b/src/dynarmic/tests/A32/fuzz_arm.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -93,7 +93,7 @@ bool ShouldTestInst(u32 instruction, u32 pc, bool is_thumb, bool is_last_inst, A return false; } - for (const auto& ir_inst : block) { + for (const auto& ir_inst : block.instructions) { switch (ir_inst.GetOpcode()) { case IR::Opcode::A32ExceptionRaised: case IR::Opcode::A32CallSupervisor: diff --git a/src/dynarmic/tests/A64/fuzz_with_unicorn.cpp b/src/dynarmic/tests/A64/fuzz_with_unicorn.cpp index 2e1e56a291..332806fbfb 100644 --- a/src/dynarmic/tests/A64/fuzz_with_unicorn.cpp +++ b/src/dynarmic/tests/A64/fuzz_with_unicorn.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -45,7 +45,7 @@ static bool ShouldTestInst(u32 instruction, u64 pc, bool is_last_inst) { return false; if (auto terminal = block.GetTerminal(); boost::get(&terminal)) return false; - for (const auto& ir_inst : block) { + for (const auto& ir_inst : block.instructions) { switch (ir_inst.GetOpcode()) { case IR::Opcode::A64ExceptionRaised: case IR::Opcode::A64CallSupervisor: diff --git a/src/dynarmic/tests/decoder_tests.cpp b/src/dynarmic/tests/decoder_tests.cpp index 4ad9d90833..1b406fd915 100644 --- a/src/dynarmic/tests/decoder_tests.cpp +++ b/src/dynarmic/tests/decoder_tests.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -36,9 +36,9 @@ TEST_CASE("ASIMD Decoder: Ensure table order correctness", "[decode][a32][.]") { const auto is_decode_error = [&get_ir](const A32::ASIMDMatcher& matcher, u32 instruction) { const auto block = get_ir(matcher, instruction); - return std::find_if(block.cbegin(), block.cend(), [](auto const& e) { + return std::find_if(block.instructions.cbegin(), block.instructions.cend(), [](auto const& e) { return e.GetOpcode() == IR::Opcode::A32ExceptionRaised && A32::Exception(e.GetArg(1).GetU64()) == A32::Exception::DecodeError; - }) != block.cend(); + }) != block.instructions.cend(); }; for (auto iter = table.cbegin(); iter != table.cend(); ++iter) { diff --git a/src/dynarmic/tests/test_generator.cpp b/src/dynarmic/tests/test_generator.cpp index 7330e143b6..09d24596d3 100644 --- a/src/dynarmic/tests/test_generator.cpp +++ b/src/dynarmic/tests/test_generator.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -54,7 +54,7 @@ bool ShouldTestInst(IR::Block& block) { return false; } - for (const auto& ir_inst : block) { + for (const auto& ir_inst : block.instructions) { switch (ir_inst.GetOpcode()) { // A32 case IR::Opcode::A32GetFpscr: diff --git a/src/shader_recompiler/frontend/ir/basic_block.cpp b/src/shader_recompiler/frontend/ir/basic_block.cpp index 14293770ed..68fab72b36 100644 --- a/src/shader_recompiler/frontend/ir/basic_block.cpp +++ b/src/shader_recompiler/frontend/ir/basic_block.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -16,7 +19,7 @@ Block::Block(ObjectPool& inst_pool_) : inst_pool{&inst_pool_} {} Block::~Block() = default; void Block::AppendNewInst(Opcode op, std::initializer_list args) { - PrependNewInst(end(), op, args); + PrependNewInst(instructions.end(), op, args); } Block::iterator Block::PrependNewInst(iterator insertion_point, const Inst& base_inst) {