• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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         if let SrcRef::SSA(ssa) = &src.src_ref {
34             for val in ssa.iter() {
35                 self.mark_ssa_live(val);
36             }
37         }
38     }
39 
mark_phi_live(&mut self, id: u32)40     fn mark_phi_live(&mut self, id: u32) {
41         self.new_live |= self.live_phi.insert(id);
42     }
43 
is_dst_live(&self, dst: &Dst) -> bool44     fn is_dst_live(&self, dst: &Dst) -> bool {
45         match dst {
46             Dst::SSA(ssa) => {
47                 for val in ssa.iter() {
48                     if self.live_ssa.get(val).is_some() {
49                         return true;
50                     }
51                 }
52                 false
53             }
54             Dst::None => false,
55             _ => panic!("Invalid SSA destination"),
56         }
57     }
58 
is_phi_live(&self, id: u32) -> bool59     fn is_phi_live(&self, id: u32) -> bool {
60         self.live_phi.get(&id).is_some()
61     }
62 
is_instr_live(&self, instr: &Instr) -> bool63     fn is_instr_live(&self, instr: &Instr) -> bool {
64         if instr.pred.is_false() {
65             return false;
66         }
67 
68         if !instr.can_eliminate() {
69             return true;
70         }
71 
72         for dst in instr.dsts() {
73             if self.is_dst_live(dst) {
74                 return true;
75             }
76         }
77 
78         false
79     }
80 
mark_instr(&mut self, instr: &Instr)81     fn mark_instr(&mut self, instr: &Instr) {
82         match &instr.op {
83             Op::PhiSrcs(phi) => {
84                 assert!(instr.pred.is_true());
85                 for (id, src) in phi.srcs.iter() {
86                     if self.is_phi_live(*id) {
87                         self.mark_src_live(src);
88                     } else {
89                         self.any_dead = true;
90                     }
91                 }
92             }
93             Op::PhiDsts(phi) => {
94                 assert!(instr.pred.is_true());
95                 for (id, dst) in phi.dsts.iter() {
96                     if self.is_dst_live(dst) {
97                         self.mark_phi_live(*id);
98                     } else {
99                         self.any_dead = true;
100                     }
101                 }
102             }
103             Op::ParCopy(pcopy) => {
104                 assert!(instr.pred.is_true());
105                 for (dst, src) in pcopy.dsts_srcs.iter() {
106                     if self.is_dst_live(dst) {
107                         self.mark_src_live(src);
108                     } else {
109                         self.any_dead = true;
110                     }
111                 }
112             }
113             _ => {
114                 if self.is_instr_live(instr) {
115                     if let PredRef::SSA(ssa) = &instr.pred.pred_ref {
116                         self.mark_ssa_live(ssa);
117                     }
118 
119                     for src in instr.srcs() {
120                         self.mark_src_live(src);
121                     }
122                 } else {
123                     self.any_dead = true;
124                 }
125             }
126         }
127     }
128 
map_instr(&self, mut instr: Box<Instr>) -> MappedInstrs129     fn map_instr(&self, mut instr: Box<Instr>) -> MappedInstrs {
130         let is_live = match &mut instr.op {
131             Op::PhiSrcs(phi) => {
132                 phi.srcs.retain(|id, _| self.is_phi_live(*id));
133                 !phi.srcs.is_empty()
134             }
135             Op::PhiDsts(phi) => {
136                 phi.dsts.retain(|_, dst| self.is_dst_live(dst));
137                 !phi.dsts.is_empty()
138             }
139             Op::ParCopy(pcopy) => {
140                 pcopy.dsts_srcs.retain(|dst, _| self.is_dst_live(dst));
141                 !pcopy.dsts_srcs.is_empty()
142             }
143             _ => self.is_instr_live(&instr),
144         };
145 
146         if is_live {
147             MappedInstrs::One(instr)
148         } else {
149             if DEBUG.annotate() {
150                 MappedInstrs::One(Instr::new_boxed(OpAnnotate {
151                     annotation: "killed by dce".into(),
152                 }))
153             } else {
154                 MappedInstrs::None
155             }
156         }
157     }
158 
run(&mut self, f: &mut Function)159     pub fn run(&mut self, f: &mut Function) {
160         loop {
161             self.new_live = false;
162             self.any_dead = false;
163 
164             for b in f.blocks.iter().rev() {
165                 for instr in b.instrs.iter().rev() {
166                     self.mark_instr(instr);
167                 }
168             }
169 
170             if !self.new_live {
171                 break;
172             }
173         }
174 
175         if self.any_dead {
176             f.map_instrs(|instr, _| self.map_instr(instr));
177         }
178     }
179 }
180 
181 impl Function {
opt_dce(&mut self)182     pub fn opt_dce(&mut self) {
183         DeadCodePass::new().run(self);
184     }
185 }
186 
187 impl Shader {
opt_dce(&mut self)188     pub fn opt_dce(&mut self) {
189         for f in &mut self.functions {
190             f.opt_dce();
191         }
192     }
193 }
194