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