summaryrefslogtreecommitdiff
path: root/src/shader_recompiler/frontend/maxwell
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2021-02-02 21:07:00 -0300
committerGravatar ameerj2021-07-22 21:51:21 -0400
commit6c4cc0cd062fbbba5349da1108d3c23cb330ca8a (patch)
tree544291931da8a85fafcea71964c77d9278ec7f29 /src/shader_recompiler/frontend/maxwell
parentshader: Initial recompiler work (diff)
downloadyuzu-6c4cc0cd062fbbba5349da1108d3c23cb330ca8a.tar.gz
yuzu-6c4cc0cd062fbbba5349da1108d3c23cb330ca8a.tar.xz
yuzu-6c4cc0cd062fbbba5349da1108d3c23cb330ca8a.zip
shader: SSA and dominance
Diffstat (limited to '')
-rw-r--r--src/shader_recompiler/frontend/maxwell/control_flow.cpp130
-rw-r--r--src/shader_recompiler/frontend/maxwell/control_flow.h44
-rw-r--r--src/shader_recompiler/frontend/maxwell/program.cpp75
-rw-r--r--src/shader_recompiler/frontend/maxwell/program.h11
-rw-r--r--src/shader_recompiler/frontend/maxwell/termination_code.cpp7
-rw-r--r--src/shader_recompiler/frontend/maxwell/termination_code.h1
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/impl.h4
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp6
8 files changed, 223 insertions, 55 deletions
diff --git a/src/shader_recompiler/frontend/maxwell/control_flow.cpp b/src/shader_recompiler/frontend/maxwell/control_flow.cpp
index fc4dba826..21ee98137 100644
--- a/src/shader_recompiler/frontend/maxwell/control_flow.cpp
+++ b/src/shader_recompiler/frontend/maxwell/control_flow.cpp
@@ -36,6 +36,7 @@ static std::array<Block, 2> Split(Block&& block, Location pc, BlockId new_id) {
36 .cond{true}, 36 .cond{true},
37 .branch_true{new_id}, 37 .branch_true{new_id},
38 .branch_false{UNREACHABLE_BLOCK_ID}, 38 .branch_false{UNREACHABLE_BLOCK_ID},
39 .imm_predecessors{},
39 }, 40 },
40 Block{ 41 Block{
41 .begin{pc}, 42 .begin{pc},
@@ -46,6 +47,7 @@ static std::array<Block, 2> Split(Block&& block, Location pc, BlockId new_id) {
46 .cond{block.cond}, 47 .cond{block.cond},
47 .branch_true{block.branch_true}, 48 .branch_true{block.branch_true},
48 .branch_false{block.branch_false}, 49 .branch_false{block.branch_false},
50 .imm_predecessors{},
49 }, 51 },
50 }; 52 };
51} 53}
@@ -108,7 +110,7 @@ static bool HasFlowTest(Opcode opcode) {
108 } 110 }
109} 111}
110 112
111static std::string Name(const Block& block) { 113static std::string NameOf(const Block& block) {
112 if (block.begin.IsVirtual()) { 114 if (block.begin.IsVirtual()) {
113 return fmt::format("\"Virtual {}\"", block.id); 115 return fmt::format("\"Virtual {}\"", block.id);
114 } else { 116 } else {
@@ -154,13 +156,127 @@ bool Block::Contains(Location pc) const noexcept {
154} 156}
155 157
156Function::Function(Location start_address) 158Function::Function(Location start_address)
157 : entrypoint{start_address}, labels{Label{ 159 : entrypoint{start_address}, labels{{
158 .address{start_address}, 160 .address{start_address},
159 .block_id{0}, 161 .block_id{0},
160 .stack{}, 162 .stack{},
161 }} {} 163 }} {}
162 164
165void Function::BuildBlocksMap() {
166 const size_t num_blocks{NumBlocks()};
167 blocks_map.resize(num_blocks);
168 for (size_t block_index = 0; block_index < num_blocks; ++block_index) {
169 Block& block{blocks_data[block_index]};
170 blocks_map[block.id] = &block;
171 }
172}
173
174void Function::BuildImmediatePredecessors() {
175 for (const Block& block : blocks_data) {
176 if (block.branch_true != UNREACHABLE_BLOCK_ID) {
177 blocks_map[block.branch_true]->imm_predecessors.push_back(block.id);
178 }
179 if (block.branch_false != UNREACHABLE_BLOCK_ID) {
180 blocks_map[block.branch_false]->imm_predecessors.push_back(block.id);
181 }
182 }
183}
184
185void Function::BuildPostOrder() {
186 boost::container::small_vector<BlockId, 0x110> block_stack;
187 post_order_map.resize(NumBlocks());
188
189 Block& first_block{blocks_data[blocks.front()]};
190 first_block.post_order_visited = true;
191 block_stack.push_back(first_block.id);
192
193 const auto visit_branch = [&](BlockId block_id, BlockId branch_id) {
194 if (branch_id == UNREACHABLE_BLOCK_ID) {
195 return false;
196 }
197 if (blocks_map[branch_id]->post_order_visited) {
198 return false;
199 }
200 blocks_map[branch_id]->post_order_visited = true;
201
202 // Calling push_back twice is faster than insert on msvc
203 block_stack.push_back(block_id);
204 block_stack.push_back(branch_id);
205 return true;
206 };
207 while (!block_stack.empty()) {
208 const Block* const block{blocks_map[block_stack.back()]};
209 block_stack.pop_back();
210
211 if (!visit_branch(block->id, block->branch_true) &&
212 !visit_branch(block->id, block->branch_false)) {
213 post_order_map[block->id] = static_cast<u32>(post_order_blocks.size());
214 post_order_blocks.push_back(block->id);
215 }
216 }
217}
218
219void Function::BuildImmediateDominators() {
220 auto transform_block_id{std::views::transform([this](BlockId id) { return blocks_map[id]; })};
221 auto reverse_order_but_first{std::views::reverse | std::views::drop(1) | transform_block_id};
222 auto has_idom{std::views::filter([](Block* block) { return block->imm_dominator; })};
223 auto intersect{[this](Block* finger1, Block* finger2) {
224 while (finger1 != finger2) {
225 while (post_order_map[finger1->id] < post_order_map[finger2->id]) {
226 finger1 = finger1->imm_dominator;
227 }
228 while (post_order_map[finger2->id] < post_order_map[finger1->id]) {
229 finger2 = finger2->imm_dominator;
230 }
231 }
232 return finger1;
233 }};
234 for (Block& block : blocks_data) {
235 block.imm_dominator = nullptr;
236 }
237 Block* const start_block{&blocks_data[blocks.front()]};
238 start_block->imm_dominator = start_block;
239
240 bool changed{true};
241 while (changed) {
242 changed = false;
243 for (Block* const block : post_order_blocks | reverse_order_but_first) {
244 Block* new_idom{};
245 for (Block* predecessor : block->imm_predecessors | transform_block_id | has_idom) {
246 new_idom = new_idom ? intersect(predecessor, new_idom) : predecessor;
247 }
248 changed |= block->imm_dominator != new_idom;
249 block->imm_dominator = new_idom;
250 }
251 }
252}
253
254void Function::BuildDominanceFrontier() {
255 auto transform_block_id{std::views::transform([this](BlockId id) { return blocks_map[id]; })};
256 auto has_enough_predecessors{[](Block& block) { return block.imm_predecessors.size() >= 2; }};
257 for (Block& block : blocks_data | std::views::filter(has_enough_predecessors)) {
258 for (Block* current : block.imm_predecessors | transform_block_id) {
259 while (current != block.imm_dominator) {
260 current->dominance_frontiers.push_back(current->id);
261 current = current->imm_dominator;
262 }
263 }
264 }
265}
266
163CFG::CFG(Environment& env_, Location start_address) : env{env_} { 267CFG::CFG(Environment& env_, Location start_address) : env{env_} {
268 VisitFunctions(start_address);
269
270 for (Function& function : functions) {
271 function.BuildBlocksMap();
272 function.BuildImmediatePredecessors();
273 function.BuildPostOrder();
274 function.BuildImmediateDominators();
275 function.BuildDominanceFrontier();
276 }
277}
278
279void CFG::VisitFunctions(Location start_address) {
164 functions.emplace_back(start_address); 280 functions.emplace_back(start_address);
165 for (FunctionId function_id = 0; function_id < functions.size(); ++function_id) { 281 for (FunctionId function_id = 0; function_id < functions.size(); ++function_id) {
166 while (!functions[function_id].labels.empty()) { 282 while (!functions[function_id].labels.empty()) {
@@ -202,6 +318,7 @@ void CFG::AnalyzeLabel(FunctionId function_id, Label& label) {
202 .cond{true}, 318 .cond{true},
203 .branch_true{UNREACHABLE_BLOCK_ID}, 319 .branch_true{UNREACHABLE_BLOCK_ID},
204 .branch_false{UNREACHABLE_BLOCK_ID}, 320 .branch_false{UNREACHABLE_BLOCK_ID},
321 .imm_predecessors{},
205 }; 322 };
206 // Analyze instructions until it reaches an already visited block or there's a branch 323 // Analyze instructions until it reaches an already visited block or there's a branch
207 bool is_branch{false}; 324 bool is_branch{false};
@@ -310,7 +427,7 @@ CFG::AnalysisState CFG::AnalyzeInst(Block& block, FunctionId function_id, Locati
310 // Technically CAL pushes into PRET, but that's implicit in the function call for us 427 // Technically CAL pushes into PRET, but that's implicit in the function call for us
311 // Insert the function into the list if it doesn't exist 428 // Insert the function into the list if it doesn't exist
312 if (std::ranges::find(functions, cal_pc, &Function::entrypoint) == functions.end()) { 429 if (std::ranges::find(functions, cal_pc, &Function::entrypoint) == functions.end()) {
313 functions.push_back(cal_pc); 430 functions.emplace_back(cal_pc);
314 } 431 }
315 // Handle CAL like a regular instruction 432 // Handle CAL like a regular instruction
316 break; 433 break;
@@ -352,6 +469,7 @@ void CFG::AnalyzeCondInst(Block& block, FunctionId function_id, Location pc,
352 .cond{cond}, 469 .cond{cond},
353 .branch_true{conditional_block_id}, 470 .branch_true{conditional_block_id},
354 .branch_false{UNREACHABLE_BLOCK_ID}, 471 .branch_false{UNREACHABLE_BLOCK_ID},
472 .imm_predecessors{},
355 })}; 473 })};
356 // Set the end properties of the conditional instruction and give it a new identity 474 // Set the end properties of the conditional instruction and give it a new identity
357 Block& conditional_block{block}; 475 Block& conditional_block{block};
@@ -465,14 +583,14 @@ std::string CFG::Dot() const {
465 dot += fmt::format("\t\tnode [style=filled];\n"); 583 dot += fmt::format("\t\tnode [style=filled];\n");
466 for (const u32 block_index : function.blocks) { 584 for (const u32 block_index : function.blocks) {
467 const Block& block{function.blocks_data[block_index]}; 585 const Block& block{function.blocks_data[block_index]};
468 const std::string name{Name(block)}; 586 const std::string name{NameOf(block)};
469 const auto add_branch = [&](BlockId branch_id, bool add_label) { 587 const auto add_branch = [&](BlockId branch_id, bool add_label) {
470 const auto it{std::ranges::find(function.blocks_data, branch_id, &Block::id)}; 588 const auto it{std::ranges::find(function.blocks_data, branch_id, &Block::id)};
471 dot += fmt::format("\t\t{}->", name); 589 dot += fmt::format("\t\t{}->", name);
472 if (it == function.blocks_data.end()) { 590 if (it == function.blocks_data.end()) {
473 dot += fmt::format("\"Unknown label {}\"", branch_id); 591 dot += fmt::format("\"Unknown label {}\"", branch_id);
474 } else { 592 } else {
475 dot += Name(*it); 593 dot += NameOf(*it);
476 }; 594 };
477 if (add_label && block.cond != true && block.cond != false) { 595 if (add_label && block.cond != true && block.cond != false) {
478 dot += fmt::format(" [label=\"{}\"]", block.cond); 596 dot += fmt::format(" [label=\"{}\"]", block.cond);
@@ -520,7 +638,7 @@ std::string CFG::Dot() const {
520 if (functions.front().blocks.empty()) { 638 if (functions.front().blocks.empty()) {
521 dot += "Start;\n"; 639 dot += "Start;\n";
522 } else { 640 } else {
523 dot += fmt::format("\tStart -> {};\n", Name(functions.front().blocks_data.front())); 641 dot += fmt::format("\tStart -> {};\n", NameOf(functions.front().blocks_data.front()));
524 } 642 }
525 dot += fmt::format("\tStart [shape=diamond];\n"); 643 dot += fmt::format("\tStart [shape=diamond];\n");
526 } 644 }
diff --git a/src/shader_recompiler/frontend/maxwell/control_flow.h b/src/shader_recompiler/frontend/maxwell/control_flow.h
index b2ab0cdc3..20ada8afd 100644
--- a/src/shader_recompiler/frontend/maxwell/control_flow.h
+++ b/src/shader_recompiler/frontend/maxwell/control_flow.h
@@ -70,6 +70,12 @@ struct Block {
70 IR::Condition cond; 70 IR::Condition cond;
71 BlockId branch_true; 71 BlockId branch_true;
72 BlockId branch_false; 72 BlockId branch_false;
73 boost::container::small_vector<BlockId, 4> imm_predecessors;
74 boost::container::small_vector<BlockId, 8> dominance_frontiers;
75 union {
76 bool post_order_visited{false};
77 Block* imm_dominator;
78 };
73}; 79};
74 80
75struct Label { 81struct Label {
@@ -81,11 +87,30 @@ struct Label {
81struct Function { 87struct Function {
82 Function(Location start_address); 88 Function(Location start_address);
83 89
90 void BuildBlocksMap();
91
92 void BuildImmediatePredecessors();
93
94 void BuildPostOrder();
95
96 void BuildImmediateDominators();
97
98 void BuildDominanceFrontier();
99
100 [[nodiscard]] size_t NumBlocks() const noexcept {
101 return static_cast<size_t>(current_block_id) + 1;
102 }
103
84 Location entrypoint; 104 Location entrypoint;
85 BlockId current_block_id{0}; 105 BlockId current_block_id{0};
86 boost::container::small_vector<Label, 16> labels; 106 boost::container::small_vector<Label, 16> labels;
87 boost::container::small_vector<u32, 0x130> blocks; 107 boost::container::small_vector<u32, 0x130> blocks;
88 boost::container::small_vector<Block, 0x130> blocks_data; 108 boost::container::small_vector<Block, 0x130> blocks_data;
109 // Translates from BlockId to block index
110 boost::container::small_vector<Block*, 0x130> blocks_map;
111
112 boost::container::small_vector<u32, 0x130> post_order_blocks;
113 boost::container::small_vector<BlockId, 0x130> post_order_map;
89}; 114};
90 115
91class CFG { 116class CFG {
@@ -97,6 +122,12 @@ class CFG {
97public: 122public:
98 explicit CFG(Environment& env, Location start_address); 123 explicit CFG(Environment& env, Location start_address);
99 124
125 CFG& operator=(const CFG&) = delete;
126 CFG(const CFG&) = delete;
127
128 CFG& operator=(CFG&&) = delete;
129 CFG(CFG&&) = delete;
130
100 [[nodiscard]] std::string Dot() const; 131 [[nodiscard]] std::string Dot() const;
101 132
102 [[nodiscard]] std::span<const Function> Functions() const noexcept { 133 [[nodiscard]] std::span<const Function> Functions() const noexcept {
@@ -104,20 +135,22 @@ public:
104 } 135 }
105 136
106private: 137private:
138 void VisitFunctions(Location start_address);
139
107 void AnalyzeLabel(FunctionId function_id, Label& label); 140 void AnalyzeLabel(FunctionId function_id, Label& label);
108 141
109 /// Inspect already visited blocks. 142 /// Inspect already visited blocks.
110 /// Return true when the block has already been visited 143 /// Return true when the block has already been visited
111 [[nodiscard]] bool InspectVisitedBlocks(FunctionId function_id, const Label& label); 144 bool InspectVisitedBlocks(FunctionId function_id, const Label& label);
112 145
113 [[nodiscard]] AnalysisState AnalyzeInst(Block& block, FunctionId function_id, Location pc); 146 AnalysisState AnalyzeInst(Block& block, FunctionId function_id, Location pc);
114 147
115 void AnalyzeCondInst(Block& block, FunctionId function_id, Location pc, EndClass insn_end_class, 148 void AnalyzeCondInst(Block& block, FunctionId function_id, Location pc, EndClass insn_end_class,
116 IR::Condition cond); 149 IR::Condition cond);
117 150
118 /// Return true when the branch instruction is confirmed to be a branch 151 /// Return true when the branch instruction is confirmed to be a branch
119 [[nodiscard]] bool AnalyzeBranch(Block& block, FunctionId function_id, Location pc, 152 bool AnalyzeBranch(Block& block, FunctionId function_id, Location pc, Instruction inst,
120 Instruction inst, Opcode opcode); 153 Opcode opcode);
121 154
122 void AnalyzeBRA(Block& block, FunctionId function_id, Location pc, Instruction inst, 155 void AnalyzeBRA(Block& block, FunctionId function_id, Location pc, Instruction inst,
123 bool is_absolute); 156 bool is_absolute);
@@ -126,8 +159,7 @@ private:
126 AnalysisState AnalyzeEXIT(Block& block, FunctionId function_id, Location pc, Instruction inst); 159 AnalysisState AnalyzeEXIT(Block& block, FunctionId function_id, Location pc, Instruction inst);
127 160
128 /// Return the branch target block id 161 /// Return the branch target block id
129 [[nodiscard]] BlockId AddLabel(const Block& block, Stack stack, Location pc, 162 BlockId AddLabel(const Block& block, Stack stack, Location pc, FunctionId function_id);
130 FunctionId function_id);
131 163
132 Environment& env; 164 Environment& env;
133 boost::container::small_vector<Function, 1> functions; 165 boost::container::small_vector<Function, 1> functions;
diff --git a/src/shader_recompiler/frontend/maxwell/program.cpp b/src/shader_recompiler/frontend/maxwell/program.cpp
index 67a98ba57..49d1f4bfb 100644
--- a/src/shader_recompiler/frontend/maxwell/program.cpp
+++ b/src/shader_recompiler/frontend/maxwell/program.cpp
@@ -8,40 +8,53 @@
8#include "shader_recompiler/frontend/maxwell/program.h" 8#include "shader_recompiler/frontend/maxwell/program.h"
9#include "shader_recompiler/frontend/maxwell/termination_code.h" 9#include "shader_recompiler/frontend/maxwell/termination_code.h"
10#include "shader_recompiler/frontend/maxwell/translate/translate.h" 10#include "shader_recompiler/frontend/maxwell/translate/translate.h"
11#include "shader_recompiler/ir_opt/passes.h"
11 12
12namespace Shader::Maxwell { 13namespace Shader::Maxwell {
14namespace {
15void TranslateCode(Environment& env, const Flow::Function& cfg_function, IR::Function& function,
16 std::span<IR::Block*> block_map, IR::Block* block_memory) {
17 const size_t num_blocks{cfg_function.blocks.size()};
18 function.blocks.reserve(num_blocks);
13 19
14Program::Function::~Function() { 20 for (const Flow::BlockId block_id : cfg_function.blocks) {
15 std::ranges::for_each(blocks, &std::destroy_at<IR::Block>); 21 const Flow::Block& flow_block{cfg_function.blocks_data[block_id]};
16}
17
18Program::Program(Environment& env, const Flow::CFG& cfg) {
19 std::vector<IR::Block*> block_map;
20 functions.reserve(cfg.Functions().size());
21 22
22 for (const Flow::Function& cfg_function : cfg.Functions()) { 23 function.blocks.emplace_back(std::construct_at(block_memory, Translate(env, flow_block)));
23 Function& function{functions.emplace_back()}; 24 block_map[flow_block.id] = function.blocks.back().get();
25 ++block_memory;
26 }
27}
24 28
25 const size_t num_blocks{cfg_function.blocks.size()}; 29void EmitTerminationInsts(const Flow::Function& cfg_function,
26 IR::Block* block_memory{block_alloc_pool.allocate(num_blocks)}; 30 std::span<IR::Block* const> block_map) {
27 function.blocks.reserve(num_blocks); 31 for (const Flow::BlockId block_id : cfg_function.blocks) {
32 const Flow::Block& flow_block{cfg_function.blocks_data[block_id]};
33 EmitTerminationCode(flow_block, block_map);
34 }
35}
28 36
29 block_map.resize(cfg_function.blocks_data.size()); 37void TranslateFunction(Environment& env, const Flow::Function& cfg_function, IR::Function& function,
38 IR::Block* block_memory) {
39 std::vector<IR::Block*> block_map;
40 block_map.resize(cfg_function.blocks_data.size());
30 41
31 // Visit the instructions of all blocks 42 TranslateCode(env, cfg_function, function, block_map, block_memory);
32 for (const Flow::BlockId block_id : cfg_function.blocks) { 43 EmitTerminationInsts(cfg_function, block_map);
33 const Flow::Block& flow_block{cfg_function.blocks_data[block_id]}; 44}
45} // Anonymous namespace
34 46
35 IR::Block* const block{std::construct_at(block_memory, Translate(env, flow_block))}; 47Program::Program(Environment& env, const Flow::CFG& cfg) {
36 ++block_memory; 48 functions.reserve(cfg.Functions().size());
37 function.blocks.push_back(block); 49 for (const Flow::Function& cfg_function : cfg.Functions()) {
38 block_map[flow_block.id] = block; 50 TranslateFunction(env, cfg_function, functions.emplace_back(),
39 } 51 block_alloc_pool.allocate(cfg_function.blocks.size()));
40 // Now that all blocks are defined, emit the termination instructions 52 }
41 for (const Flow::BlockId block_id : cfg_function.blocks) { 53 std::ranges::for_each(functions, Optimization::SsaRewritePass);
42 const Flow::Block& flow_block{cfg_function.blocks_data[block_id]}; 54 for (IR::Function& function : functions) {
43 EmitTerminationCode(flow_block, block_map); 55 Optimization::Invoke(Optimization::DeadCodeEliminationPass, function);
44 } 56 Optimization::Invoke(Optimization::IdentityRemovalPass, function);
57 // Optimization::Invoke(Optimization::VerificationPass, function);
45 } 58 }
46} 59}
47 60
@@ -50,16 +63,16 @@ std::string DumpProgram(const Program& program) {
50 std::map<const IR::Inst*, size_t> inst_to_index; 63 std::map<const IR::Inst*, size_t> inst_to_index;
51 std::map<const IR::Block*, size_t> block_to_index; 64 std::map<const IR::Block*, size_t> block_to_index;
52 65
53 for (const Program::Function& function : program.functions) { 66 for (const IR::Function& function : program.functions) {
54 for (const IR::Block* const block : function.blocks) { 67 for (const auto& block : function.blocks) {
55 block_to_index.emplace(block, index); 68 block_to_index.emplace(block.get(), index);
56 ++index; 69 ++index;
57 } 70 }
58 } 71 }
59 std::string ret; 72 std::string ret;
60 for (const Program::Function& function : program.functions) { 73 for (const IR::Function& function : program.functions) {
61 ret += fmt::format("Function\n"); 74 ret += fmt::format("Function\n");
62 for (const IR::Block* const block : function.blocks) { 75 for (const auto& block : function.blocks) {
63 ret += IR::DumpBlock(*block, block_to_index, inst_to_index, index) + '\n'; 76 ret += IR::DumpBlock(*block, block_to_index, inst_to_index, index) + '\n';
64 } 77 }
65 } 78 }
diff --git a/src/shader_recompiler/frontend/maxwell/program.h b/src/shader_recompiler/frontend/maxwell/program.h
index 7814b2c01..36e678a9e 100644
--- a/src/shader_recompiler/frontend/maxwell/program.h
+++ b/src/shader_recompiler/frontend/maxwell/program.h
@@ -4,13 +4,16 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <memory>
7#include <string> 8#include <string>
8#include <vector> 9#include <vector>
9 10
11#include <boost/container/small_vector.hpp>
10#include <boost/pool/pool_alloc.hpp> 12#include <boost/pool/pool_alloc.hpp>
11 13
12#include "shader_recompiler/environment.h" 14#include "shader_recompiler/environment.h"
13#include "shader_recompiler/frontend/ir/basic_block.h" 15#include "shader_recompiler/frontend/ir/basic_block.h"
16#include "shader_recompiler/frontend/ir/function.h"
14#include "shader_recompiler/frontend/maxwell/control_flow.h" 17#include "shader_recompiler/frontend/maxwell/control_flow.h"
15 18
16namespace Shader::Maxwell { 19namespace Shader::Maxwell {
@@ -22,16 +25,10 @@ public:
22 explicit Program(Environment& env, const Flow::CFG& cfg); 25 explicit Program(Environment& env, const Flow::CFG& cfg);
23 26
24private: 27private:
25 struct Function {
26 ~Function();
27
28 std::vector<IR::Block*> blocks;
29 };
30
31 boost::pool_allocator<IR::Block, boost::default_user_allocator_new_delete, 28 boost::pool_allocator<IR::Block, boost::default_user_allocator_new_delete,
32 boost::details::pool::null_mutex> 29 boost::details::pool::null_mutex>
33 block_alloc_pool; 30 block_alloc_pool;
34 std::vector<Function> functions; 31 boost::container::small_vector<IR::Function, 1> functions;
35}; 32};
36 33
37[[nodiscard]] std::string DumpProgram(const Program& program); 34[[nodiscard]] std::string DumpProgram(const Program& program);
diff --git a/src/shader_recompiler/frontend/maxwell/termination_code.cpp b/src/shader_recompiler/frontend/maxwell/termination_code.cpp
index a4ea5c5e3..ed5137f20 100644
--- a/src/shader_recompiler/frontend/maxwell/termination_code.cpp
+++ b/src/shader_recompiler/frontend/maxwell/termination_code.cpp
@@ -47,12 +47,19 @@ static IR::U1 GetCond(IR::Condition cond, IR::IREmitter& ir) {
47 47
48static void EmitBranch(const Flow::Block& flow_block, std::span<IR::Block* const> block_map, 48static void EmitBranch(const Flow::Block& flow_block, std::span<IR::Block* const> block_map,
49 IR::IREmitter& ir) { 49 IR::IREmitter& ir) {
50 const auto add_immediate_predecessor = [&](Flow::BlockId label) {
51 block_map[label]->AddImmediatePredecessor(&ir.block);
52 };
50 if (flow_block.cond == true) { 53 if (flow_block.cond == true) {
54 add_immediate_predecessor(flow_block.branch_true);
51 return ir.Branch(block_map[flow_block.branch_true]); 55 return ir.Branch(block_map[flow_block.branch_true]);
52 } 56 }
53 if (flow_block.cond == false) { 57 if (flow_block.cond == false) {
58 add_immediate_predecessor(flow_block.branch_false);
54 return ir.Branch(block_map[flow_block.branch_false]); 59 return ir.Branch(block_map[flow_block.branch_false]);
55 } 60 }
61 add_immediate_predecessor(flow_block.branch_true);
62 add_immediate_predecessor(flow_block.branch_false);
56 return ir.BranchConditional(GetCond(flow_block.cond, ir), block_map[flow_block.branch_true], 63 return ir.BranchConditional(GetCond(flow_block.cond, ir), block_map[flow_block.branch_true],
57 block_map[flow_block.branch_false]); 64 block_map[flow_block.branch_false]);
58} 65}
diff --git a/src/shader_recompiler/frontend/maxwell/termination_code.h b/src/shader_recompiler/frontend/maxwell/termination_code.h
index b0d667942..04e044534 100644
--- a/src/shader_recompiler/frontend/maxwell/termination_code.h
+++ b/src/shader_recompiler/frontend/maxwell/termination_code.h
@@ -11,6 +11,7 @@
11 11
12namespace Shader::Maxwell { 12namespace Shader::Maxwell {
13 13
14/// Emit termination instructions and collect immediate predecessors
14void EmitTerminationCode(const Flow::Block& flow_block, std::span<IR::Block* const> block_map); 15void EmitTerminationCode(const Flow::Block& flow_block, std::span<IR::Block* const> block_map);
15 16
16} // namespace Shader::Maxwell 17} // namespace Shader::Maxwell
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h b/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h
index bc607b002..8be7d6ff1 100644
--- a/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h
@@ -208,7 +208,7 @@ public:
208 void P2R_reg(u64 insn); 208 void P2R_reg(u64 insn);
209 void P2R_cbuf(u64 insn); 209 void P2R_cbuf(u64 insn);
210 void P2R_imm(u64 insn); 210 void P2R_imm(u64 insn);
211 void PBK(u64 insn); 211 void PBK();
212 void PCNT(u64 insn); 212 void PCNT(u64 insn);
213 void PEXIT(u64 insn); 213 void PEXIT(u64 insn);
214 void PIXLD(u64 insn); 214 void PIXLD(u64 insn);
@@ -252,7 +252,7 @@ public:
252 void SHR_reg(u64 insn); 252 void SHR_reg(u64 insn);
253 void SHR_cbuf(u64 insn); 253 void SHR_cbuf(u64 insn);
254 void SHR_imm(u64 insn); 254 void SHR_imm(u64 insn);
255 void SSY(u64 insn); 255 void SSY();
256 void ST(u64 insn); 256 void ST(u64 insn);
257 void STG(u64 insn); 257 void STG(u64 insn);
258 void STL(u64 insn); 258 void STL(u64 insn);
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp
index c907c1ffb..0f52696d1 100644
--- a/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp
@@ -762,7 +762,7 @@ void TranslatorVisitor::P2R_imm(u64) {
762 ThrowNotImplemented(Opcode::P2R_imm); 762 ThrowNotImplemented(Opcode::P2R_imm);
763} 763}
764 764
765void TranslatorVisitor::PBK(u64) { 765void TranslatorVisitor::PBK() {
766 // PBK is a no-op 766 // PBK is a no-op
767} 767}
768 768
@@ -938,8 +938,8 @@ void TranslatorVisitor::SHR_imm(u64) {
938 ThrowNotImplemented(Opcode::SHR_imm); 938 ThrowNotImplemented(Opcode::SHR_imm);
939} 939}
940 940
941void TranslatorVisitor::SSY(u64) { 941void TranslatorVisitor::SSY() {
942 ThrowNotImplemented(Opcode::SSY); 942 // SSY is a no-op
943} 943}
944 944
945void TranslatorVisitor::ST(u64) { 945void TranslatorVisitor::ST(u64) {