From 429a7f6fe96f75a4a513f5a7179e31b9df32f2ef Mon Sep 17 00:00:00 2001 From: Yang Liu Date: Thu, 4 Jun 2026 15:13:08 +0800 Subject: [PATCH] [dynarmic,loongarch] addressing Lizzie comments --- .../dynarmic/backend/loongarch64/code_block.h | 2 +- .../backend/loongarch64/emit_loongarch64.h | 2 +- .../backend/loongarch64/reg_alloc.cpp | 151 +++++++++--------- .../dynarmic/backend/loongarch64/reg_alloc.h | 33 ++-- 4 files changed, 95 insertions(+), 93 deletions(-) diff --git a/src/dynarmic/src/dynarmic/backend/loongarch64/code_block.h b/src/dynarmic/src/dynarmic/backend/loongarch64/code_block.h index bedf8a6db4..133d748c41 100644 --- a/src/dynarmic/src/dynarmic/backend/loongarch64/code_block.h +++ b/src/dynarmic/src/dynarmic/backend/loongarch64/code_block.h @@ -20,7 +20,7 @@ public: explicit CodeBlock(std::size_t size) noexcept : memsize(size) { mem = static_cast(mmap(nullptr, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | MAP_PRIVATE, -1, 0)); - ASSERT(mem != nullptr); + ASSERT(mem != MAP_FAILED); la_init_assembler(&as, mem, size); } diff --git a/src/dynarmic/src/dynarmic/backend/loongarch64/emit_loongarch64.h b/src/dynarmic/src/dynarmic/backend/loongarch64/emit_loongarch64.h index 5e8b9192e0..c66d357957 100644 --- a/src/dynarmic/src/dynarmic/backend/loongarch64/emit_loongarch64.h +++ b/src/dynarmic/src/dynarmic/backend/loongarch64/emit_loongarch64.h @@ -37,10 +37,10 @@ struct Relocation { }; struct EmittedBlockInfo { + std::vector relocations; CodePtr entry_point; size_t size; size_t cycle_count; - std::vector relocations; }; struct EmitConfig {}; diff --git a/src/dynarmic/src/dynarmic/backend/loongarch64/reg_alloc.cpp b/src/dynarmic/src/dynarmic/backend/loongarch64/reg_alloc.cpp index 64af8503ee..5ff7edb6a8 100644 --- a/src/dynarmic/src/dynarmic/backend/loongarch64/reg_alloc.cpp +++ b/src/dynarmic/src/dynarmic/backend/loongarch64/reg_alloc.cpp @@ -5,6 +5,7 @@ #include #include +#include #include "dynarmic/backend/loongarch64/lagoon_cpp.h" @@ -82,7 +83,7 @@ void HostLocInfo::SetupScratchLocation() { } bool HostLocInfo::IsCompletelyEmpty() const { - return values.empty() && !locked && !realized && !accumulated_uses && !expected_uses && !uses_this_inst; + return values.empty() && !locked && !accumulated_uses && !expected_uses && !uses_this_inst && !realized; } void HostLocInfo::UpdateUses() { @@ -97,7 +98,7 @@ void HostLocInfo::UpdateUses() { } RegAlloc::ArgumentInfo RegAlloc::GetArgumentInfo(IR::Inst* inst) { - ArgumentInfo ret = {Argument{*this}, Argument{*this}, Argument{*this}, Argument{*this}}; + ArgumentInfo ret = {Argument{}, Argument{}, Argument{}, Argument{}}; for (size_t i = 0; i < inst->NumArgs(); i++) { const IR::Value arg = inst->GetArg(i); ret[i].value = arg; @@ -114,14 +115,8 @@ bool RegAlloc::IsValueLive(IR::Inst* inst) const { } void RegAlloc::UpdateAllUses() { - for (auto& gpr : gprs) { - gpr.UpdateUses(); - } - for (auto& fpr : fprs) { - fpr.UpdateUses(); - } - for (auto& spill : spills) { - spill.UpdateUses(); + for (auto& info : hostloc_info) { + info.UpdateUses(); } } @@ -141,17 +136,15 @@ void RegAlloc::DefineAsExisting(IR::Inst* inst, Argument& arg) { void RegAlloc::AssertNoMoreUses() const { // TODO: Re-enable this assert once all register allocation issues are fixed // const auto is_empty = [](const auto& i) { return i.IsCompletelyEmpty(); }; - // ASSERT(std::all_of(gprs.begin(), gprs.end(), is_empty)); - // ASSERT(std::all_of(fprs.begin(), fprs.end(), is_empty)); - // ASSERT(std::all_of(spills.begin(), spills.end(), is_empty)); + // ASSERT(std::all_of(hostloc_info.begin(), hostloc_info.end(), is_empty)); } template u32 RegAlloc::GenerateImmediate(const IR::Value& value) { if constexpr (kind == HostLoc::Kind::Gpr) { - const u32 new_location_index = AllocateRegister(gprs, gpr_order); + const u32 new_location_index = AllocateRegister(gpr_order, GprOffset); SpillGpr(new_location_index); - gprs[new_location_index].SetupScratchLocation(); + hostloc_info[GprOffset + new_location_index].SetupScratchLocation(); la_load_immediate64(&as, static_cast(new_location_index), static_cast(value.GetImmediateAsU64())); @@ -183,7 +176,7 @@ u32 RegAlloc::RealizeReadImpl(const IR::Value& value) { ASSERT(!ValueInfo(*current_location).locked); if constexpr (required_kind == HostLoc::Kind::Gpr) { - const u32 new_location_index = AllocateRegister(gprs, gpr_order); + const u32 new_location_index = AllocateRegister(gpr_order, GprOffset); SpillGpr(new_location_index); switch (current_location->kind) { @@ -199,11 +192,11 @@ u32 RegAlloc::RealizeReadImpl(const IR::Value& value) { break; } - gprs[new_location_index] = std::exchange(ValueInfo(*current_location), {}); - gprs[new_location_index].realized = true; + hostloc_info[GprOffset + new_location_index] = std::exchange(ValueInfo(*current_location), {}); + hostloc_info[GprOffset + new_location_index].realized = true; return new_location_index; } else if constexpr (required_kind == HostLoc::Kind::Fpr) { - const u32 new_location_index = AllocateRegister(fprs, fpr_order); + const u32 new_location_index = AllocateRegister(fpr_order, FprOffset); SpillFpr(new_location_index); switch (current_location->kind) { @@ -219,27 +212,26 @@ u32 RegAlloc::RealizeReadImpl(const IR::Value& value) { break; } - fprs[new_location_index] = std::exchange(ValueInfo(*current_location), {}); - fprs[new_location_index].realized = true; + hostloc_info[FprOffset + new_location_index] = std::exchange(ValueInfo(*current_location), {}); + hostloc_info[FprOffset + new_location_index].realized = true; return new_location_index; } else { UNREACHABLE(); } } -template -u32 RegAlloc::RealizeWriteImpl(const IR::Inst* value) { +u32 RegAlloc::RealizeWriteImpl(const IR::Inst* value, HostLoc::Kind required_kind) { if (value == nullptr) { // Scratch register allocation - if constexpr (required_kind == HostLoc::Kind::Gpr) { - const u32 idx = AllocateRegister(gprs, gpr_order); + if (required_kind == HostLoc::Kind::Gpr) { + const u32 idx = AllocateRegister(gpr_order, GprOffset); SpillGpr(idx); - gprs[idx].SetupScratchLocation(); + hostloc_info[GprOffset + idx].SetupScratchLocation(); return idx; - } else if constexpr (required_kind == HostLoc::Kind::Fpr) { - const u32 idx = AllocateRegister(fprs, fpr_order); + } else if (required_kind == HostLoc::Kind::Fpr) { + const u32 idx = AllocateRegister(fpr_order, FprOffset); SpillFpr(idx); - fprs[idx].SetupScratchLocation(); + hostloc_info[FprOffset + idx].SetupScratchLocation(); return idx; } } @@ -254,15 +246,15 @@ u32 RegAlloc::RealizeWriteImpl(const IR::Inst* value) { info.expected_uses = value->UseCount(); }; - if constexpr (required_kind == HostLoc::Kind::Gpr) { - const u32 new_location_index = AllocateRegister(gprs, gpr_order); + if (required_kind == HostLoc::Kind::Gpr) { + const u32 new_location_index = AllocateRegister(gpr_order, GprOffset); SpillGpr(new_location_index); - setup_location(gprs[new_location_index]); + setup_location(hostloc_info[GprOffset + new_location_index]); return new_location_index; - } else if constexpr (required_kind == HostLoc::Kind::Fpr) { - const u32 new_location_index = AllocateRegister(fprs, fpr_order); + } else if (required_kind == HostLoc::Kind::Fpr) { + const u32 new_location_index = AllocateRegister(fpr_order, FprOffset); SpillFpr(new_location_index); - setup_location(fprs[new_location_index]); + setup_location(hostloc_info[FprOffset + new_location_index]); return new_location_index; } else { UNREACHABLE(); @@ -271,61 +263,79 @@ u32 RegAlloc::RealizeWriteImpl(const IR::Inst* value) { template u32 RegAlloc::RealizeReadImpl(const IR::Value& value); template u32 RegAlloc::RealizeReadImpl(const IR::Value& value); -template u32 RegAlloc::RealizeWriteImpl(const IR::Inst* value); -template u32 RegAlloc::RealizeWriteImpl(const IR::Inst* value); -u32 RegAlloc::AllocateRegister(const std::array& regs, const std::vector& order) const { - const auto empty = std::find_if(order.begin(), order.end(), [&](u32 i) { return regs[i].values.empty() && !regs[i].locked; }); +u32 RegAlloc::AllocateRegister(const std::vector& order, size_t base_offset) { + const auto empty = std::find_if(order.begin(), order.end(), [&](u32 i) { + auto& info = hostloc_info[base_offset + i]; + return info.values.empty() && !info.locked; + }); if (empty != order.end()) { return *empty; } std::vector candidates; - std::copy_if(order.begin(), order.end(), std::back_inserter(candidates), [&](u32 i) { return !regs[i].locked; }); + std::copy_if(order.begin(), order.end(), std::back_inserter(candidates), [&](u32 i) { + return !hostloc_info[base_offset + i].locked; + }); + ASSERT(!candidates.empty()); - // TODO: LRU - std::uniform_int_distribution dis{0, candidates.size() - 1}; - return candidates[dis(rand_gen)]; + u32 best = candidates[0]; + size_t min_lru = hostloc_info[base_offset + best].lru_counter; + for (size_t i = 1; i < candidates.size(); ++i) { + auto& info = hostloc_info[base_offset + candidates[i]]; + if (info.lru_counter < min_lru) { + min_lru = info.lru_counter; + best = candidates[i]; + } + } + hostloc_info[base_offset + best].lru_counter++; + return best; } void RegAlloc::SpillGpr(u32 index) { - ASSERT(!gprs[index].locked && !gprs[index].realized); - if (gprs[index].values.empty()) { + auto& gpr_info = hostloc_info[GprOffset + index]; + ASSERT(!gpr_info.locked && !gpr_info.realized); + if (gpr_info.values.empty()) { return; } const u32 new_location_index = FindFreeSpill(); la_st_d(&as, static_cast(index), LA_SP, static_cast(spill_offset + new_location_index * spill_slot_size)); - spills[new_location_index] = std::exchange(gprs[index], {}); + hostloc_info[SpillOffset + new_location_index] = std::exchange(gpr_info, {}); } void RegAlloc::SpillFpr(u32 index) { - ASSERT(!fprs[index].locked && !fprs[index].realized); - if (fprs[index].values.empty()) { + auto& fpr_info = hostloc_info[FprOffset + index]; + ASSERT(!fpr_info.locked && !fpr_info.realized); + if (fpr_info.values.empty()) { return; } const u32 new_location_index = FindFreeSpill(); la_fst_d(&as, static_cast(index), LA_SP, static_cast(spill_offset + new_location_index * spill_slot_size)); - spills[new_location_index] = std::exchange(fprs[index], {}); + hostloc_info[SpillOffset + new_location_index] = std::exchange(fpr_info, {}); } u32 RegAlloc::FindFreeSpill() const { - const auto iter = std::find_if(spills.begin(), spills.end(), [](const HostLocInfo& info) { return info.values.empty(); }); - ASSERT(iter != spills.end() && "All spill locations are full"); - return static_cast(iter - spills.begin()); + for (size_t i = 0; i < SpillCount; ++i) { + if (hostloc_info[SpillOffset + i].values.empty()) { + return static_cast(i); + } + } + UNREACHABLE(); } std::optional RegAlloc::ValueLocation(const IR::Inst* value) const { - const auto contains_value = [value](const HostLocInfo& info) { - return info.Contains(value); - }; - if (const auto iter = std::find_if(gprs.begin(), gprs.end(), contains_value); iter != gprs.end()) { - return HostLoc{HostLoc::Kind::Gpr, static_cast(iter - gprs.begin())}; - } else if (const auto iter = std::find_if(fprs.begin(), fprs.end(), contains_value); iter != fprs.end()) { - return HostLoc{HostLoc::Kind::Fpr, static_cast(iter - fprs.begin())}; - } else if (const auto iter = std::find_if(spills.begin(), spills.end(), contains_value); iter != spills.end()) { - return HostLoc{HostLoc::Kind::Spill, static_cast(iter - spills.begin())}; + for (size_t i = 0; i < hostloc_info.size(); ++i) { + if (hostloc_info[i].Contains(value)) { + if (i < GprCount) { + return HostLoc{HostLoc::Kind::Gpr, static_cast(i)}; + } else if (i < GprCount + FprCount) { + return HostLoc{HostLoc::Kind::Fpr, static_cast(i - GprCount)}; + } else { + return HostLoc{HostLoc::Kind::Spill, static_cast(i - GprCount - FprCount)}; + } + } } return std::nullopt; } @@ -333,25 +343,20 @@ std::optional RegAlloc::ValueLocation(const IR::Inst* value) const { HostLocInfo& RegAlloc::ValueInfo(HostLoc host_loc) { switch (host_loc.kind) { case HostLoc::Kind::Gpr: - return gprs[size_t(host_loc.index)]; + return hostloc_info[GprOffset + host_loc.index]; case HostLoc::Kind::Fpr: - return fprs[size_t(host_loc.index)]; + return hostloc_info[FprOffset + host_loc.index]; case HostLoc::Kind::Spill: - return spills[size_t(host_loc.index)]; + return hostloc_info[SpillOffset + host_loc.index]; } UNREACHABLE(); } HostLocInfo& RegAlloc::ValueInfo(const IR::Inst* value) { - const auto contains_value = [value](const HostLocInfo& info) { - return info.Contains(value); - }; - if (const auto iter = std::find_if(gprs.begin(), gprs.end(), contains_value); iter != gprs.end()) { - return *iter; - } else if (const auto iter = std::find_if(fprs.begin(), fprs.end(), contains_value); iter != fprs.end()) { - return *iter; - } else if (const auto iter = std::find_if(spills.begin(), spills.end(), contains_value); iter != spills.end()) { - return *iter; + for (auto& info : hostloc_info) { + if (info.Contains(value)) { + return info; + } } UNREACHABLE(); } diff --git a/src/dynarmic/src/dynarmic/backend/loongarch64/reg_alloc.h b/src/dynarmic/src/dynarmic/backend/loongarch64/reg_alloc.h index 57a7d72b0f..f3c5ff881b 100644 --- a/src/dynarmic/src/dynarmic/backend/loongarch64/reg_alloc.h +++ b/src/dynarmic/src/dynarmic/backend/loongarch64/reg_alloc.h @@ -5,7 +5,6 @@ #include #include -#include #include #include @@ -73,12 +72,10 @@ public: private: friend class RegAlloc; - explicit Argument(RegAlloc& reg_alloc) - : reg_alloc{reg_alloc} {} + explicit Argument() {} - bool allocated = false; - RegAlloc& reg_alloc; IR::Value value; + bool allocated = false; }; template @@ -111,10 +108,11 @@ private: struct HostLocInfo final { std::vector values; size_t locked = 0; - bool realized = false; size_t uses_this_inst = 0; size_t accumulated_uses = 0; size_t expected_uses = 0; + bool realized = false; + size_t lru_counter = 0; bool Contains(const IR::Inst*) const; void SetupScratchLocation(); @@ -127,7 +125,7 @@ public: using ArgumentInfo = std::array; explicit RegAlloc(lagoon_assembler_t& as, std::vector gpr_order, std::vector fpr_order) - : as{as}, gpr_order{gpr_order}, fpr_order{fpr_order}, rand_gen{std::random_device{}()} {} + : as{as}, gpr_order{std::move(gpr_order)}, fpr_order{std::move(fpr_order)} {} ArgumentInfo GetArgumentInfo(IR::Inst* inst); bool IsValueLive(IR::Inst* inst) const; @@ -146,8 +144,6 @@ public: void DefineAsExisting(IR::Inst* inst, Argument& arg); - void SpillAll(); - template static void Realize(Ts&... rs) { static_assert((mcl::is_instance_of_template() && ...)); @@ -165,10 +161,9 @@ private: u32 GenerateImmediate(const IR::Value& value); template u32 RealizeReadImpl(const IR::Value& value); - template - u32 RealizeWriteImpl(const IR::Inst* value); + u32 RealizeWriteImpl(const IR::Inst* value, HostLoc::Kind required_kind); - u32 AllocateRegister(const std::array& regs, const std::vector& order) const; + u32 AllocateRegister(const std::vector& order, size_t base_offset); void SpillGpr(u32 index); void SpillFpr(u32 index); u32 FindFreeSpill() const; @@ -181,11 +176,13 @@ private: std::vector gpr_order; std::vector fpr_order; - std::array gprs; - std::array fprs; - std::array spills; + static constexpr size_t GprCount = 32; + static constexpr size_t FprCount = 32; + static constexpr size_t GprOffset = 0; + static constexpr size_t FprOffset = GprCount; + static constexpr size_t SpillOffset = GprCount + FprCount; - mutable std::mt19937 rand_gen; + std::array hostloc_info; }; template @@ -226,9 +223,9 @@ RAReg::~RAReg() { template void RAReg::Realize() { if (write && value.IsEmpty()) { - reg = T{reg_alloc.RealizeWriteImpl(nullptr)}; + reg = T{reg_alloc.RealizeWriteImpl(nullptr, kind)}; } else { - reg = T{write ? reg_alloc.RealizeWriteImpl(value.GetInst()) : reg_alloc.RealizeReadImpl(value)}; + reg = T{write ? reg_alloc.RealizeWriteImpl(value.GetInst(), kind) : reg_alloc.RealizeReadImpl(value)}; } }