summaryrefslogtreecommitdiff
path: root/src/shader_recompiler/ir_opt/ssa_rewrite_pass.cpp
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2021-04-05 19:10:55 -0300
committerGravatar ameerj2021-07-22 21:51:26 -0400
commit417fb5d385daa0fb40329709e6b4a53937580989 (patch)
tree8ce5696b557b127e79a983957f0a5d77afe5aec4 /src/shader_recompiler/ir_opt/ssa_rewrite_pass.cpp
parentshader: Fix ShadowCube declaration type, set number of pipeline threads based... (diff)
downloadyuzu-417fb5d385daa0fb40329709e6b4a53937580989.tar.gz
yuzu-417fb5d385daa0fb40329709e6b4a53937580989.tar.xz
yuzu-417fb5d385daa0fb40329709e6b4a53937580989.zip
shader: Move recursive SSA rewrite to the heap
Diffstat (limited to 'src/shader_recompiler/ir_opt/ssa_rewrite_pass.cpp')
-rw-r--r--src/shader_recompiler/ir_opt/ssa_rewrite_pass.cpp118
1 files changed, 89 insertions, 29 deletions
diff --git a/src/shader_recompiler/ir_opt/ssa_rewrite_pass.cpp b/src/shader_recompiler/ir_opt/ssa_rewrite_pass.cpp
index 259233746..ca36253d1 100644
--- a/src/shader_recompiler/ir_opt/ssa_rewrite_pass.cpp
+++ b/src/shader_recompiler/ir_opt/ssa_rewrite_pass.cpp
@@ -119,6 +119,26 @@ IR::Opcode UndefOpcode(IndirectBranchVariable) noexcept {
119 return inst.Opcode() == IR::Opcode::Phi; 119 return inst.Opcode() == IR::Opcode::Phi;
120} 120}
121 121
122enum class Status {
123 Start,
124 SetValue,
125 PreparePhiArgument,
126 PushPhiArgument,
127};
128
129template <typename Type>
130struct ReadState {
131 ReadState(IR::Block* block_) : block{block_} {}
132 ReadState() = default;
133
134 IR::Block* block{};
135 IR::Value result{};
136 IR::Inst* phi{};
137 IR::Block* const* pred_it{};
138 IR::Block* const* pred_end{};
139 Status pc{Status::Start};
140};
141
122class Pass { 142class Pass {
123public: 143public:
124 template <typename Type> 144 template <typename Type>
@@ -127,12 +147,75 @@ public:
127 } 147 }
128 148
129 template <typename Type> 149 template <typename Type>
130 IR::Value ReadVariable(Type variable, IR::Block* block) { 150 IR::Value ReadVariable(Type variable, IR::Block* root_block) {
131 const ValueMap& def{current_def[variable]}; 151 boost::container::small_vector<ReadState<Type>, 64> stack{
132 if (const auto it{def.find(block)}; it != def.end()) { 152 ReadState<Type>(nullptr),
133 return it->second; 153 ReadState<Type>(root_block),
134 } 154 };
135 return ReadVariableRecursive(variable, block); 155 const auto prepare_phi_operand{[&] {
156 if (stack.back().pred_it == stack.back().pred_end) {
157 IR::Inst* const phi{stack.back().phi};
158 IR::Block* const block{stack.back().block};
159 const IR::Value result{TryRemoveTrivialPhi(*phi, block, UndefOpcode(variable))};
160 stack.pop_back();
161 stack.back().result = result;
162 WriteVariable(variable, block, result);
163 } else {
164 IR::Block* const imm_pred{*stack.back().pred_it};
165 stack.back().pc = Status::PushPhiArgument;
166 stack.emplace_back(imm_pred);
167 }
168 }};
169 do {
170 IR::Block* const block{stack.back().block};
171 switch (stack.back().pc) {
172 case Status::Start: {
173 const ValueMap& def{current_def[variable]};
174 if (const auto it{def.find(block)}; it != def.end()) {
175 stack.back().result = it->second;
176 } else if (!sealed_blocks.contains(block)) {
177 // Incomplete CFG
178 IR::Inst* phi{&*block->PrependNewInst(block->begin(), IR::Opcode::Phi)};
179 incomplete_phis[block].insert_or_assign(variable, phi);
180 stack.back().result = IR::Value{&*phi};
181 } else if (const std::span imm_preds{block->ImmediatePredecessors()};
182 imm_preds.size() == 1) {
183 // Optimize the common case of one predecessor: no phi needed
184 stack.back().pc = Status::SetValue;
185 stack.emplace_back(imm_preds.front());
186 break;
187 } else {
188 // Break potential cycles with operandless phi
189 IR::Inst* const phi{&*block->PrependNewInst(block->begin(), IR::Opcode::Phi)};
190 WriteVariable(variable, block, IR::Value{phi});
191
192 stack.back().phi = phi;
193 stack.back().pred_it = imm_preds.data();
194 stack.back().pred_end = imm_preds.data() + imm_preds.size();
195 prepare_phi_operand();
196 break;
197 }
198 }
199 [[fallthrough]];
200 case Status::SetValue: {
201 const IR::Value result{stack.back().result};
202 WriteVariable(variable, block, result);
203 stack.pop_back();
204 stack.back().result = result;
205 break;
206 }
207 case Status::PushPhiArgument: {
208 IR::Inst* const phi{stack.back().phi};
209 phi->AddPhiOperand(*stack.back().pred_it, stack.back().result);
210 ++stack.back().pred_it;
211 }
212 [[fallthrough]];
213 case Status::PreparePhiArgument:
214 prepare_phi_operand();
215 break;
216 }
217 } while (stack.size() > 1);
218 return stack.back().result;
136 } 219 }
137 220
138 void SealBlock(IR::Block* block) { 221 void SealBlock(IR::Block* block) {
@@ -147,29 +230,6 @@ public:
147 230
148private: 231private:
149 template <typename Type> 232 template <typename Type>
150 IR::Value ReadVariableRecursive(Type variable, IR::Block* block) {
151 IR::Value val;
152 if (!sealed_blocks.contains(block)) {
153 // Incomplete CFG
154 IR::Inst* phi{&*block->PrependNewInst(block->begin(), IR::Opcode::Phi)};
155 incomplete_phis[block].insert_or_assign(variable, phi);
156 val = IR::Value{&*phi};
157 } else if (const std::span imm_preds{block->ImmediatePredecessors()};
158 imm_preds.size() == 1) {
159 // Optimize the common case of one predecessor: no phi needed
160 val = ReadVariable(variable, imm_preds.front());
161 } else {
162 // Break potential cycles with operandless phi
163 IR::Inst& phi_inst{*block->PrependNewInst(block->begin(), IR::Opcode::Phi)};
164 val = IR::Value{&phi_inst};
165 WriteVariable(variable, block, val);
166 val = AddPhiOperands(variable, phi_inst, block);
167 }
168 WriteVariable(variable, block, val);
169 return val;
170 }
171
172 template <typename Type>
173 IR::Value AddPhiOperands(Type variable, IR::Inst& phi, IR::Block* block) { 233 IR::Value AddPhiOperands(Type variable, IR::Inst& phi, IR::Block* block) {
174 for (IR::Block* const imm_pred : block->ImmediatePredecessors()) { 234 for (IR::Block* const imm_pred : block->ImmediatePredecessors()) {
175 phi.AddPhiOperand(imm_pred, ReadVariable(variable, imm_pred)); 235 phi.AddPhiOperand(imm_pred, ReadVariable(variable, imm_pred));