diff options
| author | 2021-02-14 22:46:40 -0300 | |
|---|---|---|
| committer | 2021-07-22 21:51:22 -0400 | |
| commit | 1b0cf2309c760c1cb97a230a1572f8e87f84444a (patch) | |
| tree | 6316825f65565b4c764b7851d061be0776a89974 | |
| parent | shader: Support SSA loops on IR (diff) | |
| download | yuzu-1b0cf2309c760c1cb97a230a1572f8e87f84444a.tar.gz yuzu-1b0cf2309c760c1cb97a230a1572f8e87f84444a.tar.xz yuzu-1b0cf2309c760c1cb97a230a1572f8e87f84444a.zip | |
shader: Add support for forward declarations
| m--------- | externals/sirit | 0 | ||||
| -rw-r--r-- | src/shader_recompiler/backend/spirv/emit_spirv.cpp | 61 | ||||
| -rw-r--r-- | src/shader_recompiler/backend/spirv/emit_spirv.h | 40 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/ir/basic_block.cpp | 2 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/ir/basic_block.h | 2 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/ir/ir_emitter.h | 4 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/ir/microinstruction.cpp | 2 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/ir/microinstruction.h | 20 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/ir/modifiers.h | 10 | ||||
| -rw-r--r-- | src/shader_recompiler/ir_opt/global_memory_to_storage_buffer_pass.cpp | 4 | ||||
| -rw-r--r-- | src/shader_recompiler/main.cpp | 2 |
11 files changed, 79 insertions, 68 deletions
diff --git a/externals/sirit b/externals/sirit | |||
| Subproject c374bfd9fdff02a0cff85d005488967b1b0f675 | Subproject f819ade0efe925a782090dea9e1bf300fedffb3 | ||
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.cpp b/src/shader_recompiler/backend/spirv/emit_spirv.cpp index e29e448c7..0895414b4 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv.cpp | |||
| @@ -64,31 +64,49 @@ EmitSPIRV::EmitSPIRV(IR::Program& program) { | |||
| 64 | std::system("spirv-cross shader.spv"); | 64 | std::system("spirv-cross shader.spv"); |
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | template <auto method, typename... Args> | ||
| 68 | static void SetDefinition(EmitSPIRV& emit, EmitContext& ctx, IR::Inst* inst, Args... args) { | ||
| 69 | const Id forward_id{inst->Definition<Id>()}; | ||
| 70 | const bool has_forward_id{Sirit::ValidId(forward_id)}; | ||
| 71 | Id current_id{}; | ||
| 72 | if (has_forward_id) { | ||
| 73 | current_id = ctx.ExchangeCurrentId(forward_id); | ||
| 74 | } | ||
| 75 | const Id new_id{(emit.*method)(ctx, std::forward<Args>(args)...)}; | ||
| 76 | if (has_forward_id) { | ||
| 77 | ctx.ExchangeCurrentId(current_id); | ||
| 78 | } else { | ||
| 79 | inst->SetDefinition<Id>(new_id); | ||
| 80 | } | ||
| 81 | } | ||
| 82 | |||
| 67 | template <auto method> | 83 | template <auto method> |
| 68 | static void Invoke(EmitSPIRV& emit, EmitContext& ctx, IR::Inst* inst) { | 84 | static void Invoke(EmitSPIRV& emit, EmitContext& ctx, IR::Inst* inst) { |
| 69 | using M = decltype(method); | 85 | using M = decltype(method); |
| 70 | using std::is_invocable_r_v; | 86 | using std::is_invocable_r_v; |
| 71 | if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&>) { | 87 | if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&>) { |
| 72 | ctx.Define(inst, (emit.*method)(ctx)); | 88 | SetDefinition<method>(emit, ctx, inst); |
| 73 | } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, Id>) { | 89 | } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, Id>) { |
| 74 | ctx.Define(inst, (emit.*method)(ctx, ctx.Def(inst->Arg(0)))); | 90 | SetDefinition<method>(emit, ctx, inst, ctx.Def(inst->Arg(0))); |
| 75 | } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, Id, Id>) { | 91 | } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, Id, Id>) { |
| 76 | ctx.Define(inst, (emit.*method)(ctx, ctx.Def(inst->Arg(0)), ctx.Def(inst->Arg(1)))); | 92 | SetDefinition<method>(emit, ctx, inst, ctx.Def(inst->Arg(0)), ctx.Def(inst->Arg(1))); |
| 77 | } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, Id, Id, Id>) { | 93 | } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, Id, Id, Id>) { |
| 78 | ctx.Define(inst, (emit.*method)(ctx, ctx.Def(inst->Arg(0)), ctx.Def(inst->Arg(1)), | 94 | SetDefinition<method>(emit, ctx, inst, ctx.Def(inst->Arg(0)), ctx.Def(inst->Arg(1)), |
| 79 | ctx.Def(inst->Arg(2)))); | 95 | ctx.Def(inst->Arg(2))); |
| 96 | } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, IR::Inst*>) { | ||
| 97 | SetDefinition<method>(emit, ctx, inst, inst); | ||
| 80 | } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, IR::Inst*, Id, Id>) { | 98 | } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, IR::Inst*, Id, Id>) { |
| 81 | ctx.Define(inst, (emit.*method)(ctx, inst, ctx.Def(inst->Arg(0)), ctx.Def(inst->Arg(1)))); | 99 | SetDefinition<method>(emit, ctx, inst, inst, ctx.Def(inst->Arg(0)), ctx.Def(inst->Arg(1))); |
| 82 | } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, IR::Inst*, Id, Id, Id>) { | 100 | } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, IR::Inst*, Id, Id, Id>) { |
| 83 | ctx.Define(inst, (emit.*method)(ctx, inst, ctx.Def(inst->Arg(0)), ctx.Def(inst->Arg(1)), | 101 | SetDefinition<method>(emit, ctx, inst, inst, ctx.Def(inst->Arg(0)), ctx.Def(inst->Arg(1)), |
| 84 | ctx.Def(inst->Arg(2)))); | 102 | ctx.Def(inst->Arg(2))); |
| 85 | } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, Id, u32>) { | 103 | } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, Id, u32>) { |
| 86 | ctx.Define(inst, (emit.*method)(ctx, ctx.Def(inst->Arg(0)), inst->Arg(1).U32())); | 104 | SetDefinition<method>(emit, ctx, inst, ctx.Def(inst->Arg(0)), inst->Arg(1).U32()); |
| 87 | } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, const IR::Value&>) { | 105 | } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, const IR::Value&>) { |
| 88 | ctx.Define(inst, (emit.*method)(ctx, inst->Arg(0))); | 106 | SetDefinition<method>(emit, ctx, inst, inst->Arg(0)); |
| 89 | } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, const IR::Value&, | 107 | } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, const IR::Value&, |
| 90 | const IR::Value&>) { | 108 | const IR::Value&>) { |
| 91 | ctx.Define(inst, (emit.*method)(ctx, inst->Arg(0), inst->Arg(1))); | 109 | SetDefinition<method>(emit, ctx, inst, inst->Arg(0), inst->Arg(1)); |
| 92 | } else if constexpr (is_invocable_r_v<void, M, EmitSPIRV&, EmitContext&, IR::Inst*>) { | 110 | } else if constexpr (is_invocable_r_v<void, M, EmitSPIRV&, EmitContext&, IR::Inst*>) { |
| 93 | (emit.*method)(ctx, inst); | 111 | (emit.*method)(ctx, inst); |
| 94 | } else if constexpr (is_invocable_r_v<void, M, EmitSPIRV&, EmitContext&>) { | 112 | } else if constexpr (is_invocable_r_v<void, M, EmitSPIRV&, EmitContext&>) { |
| @@ -122,11 +140,28 @@ static Id TypeId(const EmitContext& ctx, IR::Type type) { | |||
| 122 | 140 | ||
| 123 | Id EmitSPIRV::EmitPhi(EmitContext& ctx, IR::Inst* inst) { | 141 | Id EmitSPIRV::EmitPhi(EmitContext& ctx, IR::Inst* inst) { |
| 124 | const size_t num_args{inst->NumArgs()}; | 142 | const size_t num_args{inst->NumArgs()}; |
| 125 | boost::container::small_vector<Id, 64> operands; | 143 | boost::container::small_vector<Id, 32> operands; |
| 126 | operands.reserve(num_args * 2); | 144 | operands.reserve(num_args * 2); |
| 127 | for (size_t index = 0; index < num_args; ++index) { | 145 | for (size_t index = 0; index < num_args; ++index) { |
| 146 | // Phi nodes can have forward declarations, if an argument is not defined provide a forward | ||
| 147 | // declaration of it. Invoke will take care of giving it the right definition when it's | ||
| 148 | // actually defined. | ||
| 149 | const IR::Value arg{inst->Arg(index)}; | ||
| 150 | Id def{}; | ||
| 151 | if (arg.IsImmediate()) { | ||
| 152 | // Let the context handle immediate definitions, as it already knows how | ||
| 153 | def = ctx.Def(arg); | ||
| 154 | } else { | ||
| 155 | IR::Inst* const arg_inst{arg.Inst()}; | ||
| 156 | def = arg_inst->Definition<Id>(); | ||
| 157 | if (!Sirit::ValidId(def)) { | ||
| 158 | // If it hasn't been defined, get a forward declaration | ||
| 159 | def = ctx.ForwardDeclarationId(); | ||
| 160 | arg_inst->SetDefinition<Id>(def); | ||
| 161 | } | ||
| 162 | } | ||
| 128 | IR::Block* const phi_block{inst->PhiBlock(index)}; | 163 | IR::Block* const phi_block{inst->PhiBlock(index)}; |
| 129 | operands.push_back(ctx.Def(inst->Arg(index))); | 164 | operands.push_back(def); |
| 130 | operands.push_back(ctx.BlockLabel(phi_block)); | 165 | operands.push_back(ctx.BlockLabel(phi_block)); |
| 131 | } | 166 | } |
| 132 | const Id result_type{TypeId(ctx, inst->Arg(0).Type())}; | 167 | const Id result_type{TypeId(ctx, inst->Arg(0).Type())}; |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.h b/src/shader_recompiler/backend/spirv/emit_spirv.h index 6b09757d1..7d76377b5 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv.h +++ b/src/shader_recompiler/backend/spirv/emit_spirv.h | |||
| @@ -6,8 +6,6 @@ | |||
| 6 | 6 | ||
| 7 | #include <sirit/sirit.h> | 7 | #include <sirit/sirit.h> |
| 8 | 8 | ||
| 9 | #include <boost/container/flat_map.hpp> | ||
| 10 | |||
| 11 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 12 | #include "shader_recompiler/frontend/ir/microinstruction.h" | 10 | #include "shader_recompiler/frontend/ir/microinstruction.h" |
| 13 | #include "shader_recompiler/frontend/ir/program.h" | 11 | #include "shader_recompiler/frontend/ir/program.h" |
| @@ -16,37 +14,6 @@ namespace Shader::Backend::SPIRV { | |||
| 16 | 14 | ||
| 17 | using Sirit::Id; | 15 | using Sirit::Id; |
| 18 | 16 | ||
| 19 | class DefMap { | ||
| 20 | public: | ||
| 21 | void Define(IR::Inst* inst, Id def_id) { | ||
| 22 | const InstInfo info{.use_count{inst->UseCount()}, .def_id{def_id}}; | ||
| 23 | const auto it{map.insert(map.end(), std::make_pair(inst, info))}; | ||
| 24 | if (it == map.end()) { | ||
| 25 | throw LogicError("Defining already defined instruction"); | ||
| 26 | } | ||
| 27 | } | ||
| 28 | |||
| 29 | [[nodiscard]] Id Consume(IR::Inst* inst) { | ||
| 30 | const auto it{map.find(inst)}; | ||
| 31 | if (it == map.end()) { | ||
| 32 | throw LogicError("Consuming undefined instruction"); | ||
| 33 | } | ||
| 34 | const Id def_id{it->second.def_id}; | ||
| 35 | if (--it->second.use_count == 0) { | ||
| 36 | map.erase(it); | ||
| 37 | } | ||
| 38 | return def_id; | ||
| 39 | } | ||
| 40 | |||
| 41 | private: | ||
| 42 | struct InstInfo { | ||
| 43 | int use_count; | ||
| 44 | Id def_id; | ||
| 45 | }; | ||
| 46 | |||
| 47 | boost::container::flat_map<IR::Inst*, InstInfo> map; | ||
| 48 | }; | ||
| 49 | |||
| 50 | class VectorTypes { | 17 | class VectorTypes { |
| 51 | public: | 18 | public: |
| 52 | void Define(Sirit::Module& sirit_ctx, Id base_type, std::string_view name) { | 19 | void Define(Sirit::Module& sirit_ctx, Id base_type, std::string_view name) { |
| @@ -76,7 +43,7 @@ public: | |||
| 76 | 43 | ||
| 77 | [[nodiscard]] Id Def(const IR::Value& value) { | 44 | [[nodiscard]] Id Def(const IR::Value& value) { |
| 78 | if (!value.IsImmediate()) { | 45 | if (!value.IsImmediate()) { |
| 79 | return def_map.Consume(value.Inst()); | 46 | return value.Inst()->Definition<Id>(); |
| 80 | } | 47 | } |
| 81 | switch (value.Type()) { | 48 | switch (value.Type()) { |
| 82 | case IR::Type::U1: | 49 | case IR::Type::U1: |
| @@ -90,10 +57,6 @@ public: | |||
| 90 | } | 57 | } |
| 91 | } | 58 | } |
| 92 | 59 | ||
| 93 | void Define(IR::Inst* inst, Id def_id) { | ||
| 94 | def_map.Define(inst, def_id); | ||
| 95 | } | ||
| 96 | |||
| 97 | [[nodiscard]] Id BlockLabel(IR::Block* block) const { | 60 | [[nodiscard]] Id BlockLabel(IR::Block* block) const { |
| 98 | const auto it{std::ranges::lower_bound(block_label_map, block, {}, | 61 | const auto it{std::ranges::lower_bound(block_label_map, block, {}, |
| 99 | &std::pair<IR::Block*, Id>::first)}; | 62 | &std::pair<IR::Block*, Id>::first)}; |
| @@ -117,7 +80,6 @@ public: | |||
| 117 | Id local_invocation_id{}; | 80 | Id local_invocation_id{}; |
| 118 | 81 | ||
| 119 | private: | 82 | private: |
| 120 | DefMap def_map; | ||
| 121 | std::vector<std::pair<IR::Block*, Id>> block_label_map; | 83 | std::vector<std::pair<IR::Block*, Id>> block_label_map; |
| 122 | }; | 84 | }; |
| 123 | 85 | ||
diff --git a/src/shader_recompiler/frontend/ir/basic_block.cpp b/src/shader_recompiler/frontend/ir/basic_block.cpp index c97626712..5ae91dd7d 100644 --- a/src/shader_recompiler/frontend/ir/basic_block.cpp +++ b/src/shader_recompiler/frontend/ir/basic_block.cpp | |||
| @@ -26,7 +26,7 @@ void Block::AppendNewInst(Opcode op, std::initializer_list<Value> args) { | |||
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | Block::iterator Block::PrependNewInst(iterator insertion_point, Opcode op, | 28 | Block::iterator Block::PrependNewInst(iterator insertion_point, Opcode op, |
| 29 | std::initializer_list<Value> args, u64 flags) { | 29 | std::initializer_list<Value> args, u32 flags) { |
| 30 | Inst* const inst{inst_pool->Create(op, flags)}; | 30 | Inst* const inst{inst_pool->Create(op, flags)}; |
| 31 | const auto result_it{instructions.insert(insertion_point, *inst)}; | 31 | const auto result_it{instructions.insert(insertion_point, *inst)}; |
| 32 | 32 | ||
diff --git a/src/shader_recompiler/frontend/ir/basic_block.h b/src/shader_recompiler/frontend/ir/basic_block.h index 3205705e7..778b32e43 100644 --- a/src/shader_recompiler/frontend/ir/basic_block.h +++ b/src/shader_recompiler/frontend/ir/basic_block.h | |||
| @@ -42,7 +42,7 @@ public: | |||
| 42 | 42 | ||
| 43 | /// Prepends a new instruction to this basic block before the insertion point. | 43 | /// Prepends a new instruction to this basic block before the insertion point. |
| 44 | iterator PrependNewInst(iterator insertion_point, Opcode op, | 44 | iterator PrependNewInst(iterator insertion_point, Opcode op, |
| 45 | std::initializer_list<Value> args = {}, u64 flags = 0); | 45 | std::initializer_list<Value> args = {}, u32 flags = 0); |
| 46 | 46 | ||
| 47 | /// Set the branches to jump to when all instructions have executed. | 47 | /// Set the branches to jump to when all instructions have executed. |
| 48 | void SetBranches(Condition cond, Block* branch_true, Block* branch_false); | 48 | void SetBranches(Condition cond, Block* branch_true, Block* branch_false); |
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.h b/src/shader_recompiler/frontend/ir/ir_emitter.h index 4decb46bc..24b012a39 100644 --- a/src/shader_recompiler/frontend/ir/ir_emitter.h +++ b/src/shader_recompiler/frontend/ir/ir_emitter.h | |||
| @@ -178,7 +178,7 @@ private: | |||
| 178 | } | 178 | } |
| 179 | 179 | ||
| 180 | template <typename T> | 180 | template <typename T> |
| 181 | requires(sizeof(T) <= sizeof(u64) && std::is_trivially_copyable_v<T>) struct Flags { | 181 | requires(sizeof(T) <= sizeof(u32) && std::is_trivially_copyable_v<T>) struct Flags { |
| 182 | Flags() = default; | 182 | Flags() = default; |
| 183 | Flags(T proxy_) : proxy{proxy_} {} | 183 | Flags(T proxy_) : proxy{proxy_} {} |
| 184 | 184 | ||
| @@ -187,7 +187,7 @@ private: | |||
| 187 | 187 | ||
| 188 | template <typename T = Value, typename FlagType, typename... Args> | 188 | template <typename T = Value, typename FlagType, typename... Args> |
| 189 | T Inst(Opcode op, Flags<FlagType> flags, Args... args) { | 189 | T Inst(Opcode op, Flags<FlagType> flags, Args... args) { |
| 190 | u64 raw_flags{}; | 190 | u32 raw_flags{}; |
| 191 | std::memcpy(&raw_flags, &flags.proxy, sizeof(flags.proxy)); | 191 | std::memcpy(&raw_flags, &flags.proxy, sizeof(flags.proxy)); |
| 192 | auto it{block->PrependNewInst(insertion_point, op, {Value{args}...}, raw_flags)}; | 192 | auto it{block->PrependNewInst(insertion_point, op, {Value{args}...}, raw_flags)}; |
| 193 | return T{Value{&*it}}; | 193 | return T{Value{&*it}}; |
diff --git a/src/shader_recompiler/frontend/ir/microinstruction.cpp b/src/shader_recompiler/frontend/ir/microinstruction.cpp index 9279b9692..ee76db9ad 100644 --- a/src/shader_recompiler/frontend/ir/microinstruction.cpp +++ b/src/shader_recompiler/frontend/ir/microinstruction.cpp | |||
| @@ -31,7 +31,7 @@ static void RemovePseudoInstruction(IR::Inst*& inst, IR::Opcode expected_opcode) | |||
| 31 | inst = nullptr; | 31 | inst = nullptr; |
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | Inst::Inst(IR::Opcode op_, u64 flags_) noexcept : op{op_}, flags{flags_} { | 34 | Inst::Inst(IR::Opcode op_, u32 flags_) noexcept : op{op_}, flags{flags_} { |
| 35 | if (op == Opcode::Phi) { | 35 | if (op == Opcode::Phi) { |
| 36 | std::construct_at(&phi_args); | 36 | std::construct_at(&phi_args); |
| 37 | } else { | 37 | } else { |
diff --git a/src/shader_recompiler/frontend/ir/microinstruction.h b/src/shader_recompiler/frontend/ir/microinstruction.h index ddf0f90a9..5b244fa0b 100644 --- a/src/shader_recompiler/frontend/ir/microinstruction.h +++ b/src/shader_recompiler/frontend/ir/microinstruction.h | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | 12 | ||
| 13 | #include <boost/intrusive/list.hpp> | 13 | #include <boost/intrusive/list.hpp> |
| 14 | 14 | ||
| 15 | #include "common/bit_cast.h" | ||
| 15 | #include "common/common_types.h" | 16 | #include "common/common_types.h" |
| 16 | #include "shader_recompiler/frontend/ir/opcodes.h" | 17 | #include "shader_recompiler/frontend/ir/opcodes.h" |
| 17 | #include "shader_recompiler/frontend/ir/type.h" | 18 | #include "shader_recompiler/frontend/ir/type.h" |
| @@ -25,7 +26,7 @@ constexpr size_t MAX_ARG_COUNT = 4; | |||
| 25 | 26 | ||
| 26 | class Inst : public boost::intrusive::list_base_hook<> { | 27 | class Inst : public boost::intrusive::list_base_hook<> { |
| 27 | public: | 28 | public: |
| 28 | explicit Inst(Opcode op_, u64 flags_) noexcept; | 29 | explicit Inst(Opcode op_, u32 flags_) noexcept; |
| 29 | ~Inst(); | 30 | ~Inst(); |
| 30 | 31 | ||
| 31 | Inst& operator=(const Inst&) = delete; | 32 | Inst& operator=(const Inst&) = delete; |
| @@ -86,13 +87,25 @@ public: | |||
| 86 | void ReplaceUsesWith(Value replacement); | 87 | void ReplaceUsesWith(Value replacement); |
| 87 | 88 | ||
| 88 | template <typename FlagsType> | 89 | template <typename FlagsType> |
| 89 | requires(sizeof(FlagsType) <= sizeof(u64) && std::is_trivially_copyable_v<FlagsType>) | 90 | requires(sizeof(FlagsType) <= sizeof(u32) && std::is_trivially_copyable_v<FlagsType>) |
| 90 | [[nodiscard]] FlagsType Flags() const noexcept { | 91 | [[nodiscard]] FlagsType Flags() const noexcept { |
| 91 | FlagsType ret; | 92 | FlagsType ret; |
| 92 | std::memcpy(&ret, &flags, sizeof(ret)); | 93 | std::memcpy(&ret, &flags, sizeof(ret)); |
| 93 | return ret; | 94 | return ret; |
| 94 | } | 95 | } |
| 95 | 96 | ||
| 97 | /// Intrusively store the host definition of this instruction. | ||
| 98 | template <typename DefinitionType> | ||
| 99 | void SetDefinition(DefinitionType def) { | ||
| 100 | definition = Common::BitCast<u32>(def); | ||
| 101 | } | ||
| 102 | |||
| 103 | /// Return the intrusively stored host definition of this instruction. | ||
| 104 | template <typename DefinitionType> | ||
| 105 | [[nodiscard]] DefinitionType Definition() const noexcept { | ||
| 106 | return Common::BitCast<DefinitionType>(definition); | ||
| 107 | } | ||
| 108 | |||
| 96 | private: | 109 | private: |
| 97 | struct NonTriviallyDummy { | 110 | struct NonTriviallyDummy { |
| 98 | NonTriviallyDummy() noexcept {} | 111 | NonTriviallyDummy() noexcept {} |
| @@ -103,7 +116,8 @@ private: | |||
| 103 | 116 | ||
| 104 | IR::Opcode op{}; | 117 | IR::Opcode op{}; |
| 105 | int use_count{}; | 118 | int use_count{}; |
| 106 | u64 flags{}; | 119 | u32 flags{}; |
| 120 | u32 definition{}; | ||
| 107 | union { | 121 | union { |
| 108 | NonTriviallyDummy dummy{}; | 122 | NonTriviallyDummy dummy{}; |
| 109 | std::array<Value, MAX_ARG_COUNT> args; | 123 | std::array<Value, MAX_ARG_COUNT> args; |
diff --git a/src/shader_recompiler/frontend/ir/modifiers.h b/src/shader_recompiler/frontend/ir/modifiers.h index 28bb9e798..c288eede0 100644 --- a/src/shader_recompiler/frontend/ir/modifiers.h +++ b/src/shader_recompiler/frontend/ir/modifiers.h | |||
| @@ -6,13 +6,13 @@ | |||
| 6 | 6 | ||
| 7 | namespace Shader::IR { | 7 | namespace Shader::IR { |
| 8 | 8 | ||
| 9 | enum class FmzMode { | 9 | enum class FmzMode : u8 { |
| 10 | None, // Denorms are not flushed, NAN is propagated (nouveau) | 10 | None, // Denorms are not flushed, NAN is propagated (nouveau) |
| 11 | FTZ, // Flush denorms to zero, NAN is propagated (D3D11, NVN, GL, VK) | 11 | FTZ, // Flush denorms to zero, NAN is propagated (D3D11, NVN, GL, VK) |
| 12 | FMZ, // Flush denorms to zero, x * 0 == 0 (D3D9) | 12 | FMZ, // Flush denorms to zero, x * 0 == 0 (D3D9) |
| 13 | }; | 13 | }; |
| 14 | 14 | ||
| 15 | enum class FpRounding { | 15 | enum class FpRounding : u8 { |
| 16 | RN, // Round to nearest even, | 16 | RN, // Round to nearest even, |
| 17 | RM, // Round towards negative infinity | 17 | RM, // Round towards negative infinity |
| 18 | RP, // Round towards positive infinity | 18 | RP, // Round towards positive infinity |
| @@ -21,8 +21,8 @@ enum class FpRounding { | |||
| 21 | 21 | ||
| 22 | struct FpControl { | 22 | struct FpControl { |
| 23 | bool no_contraction{false}; | 23 | bool no_contraction{false}; |
| 24 | FpRounding rounding : 8 = FpRounding::RN; | 24 | FpRounding rounding{FpRounding::RN}; |
| 25 | FmzMode fmz_mode : 8 = FmzMode::FTZ; | 25 | FmzMode fmz_mode{FmzMode::FTZ}; |
| 26 | }; | 26 | }; |
| 27 | static_assert(sizeof(FpControl) <= sizeof(u64)); | 27 | static_assert(sizeof(FpControl) <= sizeof(u32)); |
| 28 | } // namespace Shader::IR | 28 | } // namespace Shader::IR |
diff --git a/src/shader_recompiler/ir_opt/global_memory_to_storage_buffer_pass.cpp b/src/shader_recompiler/ir_opt/global_memory_to_storage_buffer_pass.cpp index 34393e1d5..08fd364bb 100644 --- a/src/shader_recompiler/ir_opt/global_memory_to_storage_buffer_pass.cpp +++ b/src/shader_recompiler/ir_opt/global_memory_to_storage_buffer_pass.cpp | |||
| @@ -161,8 +161,8 @@ std::optional<StorageBufferAddr> Track(const IR::Value& value, const Bias* bias) | |||
| 161 | return std::nullopt; | 161 | return std::nullopt; |
| 162 | } | 162 | } |
| 163 | const StorageBufferAddr storage_buffer{ | 163 | const StorageBufferAddr storage_buffer{ |
| 164 | .index = index.U32(), | 164 | .index{index.U32()}, |
| 165 | .offset = offset.U32(), | 165 | .offset{offset.U32()}, |
| 166 | }; | 166 | }; |
| 167 | if (bias && !MeetsBias(storage_buffer, *bias)) { | 167 | if (bias && !MeetsBias(storage_buffer, *bias)) { |
| 168 | // We have to blacklist some addresses in case we wrongly point to them | 168 | // We have to blacklist some addresses in case we wrongly point to them |
diff --git a/src/shader_recompiler/main.cpp b/src/shader_recompiler/main.cpp index 29f65966c..3b110af61 100644 --- a/src/shader_recompiler/main.cpp +++ b/src/shader_recompiler/main.cpp | |||
| @@ -76,5 +76,5 @@ int main() { | |||
| 76 | fmt::print(stdout, "{}\n", cfg.Dot()); | 76 | fmt::print(stdout, "{}\n", cfg.Dot()); |
| 77 | IR::Program program{TranslateProgram(*inst_pool, *block_pool, env, cfg)}; | 77 | IR::Program program{TranslateProgram(*inst_pool, *block_pool, env, cfg)}; |
| 78 | fmt::print(stdout, "{}\n", IR::DumpProgram(program)); | 78 | fmt::print(stdout, "{}\n", IR::DumpProgram(program)); |
| 79 | // Backend::SPIRV::EmitSPIRV spirv{program}; | 79 | Backend::SPIRV::EmitSPIRV spirv{program}; |
| 80 | } | 80 | } |