diff options
| author | 2021-05-14 00:40:54 -0300 | |
|---|---|---|
| committer | 2021-07-22 21:51:31 -0400 | |
| commit | d54d7de40e7295827b0e4e4026441b53d3fc9569 (patch) | |
| tree | 29b5074f851292dace7aeb5da7716675544b3735 /src/shader_recompiler/frontend/ir | |
| parent | glasm: Implement Storage atomics (diff) | |
| download | yuzu-d54d7de40e7295827b0e4e4026441b53d3fc9569.tar.gz yuzu-d54d7de40e7295827b0e4e4026441b53d3fc9569.tar.xz yuzu-d54d7de40e7295827b0e4e4026441b53d3fc9569.zip | |
glasm: Rework control flow introducing a syntax list
This commit regresses VertexA shaders, their transformation pass has to
be adapted to the new control flow.
Diffstat (limited to '')
| -rw-r--r-- | src/shader_recompiler/frontend/ir/abstract_syntax_list.h | 56 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/ir/basic_block.cpp | 56 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/ir/basic_block.h | 51 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/ir/ir_emitter.cpp | 60 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/ir/ir_emitter.h | 11 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/ir/microinstruction.cpp | 11 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/ir/opcodes.h | 1 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/ir/opcodes.inc | 21 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/ir/post_order.cpp | 36 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/ir/post_order.h | 3 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/ir/program.h | 4 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/ir/type.h | 49 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/ir/value.cpp | 8 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/ir/value.h | 9 |
14 files changed, 151 insertions, 225 deletions
diff --git a/src/shader_recompiler/frontend/ir/abstract_syntax_list.h b/src/shader_recompiler/frontend/ir/abstract_syntax_list.h new file mode 100644 index 000000000..1366414c2 --- /dev/null +++ b/src/shader_recompiler/frontend/ir/abstract_syntax_list.h | |||
| @@ -0,0 +1,56 @@ | |||
| 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 <vector> | ||
| 8 | |||
| 9 | #include "shader_recompiler/frontend/ir/value.h" | ||
| 10 | |||
| 11 | namespace Shader::IR { | ||
| 12 | |||
| 13 | class Block; | ||
| 14 | |||
| 15 | struct AbstractSyntaxNode { | ||
| 16 | enum class Type { | ||
| 17 | Block, | ||
| 18 | If, | ||
| 19 | EndIf, | ||
| 20 | Loop, | ||
| 21 | Repeat, | ||
| 22 | Break, | ||
| 23 | Return, | ||
| 24 | Unreachable, | ||
| 25 | }; | ||
| 26 | Type type{}; | ||
| 27 | union { | ||
| 28 | Block* block{}; | ||
| 29 | struct { | ||
| 30 | U1 cond; | ||
| 31 | Block* body; | ||
| 32 | Block* merge; | ||
| 33 | } if_node; | ||
| 34 | struct { | ||
| 35 | Block* merge; | ||
| 36 | } end_if; | ||
| 37 | struct { | ||
| 38 | Block* body; | ||
| 39 | Block* continue_block; | ||
| 40 | Block* merge; | ||
| 41 | } loop; | ||
| 42 | struct { | ||
| 43 | U1 cond; | ||
| 44 | Block* loop_header; | ||
| 45 | Block* merge; | ||
| 46 | } repeat; | ||
| 47 | struct { | ||
| 48 | U1 cond; | ||
| 49 | Block* merge; | ||
| 50 | Block* skip; | ||
| 51 | } break_node; | ||
| 52 | }; | ||
| 53 | }; | ||
| 54 | using AbstractSyntaxList = std::vector<AbstractSyntaxNode>; | ||
| 55 | |||
| 56 | } // namespace Shader::IR | ||
diff --git a/src/shader_recompiler/frontend/ir/basic_block.cpp b/src/shader_recompiler/frontend/ir/basic_block.cpp index f92fc2571..7c08b25ce 100644 --- a/src/shader_recompiler/frontend/ir/basic_block.cpp +++ b/src/shader_recompiler/frontend/ir/basic_block.cpp | |||
| @@ -14,10 +14,7 @@ | |||
| 14 | 14 | ||
| 15 | namespace Shader::IR { | 15 | namespace Shader::IR { |
| 16 | 16 | ||
| 17 | Block::Block(ObjectPool<Inst>& inst_pool_, u32 begin, u32 end) | 17 | Block::Block(ObjectPool<Inst>& inst_pool_) : inst_pool{&inst_pool_} {} |
| 18 | : inst_pool{&inst_pool_}, location_begin{begin}, location_end{end} {} | ||
| 19 | |||
| 20 | Block::Block(ObjectPool<Inst>& inst_pool_) : Block{inst_pool_, 0, 0} {} | ||
| 21 | 18 | ||
| 22 | Block::~Block() = default; | 19 | Block::~Block() = default; |
| 23 | 20 | ||
| @@ -40,39 +37,15 @@ Block::iterator Block::PrependNewInst(iterator insertion_point, Opcode op, | |||
| 40 | return result_it; | 37 | return result_it; |
| 41 | } | 38 | } |
| 42 | 39 | ||
| 43 | void Block::SetBranches(Condition cond, Block* branch_true_, Block* branch_false_) { | 40 | void Block::AddBranch(Block* block) { |
| 44 | branch_cond = cond; | 41 | if (std::ranges::find(imm_successors, block) != imm_successors.end()) { |
| 45 | branch_true = branch_true_; | 42 | throw LogicError("Successor already inserted"); |
| 46 | branch_false = branch_false_; | 43 | } |
| 47 | } | 44 | if (std::ranges::find(block->imm_predecessors, this) != block->imm_predecessors.end()) { |
| 48 | 45 | throw LogicError("Predecessor already inserted"); | |
| 49 | void Block::SetBranch(Block* branch) { | ||
| 50 | branch_cond = Condition{true}; | ||
| 51 | branch_true = branch; | ||
| 52 | } | ||
| 53 | |||
| 54 | void Block::SetReturn() { | ||
| 55 | branch_cond = Condition{true}; | ||
| 56 | branch_true = nullptr; | ||
| 57 | branch_false = nullptr; | ||
| 58 | } | ||
| 59 | |||
| 60 | bool Block::IsVirtual() const noexcept { | ||
| 61 | return location_begin == location_end; | ||
| 62 | } | ||
| 63 | |||
| 64 | u32 Block::LocationBegin() const noexcept { | ||
| 65 | return location_begin; | ||
| 66 | } | ||
| 67 | |||
| 68 | u32 Block::LocationEnd() const noexcept { | ||
| 69 | return location_end; | ||
| 70 | } | ||
| 71 | |||
| 72 | void Block::AddImmediatePredecessor(Block* block) { | ||
| 73 | if (std::ranges::find(imm_predecessors, block) == imm_predecessors.end()) { | ||
| 74 | imm_predecessors.push_back(block); | ||
| 75 | } | 46 | } |
| 47 | imm_successors.push_back(block); | ||
| 48 | block->imm_predecessors.push_back(this); | ||
| 76 | } | 49 | } |
| 77 | 50 | ||
| 78 | static std::string BlockToIndex(const std::map<const Block*, size_t>& block_to_index, | 51 | static std::string BlockToIndex(const std::map<const Block*, size_t>& block_to_index, |
| @@ -92,15 +65,11 @@ static size_t InstIndex(std::map<const Inst*, size_t>& inst_to_index, size_t& in | |||
| 92 | return it->second; | 65 | return it->second; |
| 93 | } | 66 | } |
| 94 | 67 | ||
| 95 | static std::string ArgToIndex(const std::map<const Block*, size_t>& block_to_index, | 68 | static std::string ArgToIndex(std::map<const Inst*, size_t>& inst_to_index, size_t& inst_index, |
| 96 | std::map<const Inst*, size_t>& inst_to_index, size_t& inst_index, | ||
| 97 | const Value& arg) { | 69 | const Value& arg) { |
| 98 | if (arg.IsEmpty()) { | 70 | if (arg.IsEmpty()) { |
| 99 | return "<null>"; | 71 | return "<null>"; |
| 100 | } | 72 | } |
| 101 | if (arg.IsLabel()) { | ||
| 102 | return BlockToIndex(block_to_index, arg.Label()); | ||
| 103 | } | ||
| 104 | if (!arg.IsImmediate() || arg.IsIdentity()) { | 73 | if (!arg.IsImmediate() || arg.IsIdentity()) { |
| 105 | return fmt::format("%{}", InstIndex(inst_to_index, inst_index, arg.Inst())); | 74 | return fmt::format("%{}", InstIndex(inst_to_index, inst_index, arg.Inst())); |
| 106 | } | 75 | } |
| @@ -140,8 +109,7 @@ std::string DumpBlock(const Block& block, const std::map<const Block*, size_t>& | |||
| 140 | if (const auto it{block_to_index.find(&block)}; it != block_to_index.end()) { | 109 | if (const auto it{block_to_index.find(&block)}; it != block_to_index.end()) { |
| 141 | ret += fmt::format(" ${}", it->second); | 110 | ret += fmt::format(" ${}", it->second); |
| 142 | } | 111 | } |
| 143 | ret += fmt::format(": begin={:04x} end={:04x}\n", block.LocationBegin(), block.LocationEnd()); | 112 | ret += '\n'; |
| 144 | |||
| 145 | for (const Inst& inst : block) { | 113 | for (const Inst& inst : block) { |
| 146 | const Opcode op{inst.GetOpcode()}; | 114 | const Opcode op{inst.GetOpcode()}; |
| 147 | ret += fmt::format("[{:016x}] ", reinterpret_cast<u64>(&inst)); | 115 | ret += fmt::format("[{:016x}] ", reinterpret_cast<u64>(&inst)); |
| @@ -153,7 +121,7 @@ std::string DumpBlock(const Block& block, const std::map<const Block*, size_t>& | |||
| 153 | const size_t arg_count{inst.NumArgs()}; | 121 | const size_t arg_count{inst.NumArgs()}; |
| 154 | for (size_t arg_index = 0; arg_index < arg_count; ++arg_index) { | 122 | for (size_t arg_index = 0; arg_index < arg_count; ++arg_index) { |
| 155 | const Value arg{inst.Arg(arg_index)}; | 123 | const Value arg{inst.Arg(arg_index)}; |
| 156 | const std::string arg_str{ArgToIndex(block_to_index, inst_to_index, inst_index, arg)}; | 124 | const std::string arg_str{ArgToIndex(inst_to_index, inst_index, arg)}; |
| 157 | ret += arg_index != 0 ? ", " : " "; | 125 | ret += arg_index != 0 ? ", " : " "; |
| 158 | if (op == Opcode::Phi) { | 126 | if (op == Opcode::Phi) { |
| 159 | ret += fmt::format("[ {}, {} ]", arg_str, | 127 | ret += fmt::format("[ {}, {} ]", arg_str, |
diff --git a/src/shader_recompiler/frontend/ir/basic_block.h b/src/shader_recompiler/frontend/ir/basic_block.h index 0b0c97af6..7e134b4c7 100644 --- a/src/shader_recompiler/frontend/ir/basic_block.h +++ b/src/shader_recompiler/frontend/ir/basic_block.h | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | #include <boost/intrusive/list.hpp> | 12 | #include <boost/intrusive/list.hpp> |
| 13 | 13 | ||
| 14 | #include "common/bit_cast.h" | 14 | #include "common/bit_cast.h" |
| 15 | #include "common/common_types.h" | ||
| 15 | #include "shader_recompiler/frontend/ir/condition.h" | 16 | #include "shader_recompiler/frontend/ir/condition.h" |
| 16 | #include "shader_recompiler/frontend/ir/value.h" | 17 | #include "shader_recompiler/frontend/ir/value.h" |
| 17 | #include "shader_recompiler/object_pool.h" | 18 | #include "shader_recompiler/object_pool.h" |
| @@ -27,7 +28,6 @@ public: | |||
| 27 | using reverse_iterator = InstructionList::reverse_iterator; | 28 | using reverse_iterator = InstructionList::reverse_iterator; |
| 28 | using const_reverse_iterator = InstructionList::const_reverse_iterator; | 29 | using const_reverse_iterator = InstructionList::const_reverse_iterator; |
| 29 | 30 | ||
| 30 | explicit Block(ObjectPool<Inst>& inst_pool_, u32 begin, u32 end); | ||
| 31 | explicit Block(ObjectPool<Inst>& inst_pool_); | 31 | explicit Block(ObjectPool<Inst>& inst_pool_); |
| 32 | ~Block(); | 32 | ~Block(); |
| 33 | 33 | ||
| @@ -44,22 +44,8 @@ public: | |||
| 44 | iterator PrependNewInst(iterator insertion_point, Opcode op, | 44 | iterator PrependNewInst(iterator insertion_point, Opcode op, |
| 45 | std::initializer_list<Value> args = {}, u32 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 | /// Adds a new branch to this basic block. |
| 48 | void SetBranches(Condition cond, Block* branch_true, Block* branch_false); | 48 | void AddBranch(Block* block); |
| 49 | /// Set the branch to unconditionally jump to when all instructions have executed. | ||
| 50 | void SetBranch(Block* branch); | ||
| 51 | /// Mark the block as a return block. | ||
| 52 | void SetReturn(); | ||
| 53 | |||
| 54 | /// Returns true when the block does not implement any guest instructions directly. | ||
| 55 | [[nodiscard]] bool IsVirtual() const noexcept; | ||
| 56 | /// Gets the starting location of this basic block. | ||
| 57 | [[nodiscard]] u32 LocationBegin() const noexcept; | ||
| 58 | /// Gets the end location for this basic block. | ||
| 59 | [[nodiscard]] u32 LocationEnd() const noexcept; | ||
| 60 | |||
| 61 | /// Adds a new immediate predecessor to this basic block. | ||
| 62 | void AddImmediatePredecessor(Block* block); | ||
| 63 | 49 | ||
| 64 | /// Gets a mutable reference to the instruction list for this basic block. | 50 | /// Gets a mutable reference to the instruction list for this basic block. |
| 65 | [[nodiscard]] InstructionList& Instructions() noexcept { | 51 | [[nodiscard]] InstructionList& Instructions() noexcept { |
| @@ -71,9 +57,13 @@ public: | |||
| 71 | } | 57 | } |
| 72 | 58 | ||
| 73 | /// Gets an immutable span to the immediate predecessors. | 59 | /// Gets an immutable span to the immediate predecessors. |
| 74 | [[nodiscard]] std::span<Block* const> ImmediatePredecessors() const noexcept { | 60 | [[nodiscard]] std::span<Block* const> ImmPredecessors() const noexcept { |
| 75 | return imm_predecessors; | 61 | return imm_predecessors; |
| 76 | } | 62 | } |
| 63 | /// Gets an immutable span to the immediate successors. | ||
| 64 | [[nodiscard]] std::span<Block* const> ImmSuccessors() const noexcept { | ||
| 65 | return imm_successors; | ||
| 66 | } | ||
| 77 | 67 | ||
| 78 | /// Intrusively store the host definition of this instruction. | 68 | /// Intrusively store the host definition of this instruction. |
| 79 | template <typename DefinitionType> | 69 | template <typename DefinitionType> |
| @@ -87,19 +77,6 @@ public: | |||
| 87 | return Common::BitCast<DefinitionType>(definition); | 77 | return Common::BitCast<DefinitionType>(definition); |
| 88 | } | 78 | } |
| 89 | 79 | ||
| 90 | [[nodiscard]] Condition BranchCondition() const noexcept { | ||
| 91 | return branch_cond; | ||
| 92 | } | ||
| 93 | [[nodiscard]] bool IsTerminationBlock() const noexcept { | ||
| 94 | return !branch_true && !branch_false; | ||
| 95 | } | ||
| 96 | [[nodiscard]] Block* TrueBranch() const noexcept { | ||
| 97 | return branch_true; | ||
| 98 | } | ||
| 99 | [[nodiscard]] Block* FalseBranch() const noexcept { | ||
| 100 | return branch_false; | ||
| 101 | } | ||
| 102 | |||
| 103 | void SetSsaRegValue(IR::Reg reg, const Value& value) noexcept { | 80 | void SetSsaRegValue(IR::Reg reg, const Value& value) noexcept { |
| 104 | ssa_reg_values[RegIndex(reg)] = value; | 81 | ssa_reg_values[RegIndex(reg)] = value; |
| 105 | } | 82 | } |
| @@ -178,22 +155,14 @@ public: | |||
| 178 | private: | 155 | private: |
| 179 | /// Memory pool for instruction list | 156 | /// Memory pool for instruction list |
| 180 | ObjectPool<Inst>* inst_pool; | 157 | ObjectPool<Inst>* inst_pool; |
| 181 | /// Starting location of this block | ||
| 182 | u32 location_begin; | ||
| 183 | /// End location of this block | ||
| 184 | u32 location_end; | ||
| 185 | 158 | ||
| 186 | /// List of instructions in this block | 159 | /// List of instructions in this block |
| 187 | InstructionList instructions; | 160 | InstructionList instructions; |
| 188 | 161 | ||
| 189 | /// Condition to choose the branch to take | ||
| 190 | Condition branch_cond{true}; | ||
| 191 | /// Block to jump into when the branch condition evaluates as true | ||
| 192 | Block* branch_true{nullptr}; | ||
| 193 | /// Block to jump into when the branch condition evaluates as false | ||
| 194 | Block* branch_false{nullptr}; | ||
| 195 | /// Block immediate predecessors | 162 | /// Block immediate predecessors |
| 196 | std::vector<Block*> imm_predecessors; | 163 | std::vector<Block*> imm_predecessors; |
| 164 | /// Block immediate successors | ||
| 165 | std::vector<Block*> imm_successors; | ||
| 197 | 166 | ||
| 198 | /// Intrusively store the value of a register in the block. | 167 | /// Intrusively store the value of a register in the block. |
| 199 | std::array<Value, NUM_REGS> ssa_reg_values; | 168 | std::array<Value, NUM_REGS> ssa_reg_values; |
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.cpp b/src/shader_recompiler/frontend/ir/ir_emitter.cpp index ce6c9af07..eb45aa477 100644 --- a/src/shader_recompiler/frontend/ir/ir_emitter.cpp +++ b/src/shader_recompiler/frontend/ir/ir_emitter.cpp | |||
| @@ -61,25 +61,28 @@ F64 IREmitter::Imm64(f64 value) const { | |||
| 61 | return F64{Value{value}}; | 61 | return F64{Value{value}}; |
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | void IREmitter::Branch(Block* label) { | 64 | void IREmitter::Prologue() { |
| 65 | label->AddImmediatePredecessor(block); | 65 | Inst(Opcode::Prologue); |
| 66 | block->SetBranch(label); | ||
| 67 | Inst(Opcode::Branch, label); | ||
| 68 | } | 66 | } |
| 69 | 67 | ||
| 70 | void IREmitter::BranchConditional(const U1& condition, Block* true_label, Block* false_label) { | 68 | void IREmitter::Epilogue() { |
| 71 | block->SetBranches(IR::Condition{true}, true_label, false_label); | 69 | Inst(Opcode::Epilogue); |
| 72 | true_label->AddImmediatePredecessor(block); | ||
| 73 | false_label->AddImmediatePredecessor(block); | ||
| 74 | Inst(Opcode::BranchConditional, condition, true_label, false_label); | ||
| 75 | } | 70 | } |
| 76 | 71 | ||
| 77 | void IREmitter::LoopMerge(Block* merge_block, Block* continue_target) { | 72 | void IREmitter::BranchConditionRef(const U1& cond) { |
| 78 | Inst(Opcode::LoopMerge, merge_block, continue_target); | 73 | Inst(Opcode::BranchConditionRef, cond); |
| 79 | } | 74 | } |
| 80 | 75 | ||
| 81 | void IREmitter::SelectionMerge(Block* merge_block) { | 76 | void IREmitter::DemoteToHelperInvocation() { |
| 82 | Inst(Opcode::SelectionMerge, merge_block); | 77 | Inst(Opcode::DemoteToHelperInvocation); |
| 78 | } | ||
| 79 | |||
| 80 | void IREmitter::EmitVertex(const U32& stream) { | ||
| 81 | Inst(Opcode::EmitVertex, stream); | ||
| 82 | } | ||
| 83 | |||
| 84 | void IREmitter::EndPrimitive(const U32& stream) { | ||
| 85 | Inst(Opcode::EndPrimitive, stream); | ||
| 83 | } | 86 | } |
| 84 | 87 | ||
| 85 | void IREmitter::Barrier() { | 88 | void IREmitter::Barrier() { |
| @@ -94,37 +97,6 @@ void IREmitter::DeviceMemoryBarrier() { | |||
| 94 | Inst(Opcode::DeviceMemoryBarrier); | 97 | Inst(Opcode::DeviceMemoryBarrier); |
| 95 | } | 98 | } |
| 96 | 99 | ||
| 97 | void IREmitter::Return() { | ||
| 98 | block->SetReturn(); | ||
| 99 | Inst(Opcode::Return); | ||
| 100 | } | ||
| 101 | |||
| 102 | void IREmitter::Unreachable() { | ||
| 103 | Inst(Opcode::Unreachable); | ||
| 104 | } | ||
| 105 | |||
| 106 | void IREmitter::DemoteToHelperInvocation(Block* continue_label) { | ||
| 107 | block->SetBranch(continue_label); | ||
| 108 | continue_label->AddImmediatePredecessor(block); | ||
| 109 | Inst(Opcode::DemoteToHelperInvocation, continue_label); | ||
| 110 | } | ||
| 111 | |||
| 112 | void IREmitter::Prologue() { | ||
| 113 | Inst(Opcode::Prologue); | ||
| 114 | } | ||
| 115 | |||
| 116 | void IREmitter::Epilogue() { | ||
| 117 | Inst(Opcode::Epilogue); | ||
| 118 | } | ||
| 119 | |||
| 120 | void IREmitter::EmitVertex(const U32& stream) { | ||
| 121 | Inst(Opcode::EmitVertex, stream); | ||
| 122 | } | ||
| 123 | |||
| 124 | void IREmitter::EndPrimitive(const U32& stream) { | ||
| 125 | Inst(Opcode::EndPrimitive, stream); | ||
| 126 | } | ||
| 127 | |||
| 128 | U32 IREmitter::GetReg(IR::Reg reg) { | 100 | U32 IREmitter::GetReg(IR::Reg reg) { |
| 129 | return Inst<U32>(Opcode::GetRegister, reg); | 101 | return Inst<U32>(Opcode::GetRegister, reg); |
| 130 | } | 102 | } |
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.h b/src/shader_recompiler/frontend/ir/ir_emitter.h index fd41b7e89..7a83c33d3 100644 --- a/src/shader_recompiler/frontend/ir/ir_emitter.h +++ b/src/shader_recompiler/frontend/ir/ir_emitter.h | |||
| @@ -32,17 +32,10 @@ public: | |||
| 32 | [[nodiscard]] U64 Imm64(s64 value) const; | 32 | [[nodiscard]] U64 Imm64(s64 value) const; |
| 33 | [[nodiscard]] F64 Imm64(f64 value) const; | 33 | [[nodiscard]] F64 Imm64(f64 value) const; |
| 34 | 34 | ||
| 35 | void Branch(Block* label); | ||
| 36 | void BranchConditional(const U1& condition, Block* true_label, Block* false_label); | ||
| 37 | void LoopMerge(Block* merge_block, Block* continue_target); | ||
| 38 | void SelectionMerge(Block* merge_block); | ||
| 39 | void Return(); | ||
| 40 | void Unreachable(); | ||
| 41 | void DemoteToHelperInvocation(Block* continue_label); | ||
| 42 | |||
| 43 | void Prologue(); | 35 | void Prologue(); |
| 44 | void Epilogue(); | 36 | void Epilogue(); |
| 45 | 37 | void BranchConditionRef(const U1& cond); | |
| 38 | void DemoteToHelperInvocation(); | ||
| 46 | void EmitVertex(const U32& stream); | 39 | void EmitVertex(const U32& stream); |
| 47 | void EndPrimitive(const U32& stream); | 40 | void EndPrimitive(const U32& stream); |
| 48 | 41 | ||
diff --git a/src/shader_recompiler/frontend/ir/microinstruction.cpp b/src/shader_recompiler/frontend/ir/microinstruction.cpp index 616ef17d4..364574240 100644 --- a/src/shader_recompiler/frontend/ir/microinstruction.cpp +++ b/src/shader_recompiler/frontend/ir/microinstruction.cpp | |||
| @@ -56,19 +56,14 @@ Inst::~Inst() { | |||
| 56 | 56 | ||
| 57 | bool Inst::MayHaveSideEffects() const noexcept { | 57 | bool Inst::MayHaveSideEffects() const noexcept { |
| 58 | switch (op) { | 58 | switch (op) { |
| 59 | case Opcode::Branch: | 59 | case Opcode::Prologue: |
| 60 | case Opcode::BranchConditional: | 60 | case Opcode::Epilogue: |
| 61 | case Opcode::LoopMerge: | 61 | case Opcode::BranchConditionRef: |
| 62 | case Opcode::SelectionMerge: | ||
| 63 | case Opcode::Return: | ||
| 64 | case Opcode::Join: | 62 | case Opcode::Join: |
| 65 | case Opcode::Unreachable: | ||
| 66 | case Opcode::DemoteToHelperInvocation: | 63 | case Opcode::DemoteToHelperInvocation: |
| 67 | case Opcode::Barrier: | 64 | case Opcode::Barrier: |
| 68 | case Opcode::WorkgroupMemoryBarrier: | 65 | case Opcode::WorkgroupMemoryBarrier: |
| 69 | case Opcode::DeviceMemoryBarrier: | 66 | case Opcode::DeviceMemoryBarrier: |
| 70 | case Opcode::Prologue: | ||
| 71 | case Opcode::Epilogue: | ||
| 72 | case Opcode::EmitVertex: | 67 | case Opcode::EmitVertex: |
| 73 | case Opcode::EndPrimitive: | 68 | case Opcode::EndPrimitive: |
| 74 | case Opcode::SetAttribute: | 69 | case Opcode::SetAttribute: |
diff --git a/src/shader_recompiler/frontend/ir/opcodes.h b/src/shader_recompiler/frontend/ir/opcodes.h index 2b9c0ed8c..56b001902 100644 --- a/src/shader_recompiler/frontend/ir/opcodes.h +++ b/src/shader_recompiler/frontend/ir/opcodes.h | |||
| @@ -30,7 +30,6 @@ struct OpcodeMeta { | |||
| 30 | // using enum Type; | 30 | // using enum Type; |
| 31 | constexpr Type Void{Type::Void}; | 31 | constexpr Type Void{Type::Void}; |
| 32 | constexpr Type Opaque{Type::Opaque}; | 32 | constexpr Type Opaque{Type::Opaque}; |
| 33 | constexpr Type Label{Type::Label}; | ||
| 34 | constexpr Type Reg{Type::Reg}; | 33 | constexpr Type Reg{Type::Reg}; |
| 35 | constexpr Type Pred{Type::Pred}; | 34 | constexpr Type Pred{Type::Pred}; |
| 36 | constexpr Type Attribute{Type::Attribute}; | 35 | constexpr Type Attribute{Type::Attribute}; |
diff --git a/src/shader_recompiler/frontend/ir/opcodes.inc b/src/shader_recompiler/frontend/ir/opcodes.inc index 9165421f8..75ddb6b6f 100644 --- a/src/shader_recompiler/frontend/ir/opcodes.inc +++ b/src/shader_recompiler/frontend/ir/opcodes.inc | |||
| @@ -7,27 +7,20 @@ OPCODE(Phi, Opaque, | |||
| 7 | OPCODE(Identity, Opaque, Opaque, ) | 7 | OPCODE(Identity, Opaque, Opaque, ) |
| 8 | OPCODE(Void, Void, ) | 8 | OPCODE(Void, Void, ) |
| 9 | 9 | ||
| 10 | // Control flow | 10 | // Special operations |
| 11 | OPCODE(Branch, Void, Label, ) | 11 | OPCODE(Prologue, Void, ) |
| 12 | OPCODE(BranchConditional, Void, U1, Label, Label, ) | 12 | OPCODE(Epilogue, Void, ) |
| 13 | OPCODE(LoopMerge, Void, Label, Label, ) | 13 | OPCODE(BranchConditionRef, Void, U1, ) |
| 14 | OPCODE(SelectionMerge, Void, Label, ) | ||
| 15 | OPCODE(Return, Void, ) | ||
| 16 | OPCODE(Join, Void, ) | 14 | OPCODE(Join, Void, ) |
| 17 | OPCODE(Unreachable, Void, ) | 15 | OPCODE(DemoteToHelperInvocation, Void, ) |
| 18 | OPCODE(DemoteToHelperInvocation, Void, Label, ) | 16 | OPCODE(EmitVertex, Void, U32, ) |
| 17 | OPCODE(EndPrimitive, Void, U32, ) | ||
| 19 | 18 | ||
| 20 | // Barriers | 19 | // Barriers |
| 21 | OPCODE(Barrier, Void, ) | 20 | OPCODE(Barrier, Void, ) |
| 22 | OPCODE(WorkgroupMemoryBarrier, Void, ) | 21 | OPCODE(WorkgroupMemoryBarrier, Void, ) |
| 23 | OPCODE(DeviceMemoryBarrier, Void, ) | 22 | OPCODE(DeviceMemoryBarrier, Void, ) |
| 24 | 23 | ||
| 25 | // Special operations | ||
| 26 | OPCODE(Prologue, Void, ) | ||
| 27 | OPCODE(Epilogue, Void, ) | ||
| 28 | OPCODE(EmitVertex, Void, U32, ) | ||
| 29 | OPCODE(EndPrimitive, Void, U32, ) | ||
| 30 | |||
| 31 | // Context getters/setters | 24 | // Context getters/setters |
| 32 | OPCODE(GetRegister, U32, Reg, ) | 25 | OPCODE(GetRegister, U32, Reg, ) |
| 33 | OPCODE(SetRegister, Void, Reg, U32, ) | 26 | OPCODE(SetRegister, Void, Reg, U32, ) |
diff --git a/src/shader_recompiler/frontend/ir/post_order.cpp b/src/shader_recompiler/frontend/ir/post_order.cpp index 8709a2ea1..1a28df7fb 100644 --- a/src/shader_recompiler/frontend/ir/post_order.cpp +++ b/src/shader_recompiler/frontend/ir/post_order.cpp | |||
| @@ -2,6 +2,8 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <algorithm> | ||
| 6 | |||
| 5 | #include <boost/container/flat_set.hpp> | 7 | #include <boost/container/flat_set.hpp> |
| 6 | #include <boost/container/small_vector.hpp> | 8 | #include <boost/container/small_vector.hpp> |
| 7 | 9 | ||
| @@ -10,35 +12,31 @@ | |||
| 10 | 12 | ||
| 11 | namespace Shader::IR { | 13 | namespace Shader::IR { |
| 12 | 14 | ||
| 13 | BlockList PostOrder(const BlockList& blocks) { | 15 | BlockList PostOrder(const AbstractSyntaxNode& root) { |
| 14 | boost::container::small_vector<Block*, 16> block_stack; | 16 | boost::container::small_vector<Block*, 16> block_stack; |
| 15 | boost::container::flat_set<Block*> visited; | 17 | boost::container::flat_set<Block*> visited; |
| 16 | |||
| 17 | BlockList post_order_blocks; | 18 | BlockList post_order_blocks; |
| 18 | post_order_blocks.reserve(blocks.size()); | ||
| 19 | 19 | ||
| 20 | Block* const first_block{blocks.front()}; | 20 | if (root.type != AbstractSyntaxNode::Type::Block) { |
| 21 | throw LogicError("First node in abstract syntax list root is not a block"); | ||
| 22 | } | ||
| 23 | Block* const first_block{root.block}; | ||
| 21 | visited.insert(first_block); | 24 | visited.insert(first_block); |
| 22 | block_stack.push_back(first_block); | 25 | block_stack.push_back(first_block); |
| 23 | 26 | ||
| 24 | const auto visit_branch = [&](Block* block, Block* branch) { | ||
| 25 | if (!branch) { | ||
| 26 | return false; | ||
| 27 | } | ||
| 28 | if (!visited.insert(branch).second) { | ||
| 29 | return false; | ||
| 30 | } | ||
| 31 | // Calling push_back twice is faster than insert on MSVC | ||
| 32 | block_stack.push_back(block); | ||
| 33 | block_stack.push_back(branch); | ||
| 34 | return true; | ||
| 35 | }; | ||
| 36 | while (!block_stack.empty()) { | 27 | while (!block_stack.empty()) { |
| 37 | Block* const block{block_stack.back()}; | 28 | Block* const block{block_stack.back()}; |
| 29 | const auto visit{[&](Block* branch) { | ||
| 30 | if (!visited.insert(branch).second) { | ||
| 31 | return false; | ||
| 32 | } | ||
| 33 | // Calling push_back twice is faster than insert on MSVC | ||
| 34 | block_stack.push_back(block); | ||
| 35 | block_stack.push_back(branch); | ||
| 36 | return true; | ||
| 37 | }}; | ||
| 38 | block_stack.pop_back(); | 38 | block_stack.pop_back(); |
| 39 | 39 | if (std::ranges::none_of(block->ImmSuccessors(), visit)) { | |
| 40 | if (!visit_branch(block, block->TrueBranch()) && | ||
| 41 | !visit_branch(block, block->FalseBranch())) { | ||
| 42 | post_order_blocks.push_back(block); | 40 | post_order_blocks.push_back(block); |
| 43 | } | 41 | } |
| 44 | } | 42 | } |
diff --git a/src/shader_recompiler/frontend/ir/post_order.h b/src/shader_recompiler/frontend/ir/post_order.h index 30137ff57..58a0467a0 100644 --- a/src/shader_recompiler/frontend/ir/post_order.h +++ b/src/shader_recompiler/frontend/ir/post_order.h | |||
| @@ -5,9 +5,10 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "shader_recompiler/frontend/ir/basic_block.h" | 7 | #include "shader_recompiler/frontend/ir/basic_block.h" |
| 8 | #include "shader_recompiler/frontend/ir/abstract_syntax_list.h" | ||
| 8 | 9 | ||
| 9 | namespace Shader::IR { | 10 | namespace Shader::IR { |
| 10 | 11 | ||
| 11 | BlockList PostOrder(const BlockList& blocks); | 12 | BlockList PostOrder(const AbstractSyntaxNode& root); |
| 12 | 13 | ||
| 13 | } // namespace Shader::IR | 14 | } // namespace Shader::IR |
diff --git a/src/shader_recompiler/frontend/ir/program.h b/src/shader_recompiler/frontend/ir/program.h index 51e1a8c77..9ede5b48d 100644 --- a/src/shader_recompiler/frontend/ir/program.h +++ b/src/shader_recompiler/frontend/ir/program.h | |||
| @@ -7,8 +7,7 @@ | |||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <string> | 8 | #include <string> |
| 9 | 9 | ||
| 10 | #include <boost/container/small_vector.hpp> | 10 | #include "shader_recompiler/frontend/ir/abstract_syntax_list.h" |
| 11 | |||
| 12 | #include "shader_recompiler/frontend/ir/basic_block.h" | 11 | #include "shader_recompiler/frontend/ir/basic_block.h" |
| 13 | #include "shader_recompiler/program_header.h" | 12 | #include "shader_recompiler/program_header.h" |
| 14 | #include "shader_recompiler/shader_info.h" | 13 | #include "shader_recompiler/shader_info.h" |
| @@ -17,6 +16,7 @@ | |||
| 17 | namespace Shader::IR { | 16 | namespace Shader::IR { |
| 18 | 17 | ||
| 19 | struct Program { | 18 | struct Program { |
| 19 | AbstractSyntaxList syntax_list; | ||
| 20 | BlockList blocks; | 20 | BlockList blocks; |
| 21 | BlockList post_order_blocks; | 21 | BlockList post_order_blocks; |
| 22 | Info info; | 22 | Info info; |
diff --git a/src/shader_recompiler/frontend/ir/type.h b/src/shader_recompiler/frontend/ir/type.h index 8b3b33852..294b230c4 100644 --- a/src/shader_recompiler/frontend/ir/type.h +++ b/src/shader_recompiler/frontend/ir/type.h | |||
| @@ -16,31 +16,30 @@ namespace Shader::IR { | |||
| 16 | enum class Type { | 16 | enum class Type { |
| 17 | Void = 0, | 17 | Void = 0, |
| 18 | Opaque = 1 << 0, | 18 | Opaque = 1 << 0, |
| 19 | Label = 1 << 1, | 19 | Reg = 1 << 1, |
| 20 | Reg = 1 << 2, | 20 | Pred = 1 << 2, |
| 21 | Pred = 1 << 3, | 21 | Attribute = 1 << 3, |
| 22 | Attribute = 1 << 4, | 22 | Patch = 1 << 4, |
| 23 | Patch = 1 << 5, | 23 | U1 = 1 << 5, |
| 24 | U1 = 1 << 6, | 24 | U8 = 1 << 6, |
| 25 | U8 = 1 << 7, | 25 | U16 = 1 << 7, |
| 26 | U16 = 1 << 8, | 26 | U32 = 1 << 8, |
| 27 | U32 = 1 << 9, | 27 | U64 = 1 << 9, |
| 28 | U64 = 1 << 10, | 28 | F16 = 1 << 10, |
| 29 | F16 = 1 << 11, | 29 | F32 = 1 << 11, |
| 30 | F32 = 1 << 12, | 30 | F64 = 1 << 12, |
| 31 | F64 = 1 << 13, | 31 | U32x2 = 1 << 13, |
| 32 | U32x2 = 1 << 14, | 32 | U32x3 = 1 << 14, |
| 33 | U32x3 = 1 << 15, | 33 | U32x4 = 1 << 15, |
| 34 | U32x4 = 1 << 16, | 34 | F16x2 = 1 << 16, |
| 35 | F16x2 = 1 << 17, | 35 | F16x3 = 1 << 17, |
| 36 | F16x3 = 1 << 18, | 36 | F16x4 = 1 << 18, |
| 37 | F16x4 = 1 << 19, | 37 | F32x2 = 1 << 19, |
| 38 | F32x2 = 1 << 20, | 38 | F32x3 = 1 << 20, |
| 39 | F32x3 = 1 << 21, | 39 | F32x4 = 1 << 21, |
| 40 | F32x4 = 1 << 22, | 40 | F64x2 = 1 << 22, |
| 41 | F64x2 = 1 << 23, | 41 | F64x3 = 1 << 23, |
| 42 | F64x3 = 1 << 24, | 42 | F64x4 = 1 << 24, |
| 43 | F64x4 = 1 << 25, | ||
| 44 | }; | 43 | }; |
| 45 | DECLARE_ENUM_FLAG_OPERATORS(Type) | 44 | DECLARE_ENUM_FLAG_OPERATORS(Type) |
| 46 | 45 | ||
diff --git a/src/shader_recompiler/frontend/ir/value.cpp b/src/shader_recompiler/frontend/ir/value.cpp index b962f170d..d365ea1bc 100644 --- a/src/shader_recompiler/frontend/ir/value.cpp +++ b/src/shader_recompiler/frontend/ir/value.cpp | |||
| @@ -9,8 +9,6 @@ namespace Shader::IR { | |||
| 9 | 9 | ||
| 10 | Value::Value(IR::Inst* value) noexcept : type{Type::Opaque}, inst{value} {} | 10 | Value::Value(IR::Inst* value) noexcept : type{Type::Opaque}, inst{value} {} |
| 11 | 11 | ||
| 12 | Value::Value(IR::Block* value) noexcept : type{Type::Label}, label{value} {} | ||
| 13 | |||
| 14 | Value::Value(IR::Reg value) noexcept : type{Type::Reg}, reg{value} {} | 12 | Value::Value(IR::Reg value) noexcept : type{Type::Reg}, reg{value} {} |
| 15 | 13 | ||
| 16 | Value::Value(IR::Pred value) noexcept : type{Type::Pred}, pred{value} {} | 14 | Value::Value(IR::Pred value) noexcept : type{Type::Pred}, pred{value} {} |
| @@ -33,10 +31,6 @@ Value::Value(u64 value) noexcept : type{Type::U64}, imm_u64{value} {} | |||
| 33 | 31 | ||
| 34 | Value::Value(f64 value) noexcept : type{Type::F64}, imm_f64{value} {} | 32 | Value::Value(f64 value) noexcept : type{Type::F64}, imm_f64{value} {} |
| 35 | 33 | ||
| 36 | bool Value::IsLabel() const noexcept { | ||
| 37 | return type == Type::Label; | ||
| 38 | } | ||
| 39 | |||
| 40 | IR::Type Value::Type() const noexcept { | 34 | IR::Type Value::Type() const noexcept { |
| 41 | if (IsPhi()) { | 35 | if (IsPhi()) { |
| 42 | // The type of a phi node is stored in its flags | 36 | // The type of a phi node is stored in its flags |
| @@ -60,8 +54,6 @@ bool Value::operator==(const Value& other) const { | |||
| 60 | return true; | 54 | return true; |
| 61 | case Type::Opaque: | 55 | case Type::Opaque: |
| 62 | return inst == other.inst; | 56 | return inst == other.inst; |
| 63 | case Type::Label: | ||
| 64 | return label == other.label; | ||
| 65 | case Type::Reg: | 57 | case Type::Reg: |
| 66 | return reg == other.reg; | 58 | return reg == other.reg; |
| 67 | case Type::Pred: | 59 | case Type::Pred: |
diff --git a/src/shader_recompiler/frontend/ir/value.h b/src/shader_recompiler/frontend/ir/value.h index beaf149f3..2ce49f953 100644 --- a/src/shader_recompiler/frontend/ir/value.h +++ b/src/shader_recompiler/frontend/ir/value.h | |||
| @@ -37,7 +37,6 @@ class Value { | |||
| 37 | public: | 37 | public: |
| 38 | Value() noexcept = default; | 38 | Value() noexcept = default; |
| 39 | explicit Value(IR::Inst* value) noexcept; | 39 | explicit Value(IR::Inst* value) noexcept; |
| 40 | explicit Value(IR::Block* value) noexcept; | ||
| 41 | explicit Value(IR::Reg value) noexcept; | 40 | explicit Value(IR::Reg value) noexcept; |
| 42 | explicit Value(IR::Pred value) noexcept; | 41 | explicit Value(IR::Pred value) noexcept; |
| 43 | explicit Value(IR::Attribute value) noexcept; | 42 | explicit Value(IR::Attribute value) noexcept; |
| @@ -54,11 +53,9 @@ public: | |||
| 54 | [[nodiscard]] bool IsPhi() const noexcept; | 53 | [[nodiscard]] bool IsPhi() const noexcept; |
| 55 | [[nodiscard]] bool IsEmpty() const noexcept; | 54 | [[nodiscard]] bool IsEmpty() const noexcept; |
| 56 | [[nodiscard]] bool IsImmediate() const noexcept; | 55 | [[nodiscard]] bool IsImmediate() const noexcept; |
| 57 | [[nodiscard]] bool IsLabel() const noexcept; | ||
| 58 | [[nodiscard]] IR::Type Type() const noexcept; | 56 | [[nodiscard]] IR::Type Type() const noexcept; |
| 59 | 57 | ||
| 60 | [[nodiscard]] IR::Inst* Inst() const; | 58 | [[nodiscard]] IR::Inst* Inst() const; |
| 61 | [[nodiscard]] IR::Block* Label() const; | ||
| 62 | [[nodiscard]] IR::Inst* InstRecursive() const; | 59 | [[nodiscard]] IR::Inst* InstRecursive() const; |
| 63 | [[nodiscard]] IR::Value Resolve() const; | 60 | [[nodiscard]] IR::Value Resolve() const; |
| 64 | [[nodiscard]] IR::Reg Reg() const; | 61 | [[nodiscard]] IR::Reg Reg() const; |
| @@ -80,7 +77,6 @@ private: | |||
| 80 | IR::Type type{}; | 77 | IR::Type type{}; |
| 81 | union { | 78 | union { |
| 82 | IR::Inst* inst{}; | 79 | IR::Inst* inst{}; |
| 83 | IR::Block* label; | ||
| 84 | IR::Reg reg; | 80 | IR::Reg reg; |
| 85 | IR::Pred pred; | 81 | IR::Pred pred; |
| 86 | IR::Attribute attribute; | 82 | IR::Attribute attribute; |
| @@ -304,11 +300,6 @@ inline IR::Inst* Value::Inst() const { | |||
| 304 | return inst; | 300 | return inst; |
| 305 | } | 301 | } |
| 306 | 302 | ||
| 307 | inline IR::Block* Value::Label() const { | ||
| 308 | DEBUG_ASSERT(type == Type::Label); | ||
| 309 | return label; | ||
| 310 | } | ||
| 311 | |||
| 312 | inline IR::Inst* Value::InstRecursive() const { | 303 | inline IR::Inst* Value::InstRecursive() const { |
| 313 | DEBUG_ASSERT(type == Type::Opaque); | 304 | DEBUG_ASSERT(type == Type::Opaque); |
| 314 | if (IsIdentity()) { | 305 | if (IsIdentity()) { |