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.cpp108
1 files changed, 107 insertions, 1 deletions
diff --git a/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp b/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp
index 8b3e0a15c..f124dc8c0 100644
--- a/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp
+++ b/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp
@@ -660,6 +660,9 @@ public:
660 IR::Block& first_block{*syntax_list.front().data.block}; 660 IR::Block& first_block{*syntax_list.front().data.block};
661 IR::IREmitter ir(first_block, first_block.begin()); 661 IR::IREmitter ir(first_block, first_block.begin());
662 ir.Prologue(); 662 ir.Prologue();
663 if (uses_demote_to_helper) {
664 DemoteCombinationPass();
665 }
663 } 666 }
664 667
665private: 668private:
@@ -809,7 +812,14 @@ private:
809 } 812 }
810 case StatementType::Return: { 813 case StatementType::Return: {
811 ensure_block(); 814 ensure_block();
812 IR::IREmitter{*current_block}.Epilogue(); 815 IR::Block* return_block{block_pool.Create(inst_pool)};
816 IR::IREmitter{*return_block}.Epilogue();
817 current_block->AddBranch(return_block);
818
819 auto& merge{syntax_list.emplace_back()};
820 merge.type = IR::AbstractSyntaxNode::Type::Block;
821 merge.data.block = return_block;
822
813 current_block = nullptr; 823 current_block = nullptr;
814 syntax_list.emplace_back().type = IR::AbstractSyntaxNode::Type::Return; 824 syntax_list.emplace_back().type = IR::AbstractSyntaxNode::Type::Return;
815 break; 825 break;
@@ -824,6 +834,7 @@ private:
824 auto& merge{syntax_list.emplace_back()}; 834 auto& merge{syntax_list.emplace_back()};
825 merge.type = IR::AbstractSyntaxNode::Type::Block; 835 merge.type = IR::AbstractSyntaxNode::Type::Block;
826 merge.data.block = demote_block; 836 merge.data.block = demote_block;
837 uses_demote_to_helper = true;
827 break; 838 break;
828 } 839 }
829 case StatementType::Unreachable: { 840 case StatementType::Unreachable: {
@@ -855,11 +866,106 @@ private:
855 return block_pool.Create(inst_pool); 866 return block_pool.Create(inst_pool);
856 } 867 }
857 868
869 void DemoteCombinationPass() {
870 using Type = IR::AbstractSyntaxNode::Type;
871 std::vector<IR::Block*> demote_blocks;
872 std::vector<IR::U1> demote_conds;
873 u32 num_epilogues{};
874 for (const IR::AbstractSyntaxNode& node : syntax_list) {
875 if (node.type != Type::Block) {
876 continue;
877 }
878 for (const IR::Inst& inst : node.data.block->Instructions()) {
879 const IR::Opcode op{inst.GetOpcode()};
880 if (op == IR::Opcode::DemoteToHelperInvocation) {
881 demote_blocks.push_back(node.data.block);
882 break;
883 }
884 if (op == IR::Opcode::Epilogue) {
885 ++num_epilogues;
886 }
887 }
888 }
889 if (demote_blocks.size() == 0) {
890 return;
891 }
892 if (num_epilogues > 1) {
893 LOG_DEBUG(Shader, "Combining demotes with more than one return is not implemented.");
894 return;
895 }
896 s64 last_iterator_offset{};
897 auto& asl{syntax_list};
898 for (const IR::Block* demote_block : demote_blocks) {
899 const auto start_it{asl.begin() + last_iterator_offset};
900 auto asl_it{std::find_if(start_it, asl.end(), [&](const IR::AbstractSyntaxNode& asn) {
901 return asn.type == Type::If && asn.data.if_node.body == demote_block;
902 })};
903 if (asl_it == asl.end()) {
904 // Demote without a conditional branch.
905 // No need to proceed since all fragment instances will be demoted regardless.
906 return;
907 }
908 const IR::Block* const end_if = asl_it->data.if_node.merge;
909 demote_conds.push_back(asl_it->data.if_node.cond);
910 last_iterator_offset = std::distance(asl.begin(), asl_it);
911
912 asl_it = asl.erase(asl_it);
913 asl_it = std::find_if(asl_it, asl.end(), [&](const IR::AbstractSyntaxNode& asn) {
914 return asn.type == Type::Block && asn.data.block == demote_block;
915 });
916
917 asl_it = asl.erase(asl_it);
918 asl_it = std::find_if(asl_it, asl.end(), [&](const IR::AbstractSyntaxNode& asn) {
919 return asn.type == Type::EndIf && asn.data.end_if.merge == end_if;
920 });
921 asl_it = asl.erase(asl_it);
922 }
923 const auto epilogue_func{[](const IR::AbstractSyntaxNode& asn) {
924 if (asn.type != Type::Block) {
925 return false;
926 }
927 for (const auto& inst : asn.data.block->Instructions()) {
928 if (inst.GetOpcode() == IR::Opcode::Epilogue) {
929 return true;
930 }
931 }
932 return false;
933 }};
934 const auto reverse_it{std::find_if(asl.rbegin(), asl.rend(), epilogue_func)};
935 const auto return_block_it{(reverse_it + 1).base()};
936
937 IR::IREmitter ir{*(return_block_it - 1)->data.block};
938 IR::U1 cond(IR::Value(false));
939 for (const auto& demote_cond : demote_conds) {
940 cond = ir.LogicalOr(cond, demote_cond);
941 }
942 cond.Inst()->DestructiveAddUsage(1);
943
944 IR::AbstractSyntaxNode demote_if_node{};
945 demote_if_node.type = Type::If;
946 demote_if_node.data.if_node.cond = cond;
947 demote_if_node.data.if_node.body = demote_blocks[0];
948 demote_if_node.data.if_node.merge = return_block_it->data.block;
949
950 IR::AbstractSyntaxNode demote_node{};
951 demote_node.type = Type::Block;
952 demote_node.data.block = demote_blocks[0];
953
954 IR::AbstractSyntaxNode demote_endif_node{};
955 demote_endif_node.type = Type::EndIf;
956 demote_endif_node.data.end_if.merge = return_block_it->data.block;
957
958 asl.insert(return_block_it, demote_endif_node);
959 asl.insert(return_block_it, demote_node);
960 asl.insert(return_block_it, demote_if_node);
961 }
962
858 ObjectPool<Statement>& stmt_pool; 963 ObjectPool<Statement>& stmt_pool;
859 ObjectPool<IR::Inst>& inst_pool; 964 ObjectPool<IR::Inst>& inst_pool;
860 ObjectPool<IR::Block>& block_pool; 965 ObjectPool<IR::Block>& block_pool;
861 Environment& env; 966 Environment& env;
862 IR::AbstractSyntaxList& syntax_list; 967 IR::AbstractSyntaxList& syntax_list;
968 bool uses_demote_to_helper{};
863 969
864// TODO: C++20 Remove this when all compilers support constexpr std::vector 970// TODO: C++20 Remove this when all compilers support constexpr std::vector
865#if __cpp_lib_constexpr_vector >= 201907 971#if __cpp_lib_constexpr_vector >= 201907