glsl: Rework var alloc to not assign unused results
This commit is contained in:
		| @@ -122,11 +122,9 @@ EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile | |||||||
|  |  | ||||||
| void EmitContext::SetupExtensions(std::string&) { | void EmitContext::SetupExtensions(std::string&) { | ||||||
|     header += "#extension GL_ARB_separate_shader_objects : enable\n"; |     header += "#extension GL_ARB_separate_shader_objects : enable\n"; | ||||||
|     if (stage != Stage::Compute) { |  | ||||||
|     // TODO: track this usage |     // TODO: track this usage | ||||||
|     header += "#extension GL_ARB_sparse_texture2 : enable\n"; |     header += "#extension GL_ARB_sparse_texture2 : enable\n"; | ||||||
|     header += "#extension GL_EXT_texture_shadow_lod : enable\n"; |     header += "#extension GL_EXT_texture_shadow_lod : enable\n"; | ||||||
|     } |  | ||||||
|     if (info.uses_int64) { |     if (info.uses_int64) { | ||||||
|         header += "#extension GL_ARB_gpu_shader_int64 : enable\n"; |         header += "#extension GL_ARB_gpu_shader_int64 : enable\n"; | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -37,7 +37,13 @@ public: | |||||||
|  |  | ||||||
|     template <GlslVarType type, typename... Args> |     template <GlslVarType type, typename... Args> | ||||||
|     void Add(const char* format_str, IR::Inst& inst, Args&&... args) { |     void Add(const char* format_str, IR::Inst& inst, Args&&... args) { | ||||||
|         code += fmt::format(format_str, var_alloc.Define(inst, type), std::forward<Args>(args)...); |         const auto var_def{var_alloc.AddDefine(inst, type)}; | ||||||
|  |         if (var_def.empty()) { | ||||||
|  |             // skip assigment. | ||||||
|  |             code += fmt::format(&format_str[3], std::forward<Args>(args)...); | ||||||
|  |         } else { | ||||||
|  |             code += fmt::format(format_str, var_def, std::forward<Args>(args)...); | ||||||
|  |         } | ||||||
|         // TODO: Remove this |         // TODO: Remove this | ||||||
|         code += '\n'; |         code += '\n'; | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -11,8 +11,7 @@ | |||||||
|  |  | ||||||
| namespace Shader::Backend::GLSL { | namespace Shader::Backend::GLSL { | ||||||
| namespace { | namespace { | ||||||
| static constexpr std::string_view cas_loop{R"({}; | static constexpr std::string_view cas_loop{R"(for (;;){{ | ||||||
| for (;;){{ |  | ||||||
|     uint old_value={}; |     uint old_value={}; | ||||||
|     {}=atomicCompSwap({},old_value,{}({},{})); |     {}=atomicCompSwap({},old_value,{}({},{})); | ||||||
|     if ({}==old_value){{break;}} |     if ({}==old_value){{break;}} | ||||||
| @@ -22,14 +21,14 @@ void SharedCasFunction(EmitContext& ctx, IR::Inst& inst, std::string_view offset | |||||||
|                        std::string_view value, std::string_view function) { |                        std::string_view value, std::string_view function) { | ||||||
|     const auto ret{ctx.var_alloc.Define(inst, GlslVarType::U32)}; |     const auto ret{ctx.var_alloc.Define(inst, GlslVarType::U32)}; | ||||||
|     const std::string smem{fmt::format("smem[{}/4]", offset)}; |     const std::string smem{fmt::format("smem[{}/4]", offset)}; | ||||||
|     ctx.Add(cas_loop.data(), ret, smem, ret, smem, function, smem, value, ret); |     ctx.Add(cas_loop.data(), smem, ret, smem, function, smem, value, ret); | ||||||
| } | } | ||||||
|  |  | ||||||
| void SsboCasFunction(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, | void SsboCasFunction(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, | ||||||
|                      const IR::Value& offset, std::string_view value, std::string_view function) { |                      const IR::Value& offset, std::string_view value, std::string_view function) { | ||||||
|     const auto ret{ctx.var_alloc.Define(inst, GlslVarType::U32)}; |     const auto ret{ctx.var_alloc.Define(inst, GlslVarType::U32)}; | ||||||
|     const std::string ssbo{fmt::format("ssbo{}[{}]", binding.U32(), offset.U32())}; |     const std::string ssbo{fmt::format("ssbo{}[{}]", binding.U32(), offset.U32())}; | ||||||
|     ctx.Add(cas_loop.data(), ret, ssbo, ret, ssbo, function, ssbo, value, ret); |     ctx.Add(cas_loop.data(), ssbo, ret, ssbo, function, ssbo, value, ret); | ||||||
| } | } | ||||||
|  |  | ||||||
| void SsboCasFunctionF32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, | void SsboCasFunctionF32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, | ||||||
| @@ -37,7 +36,7 @@ void SsboCasFunctionF32(EmitContext& ctx, IR::Inst& inst, const IR::Value& bindi | |||||||
|                         std::string_view function) { |                         std::string_view function) { | ||||||
|     const std::string ssbo{fmt::format("ssbo{}[{}]", binding.U32(), offset.U32())}; |     const std::string ssbo{fmt::format("ssbo{}[{}]", binding.U32(), offset.U32())}; | ||||||
|     const auto ret{ctx.var_alloc.Define(inst, GlslVarType::U32)}; |     const auto ret{ctx.var_alloc.Define(inst, GlslVarType::U32)}; | ||||||
|     ctx.Add(cas_loop.data(), ret, ssbo, ret, ssbo, function, ssbo, value, ret); |     ctx.Add(cas_loop.data(), ssbo, ret, ssbo, function, ssbo, value, ret); | ||||||
|     ctx.AddF32("{}=uintBitsToFloat({});", inst, ret); |     ctx.AddF32("{}=uintBitsToFloat({});", inst, ret); | ||||||
| } | } | ||||||
| } // namespace | } // namespace | ||||||
|   | |||||||
| @@ -26,7 +26,13 @@ void EmitIdentity(EmitContext&, IR::Inst& inst, const IR::Value& value) { | |||||||
| } | } | ||||||
|  |  | ||||||
| void EmitConditionRef(EmitContext& ctx, IR::Inst& inst, const IR::Value& value) { | void EmitConditionRef(EmitContext& ctx, IR::Inst& inst, const IR::Value& value) { | ||||||
|     ctx.AddU1("{}={};", inst, ctx.var_alloc.Consume(value)); |     // Fake one usage to get a real variable out of the condition | ||||||
|  |     inst.DestructiveAddUsage(1); | ||||||
|  |     const auto ret{ctx.var_alloc.Define(inst, GlslVarType::U1)}; | ||||||
|  |     const auto input{ctx.var_alloc.Consume(value)}; | ||||||
|  |     if (ret != input) { | ||||||
|  |         ctx.Add("{}={};", ret, input); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| void EmitBitCastU16F16([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Inst& inst) { | void EmitBitCastU16F16([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Inst& inst) { | ||||||
|   | |||||||
| @@ -9,8 +9,14 @@ | |||||||
| #include "shader_recompiler/frontend/ir/value.h" | #include "shader_recompiler/frontend/ir/value.h" | ||||||
|  |  | ||||||
| namespace Shader::Backend::GLSL { | namespace Shader::Backend::GLSL { | ||||||
|  | namespace { | ||||||
| static constexpr std::string_view SWIZZLE{"xyzw"}; | static constexpr std::string_view SWIZZLE{"xyzw"}; | ||||||
|  | void CompositeInsert(EmitContext& ctx, std::string_view result, std::string_view composite, | ||||||
|  |                      std::string_view object, u32 index) { | ||||||
|  |     ctx.Add("{}={};", result, composite); | ||||||
|  |     ctx.Add("{}.{}={};", result, SWIZZLE[index], object); | ||||||
|  | } | ||||||
|  | } // namespace | ||||||
| void EmitCompositeConstructU32x2(EmitContext& ctx, IR::Inst& inst, std::string_view e1, | void EmitCompositeConstructU32x2(EmitContext& ctx, IR::Inst& inst, std::string_view e1, | ||||||
|                                  std::string_view e2) { |                                  std::string_view e2) { | ||||||
|     ctx.AddU32x2("{}=uvec2({},{});", inst, e1, e2); |     ctx.AddU32x2("{}=uvec2({},{});", inst, e1, e2); | ||||||
| @@ -41,19 +47,22 @@ void EmitCompositeExtractU32x4(EmitContext& ctx, IR::Inst& inst, std::string_vie | |||||||
|     ctx.AddU32("{}={}.{};", inst, composite, SWIZZLE[index]); |     ctx.AddU32("{}={}.{};", inst, composite, SWIZZLE[index]); | ||||||
| } | } | ||||||
|  |  | ||||||
| void EmitCompositeInsertU32x2(EmitContext& ctx, std::string_view composite, std::string_view object, | void EmitCompositeInsertU32x2(EmitContext& ctx, IR::Inst& inst, std::string_view composite, | ||||||
|                               u32 index) { |                               std::string_view object, u32 index) { | ||||||
|     ctx.Add("{}.{}={};", composite, SWIZZLE[index], object); |     const auto ret{ctx.var_alloc.Define(inst, GlslVarType::U32x2)}; | ||||||
|  |     CompositeInsert(ctx, ret, composite, object, index); | ||||||
| } | } | ||||||
|  |  | ||||||
| void EmitCompositeInsertU32x3(EmitContext& ctx, std::string_view composite, std::string_view object, | void EmitCompositeInsertU32x3(EmitContext& ctx, IR::Inst& inst, std::string_view composite, | ||||||
|                               u32 index) { |                               std::string_view object, u32 index) { | ||||||
|     ctx.Add("{}.{}={};", composite, SWIZZLE[index], object); |     const auto ret{ctx.var_alloc.Define(inst, GlslVarType::U32x3)}; | ||||||
|  |     CompositeInsert(ctx, ret, composite, object, index); | ||||||
| } | } | ||||||
|  |  | ||||||
| void EmitCompositeInsertU32x4(EmitContext& ctx, std::string_view composite, std::string_view object, | void EmitCompositeInsertU32x4(EmitContext& ctx, IR::Inst& inst, std::string_view composite, | ||||||
|                               u32 index) { |                               std::string_view object, u32 index) { | ||||||
|     ctx.Add("{}.{}={};", composite, SWIZZLE[index], object); |     const auto ret{ctx.var_alloc.Define(inst, GlslVarType::U32x4)}; | ||||||
|  |     CompositeInsert(ctx, ret, composite, object, index); | ||||||
| } | } | ||||||
|  |  | ||||||
| void EmitCompositeConstructF16x2([[maybe_unused]] EmitContext& ctx, | void EmitCompositeConstructF16x2([[maybe_unused]] EmitContext& ctx, | ||||||
| @@ -146,19 +155,22 @@ void EmitCompositeExtractF32x4(EmitContext& ctx, IR::Inst& inst, std::string_vie | |||||||
|     ctx.AddF32("{}={}.{};", inst, composite, SWIZZLE[index]); |     ctx.AddF32("{}={}.{};", inst, composite, SWIZZLE[index]); | ||||||
| } | } | ||||||
|  |  | ||||||
| void EmitCompositeInsertF32x2(EmitContext& ctx, std::string_view composite, std::string_view object, | void EmitCompositeInsertF32x2(EmitContext& ctx, IR::Inst& inst, std::string_view composite, | ||||||
|                               u32 index) { |                               std::string_view object, u32 index) { | ||||||
|     ctx.Add("{}.{}={};", composite, SWIZZLE[index], object); |     const auto ret{ctx.var_alloc.Define(inst, GlslVarType::F32x2)}; | ||||||
|  |     CompositeInsert(ctx, ret, composite, object, index); | ||||||
| } | } | ||||||
|  |  | ||||||
| void EmitCompositeInsertF32x3(EmitContext& ctx, std::string_view composite, std::string_view object, | void EmitCompositeInsertF32x3(EmitContext& ctx, IR::Inst& inst, std::string_view composite, | ||||||
|                               u32 index) { |                               std::string_view object, u32 index) { | ||||||
|     ctx.Add("{}.{}={};", composite, SWIZZLE[index], object); |     const auto ret{ctx.var_alloc.Define(inst, GlslVarType::F32x3)}; | ||||||
|  |     CompositeInsert(ctx, ret, composite, object, index); | ||||||
| } | } | ||||||
|  |  | ||||||
| void EmitCompositeInsertF32x4(EmitContext& ctx, std::string_view composite, std::string_view object, | void EmitCompositeInsertF32x4(EmitContext& ctx, IR::Inst& inst, std::string_view composite, | ||||||
|                               u32 index) { |                               std::string_view object, u32 index) { | ||||||
|     ctx.Add("{}.{}={};", composite, SWIZZLE[index], object); |     const auto ret{ctx.var_alloc.Define(inst, GlslVarType::F32x4)}; | ||||||
|  |     CompositeInsert(ctx, ret, composite, object, index); | ||||||
| } | } | ||||||
|  |  | ||||||
| void EmitCompositeConstructF64x2([[maybe_unused]] EmitContext& ctx) { | void EmitCompositeConstructF64x2([[maybe_unused]] EmitContext& ctx) { | ||||||
|   | |||||||
| @@ -26,7 +26,7 @@ void EmitPhi(EmitContext& ctx, IR::Inst& inst); | |||||||
| void EmitVoid(EmitContext& ctx); | void EmitVoid(EmitContext& ctx); | ||||||
| void EmitIdentity(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); | void EmitIdentity(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); | ||||||
| void EmitConditionRef(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); | void EmitConditionRef(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); | ||||||
| void EmitReference(EmitContext&); | void EmitReference(EmitContext& ctx, const IR::Value& value); | ||||||
| void EmitPhiMove(EmitContext& ctx, const IR::Value& phi, const IR::Value& value); | void EmitPhiMove(EmitContext& ctx, const IR::Value& phi, const IR::Value& value); | ||||||
| void EmitBranch(EmitContext& ctx, std::string_view label); | void EmitBranch(EmitContext& ctx, std::string_view label); | ||||||
| void EmitBranchConditional(EmitContext& ctx, std::string_view condition, | void EmitBranchConditional(EmitContext& ctx, std::string_view condition, | ||||||
| @@ -165,12 +165,12 @@ void EmitCompositeExtractU32x3(EmitContext& ctx, IR::Inst& inst, std::string_vie | |||||||
|                                u32 index); |                                u32 index); | ||||||
| void EmitCompositeExtractU32x4(EmitContext& ctx, IR::Inst& inst, std::string_view composite, | void EmitCompositeExtractU32x4(EmitContext& ctx, IR::Inst& inst, std::string_view composite, | ||||||
|                                u32 index); |                                u32 index); | ||||||
| void EmitCompositeInsertU32x2(EmitContext& ctx, std::string_view composite, std::string_view object, | void EmitCompositeInsertU32x2(EmitContext& ctx, IR::Inst& inst, std::string_view composite, | ||||||
|                               u32 index); |                               std::string_view object, u32 index); | ||||||
| void EmitCompositeInsertU32x3(EmitContext& ctx, std::string_view composite, std::string_view object, | void EmitCompositeInsertU32x3(EmitContext& ctx, IR::Inst& inst, std::string_view composite, | ||||||
|                               u32 index); |                               std::string_view object, u32 index); | ||||||
| void EmitCompositeInsertU32x4(EmitContext& ctx, std::string_view composite, std::string_view object, | void EmitCompositeInsertU32x4(EmitContext& ctx, IR::Inst& inst, std::string_view composite, | ||||||
|                               u32 index); |                               std::string_view object, u32 index); | ||||||
| void EmitCompositeConstructF16x2(EmitContext& ctx, std::string_view e1, std::string_view e2); | void EmitCompositeConstructF16x2(EmitContext& ctx, std::string_view e1, std::string_view e2); | ||||||
| void EmitCompositeConstructF16x3(EmitContext& ctx, std::string_view e1, std::string_view e2, | void EmitCompositeConstructF16x3(EmitContext& ctx, std::string_view e1, std::string_view e2, | ||||||
|                                  std::string_view e3); |                                  std::string_view e3); | ||||||
| @@ -197,12 +197,12 @@ void EmitCompositeExtractF32x3(EmitContext& ctx, IR::Inst& inst, std::string_vie | |||||||
|                                u32 index); |                                u32 index); | ||||||
| void EmitCompositeExtractF32x4(EmitContext& ctx, IR::Inst& inst, std::string_view composite, | void EmitCompositeExtractF32x4(EmitContext& ctx, IR::Inst& inst, std::string_view composite, | ||||||
|                                u32 index); |                                u32 index); | ||||||
| void EmitCompositeInsertF32x2(EmitContext& ctx, std::string_view composite, std::string_view object, | void EmitCompositeInsertF32x2(EmitContext& ctx, IR::Inst& inst, std::string_view composite, | ||||||
|                               u32 index); |                               std::string_view object, u32 index); | ||||||
| void EmitCompositeInsertF32x3(EmitContext& ctx, std::string_view composite, std::string_view object, | void EmitCompositeInsertF32x3(EmitContext& ctx, IR::Inst& inst, std::string_view composite, | ||||||
|                               u32 index); |                               std::string_view object, u32 index); | ||||||
| void EmitCompositeInsertF32x4(EmitContext& ctx, std::string_view composite, std::string_view object, | void EmitCompositeInsertF32x4(EmitContext& ctx, IR::Inst& inst, std::string_view composite, | ||||||
|                               u32 index); |                               std::string_view object, u32 index); | ||||||
| void EmitCompositeConstructF64x2(EmitContext& ctx); | void EmitCompositeConstructF64x2(EmitContext& ctx); | ||||||
| void EmitCompositeConstructF64x3(EmitContext& ctx); | void EmitCompositeConstructF64x3(EmitContext& ctx); | ||||||
| void EmitCompositeConstructF64x4(EmitContext& ctx); | void EmitCompositeConstructF64x4(EmitContext& ctx); | ||||||
|   | |||||||
| @@ -25,7 +25,7 @@ void EmitPhi(EmitContext& ctx, IR::Inst& phi) { | |||||||
|     } |     } | ||||||
|     if (!phi.Definition<Id>().is_valid) { |     if (!phi.Definition<Id>().is_valid) { | ||||||
|         // The phi node wasn't forward defined |         // The phi node wasn't forward defined | ||||||
|         ctx.Add("{};", ctx.var_alloc.Define(phi, phi.Arg(0).Type())); |         ctx.var_alloc.PhiDefine(phi, phi.Arg(0).Type()); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -33,8 +33,8 @@ void EmitVoid(EmitContext& ctx) { | |||||||
|     // NotImplemented(); |     // NotImplemented(); | ||||||
| } | } | ||||||
|  |  | ||||||
| void EmitReference(EmitContext&) { | void EmitReference(EmitContext& ctx, const IR::Value& value) { | ||||||
|     // NotImplemented(); |     ctx.var_alloc.Consume(value); | ||||||
| } | } | ||||||
|  |  | ||||||
| void EmitPhiMove(EmitContext& ctx, const IR::Value& phi_value, const IR::Value& value) { | void EmitPhiMove(EmitContext& ctx, const IR::Value& phi_value, const IR::Value& value) { | ||||||
| @@ -42,7 +42,7 @@ void EmitPhiMove(EmitContext& ctx, const IR::Value& phi_value, const IR::Value& | |||||||
|     const auto phi_type{phi.Arg(0).Type()}; |     const auto phi_type{phi.Arg(0).Type()}; | ||||||
|     if (!phi.Definition<Id>().is_valid) { |     if (!phi.Definition<Id>().is_valid) { | ||||||
|         // The phi node wasn't forward defined |         // The phi node wasn't forward defined | ||||||
|         ctx.Add("{};", ctx.var_alloc.Define(phi, phi_type)); |         ctx.var_alloc.PhiDefine(phi, phi_type); | ||||||
|     } |     } | ||||||
|     const auto phi_reg{ctx.var_alloc.Consume(IR::Value{&phi})}; |     const auto phi_reg{ctx.var_alloc.Consume(IR::Value{&phi})}; | ||||||
|     const auto val_reg{ctx.var_alloc.Consume(value)}; |     const auto val_reg{ctx.var_alloc.Consume(value)}; | ||||||
|   | |||||||
| @@ -110,7 +110,6 @@ std::string VarAlloc::Define(IR::Inst& inst, GlslVarType type) { | |||||||
|     } else { |     } else { | ||||||
|         Id id{}; |         Id id{}; | ||||||
|         id.type.Assign(type); |         id.type.Assign(type); | ||||||
|         // id.is_null.Assign(1); |  | ||||||
|         GetUseTracker(type).uses_temp = true; |         GetUseTracker(type).uses_temp = true; | ||||||
|         inst.SetDefinition<Id>(id); |         inst.SetDefinition<Id>(id); | ||||||
|     } |     } | ||||||
| @@ -121,6 +120,20 @@ std::string VarAlloc::Define(IR::Inst& inst, IR::Type type) { | |||||||
|     return Define(inst, RegType(type)); |     return Define(inst, RegType(type)); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | std::string VarAlloc::PhiDefine(IR::Inst& inst, IR::Type type) { | ||||||
|  |     return AddDefine(inst, RegType(type)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | std::string VarAlloc::AddDefine(IR::Inst& inst, GlslVarType type) { | ||||||
|  |     if (inst.HasUses()) { | ||||||
|  |         inst.SetDefinition<Id>(Alloc(type)); | ||||||
|  |         return Representation(inst.Definition<Id>()); | ||||||
|  |     } else { | ||||||
|  |         return ""; | ||||||
|  |     } | ||||||
|  |     return Representation(inst.Definition<Id>()); | ||||||
|  | } | ||||||
|  |  | ||||||
| std::string VarAlloc::Consume(const IR::Value& value) { | std::string VarAlloc::Consume(const IR::Value& value) { | ||||||
|     return value.IsImmediate() ? MakeImm(value) : ConsumeInst(*value.InstRecursive()); |     return value.IsImmediate() ? MakeImm(value) : ConsumeInst(*value.InstRecursive()); | ||||||
| } | } | ||||||
| @@ -223,6 +236,8 @@ VarAlloc::UseTracker& VarAlloc::GetUseTracker(GlslVarType type) { | |||||||
|     switch (type) { |     switch (type) { | ||||||
|     case GlslVarType::U1: |     case GlslVarType::U1: | ||||||
|         return var_bool; |         return var_bool; | ||||||
|  |     case GlslVarType::F16x2: | ||||||
|  |         return var_f16x2; | ||||||
|     case GlslVarType::U32: |     case GlslVarType::U32: | ||||||
|         return var_u32; |         return var_u32; | ||||||
|     case GlslVarType::S32: |     case GlslVarType::S32: | ||||||
|   | |||||||
| @@ -62,9 +62,15 @@ public: | |||||||
|         bool uses_temp{}; |         bool uses_temp{}; | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|  |     /// Used for explicit usages of variables, may revert to temporaries | ||||||
|     std::string Define(IR::Inst& inst, GlslVarType type); |     std::string Define(IR::Inst& inst, GlslVarType type); | ||||||
|     std::string Define(IR::Inst& inst, IR::Type type); |     std::string Define(IR::Inst& inst, IR::Type type); | ||||||
|  |  | ||||||
|  |     /// Used to assign variables used by the IR. May return a blank string if | ||||||
|  |     /// the instruction's result is unused in the IR. | ||||||
|  |     std::string AddDefine(IR::Inst& inst, GlslVarType type); | ||||||
|  |     std::string PhiDefine(IR::Inst& inst, IR::Type type); | ||||||
|  |  | ||||||
|     std::string Consume(const IR::Value& value); |     std::string Consume(const IR::Value& value); | ||||||
|     std::string ConsumeInst(IR::Inst& inst); |     std::string ConsumeInst(IR::Inst& inst); | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user