diff options
Diffstat (limited to '')
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 | ||
| 111 | static std::string Name(const Block& block) { | 113 | static 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 | ||
| 156 | Function::Function(Location start_address) | 158 | Function::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 | ||
| 165 | void 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] = █ | ||
| 171 | } | ||
| 172 | } | ||
| 173 | |||
| 174 | void 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 | |||
| 185 | void 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 | |||
| 219 | void 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 | |||
| 254 | void 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 | |||
| 163 | CFG::CFG(Environment& env_, Location start_address) : env{env_} { | 267 | CFG::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 | |||
| 279 | void 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 | ||
| 75 | struct Label { | 81 | struct Label { |
| @@ -81,11 +87,30 @@ struct Label { | |||
| 81 | struct Function { | 87 | struct 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 | ||
| 91 | class CFG { | 116 | class CFG { |
| @@ -97,6 +122,12 @@ class CFG { | |||
| 97 | public: | 122 | public: |
| 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 | ||
| 106 | private: | 137 | private: |
| 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 | ||
| 12 | namespace Shader::Maxwell { | 13 | namespace Shader::Maxwell { |
| 14 | namespace { | ||
| 15 | void 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 | ||
| 14 | Program::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 | |||
| 18 | Program::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()}; | 29 | void 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()); | 37 | void 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))}; | 47 | Program::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 | ||
| 16 | namespace Shader::Maxwell { | 19 | namespace 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 | ||
| 24 | private: | 27 | private: |
| 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 | ||
| 48 | static void EmitBranch(const Flow::Block& flow_block, std::span<IR::Block* const> block_map, | 48 | static 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 | ||
| 12 | namespace Shader::Maxwell { | 12 | namespace Shader::Maxwell { |
| 13 | 13 | ||
| 14 | /// Emit termination instructions and collect immediate predecessors | ||
| 14 | void EmitTerminationCode(const Flow::Block& flow_block, std::span<IR::Block* const> block_map); | 15 | void 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 | ||
| 765 | void TranslatorVisitor::PBK(u64) { | 765 | void 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 | ||
| 941 | void TranslatorVisitor::SSY(u64) { | 941 | void TranslatorVisitor::SSY() { |
| 942 | ThrowNotImplemented(Opcode::SSY); | 942 | // SSY is a no-op |
| 943 | } | 943 | } |
| 944 | 944 | ||
| 945 | void TranslatorVisitor::ST(u64) { | 945 | void TranslatorVisitor::ST(u64) { |