From fdd5192ab31d1505d0d8993294175fe08b18a468 Mon Sep 17 00:00:00 2001 From: Merry Date: Fri, 3 Feb 2023 22:15:21 +0000 Subject: [PATCH] reg_alloc: Support unused values for noopt mode --- src/dynarmic/backend/arm64/emit_arm64.cpp | 14 +++++++------- src/dynarmic/backend/arm64/reg_alloc.cpp | 14 ++++++++++++-- src/dynarmic/backend/arm64/reg_alloc.h | 13 ++++++++++--- src/dynarmic/backend/x64/reg_alloc.cpp | 2 +- 4 files changed, 30 insertions(+), 13 deletions(-) diff --git a/src/dynarmic/backend/arm64/emit_arm64.cpp b/src/dynarmic/backend/arm64/emit_arm64.cpp index 05358731..df38bda2 100644 --- a/src/dynarmic/backend/arm64/emit_arm64.cpp +++ b/src/dynarmic/backend/arm64/emit_arm64.cpp @@ -52,26 +52,26 @@ void EmitIR(oaknut::CodeGenerator&, EmitContext&, IR::Inst* template<> void EmitIR(oaknut::CodeGenerator&, EmitContext& ctx, IR::Inst* inst) { [[maybe_unused]] auto args = ctx.reg_alloc.GetArgumentInfo(inst); - ASSERT(ctx.reg_alloc.IsValueLive(inst)); + ASSERT(ctx.reg_alloc.WasValueDefined(inst)); } template<> void EmitIR(oaknut::CodeGenerator&, EmitContext& ctx, IR::Inst* inst) { [[maybe_unused]] auto args = ctx.reg_alloc.GetArgumentInfo(inst); - ASSERT(ctx.reg_alloc.IsValueLive(inst)); + ASSERT(ctx.reg_alloc.WasValueDefined(inst)); } template<> void EmitIR(oaknut::CodeGenerator&, EmitContext& ctx, IR::Inst* inst) { [[maybe_unused]] auto args = ctx.reg_alloc.GetArgumentInfo(inst); - ASSERT(ctx.reg_alloc.IsValueLive(inst)); + ASSERT(ctx.reg_alloc.WasValueDefined(inst)); } template<> void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - if (ctx.reg_alloc.IsValueLive(inst)) { + if (ctx.reg_alloc.WasValueDefined(inst)) { return; } @@ -102,7 +102,7 @@ template<> void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - if (ctx.reg_alloc.IsValueLive(inst)) { + if (ctx.reg_alloc.WasValueDefined(inst)) { return; } @@ -132,13 +132,13 @@ void EmitIR(oaknut::CodeGenerator& code, EmitContext& c template<> void EmitIR(oaknut::CodeGenerator&, EmitContext& ctx, IR::Inst* inst) { [[maybe_unused]] auto args = ctx.reg_alloc.GetArgumentInfo(inst); - ASSERT(ctx.reg_alloc.IsValueLive(inst)); + ASSERT(ctx.reg_alloc.WasValueDefined(inst)); } template<> void EmitIR(oaknut::CodeGenerator&, EmitContext& ctx, IR::Inst* inst) { [[maybe_unused]] auto args = ctx.reg_alloc.GetArgumentInfo(inst); - ASSERT(ctx.reg_alloc.IsValueLive(inst)); + ASSERT(ctx.reg_alloc.WasValueDefined(inst)); } template<> diff --git a/src/dynarmic/backend/arm64/reg_alloc.cpp b/src/dynarmic/backend/arm64/reg_alloc.cpp index a8fd2ec7..9c01715e 100644 --- a/src/dynarmic/backend/arm64/reg_alloc.cpp +++ b/src/dynarmic/backend/arm64/reg_alloc.cpp @@ -140,8 +140,8 @@ RegAlloc::ArgumentInfo RegAlloc::GetArgumentInfo(IR::Inst* inst) { return ret; } -bool RegAlloc::IsValueLive(IR::Inst* inst) const { - return !!ValueLocation(inst); +bool RegAlloc::WasValueDefined(IR::Inst* inst) const { + return defined_insts.count(inst) > 0; } void RegAlloc::PrepareForCall(std::optional arg0, std::optional arg1, std::optional arg2, std::optional arg3) { @@ -189,6 +189,8 @@ void RegAlloc::PrepareForCall(std::optional arg0, } void RegAlloc::DefineAsExisting(IR::Inst* inst, Argument& arg) { + defined_insts.emplace(inst); + ASSERT(!ValueLocation(inst)); if (arg.value.IsImmediate()) { @@ -202,6 +204,8 @@ void RegAlloc::DefineAsExisting(IR::Inst* inst, Argument& arg) { } void RegAlloc::DefineAsRegister(IR::Inst* inst, oaknut::Reg reg) { + defined_insts.emplace(inst); + ASSERT(!ValueLocation(inst)); auto& info = reg.is_vector() ? fprs[reg.index()] : gprs[reg.index()]; ASSERT(info.IsCompletelyEmpty()); @@ -370,6 +374,8 @@ int RegAlloc::RealizeReadImpl(const IR::Value& value) { template int RegAlloc::RealizeWriteImpl(const IR::Inst* value) { + defined_insts.emplace(value); + ASSERT(!ValueLocation(value)); if constexpr (kind == HostLoc::Kind::Gpr) { @@ -393,6 +399,8 @@ int RegAlloc::RealizeWriteImpl(const IR::Inst* value) { template int RegAlloc::RealizeReadWriteImpl(const IR::Value& read_value, const IR::Inst* write_value) { + defined_insts.emplace(write_value); + // TODO: Move elimination const int write_loc = RealizeWriteImpl(write_value); @@ -455,6 +463,8 @@ void RegAlloc::SpillFpr(int index) { } void RegAlloc::ReadWriteFlags(Argument& read, IR::Inst* write) { + defined_insts.emplace(write); + const auto current_location = ValueLocation(read.value.GetInst()); ASSERT(current_location); diff --git a/src/dynarmic/backend/arm64/reg_alloc.h b/src/dynarmic/backend/arm64/reg_alloc.h index 6c97d4af..a280d204 100644 --- a/src/dynarmic/backend/arm64/reg_alloc.h +++ b/src/dynarmic/backend/arm64/reg_alloc.h @@ -15,6 +15,7 @@ #include #include #include +#include #include "dynarmic/backend/arm64/stack_layout.h" #include "dynarmic/ir/cond.h" @@ -95,11 +96,15 @@ public: operator T() const { return reg.value(); } - operator oaknut::WRegWsp() const requires(std::is_same_v) { + operator oaknut::WRegWsp() const + requires(std::is_same_v) + { return reg.value(); } - operator oaknut::XRegSp() const requires(std::is_same_v) { + operator oaknut::XRegSp() const + requires(std::is_same_v) + { return reg.value(); } @@ -157,7 +162,7 @@ public: : code{code}, fpsr_manager{fpsr_manager}, gpr_order{gpr_order}, fpr_order{fpr_order}, rand_gen{std::random_device{}()} {} ArgumentInfo GetArgumentInfo(IR::Inst* inst); - bool IsValueLive(IR::Inst* inst) const; + bool WasValueDefined(IR::Inst* inst) const; auto ReadX(Argument& arg) { return RAReg{*this, RWType::Read, arg.value, nullptr}; } auto ReadW(Argument& arg) { return RAReg{*this, RWType::Read, arg.value, nullptr}; } @@ -330,6 +335,8 @@ private: std::array spills; mutable std::mt19937 rand_gen; + + tsl::robin_set defined_insts; }; template diff --git a/src/dynarmic/backend/x64/reg_alloc.cpp b/src/dynarmic/backend/x64/reg_alloc.cpp index 31764398..c85551cf 100644 --- a/src/dynarmic/backend/x64/reg_alloc.cpp +++ b/src/dynarmic/backend/x64/reg_alloc.cpp @@ -275,7 +275,7 @@ RegAlloc::ArgumentInfo RegAlloc::GetArgumentInfo(IR::Inst* inst) { } void RegAlloc::RegisterPseudoOperation(IR::Inst* inst) { - ASSERT(IsValueLive(inst)); + ASSERT(IsValueLive(inst) || !inst->HasUses()); for (size_t i = 0; i < inst->NumArgs(); i++) { const IR::Value arg = inst->GetArg(i);