summaryrefslogtreecommitdiff
path: root/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp')
-rw-r--r--src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp235
1 files changed, 136 insertions, 99 deletions
diff --git a/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp b/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp
index cc5410c6d..e7e2e9c82 100644
--- a/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp
+++ b/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp
@@ -36,7 +36,6 @@ using Tree = boost::intrusive::list<Statement,
36 // Avoid linear complexity on splice, size is never called 36 // Avoid linear complexity on splice, size is never called
37 boost::intrusive::constant_time_size<false>>; 37 boost::intrusive::constant_time_size<false>>;
38using Node = Tree::iterator; 38using Node = Tree::iterator;
39using ConstNode = Tree::const_iterator;
40 39
41enum class StatementType { 40enum class StatementType {
42 Code, 41 Code,
@@ -91,7 +90,8 @@ struct IndirectBranchCond {};
91#pragma warning(disable : 26495) // Always initialize a member variable, expected in Statement 90#pragma warning(disable : 26495) // Always initialize a member variable, expected in Statement
92#endif 91#endif
93struct Statement : ListBaseHook { 92struct Statement : ListBaseHook {
94 Statement(IR::Block* code_, Statement* up_) : code{code_}, up{up_}, type{StatementType::Code} {} 93 Statement(const Flow::Block* block_, Statement* up_)
94 : block{block_}, up{up_}, type{StatementType::Code} {}
95 Statement(Goto, Statement* cond_, Node label_, Statement* up_) 95 Statement(Goto, Statement* cond_, Node label_, Statement* up_)
96 : label{label_}, cond{cond_}, up{up_}, type{StatementType::Goto} {} 96 : label{label_}, cond{cond_}, up{up_}, type{StatementType::Goto} {}
97 Statement(Label, u32 id_, Statement* up_) : id{id_}, up{up_}, type{StatementType::Label} {} 97 Statement(Label, u32 id_, Statement* up_) : id{id_}, up{up_}, type{StatementType::Label} {}
@@ -125,7 +125,7 @@ struct Statement : ListBaseHook {
125 } 125 }
126 126
127 union { 127 union {
128 IR::Block* code; 128 const Flow::Block* block;
129 Node label; 129 Node label;
130 Tree children; 130 Tree children;
131 IR::Condition guest_cond; 131 IR::Condition guest_cond;
@@ -171,8 +171,8 @@ std::string DumpTree(const Tree& tree, u32 indentation = 0) {
171 switch (stmt->type) { 171 switch (stmt->type) {
172 case StatementType::Code: 172 case StatementType::Code:
173 ret += fmt::format("{} Block {:04x} -> {:04x} (0x{:016x});\n", indent, 173 ret += fmt::format("{} Block {:04x} -> {:04x} (0x{:016x});\n", indent,
174 stmt->code->LocationBegin(), stmt->code->LocationEnd(), 174 stmt->block->begin, stmt->block->end,
175 reinterpret_cast<uintptr_t>(stmt->code)); 175 reinterpret_cast<uintptr_t>(stmt->block));
176 break; 176 break;
177 case StatementType::Goto: 177 case StatementType::Goto:
178 ret += fmt::format("{} if ({}) goto L{};\n", indent, DumpExpr(stmt->cond), 178 ret += fmt::format("{} if ({}) goto L{};\n", indent, DumpExpr(stmt->cond),
@@ -407,11 +407,7 @@ private:
407 }}; 407 }};
408 root.push_front(make_reset_variable()); 408 root.push_front(make_reset_variable());
409 root.insert(ip, make_reset_variable()); 409 root.insert(ip, make_reset_variable());
410 410 root.insert(ip, *pool.Create(&block, &root_stmt));
411 const u32 begin_offset{block.begin.Offset()};
412 const u32 end_offset{block.end.Offset()};
413 IR::Block* const ir_block{block_pool.Create(inst_pool, begin_offset, end_offset)};
414 root.insert(ip, *pool.Create(ir_block, &root_stmt));
415 411
416 switch (block.end_class) { 412 switch (block.end_class) {
417 case Flow::EndClass::Branch: { 413 case Flow::EndClass::Branch: {
@@ -620,13 +616,13 @@ private:
620 Statement root_stmt{FunctionTag{}}; 616 Statement root_stmt{FunctionTag{}};
621}; 617};
622 618
623IR::Block* TryFindForwardBlock(const Statement& stmt) { 619[[nodiscard]] Statement* TryFindForwardBlock(Statement& stmt) {
624 const Tree& tree{stmt.up->children}; 620 Tree& tree{stmt.up->children};
625 const ConstNode end{tree.cend()}; 621 const Node end{tree.end()};
626 ConstNode forward_node{std::next(Tree::s_iterator_to(stmt))}; 622 Node forward_node{std::next(Tree::s_iterator_to(stmt))};
627 while (forward_node != end && !HasChildren(forward_node->type)) { 623 while (forward_node != end && !HasChildren(forward_node->type)) {
628 if (forward_node->type == StatementType::Code) { 624 if (forward_node->type == StatementType::Code) {
629 return forward_node->code; 625 return &*forward_node;
630 } 626 }
631 ++forward_node; 627 ++forward_node;
632 } 628 }
@@ -654,21 +650,29 @@ class TranslatePass {
654public: 650public:
655 TranslatePass(ObjectPool<IR::Inst>& inst_pool_, ObjectPool<IR::Block>& block_pool_, 651 TranslatePass(ObjectPool<IR::Inst>& inst_pool_, ObjectPool<IR::Block>& block_pool_,
656 ObjectPool<Statement>& stmt_pool_, Environment& env_, Statement& root_stmt, 652 ObjectPool<Statement>& stmt_pool_, Environment& env_, Statement& root_stmt,
657 IR::BlockList& block_list_) 653 IR::AbstractSyntaxList& syntax_list_)
658 : stmt_pool{stmt_pool_}, inst_pool{inst_pool_}, block_pool{block_pool_}, env{env_}, 654 : stmt_pool{stmt_pool_}, inst_pool{inst_pool_}, block_pool{block_pool_}, env{env_},
659 block_list{block_list_} { 655 syntax_list{syntax_list_} {
660 Visit(root_stmt, nullptr, nullptr); 656 Visit(root_stmt, nullptr, nullptr);
661 657
662 IR::Block& first_block{*block_list.front()}; 658 IR::Block& first_block{*syntax_list.front().block};
663 IR::IREmitter ir{first_block, first_block.begin()}; 659 IR::IREmitter ir{first_block, first_block.begin()};
664 ir.Prologue(); 660 ir.Prologue();
665 } 661 }
666 662
667private: 663private:
668 void Visit(Statement& parent, IR::Block* continue_block, IR::Block* break_block) { 664 void Visit(Statement& parent, IR::Block* break_block, IR::Block* fallthrough_block) {
665 IR::Block* current_block{};
666 const auto ensure_block{[&] {
667 if (current_block) {
668 return;
669 }
670 current_block = block_pool.Create(inst_pool);
671 auto& node{syntax_list.emplace_back()};
672 node.type = IR::AbstractSyntaxNode::Type::Block;
673 node.block = current_block;
674 }};
669 Tree& tree{parent.children}; 675 Tree& tree{parent.children};
670 IR::Block* current_block{nullptr};
671
672 for (auto it = tree.begin(); it != tree.end(); ++it) { 676 for (auto it = tree.begin(); it != tree.end(); ++it) {
673 Statement& stmt{*it}; 677 Statement& stmt{*it};
674 switch (stmt.type) { 678 switch (stmt.type) {
@@ -676,124 +680,157 @@ private:
676 // Labels can be ignored 680 // Labels can be ignored
677 break; 681 break;
678 case StatementType::Code: { 682 case StatementType::Code: {
679 if (current_block && current_block != stmt.code) { 683 ensure_block();
680 IR::IREmitter{*current_block}.Branch(stmt.code); 684 Translate(env, current_block, stmt.block->begin.Offset(), stmt.block->end.Offset());
681 }
682 current_block = stmt.code;
683 Translate(env, stmt.code);
684 block_list.push_back(stmt.code);
685 break; 685 break;
686 } 686 }
687 case StatementType::SetVariable: { 687 case StatementType::SetVariable: {
688 if (!current_block) { 688 ensure_block();
689 current_block = MergeBlock(parent, stmt);
690 }
691 IR::IREmitter ir{*current_block}; 689 IR::IREmitter ir{*current_block};
692 ir.SetGotoVariable(stmt.id, VisitExpr(ir, *stmt.op)); 690 ir.SetGotoVariable(stmt.id, VisitExpr(ir, *stmt.op));
693 break; 691 break;
694 } 692 }
695 case StatementType::SetIndirectBranchVariable: { 693 case StatementType::SetIndirectBranchVariable: {
696 if (!current_block) { 694 ensure_block();
697 current_block = MergeBlock(parent, stmt);
698 }
699 IR::IREmitter ir{*current_block}; 695 IR::IREmitter ir{*current_block};
700 IR::U32 address{ir.IAdd(ir.GetReg(stmt.branch_reg), ir.Imm32(stmt.branch_offset))}; 696 IR::U32 address{ir.IAdd(ir.GetReg(stmt.branch_reg), ir.Imm32(stmt.branch_offset))};
701 ir.SetIndirectBranchVariable(address); 697 ir.SetIndirectBranchVariable(address);
702 break; 698 break;
703 } 699 }
704 case StatementType::If: { 700 case StatementType::If: {
705 if (!current_block) { 701 ensure_block();
706 current_block = block_pool.Create(inst_pool);
707 block_list.push_back(current_block);
708 }
709 IR::Block* const merge_block{MergeBlock(parent, stmt)}; 702 IR::Block* const merge_block{MergeBlock(parent, stmt)};
710 703
711 // Visit children
712 const size_t first_block_index{block_list.size()};
713 Visit(stmt, merge_block, break_block);
714
715 // Implement if header block 704 // Implement if header block
716 IR::Block* const first_if_block{block_list.at(first_block_index)};
717 IR::IREmitter ir{*current_block}; 705 IR::IREmitter ir{*current_block};
718 const IR::U1 cond{VisitExpr(ir, *stmt.cond)}; 706 const IR::U1 cond{VisitExpr(ir, *stmt.cond)};
719 ir.SelectionMerge(merge_block); 707 ir.BranchConditionRef(cond);
720 ir.BranchConditional(cond, first_if_block, merge_block);
721 708
709 const size_t if_node_index{syntax_list.size()};
710 syntax_list.emplace_back();
711
712 // Visit children
713 const size_t then_block_index{syntax_list.size()};
714 Visit(stmt, break_block, merge_block);
715
716 IR::Block* const then_block{syntax_list.at(then_block_index).block};
717 current_block->AddBranch(then_block);
718 current_block->AddBranch(merge_block);
722 current_block = merge_block; 719 current_block = merge_block;
720
721 auto& if_node{syntax_list[if_node_index]};
722 if_node.type = IR::AbstractSyntaxNode::Type::If;
723 if_node.if_node.cond = cond;
724 if_node.if_node.body = then_block;
725 if_node.if_node.merge = merge_block;
726
727 auto& endif_node{syntax_list.emplace_back()};
728 endif_node.type = IR::AbstractSyntaxNode::Type::EndIf;
729 endif_node.end_if.merge = merge_block;
730
731 auto& merge{syntax_list.emplace_back()};
732 merge.type = IR::AbstractSyntaxNode::Type::Block;
733 merge.block = merge_block;
723 break; 734 break;
724 } 735 }
725 case StatementType::Loop: { 736 case StatementType::Loop: {
726 IR::Block* const loop_header_block{block_pool.Create(inst_pool)}; 737 IR::Block* const loop_header_block{block_pool.Create(inst_pool)};
727 if (current_block) { 738 if (current_block) {
728 IR::IREmitter{*current_block}.Branch(loop_header_block); 739 current_block->AddBranch(loop_header_block);
729 } 740 }
730 block_list.push_back(loop_header_block); 741 auto& header_node{syntax_list.emplace_back()};
742 header_node.type = IR::AbstractSyntaxNode::Type::Block;
743 header_node.block = loop_header_block;
731 744
732 IR::Block* const new_continue_block{block_pool.Create(inst_pool)}; 745 IR::Block* const continue_block{block_pool.Create(inst_pool)};
733 IR::Block* const merge_block{MergeBlock(parent, stmt)}; 746 IR::Block* const merge_block{MergeBlock(parent, stmt)};
734 747
748 const size_t loop_node_index{syntax_list.size()};
749 syntax_list.emplace_back();
750
735 // Visit children 751 // Visit children
736 const size_t first_block_index{block_list.size()}; 752 const size_t body_block_index{syntax_list.size()};
737 Visit(stmt, new_continue_block, merge_block); 753 Visit(stmt, merge_block, continue_block);
738 754
739 // The continue block is located at the end of the loop 755 // The continue block is located at the end of the loop
740 block_list.push_back(new_continue_block); 756 IR::IREmitter ir{*continue_block};
757 const IR::U1 cond{VisitExpr(ir, *stmt.cond)};
758 ir.BranchConditionRef(cond);
741 759
742 // Implement loop header block 760 IR::Block* const body_block{syntax_list.at(body_block_index).block};
743 IR::Block* const first_loop_block{block_list.at(first_block_index)}; 761 loop_header_block->AddBranch(body_block);
744 IR::IREmitter ir{*loop_header_block};
745 ir.LoopMerge(merge_block, new_continue_block);
746 ir.Branch(first_loop_block);
747 762
748 // Implement continue block 763 continue_block->AddBranch(loop_header_block);
749 IR::IREmitter continue_ir{*new_continue_block}; 764 continue_block->AddBranch(merge_block);
750 const IR::U1 continue_cond{VisitExpr(continue_ir, *stmt.cond)};
751 continue_ir.BranchConditional(continue_cond, ir.block, merge_block);
752 765
753 current_block = merge_block; 766 current_block = merge_block;
767
768 auto& loop{syntax_list[loop_node_index]};
769 loop.type = IR::AbstractSyntaxNode::Type::Loop;
770 loop.loop.body = body_block;
771 loop.loop.continue_block = continue_block;
772 loop.loop.merge = merge_block;
773
774 auto& continue_block_node{syntax_list.emplace_back()};
775 continue_block_node.type = IR::AbstractSyntaxNode::Type::Block;
776 continue_block_node.block = continue_block;
777
778 auto& repeat{syntax_list.emplace_back()};
779 repeat.type = IR::AbstractSyntaxNode::Type::Repeat;
780 repeat.repeat.cond = cond;
781 repeat.repeat.loop_header = loop_header_block;
782 repeat.repeat.merge = merge_block;
783
784 auto& merge{syntax_list.emplace_back()};
785 merge.type = IR::AbstractSyntaxNode::Type::Block;
786 merge.block = merge_block;
754 break; 787 break;
755 } 788 }
756 case StatementType::Break: { 789 case StatementType::Break: {
757 if (!current_block) { 790 ensure_block();
758 current_block = block_pool.Create(inst_pool);
759 block_list.push_back(current_block);
760 }
761 IR::Block* const skip_block{MergeBlock(parent, stmt)}; 791 IR::Block* const skip_block{MergeBlock(parent, stmt)};
762 792
763 IR::IREmitter ir{*current_block}; 793 IR::IREmitter ir{*current_block};
764 ir.BranchConditional(VisitExpr(ir, *stmt.cond), break_block, skip_block); 794 const IR::U1 cond{VisitExpr(ir, *stmt.cond)};
765 795 ir.BranchConditionRef(cond);
796 current_block->AddBranch(break_block);
797 current_block->AddBranch(skip_block);
766 current_block = skip_block; 798 current_block = skip_block;
799
800 auto& break_node{syntax_list.emplace_back()};
801 break_node.type = IR::AbstractSyntaxNode::Type::Break;
802 break_node.break_node.cond = cond;
803 break_node.break_node.merge = break_block;
804 break_node.break_node.skip = skip_block;
805
806 auto& merge{syntax_list.emplace_back()};
807 merge.type = IR::AbstractSyntaxNode::Type::Block;
808 merge.block = skip_block;
767 break; 809 break;
768 } 810 }
769 case StatementType::Return: { 811 case StatementType::Return: {
770 if (!current_block) { 812 ensure_block();
771 current_block = block_pool.Create(inst_pool); 813 IR::IREmitter{*current_block}.Epilogue();
772 block_list.push_back(current_block);
773 }
774 IR::IREmitter ir{*current_block};
775 ir.Epilogue();
776 ir.Return();
777 current_block = nullptr; 814 current_block = nullptr;
815 syntax_list.emplace_back().type = IR::AbstractSyntaxNode::Type::Return;
778 break; 816 break;
779 } 817 }
780 case StatementType::Kill: { 818 case StatementType::Kill: {
781 if (!current_block) { 819 ensure_block();
782 current_block = block_pool.Create(inst_pool);
783 block_list.push_back(current_block);
784 }
785 IR::Block* demote_block{MergeBlock(parent, stmt)}; 820 IR::Block* demote_block{MergeBlock(parent, stmt)};
786 IR::IREmitter{*current_block}.DemoteToHelperInvocation(demote_block); 821 IR::IREmitter{*current_block}.DemoteToHelperInvocation();
822 current_block->AddBranch(demote_block);
787 current_block = demote_block; 823 current_block = demote_block;
824
825 auto& merge{syntax_list.emplace_back()};
826 merge.type = IR::AbstractSyntaxNode::Type::Block;
827 merge.block = demote_block;
788 break; 828 break;
789 } 829 }
790 case StatementType::Unreachable: { 830 case StatementType::Unreachable: {
791 if (!current_block) { 831 ensure_block();
792 current_block = block_pool.Create(inst_pool);
793 block_list.push_back(current_block);
794 }
795 IR::IREmitter{*current_block}.Unreachable();
796 current_block = nullptr; 832 current_block = nullptr;
833 syntax_list.emplace_back().type = IR::AbstractSyntaxNode::Type::Unreachable;
797 break; 834 break;
798 } 835 }
799 default: 836 default:
@@ -801,42 +838,42 @@ private:
801 } 838 }
802 } 839 }
803 if (current_block) { 840 if (current_block) {
804 IR::IREmitter ir{*current_block}; 841 if (fallthrough_block) {
805 if (continue_block) { 842 current_block->AddBranch(fallthrough_block);
806 ir.Branch(continue_block);
807 } else { 843 } else {
808 ir.Unreachable(); 844 syntax_list.emplace_back().type = IR::AbstractSyntaxNode::Type::Unreachable;
809 } 845 }
810 } 846 }
811 } 847 }
812 848
813 IR::Block* MergeBlock(Statement& parent, Statement& stmt) { 849 IR::Block* MergeBlock(Statement& parent, Statement& stmt) {
814 if (IR::Block* const block{TryFindForwardBlock(stmt)}) { 850 Statement* merge_stmt{TryFindForwardBlock(stmt)};
815 return block; 851 if (!merge_stmt) {
852 // Create a merge block we can visit later
853 merge_stmt = stmt_pool.Create(&dummy_flow_block, &parent);
854 parent.children.insert(std::next(Tree::s_iterator_to(stmt)), *merge_stmt);
816 } 855 }
817 // Create a merge block we can visit later 856 return block_pool.Create(inst_pool);
818 IR::Block* const block{block_pool.Create(inst_pool)};
819 Statement* const merge_stmt{stmt_pool.Create(block, &parent)};
820 parent.children.insert(std::next(Tree::s_iterator_to(stmt)), *merge_stmt);
821 return block;
822 } 857 }
823 858
824 ObjectPool<Statement>& stmt_pool; 859 ObjectPool<Statement>& stmt_pool;
825 ObjectPool<IR::Inst>& inst_pool; 860 ObjectPool<IR::Inst>& inst_pool;
826 ObjectPool<IR::Block>& block_pool; 861 ObjectPool<IR::Block>& block_pool;
827 Environment& env; 862 Environment& env;
828 IR::BlockList& block_list; 863 IR::AbstractSyntaxList& syntax_list;
864 // TODO: Make this constexpr when std::vector is constexpr
865 const Flow::Block dummy_flow_block;
829}; 866};
830} // Anonymous namespace 867} // Anonymous namespace
831 868
832IR::BlockList VisitAST(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Block>& block_pool, 869IR::AbstractSyntaxList BuildASL(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Block>& block_pool,
833 Environment& env, Flow::CFG& cfg) { 870 Environment& env, Flow::CFG& cfg) {
834 ObjectPool<Statement> stmt_pool{64}; 871 ObjectPool<Statement> stmt_pool{64};
835 GotoPass goto_pass{cfg, inst_pool, block_pool, stmt_pool}; 872 GotoPass goto_pass{cfg, inst_pool, block_pool, stmt_pool};
836 Statement& root{goto_pass.RootStatement()}; 873 Statement& root{goto_pass.RootStatement()};
837 IR::BlockList block_list; 874 IR::AbstractSyntaxList syntax_list;
838 TranslatePass{inst_pool, block_pool, stmt_pool, env, root, block_list}; 875 TranslatePass{inst_pool, block_pool, stmt_pool, env, root, syntax_list};
839 return block_list; 876 return syntax_list;
840} 877}
841 878
842} // namespace Shader::Maxwell 879} // namespace Shader::Maxwell