glasm: Release phi node registers after they are no longer needed
This commit is contained in:
		| @@ -172,38 +172,29 @@ bool IsReference(IR::Inst& inst) { | ||||
|     return inst.GetOpcode() == IR::Opcode::Reference; | ||||
| } | ||||
|  | ||||
| void Precolor(EmitContext& ctx, const IR::Program& program) { | ||||
| 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)) { | ||||
|             switch (phi.Arg(0).Type()) { | ||||
|             case IR::Type::U1: | ||||
|             case IR::Type::U32: | ||||
|             case IR::Type::F32: | ||||
|                 ctx.reg_alloc.Define(phi); | ||||
|                 break; | ||||
|             case IR::Type::U64: | ||||
|             case IR::Type::F64: | ||||
|                 ctx.reg_alloc.LongDefine(phi); | ||||
|                 break; | ||||
|             default: | ||||
|                 throw NotImplementedException("Phi node type {}", phi.Type()); | ||||
|             } | ||||
|             // Insert phi moves before references to avoid overwritting them | ||||
|             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}); | ||||
|             } | ||||
|             PrecolorInst(phi); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -388,7 +379,7 @@ std::string_view GetTessSpacing(TessSpacing spacing) { | ||||
| std::string EmitGLASM(const Profile& profile, const RuntimeInfo& runtime_info, IR::Program& program, | ||||
|                       Bindings& bindings) { | ||||
|     EmitContext ctx{program, bindings, profile, runtime_info}; | ||||
|     Precolor(ctx, program); | ||||
|     Precolor(program); | ||||
|     EmitCode(ctx, program); | ||||
|     std::string header{StageHeader(program.stage)}; | ||||
|     SetupOptions(program, profile, runtime_info, header); | ||||
|   | ||||
| @@ -17,10 +17,30 @@ namespace Shader::Backend::GLASM { | ||||
|  | ||||
| #define NotImplemented() throw NotImplementedException("GLASM instruction {}", __LINE__) | ||||
|  | ||||
| void EmitPhi(EmitContext& ctx, IR::Inst& inst) { | ||||
|     const size_t num_args{inst.NumArgs()}; | ||||
| static void DefinePhi(EmitContext& ctx, IR::Inst& phi) { | ||||
|     switch (phi.Arg(0).Type()) { | ||||
|     case IR::Type::U1: | ||||
|     case IR::Type::U32: | ||||
|     case IR::Type::F32: | ||||
|         ctx.reg_alloc.Define(phi); | ||||
|         break; | ||||
|     case IR::Type::U64: | ||||
|     case IR::Type::F64: | ||||
|         ctx.reg_alloc.LongDefine(phi); | ||||
|         break; | ||||
|     default: | ||||
|         throw NotImplementedException("Phi node type {}", phi.Type()); | ||||
|     } | ||||
| } | ||||
|  | ||||
| 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(inst.Arg(i)); | ||||
|         ctx.reg_alloc.Consume(phi.Arg(i)); | ||||
|     } | ||||
|     if (!phi.Definition<Id>().is_valid) { | ||||
|         // The phi node wasn't forward defined | ||||
|         DefinePhi(ctx, phi); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -30,14 +50,19 @@ void EmitReference(EmitContext& ctx, const IR::Value& value) { | ||||
|     ctx.reg_alloc.Consume(value); | ||||
| } | ||||
|  | ||||
| void EmitPhiMove(EmitContext& ctx, const IR::Value& phi, const IR::Value& value) { | ||||
|     const Register phi_reg{ctx.reg_alloc.Consume(phi)}; | ||||
| 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 | ||||
|         DefinePhi(ctx, phi); | ||||
|     } | ||||
|     const Register phi_reg{ctx.reg_alloc.Consume(IR::Value{&phi})}; | ||||
|     const Value eval_value{ctx.reg_alloc.Consume(value)}; | ||||
|  | ||||
|     if (phi == value) { | ||||
|     if (phi_reg == eval_value) { | ||||
|         return; | ||||
|     } | ||||
|     switch (phi.Inst()->Flags<IR::Type>()) { | ||||
|     switch (phi.Flags<IR::Type>()) { | ||||
|     case IR::Type::U1: | ||||
|     case IR::Type::U32: | ||||
|     case IR::Type::F32: | ||||
|   | ||||
		Reference in New Issue
	
	Block a user