reg_alloc: Support unused values for noopt mode
This commit is contained in:
parent
716a2fa5fa
commit
fdd5192ab3
4 changed files with 30 additions and 13 deletions
|
@ -52,26 +52,26 @@ void EmitIR<IR::Opcode::PushRSB>(oaknut::CodeGenerator&, EmitContext&, IR::Inst*
|
||||||
template<>
|
template<>
|
||||||
void EmitIR<IR::Opcode::GetCarryFromOp>(oaknut::CodeGenerator&, EmitContext& ctx, IR::Inst* inst) {
|
void EmitIR<IR::Opcode::GetCarryFromOp>(oaknut::CodeGenerator&, EmitContext& ctx, IR::Inst* inst) {
|
||||||
[[maybe_unused]] auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
[[maybe_unused]] auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||||
ASSERT(ctx.reg_alloc.IsValueLive(inst));
|
ASSERT(ctx.reg_alloc.WasValueDefined(inst));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
void EmitIR<IR::Opcode::GetOverflowFromOp>(oaknut::CodeGenerator&, EmitContext& ctx, IR::Inst* inst) {
|
void EmitIR<IR::Opcode::GetOverflowFromOp>(oaknut::CodeGenerator&, EmitContext& ctx, IR::Inst* inst) {
|
||||||
[[maybe_unused]] auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
[[maybe_unused]] auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||||
ASSERT(ctx.reg_alloc.IsValueLive(inst));
|
ASSERT(ctx.reg_alloc.WasValueDefined(inst));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
void EmitIR<IR::Opcode::GetGEFromOp>(oaknut::CodeGenerator&, EmitContext& ctx, IR::Inst* inst) {
|
void EmitIR<IR::Opcode::GetGEFromOp>(oaknut::CodeGenerator&, EmitContext& ctx, IR::Inst* inst) {
|
||||||
[[maybe_unused]] auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
[[maybe_unused]] auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||||
ASSERT(ctx.reg_alloc.IsValueLive(inst));
|
ASSERT(ctx.reg_alloc.WasValueDefined(inst));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
void EmitIR<IR::Opcode::GetNZCVFromOp>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
|
void EmitIR<IR::Opcode::GetNZCVFromOp>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
|
||||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||||
|
|
||||||
if (ctx.reg_alloc.IsValueLive(inst)) {
|
if (ctx.reg_alloc.WasValueDefined(inst)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,7 +102,7 @@ template<>
|
||||||
void EmitIR<IR::Opcode::GetNZFromOp>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
|
void EmitIR<IR::Opcode::GetNZFromOp>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
|
||||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||||
|
|
||||||
if (ctx.reg_alloc.IsValueLive(inst)) {
|
if (ctx.reg_alloc.WasValueDefined(inst)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,13 +132,13 @@ void EmitIR<IR::Opcode::GetNZFromOp>(oaknut::CodeGenerator& code, EmitContext& c
|
||||||
template<>
|
template<>
|
||||||
void EmitIR<IR::Opcode::GetUpperFromOp>(oaknut::CodeGenerator&, EmitContext& ctx, IR::Inst* inst) {
|
void EmitIR<IR::Opcode::GetUpperFromOp>(oaknut::CodeGenerator&, EmitContext& ctx, IR::Inst* inst) {
|
||||||
[[maybe_unused]] auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
[[maybe_unused]] auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||||
ASSERT(ctx.reg_alloc.IsValueLive(inst));
|
ASSERT(ctx.reg_alloc.WasValueDefined(inst));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
void EmitIR<IR::Opcode::GetLowerFromOp>(oaknut::CodeGenerator&, EmitContext& ctx, IR::Inst* inst) {
|
void EmitIR<IR::Opcode::GetLowerFromOp>(oaknut::CodeGenerator&, EmitContext& ctx, IR::Inst* inst) {
|
||||||
[[maybe_unused]] auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
[[maybe_unused]] auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||||
ASSERT(ctx.reg_alloc.IsValueLive(inst));
|
ASSERT(ctx.reg_alloc.WasValueDefined(inst));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
|
|
|
@ -140,8 +140,8 @@ RegAlloc::ArgumentInfo RegAlloc::GetArgumentInfo(IR::Inst* inst) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RegAlloc::IsValueLive(IR::Inst* inst) const {
|
bool RegAlloc::WasValueDefined(IR::Inst* inst) const {
|
||||||
return !!ValueLocation(inst);
|
return defined_insts.count(inst) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegAlloc::PrepareForCall(std::optional<Argument::copyable_reference> arg0, std::optional<Argument::copyable_reference> arg1, std::optional<Argument::copyable_reference> arg2, std::optional<Argument::copyable_reference> arg3) {
|
void RegAlloc::PrepareForCall(std::optional<Argument::copyable_reference> arg0, std::optional<Argument::copyable_reference> arg1, std::optional<Argument::copyable_reference> arg2, std::optional<Argument::copyable_reference> arg3) {
|
||||||
|
@ -189,6 +189,8 @@ void RegAlloc::PrepareForCall(std::optional<Argument::copyable_reference> arg0,
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegAlloc::DefineAsExisting(IR::Inst* inst, Argument& arg) {
|
void RegAlloc::DefineAsExisting(IR::Inst* inst, Argument& arg) {
|
||||||
|
defined_insts.emplace(inst);
|
||||||
|
|
||||||
ASSERT(!ValueLocation(inst));
|
ASSERT(!ValueLocation(inst));
|
||||||
|
|
||||||
if (arg.value.IsImmediate()) {
|
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) {
|
void RegAlloc::DefineAsRegister(IR::Inst* inst, oaknut::Reg reg) {
|
||||||
|
defined_insts.emplace(inst);
|
||||||
|
|
||||||
ASSERT(!ValueLocation(inst));
|
ASSERT(!ValueLocation(inst));
|
||||||
auto& info = reg.is_vector() ? fprs[reg.index()] : gprs[reg.index()];
|
auto& info = reg.is_vector() ? fprs[reg.index()] : gprs[reg.index()];
|
||||||
ASSERT(info.IsCompletelyEmpty());
|
ASSERT(info.IsCompletelyEmpty());
|
||||||
|
@ -370,6 +374,8 @@ int RegAlloc::RealizeReadImpl(const IR::Value& value) {
|
||||||
|
|
||||||
template<HostLoc::Kind kind>
|
template<HostLoc::Kind kind>
|
||||||
int RegAlloc::RealizeWriteImpl(const IR::Inst* value) {
|
int RegAlloc::RealizeWriteImpl(const IR::Inst* value) {
|
||||||
|
defined_insts.emplace(value);
|
||||||
|
|
||||||
ASSERT(!ValueLocation(value));
|
ASSERT(!ValueLocation(value));
|
||||||
|
|
||||||
if constexpr (kind == HostLoc::Kind::Gpr) {
|
if constexpr (kind == HostLoc::Kind::Gpr) {
|
||||||
|
@ -393,6 +399,8 @@ int RegAlloc::RealizeWriteImpl(const IR::Inst* value) {
|
||||||
|
|
||||||
template<HostLoc::Kind kind>
|
template<HostLoc::Kind kind>
|
||||||
int RegAlloc::RealizeReadWriteImpl(const IR::Value& read_value, const IR::Inst* write_value) {
|
int RegAlloc::RealizeReadWriteImpl(const IR::Value& read_value, const IR::Inst* write_value) {
|
||||||
|
defined_insts.emplace(write_value);
|
||||||
|
|
||||||
// TODO: Move elimination
|
// TODO: Move elimination
|
||||||
|
|
||||||
const int write_loc = RealizeWriteImpl<kind>(write_value);
|
const int write_loc = RealizeWriteImpl<kind>(write_value);
|
||||||
|
@ -455,6 +463,8 @@ void RegAlloc::SpillFpr(int index) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegAlloc::ReadWriteFlags(Argument& read, IR::Inst* write) {
|
void RegAlloc::ReadWriteFlags(Argument& read, IR::Inst* write) {
|
||||||
|
defined_insts.emplace(write);
|
||||||
|
|
||||||
const auto current_location = ValueLocation(read.value.GetInst());
|
const auto current_location = ValueLocation(read.value.GetInst());
|
||||||
ASSERT(current_location);
|
ASSERT(current_location);
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include <mcl/stdint.hpp>
|
#include <mcl/stdint.hpp>
|
||||||
#include <mcl/type_traits/is_instance_of_template.hpp>
|
#include <mcl/type_traits/is_instance_of_template.hpp>
|
||||||
#include <oaknut/oaknut.hpp>
|
#include <oaknut/oaknut.hpp>
|
||||||
|
#include <tsl/robin_set.h>
|
||||||
|
|
||||||
#include "dynarmic/backend/arm64/stack_layout.h"
|
#include "dynarmic/backend/arm64/stack_layout.h"
|
||||||
#include "dynarmic/ir/cond.h"
|
#include "dynarmic/ir/cond.h"
|
||||||
|
@ -95,11 +96,15 @@ public:
|
||||||
|
|
||||||
operator T() const { return reg.value(); }
|
operator T() const { return reg.value(); }
|
||||||
|
|
||||||
operator oaknut::WRegWsp() const requires(std::is_same_v<T, oaknut::WReg>) {
|
operator oaknut::WRegWsp() const
|
||||||
|
requires(std::is_same_v<T, oaknut::WReg>)
|
||||||
|
{
|
||||||
return reg.value();
|
return reg.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
operator oaknut::XRegSp() const requires(std::is_same_v<T, oaknut::XReg>) {
|
operator oaknut::XRegSp() const
|
||||||
|
requires(std::is_same_v<T, oaknut::XReg>)
|
||||||
|
{
|
||||||
return reg.value();
|
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{}()} {}
|
: code{code}, fpsr_manager{fpsr_manager}, gpr_order{gpr_order}, fpr_order{fpr_order}, rand_gen{std::random_device{}()} {}
|
||||||
|
|
||||||
ArgumentInfo GetArgumentInfo(IR::Inst* inst);
|
ArgumentInfo GetArgumentInfo(IR::Inst* inst);
|
||||||
bool IsValueLive(IR::Inst* inst) const;
|
bool WasValueDefined(IR::Inst* inst) const;
|
||||||
|
|
||||||
auto ReadX(Argument& arg) { return RAReg<oaknut::XReg>{*this, RWType::Read, arg.value, nullptr}; }
|
auto ReadX(Argument& arg) { return RAReg<oaknut::XReg>{*this, RWType::Read, arg.value, nullptr}; }
|
||||||
auto ReadW(Argument& arg) { return RAReg<oaknut::WReg>{*this, RWType::Read, arg.value, nullptr}; }
|
auto ReadW(Argument& arg) { return RAReg<oaknut::WReg>{*this, RWType::Read, arg.value, nullptr}; }
|
||||||
|
@ -330,6 +335,8 @@ private:
|
||||||
std::array<HostLocInfo, SpillCount> spills;
|
std::array<HostLocInfo, SpillCount> spills;
|
||||||
|
|
||||||
mutable std::mt19937 rand_gen;
|
mutable std::mt19937 rand_gen;
|
||||||
|
|
||||||
|
tsl::robin_set<IR::Inst*> defined_insts;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
|
|
@ -275,7 +275,7 @@ RegAlloc::ArgumentInfo RegAlloc::GetArgumentInfo(IR::Inst* inst) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegAlloc::RegisterPseudoOperation(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++) {
|
for (size_t i = 0; i < inst->NumArgs(); i++) {
|
||||||
const IR::Value arg = inst->GetArg(i);
|
const IR::Value arg = inst->GetArg(i);
|
||||||
|
|
Loading…
Reference in a new issue