glasm: Fix register allocation when moving immediate on GLASM
This commit is contained in:
parent
0839e46736
commit
deda89372f
3 changed files with 92 additions and 45 deletions
|
@ -39,14 +39,16 @@ struct Identity {
|
||||||
};
|
};
|
||||||
|
|
||||||
template <bool scalar>
|
template <bool scalar>
|
||||||
struct RegWrapper {
|
class RegWrapper {
|
||||||
RegWrapper(EmitContext& ctx, Value value)
|
public:
|
||||||
: reg_alloc{ctx.reg_alloc}, allocated{value.type != Type::Register} {
|
RegWrapper(EmitContext& ctx, const IR::Value& ir_value) : reg_alloc{ctx.reg_alloc} {
|
||||||
if (allocated) {
|
const Value value{reg_alloc.Peek(ir_value)};
|
||||||
|
if (value.type == Type::Register) {
|
||||||
|
inst = ir_value.InstRecursive();
|
||||||
|
reg = Register{value};
|
||||||
|
} else {
|
||||||
const bool is_long{value.type == Type::F64 || value.type == Type::U64};
|
const bool is_long{value.type == Type::F64 || value.type == Type::U64};
|
||||||
reg = is_long ? reg_alloc.AllocLongReg() : reg_alloc.AllocReg();
|
reg = is_long ? reg_alloc.AllocLongReg() : reg_alloc.AllocReg();
|
||||||
} else {
|
|
||||||
reg = Register{value};
|
|
||||||
}
|
}
|
||||||
switch (value.type) {
|
switch (value.type) {
|
||||||
case Type::Register:
|
case Type::Register:
|
||||||
|
@ -68,8 +70,11 @@ struct RegWrapper {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
~RegWrapper() {
|
~RegWrapper() {
|
||||||
if (allocated) {
|
if (inst) {
|
||||||
|
reg_alloc.Unref(*inst);
|
||||||
|
} else {
|
||||||
reg_alloc.FreeReg(reg);
|
reg_alloc.FreeReg(reg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,19 +83,42 @@ struct RegWrapper {
|
||||||
return std::conditional_t<scalar, ScalarRegister, Register>{Value{reg}};
|
return std::conditional_t<scalar, ScalarRegister, Register>{Value{reg}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
RegAlloc& reg_alloc;
|
RegAlloc& reg_alloc;
|
||||||
|
IR::Inst* inst{};
|
||||||
Register reg{};
|
Register reg{};
|
||||||
bool allocated{};
|
};
|
||||||
|
|
||||||
|
template <typename ArgType>
|
||||||
|
class ValueWrapper {
|
||||||
|
public:
|
||||||
|
ValueWrapper(EmitContext& ctx, const IR::Value& ir_value_)
|
||||||
|
: reg_alloc{ctx.reg_alloc}, ir_value{ir_value_}, value{reg_alloc.Peek(ir_value)} {}
|
||||||
|
|
||||||
|
~ValueWrapper() {
|
||||||
|
if (!ir_value.IsImmediate()) {
|
||||||
|
reg_alloc.Unref(*ir_value.InstRecursive());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ArgType Extract() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
RegAlloc& reg_alloc;
|
||||||
|
const IR::Value& ir_value;
|
||||||
|
ArgType value;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename ArgType>
|
template <typename ArgType>
|
||||||
auto Arg(EmitContext& ctx, const IR::Value& arg) {
|
auto Arg(EmitContext& ctx, const IR::Value& arg) {
|
||||||
if constexpr (std::is_same_v<ArgType, Register>) {
|
if constexpr (std::is_same_v<ArgType, Register>) {
|
||||||
return RegWrapper<false>{ctx, ctx.reg_alloc.Consume(arg)};
|
return RegWrapper<false>{ctx, arg};
|
||||||
} else if constexpr (std::is_same_v<ArgType, ScalarRegister>) {
|
} else if constexpr (std::is_same_v<ArgType, ScalarRegister>) {
|
||||||
return RegWrapper<true>{ctx, ctx.reg_alloc.Consume(arg)};
|
return RegWrapper<true>{ctx, arg};
|
||||||
} else if constexpr (std::is_base_of_v<Value, ArgType>) {
|
} else if constexpr (std::is_base_of_v<Value, ArgType>) {
|
||||||
return Identity{ArgType{ctx.reg_alloc.Consume(arg)}};
|
return ValueWrapper<ArgType>{ctx, arg};
|
||||||
} else if constexpr (std::is_same_v<ArgType, const IR::Value&>) {
|
} else if constexpr (std::is_same_v<ArgType, const IR::Value&>) {
|
||||||
return Identity{arg};
|
return Identity{arg};
|
||||||
} else if constexpr (std::is_same_v<ArgType, u32>) {
|
} else if constexpr (std::is_same_v<ArgType, u32>) {
|
||||||
|
|
|
@ -21,10 +21,40 @@ Register RegAlloc::LongDefine(IR::Inst& inst) {
|
||||||
return Define(inst, true);
|
return Define(inst, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Value RegAlloc::Peek(const IR::Value& value) {
|
||||||
|
return value.IsImmediate() ? MakeImm(value) : PeekInst(*value.InstRecursive());
|
||||||
|
}
|
||||||
|
|
||||||
Value RegAlloc::Consume(const IR::Value& value) {
|
Value RegAlloc::Consume(const IR::Value& value) {
|
||||||
if (!value.IsImmediate()) {
|
return value.IsImmediate() ? MakeImm(value) : ConsumeInst(*value.InstRecursive());
|
||||||
return Consume(*value.InstRecursive());
|
}
|
||||||
|
|
||||||
|
void RegAlloc::Unref(IR::Inst& inst) {
|
||||||
|
inst.DestructiveRemoveUsage();
|
||||||
|
if (!inst.HasUses()) {
|
||||||
|
Free(inst.Definition<Id>());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Register RegAlloc::AllocReg() {
|
||||||
|
Register ret;
|
||||||
|
ret.type = Type::Register;
|
||||||
|
ret.id = Alloc(false);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Register RegAlloc::AllocLongReg() {
|
||||||
|
Register ret;
|
||||||
|
ret.type = Type::Register;
|
||||||
|
ret.id = Alloc(true);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegAlloc::FreeReg(Register reg) {
|
||||||
|
Free(reg.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
Value RegAlloc::MakeImm(const IR::Value& value) {
|
||||||
Value ret;
|
Value ret;
|
||||||
switch (value.Type()) {
|
switch (value.Type()) {
|
||||||
case IR::Type::U1:
|
case IR::Type::U1:
|
||||||
|
@ -53,45 +83,26 @@ Value RegAlloc::Consume(const IR::Value& value) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
Register RegAlloc::AllocReg() {
|
|
||||||
Register ret;
|
|
||||||
ret.type = Type::Register;
|
|
||||||
ret.id = Alloc(false);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
Register RegAlloc::AllocLongReg() {
|
|
||||||
Register ret;
|
|
||||||
ret.type = Type::Register;
|
|
||||||
ret.id = Alloc(true);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RegAlloc::FreeReg(Register reg) {
|
|
||||||
Free(reg.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
Register RegAlloc::Define(IR::Inst& inst, bool is_long) {
|
Register RegAlloc::Define(IR::Inst& inst, bool is_long) {
|
||||||
const Id id{Alloc(is_long)};
|
inst.SetDefinition<Id>(Alloc(is_long));
|
||||||
inst.SetDefinition<Id>(id);
|
return Register{PeekInst(inst)};
|
||||||
Register ret;
|
|
||||||
ret.type = Type::Register;
|
|
||||||
ret.id = id;
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Value RegAlloc::Consume(IR::Inst& inst) {
|
Value RegAlloc::PeekInst(IR::Inst& inst) {
|
||||||
const Id id{inst.Definition<Id>()};
|
|
||||||
inst.DestructiveRemoveUsage();
|
|
||||||
if (!inst.HasUses()) {
|
|
||||||
Free(id);
|
|
||||||
}
|
|
||||||
Value ret;
|
Value ret;
|
||||||
ret.type = Type::Register;
|
ret.type = Type::Register;
|
||||||
ret.id = id;
|
ret.id = inst.Definition<Id>();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Value RegAlloc::ConsumeInst(IR::Inst& inst) {
|
||||||
|
inst.DestructiveRemoveUsage();
|
||||||
|
if (!inst.HasUses()) {
|
||||||
|
Free(inst.Definition<Id>());
|
||||||
|
}
|
||||||
|
return PeekInst(inst);
|
||||||
|
}
|
||||||
|
|
||||||
Id RegAlloc::Alloc(bool is_long) {
|
Id RegAlloc::Alloc(bool is_long) {
|
||||||
size_t& num_regs{is_long ? num_used_long_registers : num_used_registers};
|
size_t& num_regs{is_long ? num_used_long_registers : num_used_registers};
|
||||||
std::bitset<NUM_REGS>& use{is_long ? long_register_use : register_use};
|
std::bitset<NUM_REGS>& use{is_long ? long_register_use : register_use};
|
||||||
|
|
|
@ -99,8 +99,12 @@ public:
|
||||||
|
|
||||||
Register LongDefine(IR::Inst& inst);
|
Register LongDefine(IR::Inst& inst);
|
||||||
|
|
||||||
|
[[nodiscard]] Value Peek(const IR::Value& value);
|
||||||
|
|
||||||
Value Consume(const IR::Value& value);
|
Value Consume(const IR::Value& value);
|
||||||
|
|
||||||
|
void Unref(IR::Inst& inst);
|
||||||
|
|
||||||
[[nodiscard]] Register AllocReg();
|
[[nodiscard]] Register AllocReg();
|
||||||
|
|
||||||
[[nodiscard]] Register AllocLongReg();
|
[[nodiscard]] Register AllocLongReg();
|
||||||
|
@ -123,9 +127,13 @@ private:
|
||||||
static constexpr size_t NUM_REGS = 4096;
|
static constexpr size_t NUM_REGS = 4096;
|
||||||
static constexpr size_t NUM_ELEMENTS = 4;
|
static constexpr size_t NUM_ELEMENTS = 4;
|
||||||
|
|
||||||
|
Value MakeImm(const IR::Value& value);
|
||||||
|
|
||||||
Register Define(IR::Inst& inst, bool is_long);
|
Register Define(IR::Inst& inst, bool is_long);
|
||||||
|
|
||||||
Value Consume(IR::Inst& inst);
|
Value PeekInst(IR::Inst& inst);
|
||||||
|
|
||||||
|
Value ConsumeInst(IR::Inst& inst);
|
||||||
|
|
||||||
Id Alloc(bool is_long);
|
Id Alloc(bool is_long);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue