summaryrefslogtreecommitdiff
path: root/src/shader_recompiler/ir_opt/ssa_rewrite_pass.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/shader_recompiler/ir_opt/ssa_rewrite_pass.cpp')
-rw-r--r--src/shader_recompiler/ir_opt/ssa_rewrite_pass.cpp62
1 files changed, 49 insertions, 13 deletions
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