glasm: Fix register allocation when moving immediate on GLASM
This commit is contained in:
		| @@ -39,14 +39,16 @@ struct Identity { | ||||
| }; | ||||
|  | ||||
| template <bool scalar> | ||||
| struct RegWrapper { | ||||
|     RegWrapper(EmitContext& ctx, Value value) | ||||
|         : reg_alloc{ctx.reg_alloc}, allocated{value.type != Type::Register} { | ||||
|         if (allocated) { | ||||
| class RegWrapper { | ||||
| public: | ||||
|     RegWrapper(EmitContext& ctx, const IR::Value& ir_value) : reg_alloc{ctx.reg_alloc} { | ||||
|         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}; | ||||
|             reg = is_long ? reg_alloc.AllocLongReg() : reg_alloc.AllocReg(); | ||||
|         } else { | ||||
|             reg = Register{value}; | ||||
|         } | ||||
|         switch (value.type) { | ||||
|         case Type::Register: | ||||
| @@ -68,8 +70,11 @@ struct RegWrapper { | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     ~RegWrapper() { | ||||
|         if (allocated) { | ||||
|         if (inst) { | ||||
|             reg_alloc.Unref(*inst); | ||||
|         } else { | ||||
|             reg_alloc.FreeReg(reg); | ||||
|         } | ||||
|     } | ||||
| @@ -78,19 +83,42 @@ struct RegWrapper { | ||||
|         return std::conditional_t<scalar, ScalarRegister, Register>{Value{reg}}; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     RegAlloc& reg_alloc; | ||||
|     IR::Inst* inst{}; | ||||
|     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> | ||||
| auto Arg(EmitContext& ctx, const IR::Value& arg) { | ||||
|     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>) { | ||||
|         return RegWrapper<true>{ctx, ctx.reg_alloc.Consume(arg)}; | ||||
|         return RegWrapper<true>{ctx, arg}; | ||||
|     } 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&>) { | ||||
|         return Identity{arg}; | ||||
|     } else if constexpr (std::is_same_v<ArgType, u32>) { | ||||
|   | ||||
| @@ -21,10 +21,40 @@ Register RegAlloc::LongDefine(IR::Inst& inst) { | ||||
|     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) { | ||||
|     if (!value.IsImmediate()) { | ||||
|         return Consume(*value.InstRecursive()); | ||||
|     return value.IsImmediate() ? MakeImm(value) : ConsumeInst(*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; | ||||
|     switch (value.Type()) { | ||||
|     case IR::Type::U1: | ||||
| @@ -53,45 +83,26 @@ Value RegAlloc::Consume(const IR::Value& value) { | ||||
|     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) { | ||||
|     const Id id{Alloc(is_long)}; | ||||
|     inst.SetDefinition<Id>(id); | ||||
|     Register ret; | ||||
|     ret.type = Type::Register; | ||||
|     ret.id = id; | ||||
|     return ret; | ||||
|     inst.SetDefinition<Id>(Alloc(is_long)); | ||||
|     return Register{PeekInst(inst)}; | ||||
| } | ||||
|  | ||||
| Value RegAlloc::Consume(IR::Inst& inst) { | ||||
|     const Id id{inst.Definition<Id>()}; | ||||
|     inst.DestructiveRemoveUsage(); | ||||
|     if (!inst.HasUses()) { | ||||
|         Free(id); | ||||
|     } | ||||
| Value RegAlloc::PeekInst(IR::Inst& inst) { | ||||
|     Value ret; | ||||
|     ret.type = Type::Register; | ||||
|     ret.id = id; | ||||
|     ret.id = inst.Definition<Id>(); | ||||
|     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) { | ||||
|     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}; | ||||
|   | ||||
| @@ -99,8 +99,12 @@ public: | ||||
|  | ||||
|     Register LongDefine(IR::Inst& inst); | ||||
|  | ||||
|     [[nodiscard]] Value Peek(const IR::Value& value); | ||||
|  | ||||
|     Value Consume(const IR::Value& value); | ||||
|  | ||||
|     void Unref(IR::Inst& inst); | ||||
|  | ||||
|     [[nodiscard]] Register AllocReg(); | ||||
|  | ||||
|     [[nodiscard]] Register AllocLongReg(); | ||||
| @@ -123,9 +127,13 @@ private: | ||||
|     static constexpr size_t NUM_REGS = 4096; | ||||
|     static constexpr size_t NUM_ELEMENTS = 4; | ||||
|  | ||||
|     Value MakeImm(const IR::Value& value); | ||||
|  | ||||
|     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); | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user