diff options
Diffstat (limited to 'src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp')
| -rw-r--r-- | src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp | 108 |
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 | ||
| 665 | private: | 668 | private: |
| @@ -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 |