summaryrefslogtreecommitdiff
path: root/src/shader_recompiler/frontend/ir
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/shader_recompiler/frontend/ir/function.cpp5
-rw-r--r--src/shader_recompiler/frontend/ir/function.h18
-rw-r--r--src/shader_recompiler/frontend/ir/program.cpp18
-rw-r--r--src/shader_recompiler/frontend/ir/program.h5
-rw-r--r--src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp (renamed from src/shader_recompiler/frontend/ir/structured_control_flow.cpp)254
-rw-r--r--src/shader_recompiler/frontend/maxwell/structured_control_flow.h (renamed from src/shader_recompiler/frontend/ir/structured_control_flow.h)12
6 files changed, 157 insertions, 155 deletions
diff --git a/src/shader_recompiler/frontend/ir/function.cpp b/src/shader_recompiler/frontend/ir/function.cpp
deleted file mode 100644
index d1fc9461d..000000000
--- a/src/shader_recompiler/frontend/ir/function.cpp
+++ /dev/null
@@ -1,5 +0,0 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "shader_recompiler/frontend/ir/function.h"
diff --git a/src/shader_recompiler/frontend/ir/function.h b/src/shader_recompiler/frontend/ir/function.h
deleted file mode 100644
index d1f061146..000000000
--- a/src/shader_recompiler/frontend/ir/function.h
+++ /dev/null
@@ -1,18 +0,0 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <boost/container/small_vector.hpp>
8
9#include "shader_recompiler/frontend/ir/basic_block.h"
10
11namespace Shader::IR {
12
13struct Function {
14 BlockList blocks;
15 BlockList post_order_blocks;
16};
17
18} // namespace Shader::IR
diff --git a/src/shader_recompiler/frontend/ir/program.cpp b/src/shader_recompiler/frontend/ir/program.cpp
index 8c301c3a1..5f51aeb5f 100644
--- a/src/shader_recompiler/frontend/ir/program.cpp
+++ b/src/shader_recompiler/frontend/ir/program.cpp
@@ -9,7 +9,8 @@
9 9
10#include <fmt/format.h> 10#include <fmt/format.h>
11 11
12#include "shader_recompiler/frontend/ir/function.h" 12#include "shader_recompiler/frontend/ir/basic_block.h"
13#include "shader_recompiler/frontend/ir/microinstruction.h"
13#include "shader_recompiler/frontend/ir/program.h" 14#include "shader_recompiler/frontend/ir/program.h"
14 15
15namespace Shader::IR { 16namespace Shader::IR {
@@ -19,18 +20,13 @@ std::string DumpProgram(const Program& program) {
19 std::map<const IR::Inst*, size_t> inst_to_index; 20 std::map<const IR::Inst*, size_t> inst_to_index;
20 std::map<const IR::Block*, size_t> block_to_index; 21 std::map<const IR::Block*, size_t> block_to_index;
21 22
22 for (const IR::Function& function : program.functions) { 23 for (const IR::Block* const block : program.blocks) {
23 for (const IR::Block* const block : function.blocks) { 24 block_to_index.emplace(block, index);
24 block_to_index.emplace(block, index); 25 ++index;
25 ++index;
26 }
27 } 26 }
28 std::string ret; 27 std::string ret;
29 for (const IR::Function& function : program.functions) { 28 for (const auto& block : program.blocks) {
30 ret += fmt::format("Function\n"); 29 ret += IR::DumpBlock(*block, block_to_index, inst_to_index, index) + '\n';
31 for (const auto& block : function.blocks) {
32 ret += IR::DumpBlock(*block, block_to_index, inst_to_index, index) + '\n';
33 }
34 } 30 }
35 return ret; 31 return ret;
36} 32}
diff --git a/src/shader_recompiler/frontend/ir/program.h b/src/shader_recompiler/frontend/ir/program.h
index 98aab2dc6..bce8b19b3 100644
--- a/src/shader_recompiler/frontend/ir/program.h
+++ b/src/shader_recompiler/frontend/ir/program.h
@@ -8,13 +8,14 @@
8 8
9#include <boost/container/small_vector.hpp> 9#include <boost/container/small_vector.hpp>
10 10
11#include "shader_recompiler/frontend/ir/function.h" 11#include "shader_recompiler/frontend/ir/basic_block.h"
12#include "shader_recompiler/shader_info.h" 12#include "shader_recompiler/shader_info.h"
13 13
14namespace Shader::IR { 14namespace Shader::IR {
15 15
16struct Program { 16struct Program {
17 boost::container::small_vector<Function, 1> functions; 17 BlockList blocks;
18 BlockList post_order_blocks;
18 Info info; 19 Info info;
19}; 20};
20 21
diff --git a/src/shader_recompiler/frontend/ir/structured_control_flow.cpp b/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp
index bfba55a7e..5f5d9cf17 100644
--- a/src/shader_recompiler/frontend/ir/structured_control_flow.cpp
+++ b/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp
@@ -14,11 +14,14 @@
14 14
15#include <boost/intrusive/list.hpp> 15#include <boost/intrusive/list.hpp>
16 16
17#include "shader_recompiler/environment.h"
17#include "shader_recompiler/frontend/ir/basic_block.h" 18#include "shader_recompiler/frontend/ir/basic_block.h"
18#include "shader_recompiler/frontend/ir/ir_emitter.h" 19#include "shader_recompiler/frontend/ir/ir_emitter.h"
20#include "shader_recompiler/frontend/maxwell/structured_control_flow.h"
21#include "shader_recompiler/frontend/maxwell/translate/translate.h"
19#include "shader_recompiler/object_pool.h" 22#include "shader_recompiler/object_pool.h"
20 23
21namespace Shader::IR { 24namespace Shader::Maxwell {
22namespace { 25namespace {
23struct Statement; 26struct Statement;
24 27
@@ -79,7 +82,7 @@ struct Variable {};
79#pragma warning(disable : 26495) // Always initialize a member variable, expected in Statement 82#pragma warning(disable : 26495) // Always initialize a member variable, expected in Statement
80#endif 83#endif
81struct Statement : ListBaseHook { 84struct Statement : ListBaseHook {
82 Statement(Block* code_, Statement* up_) : code{code_}, up{up_}, type{StatementType::Code} {} 85 Statement(IR::Block* code_, Statement* up_) : code{code_}, up{up_}, type{StatementType::Code} {}
83 Statement(Goto, Statement* cond_, Node label_, Statement* up_) 86 Statement(Goto, Statement* cond_, Node label_, Statement* up_)
84 : label{label_}, cond{cond_}, up{up_}, type{StatementType::Goto} {} 87 : label{label_}, cond{cond_}, up{up_}, type{StatementType::Goto} {}
85 Statement(Label, u32 id_, Statement* up_) : id{id_}, up{up_}, type{StatementType::Label} {} 88 Statement(Label, u32 id_, Statement* up_) : id{id_}, up{up_}, type{StatementType::Label} {}
@@ -91,7 +94,7 @@ struct Statement : ListBaseHook {
91 : cond{cond_}, up{up_}, type{StatementType::Break} {} 94 : cond{cond_}, up{up_}, type{StatementType::Break} {}
92 Statement(Return) : type{StatementType::Return} {} 95 Statement(Return) : type{StatementType::Return} {}
93 Statement(FunctionTag) : children{}, type{StatementType::Function} {} 96 Statement(FunctionTag) : children{}, type{StatementType::Function} {}
94 Statement(Identity, Condition cond_) : guest_cond{cond_}, type{StatementType::Identity} {} 97 Statement(Identity, IR::Condition cond_) : guest_cond{cond_}, type{StatementType::Identity} {}
95 Statement(Not, Statement* op_) : op{op_}, type{StatementType::Not} {} 98 Statement(Not, Statement* op_) : op{op_}, type{StatementType::Not} {}
96 Statement(Or, Statement* op_a_, Statement* op_b_) 99 Statement(Or, Statement* op_a_, Statement* op_b_)
97 : op_a{op_a_}, op_b{op_b_}, type{StatementType::Or} {} 100 : op_a{op_a_}, op_b{op_b_}, type{StatementType::Or} {}
@@ -106,10 +109,10 @@ struct Statement : ListBaseHook {
106 } 109 }
107 110
108 union { 111 union {
109 Block* code; 112 IR::Block* code;
110 Node label; 113 Node label;
111 Tree children; 114 Tree children;
112 Condition guest_cond; 115 IR::Condition guest_cond;
113 Statement* op; 116 Statement* op;
114 Statement* op_a; 117 Statement* op_a;
115 }; 118 };
@@ -269,9 +272,10 @@ bool SearchNode(const Tree& tree, ConstNode stmt, size_t& offset) {
269 272
270class GotoPass { 273class GotoPass {
271public: 274public:
272 explicit GotoPass(std::span<Block* const> blocks, ObjectPool<Statement>& stmt_pool) 275 explicit GotoPass(Flow::CFG& cfg, ObjectPool<IR::Inst>& inst_pool_,
273 : pool{stmt_pool} { 276 ObjectPool<IR::Block>& block_pool_, ObjectPool<Statement>& stmt_pool)
274 std::vector gotos{BuildUnorderedTreeGetGotos(blocks)}; 277 : inst_pool{inst_pool_}, block_pool{block_pool_}, pool{stmt_pool} {
278 std::vector gotos{BuildTree(cfg)};
275 for (const Node& goto_stmt : gotos | std::views::reverse) { 279 for (const Node& goto_stmt : gotos | std::views::reverse) {
276 RemoveGoto(goto_stmt); 280 RemoveGoto(goto_stmt);
277 } 281 }
@@ -316,18 +320,20 @@ private:
316 } 320 }
317 } 321 }
318 // TODO: Remove this 322 // TODO: Remove this
319 Node it{goto_stmt}; 323 {
320 bool sibling{false}; 324 Node it{goto_stmt};
321 do { 325 bool sibling{false};
322 sibling |= it == label_stmt; 326 do {
323 --it; 327 sibling |= it == label_stmt;
324 } while (it != goto_stmt->up->children.begin()); 328 --it;
325 while (it != goto_stmt->up->children.end()) { 329 } while (it != goto_stmt->up->children.begin());
326 sibling |= it == label_stmt; 330 while (it != goto_stmt->up->children.end()) {
327 ++it; 331 sibling |= it == label_stmt;
328 } 332 ++it;
329 if (!sibling) { 333 }
330 throw LogicError("Not siblings"); 334 if (!sibling) {
335 throw LogicError("Not siblings");
336 }
331 } 337 }
332 // goto_stmt and label_stmt are guaranteed to be siblings, eliminate 338 // goto_stmt and label_stmt are guaranteed to be siblings, eliminate
333 if (std::next(goto_stmt) == label_stmt) { 339 if (std::next(goto_stmt) == label_stmt) {
@@ -342,63 +348,84 @@ private:
342 } 348 }
343 } 349 }
344 350
345 std::vector<Node> BuildUnorderedTreeGetGotos(std::span<Block* const> blocks) { 351 std::vector<Node> BuildTree(Flow::CFG& cfg) {
346 // Assume all blocks have two branches 352 u32 label_id{0};
347 std::vector<Node> gotos; 353 std::vector<Node> gotos;
348 gotos.reserve(blocks.size() * 2); 354 Flow::Function& first_function{cfg.Functions().front()};
349 355 BuildTree(cfg, first_function, label_id, gotos, root_stmt.children.end(), std::nullopt);
350 const std::unordered_map labels_map{BuildLabels(blocks)};
351 Tree& root{root_stmt.children};
352 auto insert_point{root.begin()};
353 // Skip all goto variables zero-initialization
354 std::advance(insert_point, labels_map.size());
355
356 for (Block* const block : blocks) {
357 // Skip label
358 ++insert_point;
359 // Skip set variable
360 ++insert_point;
361 root.insert(insert_point, *pool.Create(block, &root_stmt));
362
363 if (block->IsTerminationBlock()) {
364 root.insert(insert_point, *pool.Create(Return{}));
365 continue;
366 }
367 const Condition cond{block->BranchCondition()};
368 Statement* const true_cond{pool.Create(Identity{}, Condition{true})};
369 if (cond == Condition{true} || cond == Condition{false}) {
370 const bool is_true{cond == Condition{true}};
371 const Block* const branch{is_true ? block->TrueBranch() : block->FalseBranch()};
372 const Node label{labels_map.at(branch)};
373 Statement* const goto_stmt{pool.Create(Goto{}, true_cond, label, &root_stmt)};
374 gotos.push_back(root.insert(insert_point, *goto_stmt));
375 } else {
376 Statement* const ident_cond{pool.Create(Identity{}, cond)};
377 const Node true_label{labels_map.at(block->TrueBranch())};
378 const Node false_label{labels_map.at(block->FalseBranch())};
379 Statement* goto_true{pool.Create(Goto{}, ident_cond, true_label, &root_stmt)};
380 Statement* goto_false{pool.Create(Goto{}, true_cond, false_label, &root_stmt)};
381 gotos.push_back(root.insert(insert_point, *goto_true));
382 gotos.push_back(root.insert(insert_point, *goto_false));
383 }
384 }
385 return gotos; 356 return gotos;
386 } 357 }
387 358
388 std::unordered_map<const Block*, Node> BuildLabels(std::span<Block* const> blocks) { 359 void BuildTree(Flow::CFG& cfg, Flow::Function& function, u32& label_id,
389 // TODO: Consider storing labels intrusively inside the block 360 std::vector<Node>& gotos, Node function_insert_point,
390 std::unordered_map<const Block*, Node> labels_map; 361 std::optional<Node> return_label) {
362 Statement* const false_stmt{pool.Create(Identity{}, IR::Condition{false})};
391 Tree& root{root_stmt.children}; 363 Tree& root{root_stmt.children};
392 u32 label_id{0}; 364 std::unordered_map<Flow::Block*, Node> local_labels;
393 for (const Block* const block : blocks) { 365 local_labels.reserve(function.blocks.size());
366
367 for (Flow::Block& block : function.blocks) {
394 Statement* const label{pool.Create(Label{}, label_id, &root_stmt)}; 368 Statement* const label{pool.Create(Label{}, label_id, &root_stmt)};
395 labels_map.emplace(block, root.insert(root.end(), *label)); 369 const Node label_it{root.insert(function_insert_point, *label)};
396 Statement* const false_stmt{pool.Create(Identity{}, Condition{false})}; 370 local_labels.emplace(&block, label_it);
397 root.push_back(*pool.Create(SetVariable{}, label_id, false_stmt, &root_stmt));
398 root.push_front(*pool.Create(SetVariable{}, label_id, false_stmt, &root_stmt));
399 ++label_id; 371 ++label_id;
400 } 372 }
401 return labels_map; 373 for (Flow::Block& block : function.blocks) {
374 const Node label{local_labels.at(&block)};
375 // Insertion point
376 const Node ip{std::next(label)};
377
378 // Reset goto variables before the first block and after its respective label
379 const auto make_reset_variable{[&]() -> Statement& {
380 return *pool.Create(SetVariable{}, label->id, false_stmt, &root_stmt);
381 }};
382 root.push_front(make_reset_variable());
383 root.insert(ip, make_reset_variable());
384
385 const u32 begin_offset{block.begin.Offset()};
386 const u32 end_offset{block.end.Offset()};
387 IR::Block* const ir_block{block_pool.Create(inst_pool, begin_offset, end_offset)};
388 root.insert(ip, *pool.Create(ir_block, &root_stmt));
389
390 switch (block.end_class) {
391 case Flow::EndClass::Branch: {
392 Statement* const always_cond{pool.Create(Identity{}, IR::Condition{true})};
393 if (block.cond == IR::Condition{true}) {
394 const Node true_label{local_labels.at(block.branch_true)};
395 gotos.push_back(
396 root.insert(ip, *pool.Create(Goto{}, always_cond, true_label, &root_stmt)));
397 } else if (block.cond == IR::Condition{false}) {
398 const Node false_label{local_labels.at(block.branch_false)};
399 gotos.push_back(root.insert(
400 ip, *pool.Create(Goto{}, always_cond, false_label, &root_stmt)));
401 } else {
402 const Node true_label{local_labels.at(block.branch_true)};
403 const Node false_label{local_labels.at(block.branch_false)};
404 Statement* const true_cond{pool.Create(Identity{}, block.cond)};
405 gotos.push_back(
406 root.insert(ip, *pool.Create(Goto{}, true_cond, true_label, &root_stmt)));
407 gotos.push_back(root.insert(
408 ip, *pool.Create(Goto{}, always_cond, false_label, &root_stmt)));
409 }
410 break;
411 }
412 case Flow::EndClass::Call: {
413 Flow::Function& call{cfg.Functions()[block.function_call]};
414 const Node call_return_label{local_labels.at(block.return_block)};
415 BuildTree(cfg, call, label_id, gotos, ip, call_return_label);
416 break;
417 }
418 case Flow::EndClass::Exit:
419 root.insert(ip, *pool.Create(Return{}));
420 break;
421 case Flow::EndClass::Return: {
422 Statement* const always_cond{pool.Create(Identity{}, block.cond)};
423 auto goto_stmt{pool.Create(Goto{}, always_cond, return_label.value(), &root_stmt)};
424 gotos.push_back(root.insert(ip, *goto_stmt));
425 break;
426 }
427 }
428 }
402 } 429 }
403 430
404 void UpdateTreeUp(Statement* tree) { 431 void UpdateTreeUp(Statement* tree) {
@@ -556,11 +583,13 @@ private:
556 return offset; 583 return offset;
557 } 584 }
558 585
586 ObjectPool<IR::Inst>& inst_pool;
587 ObjectPool<IR::Block>& block_pool;
559 ObjectPool<Statement>& pool; 588 ObjectPool<Statement>& pool;
560 Statement root_stmt{FunctionTag{}}; 589 Statement root_stmt{FunctionTag{}};
561}; 590};
562 591
563Block* TryFindForwardBlock(const Statement& stmt) { 592IR::Block* TryFindForwardBlock(const Statement& stmt) {
564 const Tree& tree{stmt.up->children}; 593 const Tree& tree{stmt.up->children};
565 const ConstNode end{tree.cend()}; 594 const ConstNode end{tree.cend()};
566 ConstNode forward_node{std::next(Tree::s_iterator_to(stmt))}; 595 ConstNode forward_node{std::next(Tree::s_iterator_to(stmt))};
@@ -573,12 +602,12 @@ Block* TryFindForwardBlock(const Statement& stmt) {
573 return nullptr; 602 return nullptr;
574} 603}
575 604
576[[nodiscard]] U1 VisitExpr(IREmitter& ir, const Statement& stmt) { 605[[nodiscard]] IR::U1 VisitExpr(IR::IREmitter& ir, const Statement& stmt) {
577 switch (stmt.type) { 606 switch (stmt.type) {
578 case StatementType::Identity: 607 case StatementType::Identity:
579 return ir.Condition(stmt.guest_cond); 608 return ir.Condition(stmt.guest_cond);
580 case StatementType::Not: 609 case StatementType::Not:
581 return ir.LogicalNot(U1{VisitExpr(ir, *stmt.op)}); 610 return ir.LogicalNot(IR::U1{VisitExpr(ir, *stmt.op)});
582 case StatementType::Or: 611 case StatementType::Or:
583 return ir.LogicalOr(VisitExpr(ir, *stmt.op_a), VisitExpr(ir, *stmt.op_b)); 612 return ir.LogicalOr(VisitExpr(ir, *stmt.op_a), VisitExpr(ir, *stmt.op_b));
584 case StatementType::Variable: 613 case StatementType::Variable:
@@ -590,18 +619,18 @@ Block* TryFindForwardBlock(const Statement& stmt) {
590 619
591class TranslatePass { 620class TranslatePass {
592public: 621public:
593 TranslatePass(ObjectPool<Inst>& inst_pool_, ObjectPool<Block>& block_pool_, 622 TranslatePass(ObjectPool<IR::Inst>& inst_pool_, ObjectPool<IR::Block>& block_pool_,
594 ObjectPool<Statement>& stmt_pool_, Statement& root_stmt, 623 ObjectPool<Statement>& stmt_pool_, Environment& env_, Statement& root_stmt,
595 const std::function<void(IR::Block*)>& func_, BlockList& block_list_) 624 IR::BlockList& block_list_)
596 : stmt_pool{stmt_pool_}, inst_pool{inst_pool_}, block_pool{block_pool_}, func{func_}, 625 : stmt_pool{stmt_pool_}, inst_pool{inst_pool_}, block_pool{block_pool_}, env{env_},
597 block_list{block_list_} { 626 block_list{block_list_} {
598 Visit(root_stmt, nullptr, nullptr); 627 Visit(root_stmt, nullptr, nullptr);
599 } 628 }
600 629
601private: 630private:
602 void Visit(Statement& parent, Block* continue_block, Block* break_block) { 631 void Visit(Statement& parent, IR::Block* continue_block, IR::Block* break_block) {
603 Tree& tree{parent.children}; 632 Tree& tree{parent.children};
604 Block* current_block{nullptr}; 633 IR::Block* current_block{nullptr};
605 634
606 for (auto it = tree.begin(); it != tree.end(); ++it) { 635 for (auto it = tree.begin(); it != tree.end(); ++it) {
607 Statement& stmt{*it}; 636 Statement& stmt{*it};
@@ -611,11 +640,10 @@ private:
611 break; 640 break;
612 case StatementType::Code: { 641 case StatementType::Code: {
613 if (current_block && current_block != stmt.code) { 642 if (current_block && current_block != stmt.code) {
614 IREmitter ir{*current_block}; 643 IR::IREmitter{*current_block}.Branch(stmt.code);
615 ir.Branch(stmt.code);
616 } 644 }
617 current_block = stmt.code; 645 current_block = stmt.code;
618 func(stmt.code); 646 Translate(env, stmt.code);
619 block_list.push_back(stmt.code); 647 block_list.push_back(stmt.code);
620 break; 648 break;
621 } 649 }
@@ -623,7 +651,7 @@ private:
623 if (!current_block) { 651 if (!current_block) {
624 current_block = MergeBlock(parent, stmt); 652 current_block = MergeBlock(parent, stmt);
625 } 653 }
626 IREmitter ir{*current_block}; 654 IR::IREmitter ir{*current_block};
627 ir.SetGotoVariable(stmt.id, VisitExpr(ir, *stmt.op)); 655 ir.SetGotoVariable(stmt.id, VisitExpr(ir, *stmt.op));
628 break; 656 break;
629 } 657 }
@@ -632,16 +660,16 @@ private:
632 current_block = block_pool.Create(inst_pool); 660 current_block = block_pool.Create(inst_pool);
633 block_list.push_back(current_block); 661 block_list.push_back(current_block);
634 } 662 }
635 Block* const merge_block{MergeBlock(parent, stmt)}; 663 IR::Block* const merge_block{MergeBlock(parent, stmt)};
636 664
637 // Visit children 665 // Visit children
638 const size_t first_block_index{block_list.size()}; 666 const size_t first_block_index{block_list.size()};
639 Visit(stmt, merge_block, break_block); 667 Visit(stmt, merge_block, break_block);
640 668
641 // Implement if header block 669 // Implement if header block
642 Block* const first_if_block{block_list.at(first_block_index)}; 670 IR::Block* const first_if_block{block_list.at(first_block_index)};
643 IREmitter ir{*current_block}; 671 IR::IREmitter ir{*current_block};
644 const U1 cond{VisitExpr(ir, *stmt.cond)}; 672 const IR::U1 cond{VisitExpr(ir, *stmt.cond)};
645 ir.SelectionMerge(merge_block); 673 ir.SelectionMerge(merge_block);
646 ir.BranchConditional(cond, first_if_block, merge_block); 674 ir.BranchConditional(cond, first_if_block, merge_block);
647 675
@@ -649,14 +677,14 @@ private:
649 break; 677 break;
650 } 678 }
651 case StatementType::Loop: { 679 case StatementType::Loop: {
652 Block* const loop_header_block{block_pool.Create(inst_pool)}; 680 IR::Block* const loop_header_block{block_pool.Create(inst_pool)};
653 if (current_block) { 681 if (current_block) {
654 IREmitter{*current_block}.Branch(loop_header_block); 682 IR::IREmitter{*current_block}.Branch(loop_header_block);
655 } 683 }
656 block_list.push_back(loop_header_block); 684 block_list.push_back(loop_header_block);
657 685
658 Block* const new_continue_block{block_pool.Create(inst_pool)}; 686 IR::Block* const new_continue_block{block_pool.Create(inst_pool)};
659 Block* const merge_block{MergeBlock(parent, stmt)}; 687 IR::Block* const merge_block{MergeBlock(parent, stmt)};
660 688
661 // Visit children 689 // Visit children
662 const size_t first_block_index{block_list.size()}; 690 const size_t first_block_index{block_list.size()};
@@ -666,14 +694,14 @@ private:
666 block_list.push_back(new_continue_block); 694 block_list.push_back(new_continue_block);
667 695
668 // Implement loop header block 696 // Implement loop header block
669 Block* const first_loop_block{block_list.at(first_block_index)}; 697 IR::Block* const first_loop_block{block_list.at(first_block_index)};
670 IREmitter ir{*loop_header_block}; 698 IR::IREmitter ir{*loop_header_block};
671 ir.LoopMerge(merge_block, new_continue_block); 699 ir.LoopMerge(merge_block, new_continue_block);
672 ir.Branch(first_loop_block); 700 ir.Branch(first_loop_block);
673 701
674 // Implement continue block 702 // Implement continue block
675 IREmitter continue_ir{*new_continue_block}; 703 IR::IREmitter continue_ir{*new_continue_block};
676 const U1 continue_cond{VisitExpr(continue_ir, *stmt.cond)}; 704 const IR::U1 continue_cond{VisitExpr(continue_ir, *stmt.cond)};
677 continue_ir.BranchConditional(continue_cond, ir.block, merge_block); 705 continue_ir.BranchConditional(continue_cond, ir.block, merge_block);
678 706
679 current_block = merge_block; 707 current_block = merge_block;
@@ -684,9 +712,9 @@ private:
684 current_block = block_pool.Create(inst_pool); 712 current_block = block_pool.Create(inst_pool);
685 block_list.push_back(current_block); 713 block_list.push_back(current_block);
686 } 714 }
687 Block* const skip_block{MergeBlock(parent, stmt)}; 715 IR::Block* const skip_block{MergeBlock(parent, stmt)};
688 716
689 IREmitter ir{*current_block}; 717 IR::IREmitter ir{*current_block};
690 ir.BranchConditional(VisitExpr(ir, *stmt.cond), break_block, skip_block); 718 ir.BranchConditional(VisitExpr(ir, *stmt.cond), break_block, skip_block);
691 719
692 current_block = skip_block; 720 current_block = skip_block;
@@ -697,7 +725,7 @@ private:
697 current_block = block_pool.Create(inst_pool); 725 current_block = block_pool.Create(inst_pool);
698 block_list.push_back(current_block); 726 block_list.push_back(current_block);
699 } 727 }
700 IREmitter{*current_block}.Return(); 728 IR::IREmitter{*current_block}.Return();
701 current_block = nullptr; 729 current_block = nullptr;
702 break; 730 break;
703 } 731 }
@@ -706,39 +734,37 @@ private:
706 } 734 }
707 } 735 }
708 if (current_block && continue_block) { 736 if (current_block && continue_block) {
709 IREmitter ir{*current_block}; 737 IR::IREmitter{*current_block}.Branch(continue_block);
710 ir.Branch(continue_block);
711 } 738 }
712 } 739 }
713 740
714 Block* MergeBlock(Statement& parent, Statement& stmt) { 741 IR::Block* MergeBlock(Statement& parent, Statement& stmt) {
715 if (Block* const block{TryFindForwardBlock(stmt)}) { 742 if (IR::Block* const block{TryFindForwardBlock(stmt)}) {
716 return block; 743 return block;
717 } 744 }
718 // Create a merge block we can visit later 745 // Create a merge block we can visit later
719 Block* const block{block_pool.Create(inst_pool)}; 746 IR::Block* const block{block_pool.Create(inst_pool)};
720 Statement* const merge_stmt{stmt_pool.Create(block, &parent)}; 747 Statement* const merge_stmt{stmt_pool.Create(block, &parent)};
721 parent.children.insert(std::next(Tree::s_iterator_to(stmt)), *merge_stmt); 748 parent.children.insert(std::next(Tree::s_iterator_to(stmt)), *merge_stmt);
722 return block; 749 return block;
723 } 750 }
724 751
725 ObjectPool<Statement>& stmt_pool; 752 ObjectPool<Statement>& stmt_pool;
726 ObjectPool<Inst>& inst_pool; 753 ObjectPool<IR::Inst>& inst_pool;
727 ObjectPool<Block>& block_pool; 754 ObjectPool<IR::Block>& block_pool;
728 const std::function<void(IR::Block*)>& func; 755 Environment& env;
729 BlockList& block_list; 756 IR::BlockList& block_list;
730}; 757};
731} // Anonymous namespace 758} // Anonymous namespace
732 759
733BlockList VisitAST(ObjectPool<Inst>& inst_pool, ObjectPool<Block>& block_pool, 760IR::BlockList VisitAST(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Block>& block_pool,
734 std::span<Block* const> unordered_blocks, 761 Environment& env, Flow::CFG& cfg) {
735 const std::function<void(Block*)>& func) {
736 ObjectPool<Statement> stmt_pool{64}; 762 ObjectPool<Statement> stmt_pool{64};
737 GotoPass goto_pass{unordered_blocks, stmt_pool}; 763 GotoPass goto_pass{cfg, inst_pool, block_pool, stmt_pool};
738 BlockList block_list; 764 Statement& root{goto_pass.RootStatement()};
739 TranslatePass translate_pass{inst_pool, block_pool, stmt_pool, goto_pass.RootStatement(), 765 IR::BlockList block_list;
740 func, block_list}; 766 TranslatePass{inst_pool, block_pool, stmt_pool, env, root, block_list};
741 return block_list; 767 return block_list;
742} 768}
743 769
744} // namespace Shader::IR 770} // namespace Shader::Maxwell
diff --git a/src/shader_recompiler/frontend/ir/structured_control_flow.h b/src/shader_recompiler/frontend/maxwell/structured_control_flow.h
index a574c24f7..e4797291e 100644
--- a/src/shader_recompiler/frontend/ir/structured_control_flow.h
+++ b/src/shader_recompiler/frontend/maxwell/structured_control_flow.h
@@ -9,14 +9,16 @@
9 9
10#include <boost/intrusive/list.hpp> 10#include <boost/intrusive/list.hpp>
11 11
12#include "shader_recompiler/environment.h"
12#include "shader_recompiler/frontend/ir/basic_block.h" 13#include "shader_recompiler/frontend/ir/basic_block.h"
13#include "shader_recompiler/frontend/ir/microinstruction.h" 14#include "shader_recompiler/frontend/ir/microinstruction.h"
15#include "shader_recompiler/frontend/maxwell/control_flow.h"
14#include "shader_recompiler/object_pool.h" 16#include "shader_recompiler/object_pool.h"
15 17
16namespace Shader::IR { 18namespace Shader::Maxwell {
17 19
18[[nodiscard]] BlockList VisitAST(ObjectPool<Inst>& inst_pool, ObjectPool<Block>& block_pool, 20[[nodiscard]] IR::BlockList VisitAST(ObjectPool<IR::Inst>& inst_pool,
19 std::span<Block* const> unordered_blocks, 21 ObjectPool<IR::Block>& block_pool, Environment& env,
20 const std::function<void(Block*)>& func); 22 Flow::CFG& cfg);
21 23
22} // namespace Shader::IR 24} // namespace Shader::Maxwell