glasm: Fix register allocation when moving immediate on GLASM

This commit is contained in:
ReinUsesLisp 2021-05-10 03:47:31 -03:00 committed by ameerj
parent 0839e46736
commit deda89372f
3 changed files with 92 additions and 45 deletions

View File

@ -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>) {

View File

@ -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};

View File

@ -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);