diff options
| author | 2021-02-06 02:38:22 -0300 | |
|---|---|---|
| committer | 2021-07-22 21:51:21 -0400 | |
| commit | da8096e6e35af250dcc56a1af76b8a211df63a90 (patch) | |
| tree | 5bac3a389afddd1ba23a9fb2ea410c077c28f3b8 | |
| parent | shader: Add pools and rename files (diff) | |
| download | yuzu-da8096e6e35af250dcc56a1af76b8a211df63a90.tar.gz yuzu-da8096e6e35af250dcc56a1af76b8a211df63a90.tar.xz yuzu-da8096e6e35af250dcc56a1af76b8a211df63a90.zip | |
shader: Properly store phi on Inst
| -rw-r--r-- | src/shader_recompiler/frontend/ir/basic_block.cpp | 33 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/ir/microinstruction.cpp | 102 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/ir/microinstruction.h | 37 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/ir/opcodes.inc | 2 | ||||
| -rw-r--r-- | src/shader_recompiler/ir_opt/ssa_rewrite_pass.cpp | 22 | ||||
| -rw-r--r-- | src/shader_recompiler/object_pool.h | 11 |
6 files changed, 132 insertions, 75 deletions
diff --git a/src/shader_recompiler/frontend/ir/basic_block.cpp b/src/shader_recompiler/frontend/ir/basic_block.cpp index 1a5d82135..50c6a83cd 100644 --- a/src/shader_recompiler/frontend/ir/basic_block.cpp +++ b/src/shader_recompiler/frontend/ir/basic_block.cpp | |||
| @@ -129,26 +129,21 @@ std::string DumpBlock(const Block& block, const std::map<const Block*, size_t>& | |||
| 129 | } else { | 129 | } else { |
| 130 | ret += fmt::format(" {}", op); // '%00000 = ' -> 1 + 5 + 3 = 9 spaces | 130 | ret += fmt::format(" {}", op); // '%00000 = ' -> 1 + 5 + 3 = 9 spaces |
| 131 | } | 131 | } |
| 132 | if (op == Opcode::Phi) { | 132 | const size_t arg_count{NumArgsOf(op)}; |
| 133 | size_t val_index{0}; | 133 | for (size_t arg_index = 0; arg_index < arg_count; ++arg_index) { |
| 134 | for (const auto& [phi_block, phi_val] : inst.PhiOperands()) { | 134 | const Value arg{inst.Arg(arg_index)}; |
| 135 | ret += val_index != 0 ? ", " : " "; | 135 | const std::string arg_str{ArgToIndex(block_to_index, inst_to_index, arg)}; |
| 136 | ret += fmt::format("[ {}, {} ]", ArgToIndex(block_to_index, inst_to_index, phi_val), | 136 | ret += arg_index != 0 ? ", " : " "; |
| 137 | BlockToIndex(block_to_index, phi_block)); | 137 | if (op == Opcode::Phi) { |
| 138 | ++val_index; | 138 | ret += fmt::format("[ {}, {} ]", arg_index, |
| 139 | BlockToIndex(block_to_index, inst.PhiBlock(arg_index))); | ||
| 140 | } else { | ||
| 141 | ret += arg_str; | ||
| 139 | } | 142 | } |
| 140 | } else { | 143 | const Type actual_type{arg.Type()}; |
| 141 | const size_t arg_count{NumArgsOf(op)}; | 144 | const Type expected_type{ArgTypeOf(op, arg_index)}; |
| 142 | for (size_t arg_index = 0; arg_index < arg_count; ++arg_index) { | 145 | if (!AreTypesCompatible(actual_type, expected_type)) { |
| 143 | const Value arg{inst.Arg(arg_index)}; | 146 | ret += fmt::format("<type error: {} != {}>", actual_type, expected_type); |
| 144 | ret += arg_index != 0 ? ", " : " "; | ||
| 145 | ret += ArgToIndex(block_to_index, inst_to_index, arg); | ||
| 146 | |||
| 147 | const Type actual_type{arg.Type()}; | ||
| 148 | const Type expected_type{ArgTypeOf(op, arg_index)}; | ||
| 149 | if (!AreTypesCompatible(actual_type, expected_type)) { | ||
| 150 | ret += fmt::format("<type error: {} != {}>", actual_type, expected_type); | ||
| 151 | } | ||
| 152 | } | 147 | } |
| 153 | } | 148 | } |
| 154 | if (TypeOf(op) != Type::Void) { | 149 | if (TypeOf(op) != Type::Void) { |
diff --git a/src/shader_recompiler/frontend/ir/microinstruction.cpp b/src/shader_recompiler/frontend/ir/microinstruction.cpp index de953838c..e7ca92039 100644 --- a/src/shader_recompiler/frontend/ir/microinstruction.cpp +++ b/src/shader_recompiler/frontend/ir/microinstruction.cpp | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include <memory> | ||
| 6 | 7 | ||
| 7 | #include "shader_recompiler/exception.h" | 8 | #include "shader_recompiler/exception.h" |
| 8 | #include "shader_recompiler/frontend/ir/microinstruction.h" | 9 | #include "shader_recompiler/frontend/ir/microinstruction.h" |
| @@ -30,6 +31,22 @@ static void RemovePseudoInstruction(IR::Inst*& inst, IR::Opcode expected_opcode) | |||
| 30 | inst = nullptr; | 31 | inst = nullptr; |
| 31 | } | 32 | } |
| 32 | 33 | ||
| 34 | Inst::Inst(IR::Opcode op_, u64 flags_) noexcept : op{op_}, flags{flags_} { | ||
| 35 | if (op == Opcode::Phi) { | ||
| 36 | std::construct_at(&phi_args); | ||
| 37 | } else { | ||
| 38 | std::construct_at(&args); | ||
| 39 | } | ||
| 40 | } | ||
| 41 | |||
| 42 | Inst::~Inst() { | ||
| 43 | if (op == Opcode::Phi) { | ||
| 44 | std::destroy_at(&phi_args); | ||
| 45 | } else { | ||
| 46 | std::destroy_at(&args); | ||
| 47 | } | ||
| 48 | } | ||
| 49 | |||
| 33 | bool Inst::MayHaveSideEffects() const noexcept { | 50 | bool Inst::MayHaveSideEffects() const noexcept { |
| 34 | switch (op) { | 51 | switch (op) { |
| 35 | case Opcode::Branch: | 52 | case Opcode::Branch: |
| @@ -71,7 +88,10 @@ bool Inst::IsPseudoInstruction() const noexcept { | |||
| 71 | } | 88 | } |
| 72 | } | 89 | } |
| 73 | 90 | ||
| 74 | bool Inst::AreAllArgsImmediates() const noexcept { | 91 | bool Inst::AreAllArgsImmediates() const { |
| 92 | if (op == Opcode::Phi) { | ||
| 93 | throw LogicError("Testing for all arguments are immediates on phi instruction"); | ||
| 94 | } | ||
| 75 | return std::all_of(args.begin(), args.begin() + NumArgs(), | 95 | return std::all_of(args.begin(), args.begin() + NumArgs(), |
| 76 | [](const IR::Value& value) { return value.IsImmediate(); }); | 96 | [](const IR::Value& value) { return value.IsImmediate(); }); |
| 77 | } | 97 | } |
| @@ -101,7 +121,7 @@ Inst* Inst::GetAssociatedPseudoOperation(IR::Opcode opcode) { | |||
| 101 | } | 121 | } |
| 102 | 122 | ||
| 103 | size_t Inst::NumArgs() const { | 123 | size_t Inst::NumArgs() const { |
| 104 | return NumArgsOf(op); | 124 | return op == Opcode::Phi ? phi_args.size() : NumArgsOf(op); |
| 105 | } | 125 | } |
| 106 | 126 | ||
| 107 | IR::Type Inst::Type() const { | 127 | IR::Type Inst::Type() const { |
| @@ -109,13 +129,23 @@ IR::Type Inst::Type() const { | |||
| 109 | } | 129 | } |
| 110 | 130 | ||
| 111 | Value Inst::Arg(size_t index) const { | 131 | Value Inst::Arg(size_t index) const { |
| 112 | if (index >= NumArgsOf(op)) { | 132 | if (op == Opcode::Phi) { |
| 113 | throw InvalidArgument("Out of bounds argument index {} in opcode {}", index, op); | 133 | if (index >= phi_args.size()) { |
| 134 | throw InvalidArgument("Out of bounds argument index {} in phi instruction", index); | ||
| 135 | } | ||
| 136 | return phi_args[index].second; | ||
| 137 | } else { | ||
| 138 | if (index >= NumArgsOf(op)) { | ||
| 139 | throw InvalidArgument("Out of bounds argument index {} in opcode {}", index, op); | ||
| 140 | } | ||
| 141 | return args[index]; | ||
| 114 | } | 142 | } |
| 115 | return args[index]; | ||
| 116 | } | 143 | } |
| 117 | 144 | ||
| 118 | void Inst::SetArg(size_t index, Value value) { | 145 | void Inst::SetArg(size_t index, Value value) { |
| 146 | if (op == Opcode::Phi) { | ||
| 147 | throw LogicError("Setting argument on a phi instruction"); | ||
| 148 | } | ||
| 119 | if (index >= NumArgsOf(op)) { | 149 | if (index >= NumArgsOf(op)) { |
| 120 | throw InvalidArgument("Out of bounds argument index {} in opcode {}", index, op); | 150 | throw InvalidArgument("Out of bounds argument index {} in opcode {}", index, op); |
| 121 | } | 151 | } |
| @@ -128,15 +158,21 @@ void Inst::SetArg(size_t index, Value value) { | |||
| 128 | args[index] = value; | 158 | args[index] = value; |
| 129 | } | 159 | } |
| 130 | 160 | ||
| 131 | std::span<const std::pair<Block*, Value>> Inst::PhiOperands() const noexcept { | 161 | Block* Inst::PhiBlock(size_t index) const { |
| 132 | return phi_operands; | 162 | if (op != Opcode::Phi) { |
| 163 | throw LogicError("{} is not a Phi instruction", op); | ||
| 164 | } | ||
| 165 | if (index >= phi_args.size()) { | ||
| 166 | throw InvalidArgument("Out of bounds argument index {} in phi instruction"); | ||
| 167 | } | ||
| 168 | return phi_args[index].first; | ||
| 133 | } | 169 | } |
| 134 | 170 | ||
| 135 | void Inst::AddPhiOperand(Block* predecessor, const Value& value) { | 171 | void Inst::AddPhiOperand(Block* predecessor, const Value& value) { |
| 136 | if (!value.IsImmediate()) { | 172 | if (!value.IsImmediate()) { |
| 137 | Use(value); | 173 | Use(value); |
| 138 | } | 174 | } |
| 139 | phi_operands.emplace_back(predecessor, value); | 175 | phi_args.emplace_back(predecessor, value); |
| 140 | } | 176 | } |
| 141 | 177 | ||
| 142 | void Inst::Invalidate() { | 178 | void Inst::Invalidate() { |
| @@ -145,18 +181,22 @@ void Inst::Invalidate() { | |||
| 145 | } | 181 | } |
| 146 | 182 | ||
| 147 | void Inst::ClearArgs() { | 183 | void Inst::ClearArgs() { |
| 148 | for (auto& value : args) { | 184 | if (op == Opcode::Phi) { |
| 149 | if (!value.IsImmediate()) { | 185 | for (auto& pair : phi_args) { |
| 150 | UndoUse(value); | 186 | IR::Value& value{pair.second}; |
| 187 | if (!value.IsImmediate()) { | ||
| 188 | UndoUse(value); | ||
| 189 | } | ||
| 151 | } | 190 | } |
| 152 | value = {}; | 191 | phi_args.clear(); |
| 153 | } | 192 | } else { |
| 154 | for (auto& [phi_block, phi_op] : phi_operands) { | 193 | for (auto& value : args) { |
| 155 | if (!phi_op.IsImmediate()) { | 194 | if (!value.IsImmediate()) { |
| 156 | UndoUse(phi_op); | 195 | UndoUse(value); |
| 196 | } | ||
| 197 | value = {}; | ||
| 157 | } | 198 | } |
| 158 | } | 199 | } |
| 159 | phi_operands.clear(); | ||
| 160 | } | 200 | } |
| 161 | 201 | ||
| 162 | void Inst::ReplaceUsesWith(Value replacement) { | 202 | void Inst::ReplaceUsesWith(Value replacement) { |
| @@ -167,24 +207,29 @@ void Inst::ReplaceUsesWith(Value replacement) { | |||
| 167 | if (!replacement.IsImmediate()) { | 207 | if (!replacement.IsImmediate()) { |
| 168 | Use(replacement); | 208 | Use(replacement); |
| 169 | } | 209 | } |
| 170 | args[0] = replacement; | 210 | if (op == Opcode::Phi) { |
| 211 | phi_args[0].second = replacement; | ||
| 212 | } else { | ||
| 213 | args[0] = replacement; | ||
| 214 | } | ||
| 171 | } | 215 | } |
| 172 | 216 | ||
| 173 | void Inst::Use(const Value& value) { | 217 | void Inst::Use(const Value& value) { |
| 174 | ++value.Inst()->use_count; | 218 | Inst* const inst{value.Inst()}; |
| 219 | ++inst->use_count; | ||
| 175 | 220 | ||
| 176 | switch (op) { | 221 | switch (op) { |
| 177 | case Opcode::GetZeroFromOp: | 222 | case Opcode::GetZeroFromOp: |
| 178 | SetPseudoInstruction(value.Inst()->zero_inst, this); | 223 | SetPseudoInstruction(inst->zero_inst, this); |
| 179 | break; | 224 | break; |
| 180 | case Opcode::GetSignFromOp: | 225 | case Opcode::GetSignFromOp: |
| 181 | SetPseudoInstruction(value.Inst()->sign_inst, this); | 226 | SetPseudoInstruction(inst->sign_inst, this); |
| 182 | break; | 227 | break; |
| 183 | case Opcode::GetCarryFromOp: | 228 | case Opcode::GetCarryFromOp: |
| 184 | SetPseudoInstruction(value.Inst()->carry_inst, this); | 229 | SetPseudoInstruction(inst->carry_inst, this); |
| 185 | break; | 230 | break; |
| 186 | case Opcode::GetOverflowFromOp: | 231 | case Opcode::GetOverflowFromOp: |
| 187 | SetPseudoInstruction(value.Inst()->overflow_inst, this); | 232 | SetPseudoInstruction(inst->overflow_inst, this); |
| 188 | break; | 233 | break; |
| 189 | default: | 234 | default: |
| 190 | break; | 235 | break; |
| @@ -192,20 +237,21 @@ void Inst::Use(const Value& value) { | |||
| 192 | } | 237 | } |
| 193 | 238 | ||
| 194 | void Inst::UndoUse(const Value& value) { | 239 | void Inst::UndoUse(const Value& value) { |
| 195 | --value.Inst()->use_count; | 240 | Inst* const inst{value.Inst()}; |
| 241 | --inst->use_count; | ||
| 196 | 242 | ||
| 197 | switch (op) { | 243 | switch (op) { |
| 198 | case Opcode::GetZeroFromOp: | 244 | case Opcode::GetZeroFromOp: |
| 199 | RemovePseudoInstruction(value.Inst()->zero_inst, Opcode::GetZeroFromOp); | 245 | RemovePseudoInstruction(inst->zero_inst, Opcode::GetZeroFromOp); |
| 200 | break; | 246 | break; |
| 201 | case Opcode::GetSignFromOp: | 247 | case Opcode::GetSignFromOp: |
| 202 | RemovePseudoInstruction(value.Inst()->sign_inst, Opcode::GetSignFromOp); | 248 | RemovePseudoInstruction(inst->sign_inst, Opcode::GetSignFromOp); |
| 203 | break; | 249 | break; |
| 204 | case Opcode::GetCarryFromOp: | 250 | case Opcode::GetCarryFromOp: |
| 205 | RemovePseudoInstruction(value.Inst()->carry_inst, Opcode::GetCarryFromOp); | 251 | RemovePseudoInstruction(inst->carry_inst, Opcode::GetCarryFromOp); |
| 206 | break; | 252 | break; |
| 207 | case Opcode::GetOverflowFromOp: | 253 | case Opcode::GetOverflowFromOp: |
| 208 | RemovePseudoInstruction(value.Inst()->overflow_inst, Opcode::GetOverflowFromOp); | 254 | RemovePseudoInstruction(inst->overflow_inst, Opcode::GetOverflowFromOp); |
| 209 | break; | 255 | break; |
| 210 | default: | 256 | default: |
| 211 | break; | 257 | break; |
diff --git a/src/shader_recompiler/frontend/ir/microinstruction.h b/src/shader_recompiler/frontend/ir/microinstruction.h index 80baffb2e..ddf0f90a9 100644 --- a/src/shader_recompiler/frontend/ir/microinstruction.h +++ b/src/shader_recompiler/frontend/ir/microinstruction.h | |||
| @@ -6,8 +6,8 @@ | |||
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <cstring> | 8 | #include <cstring> |
| 9 | #include <span> | ||
| 10 | #include <type_traits> | 9 | #include <type_traits> |
| 10 | #include <utility> | ||
| 11 | #include <vector> | 11 | #include <vector> |
| 12 | 12 | ||
| 13 | #include <boost/intrusive/list.hpp> | 13 | #include <boost/intrusive/list.hpp> |
| @@ -25,7 +25,14 @@ constexpr size_t MAX_ARG_COUNT = 4; | |||
| 25 | 25 | ||
| 26 | class Inst : public boost::intrusive::list_base_hook<> { | 26 | class Inst : public boost::intrusive::list_base_hook<> { |
| 27 | public: | 27 | public: |
| 28 | explicit Inst(Opcode op_, u64 flags_) noexcept : op{op_}, flags{flags_} {} | 28 | explicit Inst(Opcode op_, u64 flags_) noexcept; |
| 29 | ~Inst(); | ||
| 30 | |||
| 31 | Inst& operator=(const Inst&) = delete; | ||
| 32 | Inst(const Inst&) = delete; | ||
| 33 | |||
| 34 | Inst& operator=(Inst&&) = delete; | ||
| 35 | Inst(Inst&&) = delete; | ||
| 29 | 36 | ||
| 30 | /// Get the number of uses this instruction has. | 37 | /// Get the number of uses this instruction has. |
| 31 | [[nodiscard]] int UseCount() const noexcept { | 38 | [[nodiscard]] int UseCount() const noexcept { |
| @@ -50,26 +57,26 @@ public: | |||
| 50 | [[nodiscard]] bool IsPseudoInstruction() const noexcept; | 57 | [[nodiscard]] bool IsPseudoInstruction() const noexcept; |
| 51 | 58 | ||
| 52 | /// Determines if all arguments of this instruction are immediates. | 59 | /// Determines if all arguments of this instruction are immediates. |
| 53 | [[nodiscard]] bool AreAllArgsImmediates() const noexcept; | 60 | [[nodiscard]] bool AreAllArgsImmediates() const; |
| 54 | 61 | ||
| 55 | /// Determines if there is a pseudo-operation associated with this instruction. | 62 | /// Determines if there is a pseudo-operation associated with this instruction. |
| 56 | [[nodiscard]] bool HasAssociatedPseudoOperation() const noexcept; | 63 | [[nodiscard]] bool HasAssociatedPseudoOperation() const noexcept; |
| 57 | /// Gets a pseudo-operation associated with this instruction | 64 | /// Gets a pseudo-operation associated with this instruction |
| 58 | [[nodiscard]] Inst* GetAssociatedPseudoOperation(IR::Opcode opcode); | 65 | [[nodiscard]] Inst* GetAssociatedPseudoOperation(IR::Opcode opcode); |
| 59 | 66 | ||
| 60 | /// Get the number of arguments this instruction has. | ||
| 61 | [[nodiscard]] size_t NumArgs() const; | ||
| 62 | |||
| 63 | /// Get the type this instruction returns. | 67 | /// Get the type this instruction returns. |
| 64 | [[nodiscard]] IR::Type Type() const; | 68 | [[nodiscard]] IR::Type Type() const; |
| 65 | 69 | ||
| 70 | /// Get the number of arguments this instruction has. | ||
| 71 | [[nodiscard]] size_t NumArgs() const; | ||
| 72 | |||
| 66 | /// Get the value of a given argument index. | 73 | /// Get the value of a given argument index. |
| 67 | [[nodiscard]] Value Arg(size_t index) const; | 74 | [[nodiscard]] Value Arg(size_t index) const; |
| 68 | /// Set the value of a given argument index. | 75 | /// Set the value of a given argument index. |
| 69 | void SetArg(size_t index, Value value); | 76 | void SetArg(size_t index, Value value); |
| 70 | 77 | ||
| 71 | /// Get an immutable span to the phi operands. | 78 | /// Get a pointer to the block of a phi argument. |
| 72 | [[nodiscard]] std::span<const std::pair<Block*, Value>> PhiOperands() const noexcept; | 79 | [[nodiscard]] Block* PhiBlock(size_t index) const; |
| 73 | /// Add phi operand to a phi instruction. | 80 | /// Add phi operand to a phi instruction. |
| 74 | void AddPhiOperand(Block* predecessor, const Value& value); | 81 | void AddPhiOperand(Block* predecessor, const Value& value); |
| 75 | 82 | ||
| @@ -87,18 +94,26 @@ public: | |||
| 87 | } | 94 | } |
| 88 | 95 | ||
| 89 | private: | 96 | private: |
| 97 | struct NonTriviallyDummy { | ||
| 98 | NonTriviallyDummy() noexcept {} | ||
| 99 | }; | ||
| 100 | |||
| 90 | void Use(const Value& value); | 101 | void Use(const Value& value); |
| 91 | void UndoUse(const Value& value); | 102 | void UndoUse(const Value& value); |
| 92 | 103 | ||
| 93 | IR::Opcode op{}; | 104 | IR::Opcode op{}; |
| 94 | int use_count{}; | 105 | int use_count{}; |
| 95 | std::array<Value, MAX_ARG_COUNT> args{}; | 106 | u64 flags{}; |
| 107 | union { | ||
| 108 | NonTriviallyDummy dummy{}; | ||
| 109 | std::array<Value, MAX_ARG_COUNT> args; | ||
| 110 | std::vector<std::pair<Block*, Value>> phi_args; | ||
| 111 | }; | ||
| 96 | Inst* zero_inst{}; | 112 | Inst* zero_inst{}; |
| 97 | Inst* sign_inst{}; | 113 | Inst* sign_inst{}; |
| 98 | Inst* carry_inst{}; | 114 | Inst* carry_inst{}; |
| 99 | Inst* overflow_inst{}; | 115 | Inst* overflow_inst{}; |
| 100 | std::vector<std::pair<Block*, Value>> phi_operands; | ||
| 101 | u64 flags{}; | ||
| 102 | }; | 116 | }; |
| 117 | static_assert(sizeof(Inst) <= 128, "Inst size unintentionally increased its size"); | ||
| 103 | 118 | ||
| 104 | } // namespace Shader::IR | 119 | } // namespace Shader::IR |
diff --git a/src/shader_recompiler/frontend/ir/opcodes.inc b/src/shader_recompiler/frontend/ir/opcodes.inc index 6eb105d92..82b04f37c 100644 --- a/src/shader_recompiler/frontend/ir/opcodes.inc +++ b/src/shader_recompiler/frontend/ir/opcodes.inc | |||
| @@ -3,9 +3,9 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | // opcode name, return type, arg1 type, arg2 type, arg3 type, arg4 type, ... | 5 | // opcode name, return type, arg1 type, arg2 type, arg3 type, arg4 type, ... |
| 6 | OPCODE(Phi, Opaque, ) | ||
| 6 | OPCODE(Void, Void, ) | 7 | OPCODE(Void, Void, ) |
| 7 | OPCODE(Identity, Opaque, Opaque, ) | 8 | OPCODE(Identity, Opaque, Opaque, ) |
| 8 | OPCODE(Phi, Opaque, /*todo*/ ) | ||
| 9 | 9 | ||
| 10 | // Control flow | 10 | // Control flow |
| 11 | OPCODE(Branch, Void, Label, ) | 11 | OPCODE(Branch, Void, Label, ) |
diff --git a/src/shader_recompiler/ir_opt/ssa_rewrite_pass.cpp b/src/shader_recompiler/ir_opt/ssa_rewrite_pass.cpp index 7713e3ba9..15a9db90a 100644 --- a/src/shader_recompiler/ir_opt/ssa_rewrite_pass.cpp +++ b/src/shader_recompiler/ir_opt/ssa_rewrite_pass.cpp | |||
| @@ -104,32 +104,34 @@ private: | |||
| 104 | val = ReadVariable(variable, preds.front()); | 104 | val = ReadVariable(variable, preds.front()); |
| 105 | } else { | 105 | } else { |
| 106 | // Break potential cycles with operandless phi | 106 | // Break potential cycles with operandless phi |
| 107 | val = IR::Value{&*block->PrependNewInst(block->begin(), IR::Opcode::Phi)}; | 107 | IR::Inst& phi_inst{*block->PrependNewInst(block->begin(), IR::Opcode::Phi)}; |
| 108 | val = IR::Value{&phi_inst}; | ||
| 108 | WriteVariable(variable, block, val); | 109 | WriteVariable(variable, block, val); |
| 109 | val = AddPhiOperands(variable, val, block); | 110 | val = AddPhiOperands(variable, phi_inst, block); |
| 110 | } | 111 | } |
| 111 | WriteVariable(variable, block, val); | 112 | WriteVariable(variable, block, val); |
| 112 | return val; | 113 | return val; |
| 113 | } | 114 | } |
| 114 | 115 | ||
| 115 | IR::Value AddPhiOperands(auto variable, const IR::Value& phi, IR::Block* block) { | 116 | IR::Value AddPhiOperands(auto variable, IR::Inst& phi, IR::Block* block) { |
| 116 | for (IR::Block* const pred : block->ImmediatePredecessors()) { | 117 | for (IR::Block* const pred : block->ImmediatePredecessors()) { |
| 117 | phi.Inst()->AddPhiOperand(pred, ReadVariable(variable, pred)); | 118 | phi.AddPhiOperand(pred, ReadVariable(variable, pred)); |
| 118 | } | 119 | } |
| 119 | return TryRemoveTrivialPhi(phi, block, UndefOpcode(variable)); | 120 | return TryRemoveTrivialPhi(phi, block, UndefOpcode(variable)); |
| 120 | } | 121 | } |
| 121 | 122 | ||
| 122 | IR::Value TryRemoveTrivialPhi(const IR::Value& phi, IR::Block* block, IR::Opcode undef_opcode) { | 123 | IR::Value TryRemoveTrivialPhi(IR::Inst& phi, IR::Block* block, IR::Opcode undef_opcode) { |
| 123 | IR::Value same; | 124 | IR::Value same; |
| 124 | for (const auto& pair : phi.Inst()->PhiOperands()) { | 125 | const size_t num_args{phi.NumArgs()}; |
| 125 | const IR::Value& op{pair.second}; | 126 | for (size_t arg_index = 0; arg_index < num_args; ++arg_index) { |
| 126 | if (op == same || op == phi) { | 127 | const IR::Value& op{phi.Arg(arg_index)}; |
| 128 | if (op == same || op == IR::Value{&phi}) { | ||
| 127 | // Unique value or self-reference | 129 | // Unique value or self-reference |
| 128 | continue; | 130 | continue; |
| 129 | } | 131 | } |
| 130 | if (!same.IsEmpty()) { | 132 | if (!same.IsEmpty()) { |
| 131 | // The phi merges at least two values: not trivial | 133 | // The phi merges at least two values: not trivial |
| 132 | return phi; | 134 | return IR::Value{&phi}; |
| 133 | } | 135 | } |
| 134 | same = op; | 136 | same = op; |
| 135 | } | 137 | } |
| @@ -139,7 +141,7 @@ private: | |||
| 139 | same = IR::Value{&*block->PrependNewInst(first_not_phi, undef_opcode)}; | 141 | same = IR::Value{&*block->PrependNewInst(first_not_phi, undef_opcode)}; |
| 140 | } | 142 | } |
| 141 | // Reroute all uses of phi to same and remove phi | 143 | // Reroute all uses of phi to same and remove phi |
| 142 | phi.Inst()->ReplaceUsesWith(same); | 144 | phi.ReplaceUsesWith(same); |
| 143 | // TODO: Try to recursively remove all phi users, which might have become trivial | 145 | // TODO: Try to recursively remove all phi users, which might have become trivial |
| 144 | return same; | 146 | return same; |
| 145 | } | 147 | } |
diff --git a/src/shader_recompiler/object_pool.h b/src/shader_recompiler/object_pool.h index 7c65bbd92..a573add32 100644 --- a/src/shader_recompiler/object_pool.h +++ b/src/shader_recompiler/object_pool.h | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | #include <memory> | 7 | #include <memory> |
| 8 | #include <type_traits> | 8 | #include <type_traits> |
| 9 | #include <utility> | ||
| 9 | 10 | ||
| 10 | namespace Shader { | 11 | namespace Shader { |
| 11 | 12 | ||
| @@ -31,14 +32,12 @@ public: | |||
| 31 | 32 | ||
| 32 | void ReleaseContents() { | 33 | void ReleaseContents() { |
| 33 | Chunk* chunk{&root}; | 34 | Chunk* chunk{&root}; |
| 34 | if (chunk) { | 35 | while (chunk) { |
| 35 | const size_t free_objects{chunk->free_objects}; | 36 | if (chunk->free_objects == chunk_size) { |
| 36 | if (free_objects == chunk_size) { | ||
| 37 | break; | 37 | break; |
| 38 | } | 38 | } |
| 39 | chunk->free_objects = chunk_size; | 39 | for (; chunk->free_objects < chunk_size; ++chunk->free_objects) { |
| 40 | for (size_t obj_id = free_objects; obj_id < chunk_size; ++obj_id) { | 40 | chunk->storage[chunk->free_objects].object.~T(); |
| 41 | chunk->storage[obj_id].object.~T(); | ||
| 42 | } | 41 | } |
| 43 | chunk = chunk->next.get(); | 42 | chunk = chunk->next.get(); |
| 44 | } | 43 | } |