diff options
Diffstat (limited to '')
| -rw-r--r-- | src/shader_recompiler/frontend/ir/basic_block.cpp | 51 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/ir/basic_block.h | 20 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/ir/function.cpp | 5 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/ir/function.h | 25 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/ir/microinstruction.cpp | 22 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/ir/microinstruction.h | 10 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/ir/opcode.inc | 8 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/ir/pred.h | 7 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/ir/reg.h | 9 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/ir/value.cpp | 37 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/ir/value.h | 3 |
11 files changed, 178 insertions, 19 deletions
diff --git a/src/shader_recompiler/frontend/ir/basic_block.cpp b/src/shader_recompiler/frontend/ir/basic_block.cpp index 0406726ad..e795618fc 100644 --- a/src/shader_recompiler/frontend/ir/basic_block.cpp +++ b/src/shader_recompiler/frontend/ir/basic_block.cpp | |||
| @@ -37,6 +37,10 @@ Block::iterator Block::PrependNewInst(iterator insertion_point, Opcode op, | |||
| 37 | return result_it; | 37 | return result_it; |
| 38 | } | 38 | } |
| 39 | 39 | ||
| 40 | void Block::AddImmediatePredecessor(IR::Block* immediate_predecessor) { | ||
| 41 | imm_predecessors.push_back(immediate_predecessor); | ||
| 42 | } | ||
| 43 | |||
| 40 | u32 Block::LocationBegin() const noexcept { | 44 | u32 Block::LocationBegin() const noexcept { |
| 41 | return location_begin; | 45 | return location_begin; |
| 42 | } | 46 | } |
| @@ -53,6 +57,18 @@ const Block::InstructionList& Block::Instructions() const noexcept { | |||
| 53 | return instructions; | 57 | return instructions; |
| 54 | } | 58 | } |
| 55 | 59 | ||
| 60 | std::span<IR::Block* const> Block::ImmediatePredecessors() const noexcept { | ||
| 61 | return imm_predecessors; | ||
| 62 | } | ||
| 63 | |||
| 64 | static std::string BlockToIndex(const std::map<const Block*, size_t>& block_to_index, | ||
| 65 | Block* block) { | ||
| 66 | if (const auto it{block_to_index.find(block)}; it != block_to_index.end()) { | ||
| 67 | return fmt::format("{{Block ${}}}", it->second); | ||
| 68 | } | ||
| 69 | return fmt::format("$<unknown block {:016x}>", reinterpret_cast<u64>(block)); | ||
| 70 | } | ||
| 71 | |||
| 56 | static std::string ArgToIndex(const std::map<const Block*, size_t>& block_to_index, | 72 | static std::string ArgToIndex(const std::map<const Block*, size_t>& block_to_index, |
| 57 | const std::map<const Inst*, size_t>& inst_to_index, | 73 | const std::map<const Inst*, size_t>& inst_to_index, |
| 58 | const Value& arg) { | 74 | const Value& arg) { |
| @@ -60,10 +76,7 @@ static std::string ArgToIndex(const std::map<const Block*, size_t>& block_to_ind | |||
| 60 | return "<null>"; | 76 | return "<null>"; |
| 61 | } | 77 | } |
| 62 | if (arg.IsLabel()) { | 78 | if (arg.IsLabel()) { |
| 63 | if (const auto it{block_to_index.find(arg.Label())}; it != block_to_index.end()) { | 79 | return BlockToIndex(block_to_index, arg.Label()); |
| 64 | return fmt::format("{{Block ${}}}", it->second); | ||
| 65 | } | ||
| 66 | return fmt::format("$<unknown block {:016x}>", reinterpret_cast<u64>(arg.Label())); | ||
| 67 | } | 80 | } |
| 68 | if (!arg.IsImmediate()) { | 81 | if (!arg.IsImmediate()) { |
| 69 | if (const auto it{inst_to_index.find(arg.Inst())}; it != inst_to_index.end()) { | 82 | if (const auto it{inst_to_index.find(arg.Inst())}; it != inst_to_index.end()) { |
| @@ -115,16 +128,26 @@ std::string DumpBlock(const Block& block, const std::map<const Block*, size_t>& | |||
| 115 | } else { | 128 | } else { |
| 116 | ret += fmt::format(" {}", op); // '%00000 = ' -> 1 + 5 + 3 = 9 spaces | 129 | ret += fmt::format(" {}", op); // '%00000 = ' -> 1 + 5 + 3 = 9 spaces |
| 117 | } | 130 | } |
| 118 | const size_t arg_count{NumArgsOf(op)}; | 131 | if (op == Opcode::Phi) { |
| 119 | for (size_t arg_index = 0; arg_index < arg_count; ++arg_index) { | 132 | size_t val_index{0}; |
| 120 | const Value arg{inst.Arg(arg_index)}; | 133 | for (const auto& [phi_block, phi_val] : inst.PhiOperands()) { |
| 121 | ret += arg_index != 0 ? ", " : " "; | 134 | ret += val_index != 0 ? ", " : " "; |
| 122 | ret += ArgToIndex(block_to_index, inst_to_index, arg); | 135 | ret += fmt::format("[ {}, {} ]", ArgToIndex(block_to_index, inst_to_index, phi_val), |
| 123 | 136 | BlockToIndex(block_to_index, phi_block)); | |
| 124 | const Type actual_type{arg.Type()}; | 137 | ++val_index; |
| 125 | const Type expected_type{ArgTypeOf(op, arg_index)}; | 138 | } |
| 126 | if (!AreTypesCompatible(actual_type, expected_type)) { | 139 | } else { |
| 127 | ret += fmt::format("<type error: {} != {}>", actual_type, expected_type); | 140 | const size_t arg_count{NumArgsOf(op)}; |
| 141 | for (size_t arg_index = 0; arg_index < arg_count; ++arg_index) { | ||
| 142 | const Value arg{inst.Arg(arg_index)}; | ||
| 143 | ret += arg_index != 0 ? ", " : " "; | ||
| 144 | ret += ArgToIndex(block_to_index, inst_to_index, arg); | ||
| 145 | |||
| 146 | const Type actual_type{arg.Type()}; | ||
| 147 | const Type expected_type{ArgTypeOf(op, arg_index)}; | ||
| 148 | if (!AreTypesCompatible(actual_type, expected_type)) { | ||
| 149 | ret += fmt::format("<type error: {} != {}>", actual_type, expected_type); | ||
| 150 | } | ||
| 128 | } | 151 | } |
| 129 | } | 152 | } |
| 130 | if (TypeOf(op) != Type::Void) { | 153 | if (TypeOf(op) != Type::Void) { |
diff --git a/src/shader_recompiler/frontend/ir/basic_block.h b/src/shader_recompiler/frontend/ir/basic_block.h index 3ed2eb957..4b6b80c4b 100644 --- a/src/shader_recompiler/frontend/ir/basic_block.h +++ b/src/shader_recompiler/frontend/ir/basic_block.h | |||
| @@ -6,6 +6,8 @@ | |||
| 6 | 6 | ||
| 7 | #include <initializer_list> | 7 | #include <initializer_list> |
| 8 | #include <map> | 8 | #include <map> |
| 9 | #include <span> | ||
| 10 | #include <vector> | ||
| 9 | 11 | ||
| 10 | #include <boost/intrusive/list.hpp> | 12 | #include <boost/intrusive/list.hpp> |
| 11 | #include <boost/pool/pool_alloc.hpp> | 13 | #include <boost/pool/pool_alloc.hpp> |
| @@ -36,7 +38,11 @@ public: | |||
| 36 | void AppendNewInst(Opcode op, std::initializer_list<Value> args); | 38 | void AppendNewInst(Opcode op, std::initializer_list<Value> args); |
| 37 | 39 | ||
| 38 | /// Prepends a new instruction to this basic block before the insertion point. | 40 | /// Prepends a new instruction to this basic block before the insertion point. |
| 39 | iterator PrependNewInst(iterator insertion_point, Opcode op, std::initializer_list<Value> args); | 41 | iterator PrependNewInst(iterator insertion_point, Opcode op, |
| 42 | std::initializer_list<Value> args = {}); | ||
| 43 | |||
| 44 | /// Adds a new immediate predecessor to the basic block. | ||
| 45 | void AddImmediatePredecessor(IR::Block* immediate_predecessor); | ||
| 40 | 46 | ||
| 41 | /// Gets the starting location of this basic block. | 47 | /// Gets the starting location of this basic block. |
| 42 | [[nodiscard]] u32 LocationBegin() const noexcept; | 48 | [[nodiscard]] u32 LocationBegin() const noexcept; |
| @@ -44,9 +50,12 @@ public: | |||
| 44 | [[nodiscard]] u32 LocationEnd() const noexcept; | 50 | [[nodiscard]] u32 LocationEnd() const noexcept; |
| 45 | 51 | ||
| 46 | /// Gets a mutable reference to the instruction list for this basic block. | 52 | /// Gets a mutable reference to the instruction list for this basic block. |
| 47 | InstructionList& Instructions() noexcept; | 53 | [[nodiscard]] InstructionList& Instructions() noexcept; |
| 48 | /// Gets an immutable reference to the instruction list for this basic block. | 54 | /// Gets an immutable reference to the instruction list for this basic block. |
| 49 | const InstructionList& Instructions() const noexcept; | 55 | [[nodiscard]] const InstructionList& Instructions() const noexcept; |
| 56 | |||
| 57 | /// Gets an immutable span to the immediate predecessors. | ||
| 58 | [[nodiscard]] std::span<IR::Block* const> ImmediatePredecessors() const noexcept; | ||
| 50 | 59 | ||
| 51 | [[nodiscard]] bool empty() const { | 60 | [[nodiscard]] bool empty() const { |
| 52 | return instructions.empty(); | 61 | return instructions.empty(); |
| @@ -115,13 +124,16 @@ private: | |||
| 115 | /// End location of this block | 124 | /// End location of this block |
| 116 | u32 location_end; | 125 | u32 location_end; |
| 117 | 126 | ||
| 118 | /// List of instructions in this block. | 127 | /// List of instructions in this block |
| 119 | InstructionList instructions; | 128 | InstructionList instructions; |
| 120 | 129 | ||
| 121 | /// Memory pool for instruction list | 130 | /// Memory pool for instruction list |
| 122 | boost::fast_pool_allocator<Inst, boost::default_user_allocator_malloc_free, | 131 | boost::fast_pool_allocator<Inst, boost::default_user_allocator_malloc_free, |
| 123 | boost::details::pool::null_mutex> | 132 | boost::details::pool::null_mutex> |
| 124 | instruction_alloc_pool; | 133 | instruction_alloc_pool; |
| 134 | |||
| 135 | /// Block immediate predecessors | ||
| 136 | std::vector<IR::Block*> imm_predecessors; | ||
| 125 | }; | 137 | }; |
| 126 | 138 | ||
| 127 | [[nodiscard]] std::string DumpBlock(const Block& block); | 139 | [[nodiscard]] std::string DumpBlock(const Block& block); |
diff --git a/src/shader_recompiler/frontend/ir/function.cpp b/src/shader_recompiler/frontend/ir/function.cpp new file mode 100644 index 000000000..d1fc9461d --- /dev/null +++ b/src/shader_recompiler/frontend/ir/function.cpp | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "shader_recompiler/frontend/ir/function.h" | ||
diff --git a/src/shader_recompiler/frontend/ir/function.h b/src/shader_recompiler/frontend/ir/function.h new file mode 100644 index 000000000..2d4dc5b98 --- /dev/null +++ b/src/shader_recompiler/frontend/ir/function.h | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <memory> | ||
| 8 | #include <vector> | ||
| 9 | |||
| 10 | #include "shader_recompiler/frontend/ir/basic_block.h" | ||
| 11 | |||
| 12 | namespace Shader::IR { | ||
| 13 | |||
| 14 | struct Function { | ||
| 15 | struct InplaceDelete { | ||
| 16 | void operator()(IR::Block* block) const noexcept { | ||
| 17 | std::destroy_at(block); | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | using UniqueBlock = std::unique_ptr<IR::Block, InplaceDelete>; | ||
| 21 | |||
| 22 | std::vector<UniqueBlock> blocks; | ||
| 23 | }; | ||
| 24 | |||
| 25 | } // namespace Shader::IR | ||
diff --git a/src/shader_recompiler/frontend/ir/microinstruction.cpp b/src/shader_recompiler/frontend/ir/microinstruction.cpp index 553fec3b7..ecf76e23d 100644 --- a/src/shader_recompiler/frontend/ir/microinstruction.cpp +++ b/src/shader_recompiler/frontend/ir/microinstruction.cpp | |||
| @@ -30,6 +30,11 @@ static void RemovePseudoInstruction(IR::Inst*& inst, IR::Opcode expected_opcode) | |||
| 30 | 30 | ||
| 31 | bool Inst::MayHaveSideEffects() const noexcept { | 31 | bool Inst::MayHaveSideEffects() const noexcept { |
| 32 | switch (op) { | 32 | switch (op) { |
| 33 | case Opcode::Branch: | ||
| 34 | case Opcode::BranchConditional: | ||
| 35 | case Opcode::Exit: | ||
| 36 | case Opcode::Return: | ||
| 37 | case Opcode::Unreachable: | ||
| 33 | case Opcode::SetAttribute: | 38 | case Opcode::SetAttribute: |
| 34 | case Opcode::SetAttributeIndexed: | 39 | case Opcode::SetAttributeIndexed: |
| 35 | case Opcode::WriteGlobalU8: | 40 | case Opcode::WriteGlobalU8: |
| @@ -113,6 +118,17 @@ void Inst::SetArg(size_t index, Value value) { | |||
| 113 | args[index] = value; | 118 | args[index] = value; |
| 114 | } | 119 | } |
| 115 | 120 | ||
| 121 | std::span<const std::pair<Block*, Value>> Inst::PhiOperands() const noexcept { | ||
| 122 | return phi_operands; | ||
| 123 | } | ||
| 124 | |||
| 125 | void Inst::AddPhiOperand(Block* predecessor, const Value& value) { | ||
| 126 | if (!value.IsImmediate()) { | ||
| 127 | Use(value); | ||
| 128 | } | ||
| 129 | phi_operands.emplace_back(predecessor, value); | ||
| 130 | } | ||
| 131 | |||
| 116 | void Inst::Invalidate() { | 132 | void Inst::Invalidate() { |
| 117 | ClearArgs(); | 133 | ClearArgs(); |
| 118 | op = Opcode::Void; | 134 | op = Opcode::Void; |
| @@ -125,6 +141,12 @@ void Inst::ClearArgs() { | |||
| 125 | } | 141 | } |
| 126 | value = {}; | 142 | value = {}; |
| 127 | } | 143 | } |
| 144 | for (auto& [phi_block, phi_op] : phi_operands) { | ||
| 145 | if (!phi_op.IsImmediate()) { | ||
| 146 | UndoUse(phi_op); | ||
| 147 | } | ||
| 148 | } | ||
| 149 | phi_operands.clear(); | ||
| 128 | } | 150 | } |
| 129 | 151 | ||
| 130 | void Inst::ReplaceUsesWith(Value replacement) { | 152 | void Inst::ReplaceUsesWith(Value replacement) { |
diff --git a/src/shader_recompiler/frontend/ir/microinstruction.h b/src/shader_recompiler/frontend/ir/microinstruction.h index 43460b950..7f1ed6710 100644 --- a/src/shader_recompiler/frontend/ir/microinstruction.h +++ b/src/shader_recompiler/frontend/ir/microinstruction.h | |||
| @@ -5,6 +5,8 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <span> | ||
| 9 | #include <vector> | ||
| 8 | 10 | ||
| 9 | #include <boost/intrusive/list.hpp> | 11 | #include <boost/intrusive/list.hpp> |
| 10 | 12 | ||
| @@ -15,6 +17,8 @@ | |||
| 15 | 17 | ||
| 16 | namespace Shader::IR { | 18 | namespace Shader::IR { |
| 17 | 19 | ||
| 20 | class Block; | ||
| 21 | |||
| 18 | constexpr size_t MAX_ARG_COUNT = 4; | 22 | constexpr size_t MAX_ARG_COUNT = 4; |
| 19 | 23 | ||
| 20 | class Inst : public boost::intrusive::list_base_hook<> { | 24 | class Inst : public boost::intrusive::list_base_hook<> { |
| @@ -59,6 +63,11 @@ public: | |||
| 59 | /// Set the value of a given argument index. | 63 | /// Set the value of a given argument index. |
| 60 | void SetArg(size_t index, Value value); | 64 | void SetArg(size_t index, Value value); |
| 61 | 65 | ||
| 66 | /// Get an immutable span to the phi operands. | ||
| 67 | [[nodiscard]] std::span<const std::pair<Block*, Value>> PhiOperands() const noexcept; | ||
| 68 | /// Add phi operand to a phi instruction. | ||
| 69 | void AddPhiOperand(Block* predecessor, const Value& value); | ||
| 70 | |||
| 62 | void Invalidate(); | 71 | void Invalidate(); |
| 63 | void ClearArgs(); | 72 | void ClearArgs(); |
| 64 | 73 | ||
| @@ -76,6 +85,7 @@ private: | |||
| 76 | Inst* carry_inst{}; | 85 | Inst* carry_inst{}; |
| 77 | Inst* overflow_inst{}; | 86 | Inst* overflow_inst{}; |
| 78 | Inst* zsco_inst{}; | 87 | Inst* zsco_inst{}; |
| 88 | std::vector<std::pair<Block*, Value>> phi_operands; | ||
| 79 | u64 flags{}; | 89 | u64 flags{}; |
| 80 | }; | 90 | }; |
| 81 | 91 | ||
diff --git a/src/shader_recompiler/frontend/ir/opcode.inc b/src/shader_recompiler/frontend/ir/opcode.inc index 371064bf3..40759e96a 100644 --- a/src/shader_recompiler/frontend/ir/opcode.inc +++ b/src/shader_recompiler/frontend/ir/opcode.inc | |||
| @@ -5,6 +5,7 @@ | |||
| 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(Void, Void, ) | 6 | OPCODE(Void, Void, ) |
| 7 | OPCODE(Identity, Opaque, Opaque, ) | 7 | OPCODE(Identity, Opaque, Opaque, ) |
| 8 | OPCODE(Phi, Opaque, /*todo*/ ) | ||
| 8 | 9 | ||
| 9 | // Control flow | 10 | // Control flow |
| 10 | OPCODE(Branch, Void, Label, ) | 11 | OPCODE(Branch, Void, Label, ) |
| @@ -35,6 +36,13 @@ OPCODE(SetSFlag, Void, U1, | |||
| 35 | OPCODE(SetCFlag, Void, U1, ) | 36 | OPCODE(SetCFlag, Void, U1, ) |
| 36 | OPCODE(SetOFlag, Void, U1, ) | 37 | OPCODE(SetOFlag, Void, U1, ) |
| 37 | 38 | ||
| 39 | // Undefined | ||
| 40 | OPCODE(Undef1, U1, ) | ||
| 41 | OPCODE(Undef8, U8, ) | ||
| 42 | OPCODE(Undef16, U16, ) | ||
| 43 | OPCODE(Undef32, U32, ) | ||
| 44 | OPCODE(Undef64, U64, ) | ||
| 45 | |||
| 38 | // Memory operations | 46 | // Memory operations |
| 39 | OPCODE(WriteGlobalU8, Void, U64, U32, ) | 47 | OPCODE(WriteGlobalU8, Void, U64, U32, ) |
| 40 | OPCODE(WriteGlobalS8, Void, U64, U32, ) | 48 | OPCODE(WriteGlobalS8, Void, U64, U32, ) |
diff --git a/src/shader_recompiler/frontend/ir/pred.h b/src/shader_recompiler/frontend/ir/pred.h index 37cc53006..daf23193f 100644 --- a/src/shader_recompiler/frontend/ir/pred.h +++ b/src/shader_recompiler/frontend/ir/pred.h | |||
| @@ -10,6 +10,13 @@ namespace Shader::IR { | |||
| 10 | 10 | ||
| 11 | enum class Pred { P0, P1, P2, P3, P4, P5, P6, PT }; | 11 | enum class Pred { P0, P1, P2, P3, P4, P5, P6, PT }; |
| 12 | 12 | ||
| 13 | constexpr size_t NUM_USER_PREDS = 6; | ||
| 14 | constexpr size_t NUM_PREDS = 7; | ||
| 15 | |||
| 16 | [[nodiscard]] constexpr size_t PredIndex(Pred pred) noexcept { | ||
| 17 | return static_cast<size_t>(pred); | ||
| 18 | } | ||
| 19 | |||
| 13 | } // namespace Shader::IR | 20 | } // namespace Shader::IR |
| 14 | 21 | ||
| 15 | template <> | 22 | template <> |
diff --git a/src/shader_recompiler/frontend/ir/reg.h b/src/shader_recompiler/frontend/ir/reg.h index 316fc4be8..771094eb9 100644 --- a/src/shader_recompiler/frontend/ir/reg.h +++ b/src/shader_recompiler/frontend/ir/reg.h | |||
| @@ -271,6 +271,9 @@ enum class Reg : u64 { | |||
| 271 | }; | 271 | }; |
| 272 | static_assert(static_cast<int>(Reg::RZ) == 255); | 272 | static_assert(static_cast<int>(Reg::RZ) == 255); |
| 273 | 273 | ||
| 274 | constexpr size_t NUM_USER_REGS = 255; | ||
| 275 | constexpr size_t NUM_REGS = 256; | ||
| 276 | |||
| 274 | [[nodiscard]] constexpr Reg operator+(Reg reg, int num) { | 277 | [[nodiscard]] constexpr Reg operator+(Reg reg, int num) { |
| 275 | if (reg == Reg::RZ) { | 278 | if (reg == Reg::RZ) { |
| 276 | // Adding or subtracting registers from RZ yields RZ | 279 | // Adding or subtracting registers from RZ yields RZ |
| @@ -290,8 +293,12 @@ static_assert(static_cast<int>(Reg::RZ) == 255); | |||
| 290 | return reg + (-num); | 293 | return reg + (-num); |
| 291 | } | 294 | } |
| 292 | 295 | ||
| 296 | [[nodiscard]] constexpr size_t RegIndex(Reg reg) noexcept { | ||
| 297 | return static_cast<size_t>(reg); | ||
| 298 | } | ||
| 299 | |||
| 293 | [[nodiscard]] constexpr bool IsAligned(Reg reg, size_t align) { | 300 | [[nodiscard]] constexpr bool IsAligned(Reg reg, size_t align) { |
| 294 | return (static_cast<size_t>(reg) / align) * align == static_cast<size_t>(reg); | 301 | return (RegIndex(reg) / align) * align == RegIndex(reg); |
| 295 | } | 302 | } |
| 296 | 303 | ||
| 297 | } // namespace Shader::IR | 304 | } // namespace Shader::IR |
diff --git a/src/shader_recompiler/frontend/ir/value.cpp b/src/shader_recompiler/frontend/ir/value.cpp index 7b5b35d6c..1e974e88c 100644 --- a/src/shader_recompiler/frontend/ir/value.cpp +++ b/src/shader_recompiler/frontend/ir/value.cpp | |||
| @@ -115,6 +115,43 @@ u64 Value::U64() const { | |||
| 115 | return imm_u64; | 115 | return imm_u64; |
| 116 | } | 116 | } |
| 117 | 117 | ||
| 118 | bool Value::operator==(const Value& other) const { | ||
| 119 | if (type != other.type) { | ||
| 120 | return false; | ||
| 121 | } | ||
| 122 | switch (type) { | ||
| 123 | case Type::Void: | ||
| 124 | return true; | ||
| 125 | case Type::Opaque: | ||
| 126 | return inst == other.inst; | ||
| 127 | case Type::Label: | ||
| 128 | return label == other.label; | ||
| 129 | case Type::Reg: | ||
| 130 | return reg == other.reg; | ||
| 131 | case Type::Pred: | ||
| 132 | return pred == other.pred; | ||
| 133 | case Type::Attribute: | ||
| 134 | return attribute == other.attribute; | ||
| 135 | case Type::U1: | ||
| 136 | return imm_u1 == other.imm_u1; | ||
| 137 | case Type::U8: | ||
| 138 | return imm_u8 == other.imm_u8; | ||
| 139 | case Type::U16: | ||
| 140 | return imm_u16 == other.imm_u16; | ||
| 141 | case Type::U32: | ||
| 142 | return imm_u32 == other.imm_u32; | ||
| 143 | case Type::U64: | ||
| 144 | return imm_u64 == other.imm_u64; | ||
| 145 | case Type::ZSCO: | ||
| 146 | throw NotImplementedException("ZSCO comparison"); | ||
| 147 | } | ||
| 148 | throw LogicError("Invalid type {}", type); | ||
| 149 | } | ||
| 150 | |||
| 151 | bool Value::operator!=(const Value& other) const { | ||
| 152 | return !operator==(other); | ||
| 153 | } | ||
| 154 | |||
| 118 | void Value::ValidateAccess(IR::Type expected) const { | 155 | void Value::ValidateAccess(IR::Type expected) const { |
| 119 | if (type != expected) { | 156 | if (type != expected) { |
| 120 | throw LogicError("Reading {} out of {}", expected, type); | 157 | throw LogicError("Reading {} out of {}", expected, type); |
diff --git a/src/shader_recompiler/frontend/ir/value.h b/src/shader_recompiler/frontend/ir/value.h index 664dacf9d..368119921 100644 --- a/src/shader_recompiler/frontend/ir/value.h +++ b/src/shader_recompiler/frontend/ir/value.h | |||
| @@ -48,6 +48,9 @@ public: | |||
| 48 | [[nodiscard]] u32 U32() const; | 48 | [[nodiscard]] u32 U32() const; |
| 49 | [[nodiscard]] u64 U64() const; | 49 | [[nodiscard]] u64 U64() const; |
| 50 | 50 | ||
| 51 | [[nodiscard]] bool operator==(const Value& other) const; | ||
| 52 | [[nodiscard]] bool operator!=(const Value& other) const; | ||
| 53 | |||
| 51 | private: | 54 | private: |
| 52 | void ValidateAccess(IR::Type expected) const; | 55 | void ValidateAccess(IR::Type expected) const; |
| 53 | 56 | ||