summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar ameerj2022-03-22 01:22:21 -0400
committerGravatar ameerj2022-03-22 02:39:31 -0400
commitf10d40a0a25dc6709b8cbd0a6793175434db6472 (patch)
tree2f70f9d51b5ace18d8341cf65815d5c172fd7964
parentMerge pull request #8038 from liamwhite/exit-register-detection (diff)
downloadyuzu-f10d40a0a25dc6709b8cbd0a6793175434db6472.tar.gz
yuzu-f10d40a0a25dc6709b8cbd0a6793175434db6472.tar.xz
yuzu-f10d40a0a25dc6709b8cbd0a6793175434db6472.zip
shader_recompiler/dead_code_elimination: Add DeadBranchElimination pass
This adds a pass to eliminate if(false) branches within the shader code
Diffstat (limited to '')
-rw-r--r--src/shader_recompiler/ir_opt/dead_code_elimination_pass.cpp71
1 files changed, 62 insertions, 9 deletions
diff --git a/src/shader_recompiler/ir_opt/dead_code_elimination_pass.cpp b/src/shader_recompiler/ir_opt/dead_code_elimination_pass.cpp
index 400836301..6c7c7b32d 100644
--- a/src/shader_recompiler/ir_opt/dead_code_elimination_pass.cpp
+++ b/src/shader_recompiler/ir_opt/dead_code_elimination_pass.cpp
@@ -7,19 +7,72 @@
7#include "shader_recompiler/ir_opt/passes.h" 7#include "shader_recompiler/ir_opt/passes.h"
8 8
9namespace Shader::Optimization { 9namespace Shader::Optimization {
10 10namespace {
11void DeadCodeEliminationPass(IR::Program& program) { 11template <bool TEST_USES>
12void DeadInstElimination(IR::Block* const block) {
12 // We iterate over the instructions in reverse order. 13 // We iterate over the instructions in reverse order.
13 // This is because removing an instruction reduces the number of uses for earlier instructions. 14 // This is because removing an instruction reduces the number of uses for earlier instructions.
14 for (IR::Block* const block : program.post_order_blocks) { 15 auto it{block->end()};
15 auto it{block->end()}; 16 while (it != block->begin()) {
16 while (it != block->begin()) { 17 --it;
17 --it; 18 if constexpr (TEST_USES) {
18 if (!it->HasUses() && !it->MayHaveSideEffects()) { 19 if (it->HasUses() || it->MayHaveSideEffects()) {
19 it->Invalidate(); 20 continue;
20 it = block->Instructions().erase(it);
21 } 21 }
22 } 22 }
23 it->Invalidate();
24 it = block->Instructions().erase(it);
25 }
26}
27
28void DeadBranchElimination(IR::Program& program) {
29 const auto begin_it{program.syntax_list.begin()};
30 for (auto node_it = begin_it; node_it != program.syntax_list.end(); ++node_it) {
31 if (node_it->type != IR::AbstractSyntaxNode::Type::If) {
32 continue;
33 }
34 IR::Inst* const cond_ref{node_it->data.if_node.cond.Inst()};
35 const IR::U1 cond{cond_ref->Arg(0)};
36 if (!cond.IsImmediate()) {
37 continue;
38 }
39 if (cond.U1()) {
40 continue;
41 }
42 // False immediate condition. Remove condition ref, erase the entire branch.
43 cond_ref->Invalidate();
44 // Account for nested if-statements within the if(false) branch
45 u32 nested_ifs{1u};
46 while (node_it->type != IR::AbstractSyntaxNode::Type::EndIf || nested_ifs > 0) {
47 node_it = program.syntax_list.erase(node_it);
48 switch (node_it->type) {
49 case IR::AbstractSyntaxNode::Type::If:
50 ++nested_ifs;
51 break;
52 case IR::AbstractSyntaxNode::Type::EndIf:
53 --nested_ifs;
54 break;
55 case IR::AbstractSyntaxNode::Type::Block: {
56 IR::Block* const block{node_it->data.block};
57 DeadInstElimination<false>(block);
58 break;
59 }
60 default:
61 break;
62 }
63 }
64 // Erase EndIf node of the if(false) branch
65 node_it = program.syntax_list.erase(node_it);
66 // Account for loop increment
67 --node_it;
68 }
69}
70} // namespace
71
72void DeadCodeEliminationPass(IR::Program& program) {
73 DeadBranchElimination(program);
74 for (IR::Block* const block : program.post_order_blocks) {
75 DeadInstElimination<true>(block);
23 } 76 }
24} 77}
25 78