glsl: Update phi node management
This commit is contained in:
		| @@ -98,18 +98,33 @@ void EmitInst(EmitContext& ctx, IR::Inst* inst) { | ||||
|     throw LogicError("Invalid opcode {}", inst->GetOpcode()); | ||||
| } | ||||
|  | ||||
| void Precolor(EmitContext& ctx, const IR::Program& program) { | ||||
| bool IsReference(IR::Inst& inst) { | ||||
|     return inst.GetOpcode() == IR::Opcode::Reference; | ||||
| } | ||||
|  | ||||
| void PrecolorInst(IR::Inst& phi) { | ||||
|     // Insert phi moves before references to avoid overwritting other phis | ||||
|     const size_t num_args{phi.NumArgs()}; | ||||
|     for (size_t i = 0; i < num_args; ++i) { | ||||
|         IR::Block& phi_block{*phi.PhiBlock(i)}; | ||||
|         auto it{std::find_if_not(phi_block.rbegin(), phi_block.rend(), IsReference).base()}; | ||||
|         IR::IREmitter ir{phi_block, it}; | ||||
|         const IR::Value arg{phi.Arg(i)}; | ||||
|         if (arg.IsImmediate()) { | ||||
|             ir.PhiMove(phi, arg); | ||||
|         } else { | ||||
|             ir.PhiMove(phi, IR::Value{&RegAlloc::AliasInst(*arg.Inst())}); | ||||
|         } | ||||
|     } | ||||
|     for (size_t i = 0; i < num_args; ++i) { | ||||
|         IR::IREmitter{*phi.PhiBlock(i)}.Reference(IR::Value{&phi}); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void Precolor(const IR::Program& program) { | ||||
|     for (IR::Block* const block : program.blocks) { | ||||
|         for (IR::Inst& phi : block->Instructions() | std::views::take_while(IR::IsPhi)) { | ||||
|             ctx.Add("{};", ctx.reg_alloc.Define(phi, phi.Arg(0).Type())); | ||||
|             const size_t num_args{phi.NumArgs()}; | ||||
|             for (size_t i = 0; i < num_args; ++i) { | ||||
|                 IR::IREmitter{*phi.PhiBlock(i)}.PhiMove(phi, phi.Arg(i)); | ||||
|             } | ||||
|             // Add reference to the phi node on the phi predecessor to avoid overwritting it | ||||
|             for (size_t i = 0; i < num_args; ++i) { | ||||
|                 IR::IREmitter{*phi.PhiBlock(i)}.Reference(IR::Value{&phi}); | ||||
|             } | ||||
|             PrecolorInst(phi); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -158,7 +173,7 @@ void EmitCode(EmitContext& ctx, const IR::Program& program) { | ||||
| std::string EmitGLSL(const Profile& profile, const RuntimeInfo&, IR::Program& program, | ||||
|                      Bindings& bindings) { | ||||
|     EmitContext ctx{program, bindings, profile}; | ||||
|     Precolor(ctx, program); | ||||
|     Precolor(program); | ||||
|     EmitCode(ctx, program); | ||||
|     return ctx.code; | ||||
| } | ||||
|   | ||||
| @@ -19,8 +19,15 @@ static void NotImplemented() { | ||||
|     throw NotImplementedException("GLSL instruction"); | ||||
| } | ||||
|  | ||||
| void EmitPhi(EmitContext& ctx, IR::Inst& inst) { | ||||
|     // NotImplemented(); | ||||
| void EmitPhi(EmitContext& ctx, IR::Inst& phi) { | ||||
|     const size_t num_args{phi.NumArgs()}; | ||||
|     for (size_t i = 0; i < num_args; ++i) { | ||||
|         ctx.reg_alloc.Consume(phi.Arg(i)); | ||||
|     } | ||||
|     if (!phi.Definition<Id>().is_valid) { | ||||
|         // The phi node wasn't forward defined | ||||
|         ctx.Add("{};", ctx.reg_alloc.Define(phi, phi.Arg(0).Type())); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void EmitVoid(EmitContext& ctx) { | ||||
| @@ -31,11 +38,18 @@ void EmitReference(EmitContext&) { | ||||
|     // NotImplemented(); | ||||
| } | ||||
|  | ||||
| void EmitPhiMove(EmitContext& ctx, const IR::Value& phi, const IR::Value& value) { | ||||
|     if (phi == value) { | ||||
| void EmitPhiMove(EmitContext& ctx, const IR::Value& phi_value, const IR::Value& value) { | ||||
|     IR::Inst& phi{RegAlloc::AliasInst(*phi_value.Inst())}; | ||||
|     if (!phi.Definition<Id>().is_valid) { | ||||
|         // The phi node wasn't forward defined | ||||
|         ctx.Add("{};", ctx.reg_alloc.Define(phi, phi.Arg(0).Type())); | ||||
|     } | ||||
|     const auto phi_reg{ctx.reg_alloc.Consume(IR::Value{&phi})}; | ||||
|     const auto val_reg{ctx.reg_alloc.Consume(value)}; | ||||
|     if (phi_reg == val_reg) { | ||||
|         return; | ||||
|     } | ||||
|     ctx.Add("{}={};", ctx.reg_alloc.Consume(phi), ctx.reg_alloc.Consume(value)); | ||||
|     ctx.Add("{}={};", phi_reg, val_reg); | ||||
| } | ||||
|  | ||||
| void EmitBranch(EmitContext& ctx, std::string_view label) { | ||||
|   | ||||
| @@ -146,10 +146,11 @@ Id RegAlloc::Alloc() { | ||||
|             } | ||||
|             register_use[reg] = true; | ||||
|             Id ret{}; | ||||
|             ret.index.Assign(static_cast<u32>(reg)); | ||||
|             ret.is_valid.Assign(1); | ||||
|             ret.is_long.Assign(0); | ||||
|             ret.is_spill.Assign(0); | ||||
|             ret.is_condition_code.Assign(0); | ||||
|             ret.index.Assign(static_cast<u32>(reg)); | ||||
|             return ret; | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -33,10 +33,12 @@ enum class Type : u32 { | ||||
| struct Id { | ||||
|     union { | ||||
|         u32 raw; | ||||
|         BitField<0, 29, u32> index; | ||||
|         BitField<29, 1, u32> is_long; | ||||
|         BitField<30, 1, u32> is_spill; | ||||
|         BitField<31, 1, u32> is_condition_code; | ||||
|         BitField<0, 1, u32> is_valid; | ||||
|         BitField<1, 1, u32> is_long; | ||||
|         BitField<2, 1, u32> is_spill; | ||||
|         BitField<3, 1, u32> is_condition_code; | ||||
|         BitField<4, 1, u32> is_null; | ||||
|         BitField<5, 27, u32> index; | ||||
|     }; | ||||
|  | ||||
|     bool operator==(Id rhs) const noexcept { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user