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