summaryrefslogtreecommitdiff
path: root/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp
diff options
context:
space:
mode:
authorGravatar ameerj2021-08-23 19:52:07 -0400
committerGravatar ameerj2021-08-28 11:35:25 -0400
commit862dc2b2b31b8353449f61dcc68d69255721f6c6 (patch)
treee37b2597909d3990ccd563d5403eff16835b6562 /src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp
parentMerge pull request #6929 from yuzu-emu/revert-6870-trace-back-stack-back-stac... (diff)
downloadyuzu-862dc2b2b31b8353449f61dcc68d69255721f6c6.tar.gz
yuzu-862dc2b2b31b8353449f61dcc68d69255721f6c6.tar.xz
yuzu-862dc2b2b31b8353449f61dcc68d69255721f6c6.zip
structured_control_flow: Add DemoteCombinationPass
Some drivers misread data when demotes are interleaved in the program. This moves demote branches to be checked at the end of the program. Fixes "wireframe" issue in Pokemon SwSh on some drivers
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