xref: /aosp_15_r20/external/mesa3d/src/nouveau/compiler/nak/opt_dce.rs (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 // Copyright © 2022 Collabora, Ltd.
2 // SPDX-License-Identifier: MIT
3 
4 use crate::{
5     api::{GetDebugFlags, DEBUG},
6     ir::*,
7 };
8 
9 use std::collections::HashSet;
10 
11 struct DeadCodePass {
12     any_dead: bool,
13     new_live: bool,
14     live_ssa: HashSet<SSAValue>,
15     live_phi: HashSet<u32>,
16 }
17 
18 impl DeadCodePass {
new() -> DeadCodePass19     pub fn new() -> DeadCodePass {
20         DeadCodePass {
21             any_dead: false,
22             new_live: false,
23             live_ssa: HashSet::new(),
24             live_phi: HashSet::new(),
25         }
26     }
27 
mark_ssa_live(&mut self, ssa: &SSAValue)28     fn mark_ssa_live(&mut self, ssa: &SSAValue) {
29         self.new_live |= self.live_ssa.insert(*ssa);
30     }
31 
mark_src_live(&mut self, src: &Src)32     fn mark_src_live(&mut self, src: &Src) {
33         for ssa in src.iter_ssa() {
34             self.mark_ssa_live(ssa);
35         }
36     }
37 
mark_phi_live(&mut self, id: u32)38     fn mark_phi_live(&mut self, id: u32) {
39         self.new_live |= self.live_phi.insert(id);
40     }
41 
is_dst_live(&self, dst: &Dst) -> bool42     fn is_dst_live(&self, dst: &Dst) -> bool {
43         match dst {
44             Dst::SSA(ssa) => {
45                 for val in ssa.iter() {
46                     if self.live_ssa.get(val).is_some() {
47                         return true;
48                     }
49                 }
50                 false
51             }
52             Dst::None => false,
53             _ => panic!("Invalid SSA destination"),
54         }
55     }
56 
is_phi_live(&self, id: u32) -> bool57     fn is_phi_live(&self, id: u32) -> bool {
58         self.live_phi.get(&id).is_some()
59     }
60 
is_instr_live(&self, instr: &Instr) -> bool61     fn is_instr_live(&self, instr: &Instr) -> bool {
62         if instr.pred.is_false() {
63             return false;
64         }
65 
66         if !instr.can_eliminate() {
67             return true;
68         }
69 
70         for dst in instr.dsts() {
71             if self.is_dst_live(dst) {
72                 return true;
73             }
74         }
75 
76         false
77     }
78 
mark_instr(&mut self, instr: &Instr)79     fn mark_instr(&mut self, instr: &Instr) {
80         match &instr.op {
81             Op::PhiSrcs(phi) => {
82                 assert!(instr.pred.is_true());
83                 for (id, src) in phi.srcs.iter() {
84                     if self.is_phi_live(*id) {
85                         self.mark_src_live(src);
86                     } else {
87                         self.any_dead = true;
88                     }
89                 }
90             }
91             Op::PhiDsts(phi) => {
92                 assert!(instr.pred.is_true());
93                 for (id, dst) in phi.dsts.iter() {
94                     if self.is_dst_live(dst) {
95                         self.mark_phi_live(*id);
96                     } else {
97                         self.any_dead = true;
98                     }
99                 }
100             }
101             Op::ParCopy(pcopy) => {
102                 assert!(instr.pred.is_true());
103                 for (dst, src) in pcopy.dsts_srcs.iter() {
104                     if self.is_dst_live(dst) {
105                         self.mark_src_live(src);
106                     } else {
107                         self.any_dead = true;
108                     }
109                 }
110             }
111             _ => {
112                 if self.is_instr_live(instr) {
113                     if let PredRef::SSA(ssa) = &instr.pred.pred_ref {
114                         self.mark_ssa_live(ssa);
115                     }
116 
117                     for src in instr.srcs() {
118                         self.mark_src_live(src);
119                     }
120                 } else {
121                     self.any_dead = true;
122                 }
123             }
124         }
125     }
126 
map_instr(&self, mut instr: Box<Instr>) -> MappedInstrs127     fn map_instr(&self, mut instr: Box<Instr>) -> MappedInstrs {
128         let is_live = match &mut instr.op {
129             Op::PhiSrcs(phi) => {
130                 phi.srcs.retain(|id, _| self.is_phi_live(*id));
131                 !phi.srcs.is_empty()
132             }
133             Op::PhiDsts(phi) => {
134                 phi.dsts.retain(|_, dst| self.is_dst_live(dst));
135                 !phi.dsts.is_empty()
136             }
137             Op::ParCopy(pcopy) => {
138                 pcopy.dsts_srcs.retain(|dst, _| self.is_dst_live(dst));
139                 !pcopy.dsts_srcs.is_empty()
140             }
141             _ => self.is_instr_live(&instr),
142         };
143 
144         if is_live {
145             MappedInstrs::One(instr)
146         } else {
147             if DEBUG.annotate() {
148                 MappedInstrs::One(Instr::new_boxed(OpAnnotate {
149                     annotation: "killed by dce".into(),
150                 }))
151             } else {
152                 MappedInstrs::None
153             }
154         }
155     }
156 
run(&mut self, f: &mut Function)157     pub fn run(&mut self, f: &mut Function) {
158         loop {
159             self.new_live = false;
160             self.any_dead = false;
161 
162             for b in f.blocks.iter().rev() {
163                 for instr in b.instrs.iter().rev() {
164                     self.mark_instr(instr);
165                 }
166             }
167 
168             if !self.new_live {
169                 break;
170             }
171         }
172 
173         if self.any_dead {
174             f.map_instrs(|instr, _| self.map_instr(instr));
175         }
176     }
177 }
178 
179 impl Function {
opt_dce(&mut self)180     pub fn opt_dce(&mut self) {
181         DeadCodePass::new().run(self);
182     }
183 }
184 
185 impl Shader<'_> {
opt_dce(&mut self)186     pub fn opt_dce(&mut self) {
187         for f in &mut self.functions {
188             f.opt_dce();
189         }
190     }
191 }
192