diff options
| author | 2021-05-10 19:32:10 -0300 | |
|---|---|---|
| committer | 2021-07-22 21:51:31 -0400 | |
| commit | 8c81a20ace8c65d0a9d58b9cf333049a2bc0383a (patch) | |
| tree | 86c653e99c02225f7ed5ee93b42d272b11404a93 /src | |
| parent | glasm: Enable unintentionally disabled register aliasing on GLASM (diff) | |
| download | yuzu-8c81a20ace8c65d0a9d58b9cf333049a2bc0383a.tar.gz yuzu-8c81a20ace8c65d0a9d58b9cf333049a2bc0383a.tar.xz yuzu-8c81a20ace8c65d0a9d58b9cf333049a2bc0383a.zip | |
glasm: Ensure reg alloc order across compilers on GLASM
Use a struct constructor to serialize register allocation arguments to
ensure registers are allocated in the same order regardless of the
compiler used.
The A and B functions can be called in any order when passed as
arguments to "foo":
foo(A(), B())
But the order is guaranteed for curly-braced constructor calls in
classes:
Foo{A(), B()}
Use this to get consistent behavior.
Diffstat (limited to 'src')
| -rw-r--r-- | src/shader_recompiler/backend/glasm/emit_glasm.cpp | 25 |
1 files changed, 14 insertions, 11 deletions
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm.cpp b/src/shader_recompiler/backend/glasm/emit_glasm.cpp index c90b80e48..047b2f89c 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm.cpp | |||
| @@ -128,24 +128,27 @@ auto Arg(EmitContext& ctx, const IR::Value& arg) { | |||
| 128 | } | 128 | } |
| 129 | } | 129 | } |
| 130 | 130 | ||
| 131 | template <auto func, bool is_first_arg_inst, typename... Args> | 131 | template <auto func, bool is_first_arg_inst> |
| 132 | void InvokeCall(EmitContext& ctx, IR::Inst* inst, Args&&... args) { | 132 | struct InvokeCall { |
| 133 | if constexpr (is_first_arg_inst) { | 133 | template <typename... Args> |
| 134 | func(ctx, *inst, args.Extract()...); | 134 | InvokeCall(EmitContext& ctx, IR::Inst* inst, Args&&... args) { |
| 135 | } else { | 135 | if constexpr (is_first_arg_inst) { |
| 136 | func(ctx, args.Extract()...); | 136 | func(ctx, *inst, args.Extract()...); |
| 137 | } else { | ||
| 138 | func(ctx, args.Extract()...); | ||
| 139 | } | ||
| 137 | } | 140 | } |
| 138 | } | 141 | }; |
| 139 | 142 | ||
| 140 | template <auto func, bool is_first_arg_inst, size_t... I> | 143 | template <auto func, bool is_first_arg_inst, size_t... I> |
| 141 | void Invoke(EmitContext& ctx, IR::Inst* inst, std::index_sequence<I...>) { | 144 | void Invoke(EmitContext& ctx, IR::Inst* inst, std::index_sequence<I...>) { |
| 142 | using Traits = FuncTraits<decltype(func)>; | 145 | using Traits = FuncTraits<decltype(func)>; |
| 143 | if constexpr (is_first_arg_inst) { | 146 | if constexpr (is_first_arg_inst) { |
| 144 | InvokeCall<func, is_first_arg_inst>( | 147 | InvokeCall<func, is_first_arg_inst>{ |
| 145 | ctx, inst, Arg<typename Traits::template ArgType<I + 2>>(ctx, inst->Arg(I))...); | 148 | ctx, inst, Arg<typename Traits::template ArgType<I + 2>>(ctx, inst->Arg(I))...}; |
| 146 | } else { | 149 | } else { |
| 147 | InvokeCall<func, is_first_arg_inst>( | 150 | InvokeCall<func, is_first_arg_inst>{ |
| 148 | ctx, inst, Arg<typename Traits::template ArgType<I + 1>>(ctx, inst->Arg(I))...); | 151 | ctx, inst, Arg<typename Traits::template ArgType<I + 1>>(ctx, inst->Arg(I))...}; |
| 149 | } | 152 | } |
| 150 | } | 153 | } |
| 151 | 154 | ||