summaryrefslogtreecommitdiff
path: root/src/shader_recompiler/ir_opt
diff options
context:
space:
mode:
Diffstat (limited to 'src/shader_recompiler/ir_opt')
-rw-r--r--src/shader_recompiler/ir_opt/dead_code_elimination_pass.cpp2
-rw-r--r--src/shader_recompiler/ir_opt/passes.h8
-rw-r--r--src/shader_recompiler/ir_opt/ssa_rewrite_pass.cpp62
3 files changed, 55 insertions, 17 deletions
diff --git a/src/shader_recompiler/ir_opt/dead_code_elimination_pass.cpp b/src/shader_recompiler/ir_opt/dead_code_elimination_pass.cpp
index bbaa412f6..132b2012a 100644
--- a/src/shader_recompiler/ir_opt/dead_code_elimination_pass.cpp
+++ b/src/shader_recompiler/ir_opt/dead_code_elimination_pass.cpp
@@ -13,7 +13,7 @@ namespace Shader::Optimization {
13void DeadCodeEliminationPass(IR::Block& block) { 13void DeadCodeEliminationPass(IR::Block& block) {
14 // We iterate over the instructions in reverse order. 14 // We iterate over the instructions in reverse order.
15 // This is because removing an instruction reduces the number of uses for earlier instructions. 15 // This is because removing an instruction reduces the number of uses for earlier instructions.
16 for (IR::Inst& inst : std::views::reverse(block)) { 16 for (IR::Inst& inst : block | std::views::reverse) {
17 if (!inst.HasUses() && !inst.MayHaveSideEffects()) { 17 if (!inst.HasUses() && !inst.MayHaveSideEffects()) {
18 inst.Invalidate(); 18 inst.Invalidate();
19 } 19 }
diff --git a/src/shader_recompiler/ir_opt/passes.h b/src/shader_recompiler/ir_opt/passes.h
index 578a24d89..30eb31588 100644
--- a/src/shader_recompiler/ir_opt/passes.h
+++ b/src/shader_recompiler/ir_opt/passes.h
@@ -4,14 +4,16 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <span>
8
7#include "shader_recompiler/frontend/ir/basic_block.h" 9#include "shader_recompiler/frontend/ir/basic_block.h"
8#include "shader_recompiler/frontend/ir/function.h" 10#include "shader_recompiler/frontend/ir/function.h"
9 11
10namespace Shader::Optimization { 12namespace Shader::Optimization {
11 13
12template <typename Func> 14template <typename Func>
13void Invoke(Func&& func, IR::Function& function) { 15void PostOrderInvoke(Func&& func, IR::Function& function) {
14 for (const auto& block : function.blocks) { 16 for (const auto& block : function.post_order_blocks) {
15 func(*block); 17 func(*block);
16 } 18 }
17} 19}
@@ -20,7 +22,7 @@ void ConstantPropagationPass(IR::Block& block);
20void DeadCodeEliminationPass(IR::Block& block); 22void DeadCodeEliminationPass(IR::Block& block);
21void GlobalMemoryToStorageBufferPass(IR::Block& block); 23void GlobalMemoryToStorageBufferPass(IR::Block& block);
22void IdentityRemovalPass(IR::Function& function); 24void IdentityRemovalPass(IR::Function& function);
23void SsaRewritePass(IR::Function& function); 25void SsaRewritePass(std::span<IR::Block* const> post_order_blocks);
24void VerificationPass(const IR::Function& function); 26void VerificationPass(const IR::Function& function);
25 27
26} // namespace Shader::Optimization 28} // namespace Shader::Optimization
diff --git a/src/shader_recompiler/ir_opt/ssa_rewrite_pass.cpp b/src/shader_recompiler/ir_opt/ssa_rewrite_pass.cpp
index 7eaf719c4..13f9c914a 100644
--- a/src/shader_recompiler/ir_opt/ssa_rewrite_pass.cpp
+++ b/src/shader_recompiler/ir_opt/ssa_rewrite_pass.cpp
@@ -14,7 +14,13 @@
14// https://link.springer.com/chapter/10.1007/978-3-642-37051-9_6 14// https://link.springer.com/chapter/10.1007/978-3-642-37051-9_6
15// 15//
16 16
17#include <ranges>
18#include <span>
19#include <variant>
20#include <vector>
21
17#include <boost/container/flat_map.hpp> 22#include <boost/container/flat_map.hpp>
23#include <boost/container/flat_set.hpp>
18 24
19#include "shader_recompiler/frontend/ir/basic_block.h" 25#include "shader_recompiler/frontend/ir/basic_block.h"
20#include "shader_recompiler/frontend/ir/function.h" 26#include "shader_recompiler/frontend/ir/function.h"
@@ -26,9 +32,9 @@
26 32
27namespace Shader::Optimization { 33namespace Shader::Optimization {
28namespace { 34namespace {
29using ValueMap = boost::container::flat_map<IR::Block*, IR::Value, std::less<IR::Block*>>; 35struct FlagTag {
30 36 auto operator<=>(const FlagTag&) const noexcept = default;
31struct FlagTag {}; 37};
32struct ZeroFlagTag : FlagTag {}; 38struct ZeroFlagTag : FlagTag {};
33struct SignFlagTag : FlagTag {}; 39struct SignFlagTag : FlagTag {};
34struct CarryFlagTag : FlagTag {}; 40struct CarryFlagTag : FlagTag {};
@@ -38,9 +44,15 @@ struct GotoVariable : FlagTag {
38 GotoVariable() = default; 44 GotoVariable() = default;
39 explicit GotoVariable(u32 index_) : index{index_} {} 45 explicit GotoVariable(u32 index_) : index{index_} {}
40 46
47 auto operator<=>(const GotoVariable&) const noexcept = default;
48
41 u32 index; 49 u32 index;
42}; 50};
43 51
52using Variant = std::variant<IR::Reg, IR::Pred, ZeroFlagTag, SignFlagTag, CarryFlagTag,
53 OverflowFlagTag, GotoVariable>;
54using ValueMap = boost::container::flat_map<IR::Block*, IR::Value, std::less<IR::Block*>>;
55
44struct DefTable { 56struct DefTable {
45 [[nodiscard]] ValueMap& operator[](IR::Reg variable) noexcept { 57 [[nodiscard]] ValueMap& operator[](IR::Reg variable) noexcept {
46 return regs[IR::RegIndex(variable)]; 58 return regs[IR::RegIndex(variable)];
@@ -102,19 +114,35 @@ public:
102 } 114 }
103 115
104 IR::Value ReadVariable(auto variable, IR::Block* block) { 116 IR::Value ReadVariable(auto variable, IR::Block* block) {
105 auto& def{current_def[variable]}; 117 const ValueMap& def{current_def[variable]};
106 if (const auto it{def.find(block)}; it != def.end()) { 118 if (const auto it{def.find(block)}; it != def.end()) {
107 return it->second; 119 return it->second;
108 } 120 }
109 return ReadVariableRecursive(variable, block); 121 return ReadVariableRecursive(variable, block);
110 } 122 }
111 123
124 void SealBlock(IR::Block* block) {
125 const auto it{incomplete_phis.find(block)};
126 if (it != incomplete_phis.end()) {
127 for (auto& [variant, phi] : it->second) {
128 std::visit([&](auto& variable) { AddPhiOperands(variable, *phi, block); }, variant);
129 }
130 }
131 sealed_blocks.insert(block);
132 }
133
112private: 134private:
113 IR::Value ReadVariableRecursive(auto variable, IR::Block* block) { 135 IR::Value ReadVariableRecursive(auto variable, IR::Block* block) {
114 IR::Value val; 136 IR::Value val;
115 if (const std::span preds{block->ImmediatePredecessors()}; preds.size() == 1) { 137 if (!sealed_blocks.contains(block)) {
138 // Incomplete CFG
139 IR::Inst* phi{&*block->PrependNewInst(block->begin(), IR::Opcode::Phi)};
140 incomplete_phis[block].insert_or_assign(variable, phi);
141 val = IR::Value{&*phi};
142 } else if (const std::span imm_preds{block->ImmediatePredecessors()};
143 imm_preds.size() == 1) {
116 // Optimize the common case of one predecessor: no phi needed 144 // Optimize the common case of one predecessor: no phi needed
117 val = ReadVariable(variable, preds.front()); 145 val = ReadVariable(variable, imm_preds.front());
118 } else { 146 } else {
119 // Break potential cycles with operandless phi 147 // Break potential cycles with operandless phi
120 IR::Inst& phi_inst{*block->PrependNewInst(block->begin(), IR::Opcode::Phi)}; 148 IR::Inst& phi_inst{*block->PrependNewInst(block->begin(), IR::Opcode::Phi)};
@@ -127,8 +155,8 @@ private:
127 } 155 }
128 156
129 IR::Value AddPhiOperands(auto variable, IR::Inst& phi, IR::Block* block) { 157 IR::Value AddPhiOperands(auto variable, IR::Inst& phi, IR::Block* block) {
130 for (IR::Block* const pred : block->ImmediatePredecessors()) { 158 for (IR::Block* const imm_pred : block->ImmediatePredecessors()) {
131 phi.AddPhiOperand(pred, ReadVariable(variable, pred)); 159 phi.AddPhiOperand(imm_pred, ReadVariable(variable, imm_pred));
132 } 160 }
133 return TryRemoveTrivialPhi(phi, block, UndefOpcode(variable)); 161 return TryRemoveTrivialPhi(phi, block, UndefOpcode(variable));
134 } 162 }
@@ -159,6 +187,9 @@ private:
159 return same; 187 return same;
160 } 188 }
161 189
190 boost::container::flat_set<IR::Block*> sealed_blocks;
191 boost::container::flat_map<IR::Block*, boost::container::flat_map<Variant, IR::Inst*>>
192 incomplete_phis;
162 DefTable current_def; 193 DefTable current_def;
163}; 194};
164 195
@@ -218,14 +249,19 @@ void VisitInst(Pass& pass, IR::Block* block, IR::Inst& inst) {
218 break; 249 break;
219 } 250 }
220} 251}
252
253void VisitBlock(Pass& pass, IR::Block* block) {
254 for (IR::Inst& inst : block->Instructions()) {
255 VisitInst(pass, block, inst);
256 }
257 pass.SealBlock(block);
258}
221} // Anonymous namespace 259} // Anonymous namespace
222 260
223void SsaRewritePass(IR::Function& function) { 261void SsaRewritePass(std::span<IR::Block* const> post_order_blocks) {
224 Pass pass; 262 Pass pass;
225 for (IR::Block* const block : function.blocks) { 263 for (IR::Block* const block : post_order_blocks | std::views::reverse) {
226 for (IR::Inst& inst : block->Instructions()) { 264 VisitBlock(pass, block);
227 VisitInst(pass, block, inst);
228 }
229 } 265 }
230} 266}
231 267