diff options
Diffstat (limited to 'src/shader_recompiler/backend/glasm/emit_glasm.cpp')
| -rw-r--r-- | src/shader_recompiler/backend/glasm/emit_glasm.cpp | 95 |
1 files changed, 77 insertions, 18 deletions
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm.cpp b/src/shader_recompiler/backend/glasm/emit_glasm.cpp index 7ec880c81..8981cf300 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm.cpp | |||
| @@ -27,22 +27,80 @@ struct FuncTraits<ReturnType_ (*)(Args...)> { | |||
| 27 | using ArgType = std::tuple_element_t<I, std::tuple<Args...>>; | 27 | using ArgType = std::tuple_element_t<I, std::tuple<Args...>>; |
| 28 | }; | 28 | }; |
| 29 | 29 | ||
| 30 | template <typename T> | ||
| 31 | struct Identity { | ||
| 32 | Identity(const T& data_) : data{data_} {} | ||
| 33 | |||
| 34 | const T& Extract() { | ||
| 35 | return data; | ||
| 36 | } | ||
| 37 | |||
| 38 | T data; | ||
| 39 | }; | ||
| 40 | |||
| 41 | template <bool scalar> | ||
| 42 | struct RegWrapper { | ||
| 43 | RegWrapper(EmitContext& ctx, Value value) | ||
| 44 | : reg_alloc{ctx.reg_alloc}, allocated{value.type != Type::Register} { | ||
| 45 | reg = allocated ? reg_alloc.AllocReg() : Register{value}; | ||
| 46 | switch (value.type) { | ||
| 47 | case Type::Register: | ||
| 48 | break; | ||
| 49 | case Type::U32: | ||
| 50 | ctx.Add("MOV.U {}.x,{};", reg, value.imm_u32); | ||
| 51 | break; | ||
| 52 | case Type::S32: | ||
| 53 | ctx.Add("MOV.S {}.x,{};", reg, value.imm_s32); | ||
| 54 | break; | ||
| 55 | case Type::F32: | ||
| 56 | ctx.Add("MOV.F {}.x,{};", reg, value.imm_f32); | ||
| 57 | break; | ||
| 58 | } | ||
| 59 | } | ||
| 60 | ~RegWrapper() { | ||
| 61 | if (allocated) { | ||
| 62 | reg_alloc.FreeReg(reg); | ||
| 63 | } | ||
| 64 | } | ||
| 65 | |||
| 66 | auto Extract() { | ||
| 67 | return std::conditional_t<scalar, ScalarRegister, Register>{Value{reg}}; | ||
| 68 | } | ||
| 69 | |||
| 70 | RegAlloc& reg_alloc; | ||
| 71 | Register reg{}; | ||
| 72 | bool allocated{}; | ||
| 73 | }; | ||
| 74 | |||
| 30 | template <typename ArgType> | 75 | template <typename ArgType> |
| 31 | auto Arg(EmitContext& ctx, const IR::Value& arg) { | 76 | auto Arg(EmitContext& ctx, const IR::Value& arg) { |
| 32 | if constexpr (std::is_same_v<ArgType, std::string_view>) { | 77 | if constexpr (std::is_same_v<ArgType, Register>) { |
| 33 | return ctx.reg_alloc.Consume(arg); | 78 | return RegWrapper<false>{ctx, ctx.reg_alloc.Consume(arg)}; |
| 79 | } else if constexpr (std::is_same_v<ArgType, ScalarRegister>) { | ||
| 80 | return RegWrapper<true>{ctx, ctx.reg_alloc.Consume(arg)}; | ||
| 81 | } else if constexpr (std::is_base_of_v<Value, ArgType>) { | ||
| 82 | return Identity{ArgType{ctx.reg_alloc.Consume(arg)}}; | ||
| 34 | } else if constexpr (std::is_same_v<ArgType, const IR::Value&>) { | 83 | } else if constexpr (std::is_same_v<ArgType, const IR::Value&>) { |
| 35 | return arg; | 84 | return Identity{arg}; |
| 36 | } else if constexpr (std::is_same_v<ArgType, u32>) { | 85 | } else if constexpr (std::is_same_v<ArgType, u32>) { |
| 37 | return arg.U32(); | 86 | return Identity{arg.U32()}; |
| 38 | } else if constexpr (std::is_same_v<ArgType, IR::Block*>) { | 87 | } else if constexpr (std::is_same_v<ArgType, IR::Block*>) { |
| 39 | return arg.Label(); | 88 | return Identity{arg.Label()}; |
| 40 | } else if constexpr (std::is_same_v<ArgType, IR::Attribute>) { | 89 | } else if constexpr (std::is_same_v<ArgType, IR::Attribute>) { |
| 41 | return arg.Attribute(); | 90 | return Identity{arg.Attribute()}; |
| 42 | } else if constexpr (std::is_same_v<ArgType, IR::Patch>) { | 91 | } else if constexpr (std::is_same_v<ArgType, IR::Patch>) { |
| 43 | return arg.Patch(); | 92 | return Identity{arg.Patch()}; |
| 44 | } else if constexpr (std::is_same_v<ArgType, IR::Reg>) { | 93 | } else if constexpr (std::is_same_v<ArgType, IR::Reg>) { |
| 45 | return arg.Reg(); | 94 | return Identity{arg.Reg()}; |
| 95 | } | ||
| 96 | } | ||
| 97 | |||
| 98 | template <auto func, bool is_first_arg_inst, typename... Args> | ||
| 99 | void InvokeCall(EmitContext& ctx, IR::Inst* inst, Args&&... args) { | ||
| 100 | if constexpr (is_first_arg_inst) { | ||
| 101 | func(ctx, *inst, std::forward<Args>(args.Extract())...); | ||
| 102 | } else { | ||
| 103 | func(ctx, std::forward<Args>(args.Extract())...); | ||
| 46 | } | 104 | } |
| 47 | } | 105 | } |
| 48 | 106 | ||
| @@ -50,9 +108,10 @@ template <auto func, bool is_first_arg_inst, size_t... I> | |||
| 50 | void Invoke(EmitContext& ctx, IR::Inst* inst, std::index_sequence<I...>) { | 108 | void Invoke(EmitContext& ctx, IR::Inst* inst, std::index_sequence<I...>) { |
| 51 | using Traits = FuncTraits<decltype(func)>; | 109 | using Traits = FuncTraits<decltype(func)>; |
| 52 | if constexpr (is_first_arg_inst) { | 110 | if constexpr (is_first_arg_inst) { |
| 53 | func(ctx, *inst, Arg<typename Traits::template ArgType<I + 2>>(ctx, inst->Arg(I))...); | 111 | func(ctx, *inst, |
| 112 | Arg<typename Traits::template ArgType<I + 2>>(ctx, inst->Arg(I)).Extract()...); | ||
| 54 | } else { | 113 | } else { |
| 55 | func(ctx, Arg<typename Traits::template ArgType<I + 1>>(ctx, inst->Arg(I))...); | 114 | func(ctx, Arg<typename Traits::template ArgType<I + 1>>(ctx, inst->Arg(I)).Extract()...); |
| 56 | } | 115 | } |
| 57 | } | 116 | } |
| 58 | 117 | ||
| @@ -81,7 +140,7 @@ void EmitInst(EmitContext& ctx, IR::Inst* inst) { | |||
| 81 | throw LogicError("Invalid opcode {}", inst->GetOpcode()); | 140 | throw LogicError("Invalid opcode {}", inst->GetOpcode()); |
| 82 | } | 141 | } |
| 83 | 142 | ||
| 84 | void Identity(IR::Inst& inst, const IR::Value& value) { | 143 | void Alias(IR::Inst& inst, const IR::Value& value) { |
| 85 | if (value.IsImmediate()) { | 144 | if (value.IsImmediate()) { |
| 86 | return; | 145 | return; |
| 87 | } | 146 | } |
| @@ -125,31 +184,31 @@ std::string EmitGLASM(const Profile&, IR::Program& program, Bindings&) { | |||
| 125 | } | 184 | } |
| 126 | 185 | ||
| 127 | void EmitIdentity(EmitContext&, IR::Inst& inst, const IR::Value& value) { | 186 | void EmitIdentity(EmitContext&, IR::Inst& inst, const IR::Value& value) { |
| 128 | Identity(inst, value); | 187 | Alias(inst, value); |
| 129 | } | 188 | } |
| 130 | 189 | ||
| 131 | void EmitBitCastU16F16(EmitContext&, IR::Inst& inst, const IR::Value& value) { | 190 | void EmitBitCastU16F16(EmitContext&, IR::Inst& inst, const IR::Value& value) { |
| 132 | Identity(inst, value); | 191 | Alias(inst, value); |
| 133 | } | 192 | } |
| 134 | 193 | ||
| 135 | void EmitBitCastU32F32(EmitContext&, IR::Inst& inst, const IR::Value& value) { | 194 | void EmitBitCastU32F32(EmitContext&, IR::Inst& inst, const IR::Value& value) { |
| 136 | Identity(inst, value); | 195 | Alias(inst, value); |
| 137 | } | 196 | } |
| 138 | 197 | ||
| 139 | void EmitBitCastU64F64(EmitContext&, IR::Inst& inst, const IR::Value& value) { | 198 | void EmitBitCastU64F64(EmitContext&, IR::Inst& inst, const IR::Value& value) { |
| 140 | Identity(inst, value); | 199 | Alias(inst, value); |
| 141 | } | 200 | } |
| 142 | 201 | ||
| 143 | void EmitBitCastF16U16(EmitContext&, IR::Inst& inst, const IR::Value& value) { | 202 | void EmitBitCastF16U16(EmitContext&, IR::Inst& inst, const IR::Value& value) { |
| 144 | Identity(inst, value); | 203 | Alias(inst, value); |
| 145 | } | 204 | } |
| 146 | 205 | ||
| 147 | void EmitBitCastF32U32(EmitContext&, IR::Inst& inst, const IR::Value& value) { | 206 | void EmitBitCastF32U32(EmitContext&, IR::Inst& inst, const IR::Value& value) { |
| 148 | Identity(inst, value); | 207 | Alias(inst, value); |
| 149 | } | 208 | } |
| 150 | 209 | ||
| 151 | void EmitBitCastF64U64(EmitContext&, IR::Inst& inst, const IR::Value& value) { | 210 | void EmitBitCastF64U64(EmitContext&, IR::Inst& inst, const IR::Value& value) { |
| 152 | Identity(inst, value); | 211 | Alias(inst, value); |
| 153 | } | 212 | } |
| 154 | 213 | ||
| 155 | } // namespace Shader::Backend::GLASM | 214 | } // namespace Shader::Backend::GLASM |