1*61046927SAndroid Build Coastguard Worker // Copyright © 2022 Collabora, Ltd. 2*61046927SAndroid Build Coastguard Worker // SPDX-License-Identifier: MIT 3*61046927SAndroid Build Coastguard Worker 4*61046927SAndroid Build Coastguard Worker use crate::ir::*; 5*61046927SAndroid Build Coastguard Worker 6*61046927SAndroid Build Coastguard Worker use compiler::bitset::BitSet; 7*61046927SAndroid Build Coastguard Worker use std::cell::RefCell; 8*61046927SAndroid Build Coastguard Worker use std::cmp::{max, Ord, Ordering}; 9*61046927SAndroid Build Coastguard Worker use std::collections::{hash_set, HashMap, HashSet}; 10*61046927SAndroid Build Coastguard Worker 11*61046927SAndroid Build Coastguard Worker #[derive(Clone)] 12*61046927SAndroid Build Coastguard Worker pub struct LiveSet { 13*61046927SAndroid Build Coastguard Worker live: PerRegFile<u32>, 14*61046927SAndroid Build Coastguard Worker set: HashSet<SSAValue>, 15*61046927SAndroid Build Coastguard Worker } 16*61046927SAndroid Build Coastguard Worker 17*61046927SAndroid Build Coastguard Worker impl LiveSet { new() -> LiveSet18*61046927SAndroid Build Coastguard Worker pub fn new() -> LiveSet { 19*61046927SAndroid Build Coastguard Worker LiveSet { 20*61046927SAndroid Build Coastguard Worker live: Default::default(), 21*61046927SAndroid Build Coastguard Worker set: HashSet::new(), 22*61046927SAndroid Build Coastguard Worker } 23*61046927SAndroid Build Coastguard Worker } 24*61046927SAndroid Build Coastguard Worker contains(&self, ssa: &SSAValue) -> bool25*61046927SAndroid Build Coastguard Worker pub fn contains(&self, ssa: &SSAValue) -> bool { 26*61046927SAndroid Build Coastguard Worker self.set.contains(ssa) 27*61046927SAndroid Build Coastguard Worker } 28*61046927SAndroid Build Coastguard Worker count(&self, file: RegFile) -> u3229*61046927SAndroid Build Coastguard Worker pub fn count(&self, file: RegFile) -> u32 { 30*61046927SAndroid Build Coastguard Worker self.live[file] 31*61046927SAndroid Build Coastguard Worker } 32*61046927SAndroid Build Coastguard Worker insert(&mut self, ssa: SSAValue) -> bool33*61046927SAndroid Build Coastguard Worker pub fn insert(&mut self, ssa: SSAValue) -> bool { 34*61046927SAndroid Build Coastguard Worker if self.set.insert(ssa) { 35*61046927SAndroid Build Coastguard Worker self.live[ssa.file()] += 1; 36*61046927SAndroid Build Coastguard Worker true 37*61046927SAndroid Build Coastguard Worker } else { 38*61046927SAndroid Build Coastguard Worker false 39*61046927SAndroid Build Coastguard Worker } 40*61046927SAndroid Build Coastguard Worker } 41*61046927SAndroid Build Coastguard Worker iter(&self) -> hash_set::Iter<SSAValue>42*61046927SAndroid Build Coastguard Worker pub fn iter(&self) -> hash_set::Iter<SSAValue> { 43*61046927SAndroid Build Coastguard Worker self.set.iter() 44*61046927SAndroid Build Coastguard Worker } 45*61046927SAndroid Build Coastguard Worker remove(&mut self, ssa: &SSAValue) -> bool46*61046927SAndroid Build Coastguard Worker pub fn remove(&mut self, ssa: &SSAValue) -> bool { 47*61046927SAndroid Build Coastguard Worker if self.set.remove(ssa) { 48*61046927SAndroid Build Coastguard Worker self.live[ssa.file()] -= 1; 49*61046927SAndroid Build Coastguard Worker true 50*61046927SAndroid Build Coastguard Worker } else { 51*61046927SAndroid Build Coastguard Worker false 52*61046927SAndroid Build Coastguard Worker } 53*61046927SAndroid Build Coastguard Worker } 54*61046927SAndroid Build Coastguard Worker insert_instr_top_down<L: BlockLiveness>( &mut self, ip: usize, instr: &Instr, bl: &L, ) -> PerRegFile<u32>55*61046927SAndroid Build Coastguard Worker pub fn insert_instr_top_down<L: BlockLiveness>( 56*61046927SAndroid Build Coastguard Worker &mut self, 57*61046927SAndroid Build Coastguard Worker ip: usize, 58*61046927SAndroid Build Coastguard Worker instr: &Instr, 59*61046927SAndroid Build Coastguard Worker bl: &L, 60*61046927SAndroid Build Coastguard Worker ) -> PerRegFile<u32> { 61*61046927SAndroid Build Coastguard Worker // Vector destinations go live before sources are killed. Even 62*61046927SAndroid Build Coastguard Worker // in the case where the destination is immediately killed, it 63*61046927SAndroid Build Coastguard Worker // still may contribute to pressure temporarily. 64*61046927SAndroid Build Coastguard Worker for dst in instr.dsts() { 65*61046927SAndroid Build Coastguard Worker if let Dst::SSA(vec) = dst { 66*61046927SAndroid Build Coastguard Worker if vec.comps() > 1 { 67*61046927SAndroid Build Coastguard Worker for ssa in vec.iter() { 68*61046927SAndroid Build Coastguard Worker self.insert(*ssa); 69*61046927SAndroid Build Coastguard Worker } 70*61046927SAndroid Build Coastguard Worker } 71*61046927SAndroid Build Coastguard Worker } 72*61046927SAndroid Build Coastguard Worker } 73*61046927SAndroid Build Coastguard Worker 74*61046927SAndroid Build Coastguard Worker let after_dsts_live = self.live; 75*61046927SAndroid Build Coastguard Worker 76*61046927SAndroid Build Coastguard Worker instr.for_each_ssa_use(|ssa| { 77*61046927SAndroid Build Coastguard Worker if !bl.is_live_after_ip(ssa, ip) { 78*61046927SAndroid Build Coastguard Worker self.remove(ssa); 79*61046927SAndroid Build Coastguard Worker } 80*61046927SAndroid Build Coastguard Worker }); 81*61046927SAndroid Build Coastguard Worker 82*61046927SAndroid Build Coastguard Worker // Scalar destinations are allocated last 83*61046927SAndroid Build Coastguard Worker for dst in instr.dsts() { 84*61046927SAndroid Build Coastguard Worker if let Dst::SSA(vec) = dst { 85*61046927SAndroid Build Coastguard Worker if vec.comps() == 1 { 86*61046927SAndroid Build Coastguard Worker self.insert(vec[0]); 87*61046927SAndroid Build Coastguard Worker } 88*61046927SAndroid Build Coastguard Worker } 89*61046927SAndroid Build Coastguard Worker } 90*61046927SAndroid Build Coastguard Worker 91*61046927SAndroid Build Coastguard Worker let max_live = PerRegFile::new_with(|file| { 92*61046927SAndroid Build Coastguard Worker max(self.live[file], after_dsts_live[file]) 93*61046927SAndroid Build Coastguard Worker }); 94*61046927SAndroid Build Coastguard Worker 95*61046927SAndroid Build Coastguard Worker // It's possible (but unlikely) that a destination is immediately 96*61046927SAndroid Build Coastguard Worker // killed. Remove any which are killed by this instruction. 97*61046927SAndroid Build Coastguard Worker instr.for_each_ssa_def(|ssa| { 98*61046927SAndroid Build Coastguard Worker debug_assert!(self.contains(ssa)); 99*61046927SAndroid Build Coastguard Worker if !bl.is_live_after_ip(ssa, ip) { 100*61046927SAndroid Build Coastguard Worker self.remove(ssa); 101*61046927SAndroid Build Coastguard Worker } 102*61046927SAndroid Build Coastguard Worker }); 103*61046927SAndroid Build Coastguard Worker 104*61046927SAndroid Build Coastguard Worker max_live 105*61046927SAndroid Build Coastguard Worker } 106*61046927SAndroid Build Coastguard Worker } 107*61046927SAndroid Build Coastguard Worker 108*61046927SAndroid Build Coastguard Worker impl FromIterator<SSAValue> for LiveSet { from_iter<T: IntoIterator<Item = SSAValue>>(iter: T) -> Self109*61046927SAndroid Build Coastguard Worker fn from_iter<T: IntoIterator<Item = SSAValue>>(iter: T) -> Self { 110*61046927SAndroid Build Coastguard Worker let mut set = LiveSet::new(); 111*61046927SAndroid Build Coastguard Worker for ssa in iter { 112*61046927SAndroid Build Coastguard Worker set.insert(ssa); 113*61046927SAndroid Build Coastguard Worker } 114*61046927SAndroid Build Coastguard Worker set 115*61046927SAndroid Build Coastguard Worker } 116*61046927SAndroid Build Coastguard Worker } 117*61046927SAndroid Build Coastguard Worker 118*61046927SAndroid Build Coastguard Worker impl Extend<SSAValue> for LiveSet { extend<T: IntoIterator<Item = SSAValue>>(&mut self, iter: T)119*61046927SAndroid Build Coastguard Worker fn extend<T: IntoIterator<Item = SSAValue>>(&mut self, iter: T) { 120*61046927SAndroid Build Coastguard Worker for ssa in iter { 121*61046927SAndroid Build Coastguard Worker self.insert(ssa); 122*61046927SAndroid Build Coastguard Worker } 123*61046927SAndroid Build Coastguard Worker } 124*61046927SAndroid Build Coastguard Worker } 125*61046927SAndroid Build Coastguard Worker 126*61046927SAndroid Build Coastguard Worker pub trait BlockLiveness { 127*61046927SAndroid Build Coastguard Worker /// Returns true if @val is still live after @ip is_live_after_ip(&self, val: &SSAValue, ip: usize) -> bool128*61046927SAndroid Build Coastguard Worker fn is_live_after_ip(&self, val: &SSAValue, ip: usize) -> bool; 129*61046927SAndroid Build Coastguard Worker 130*61046927SAndroid Build Coastguard Worker /// Returns true if @val is live-in to this block is_live_in(&self, val: &SSAValue) -> bool131*61046927SAndroid Build Coastguard Worker fn is_live_in(&self, val: &SSAValue) -> bool; 132*61046927SAndroid Build Coastguard Worker 133*61046927SAndroid Build Coastguard Worker /// Returns true if @val is live-out of this block is_live_out(&self, val: &SSAValue) -> bool134*61046927SAndroid Build Coastguard Worker fn is_live_out(&self, val: &SSAValue) -> bool; 135*61046927SAndroid Build Coastguard Worker get_instr_pressure(&self, ip: usize, instr: &Instr) -> PerRegFile<u8>136*61046927SAndroid Build Coastguard Worker fn get_instr_pressure(&self, ip: usize, instr: &Instr) -> PerRegFile<u8> { 137*61046927SAndroid Build Coastguard Worker let mut live = PerRegFile::new_with(|_| 0_i8); 138*61046927SAndroid Build Coastguard Worker 139*61046927SAndroid Build Coastguard Worker // Vector destinations go live before sources are killed. 140*61046927SAndroid Build Coastguard Worker for dst in instr.dsts() { 141*61046927SAndroid Build Coastguard Worker if let Dst::SSA(vec) = dst { 142*61046927SAndroid Build Coastguard Worker if vec.comps() > 1 { 143*61046927SAndroid Build Coastguard Worker for ssa in vec.iter() { 144*61046927SAndroid Build Coastguard Worker live[ssa.file()] += 1; 145*61046927SAndroid Build Coastguard Worker } 146*61046927SAndroid Build Coastguard Worker } 147*61046927SAndroid Build Coastguard Worker } 148*61046927SAndroid Build Coastguard Worker } 149*61046927SAndroid Build Coastguard Worker 150*61046927SAndroid Build Coastguard Worker // This is the first high point 151*61046927SAndroid Build Coastguard Worker let vec_dst_live = live; 152*61046927SAndroid Build Coastguard Worker 153*61046927SAndroid Build Coastguard Worker // Use a hash set because sources may occur more than once 154*61046927SAndroid Build Coastguard Worker let mut killed = HashSet::new(); 155*61046927SAndroid Build Coastguard Worker instr.for_each_ssa_use(|ssa| { 156*61046927SAndroid Build Coastguard Worker if !self.is_live_after_ip(ssa, ip) { 157*61046927SAndroid Build Coastguard Worker killed.insert(*ssa); 158*61046927SAndroid Build Coastguard Worker } 159*61046927SAndroid Build Coastguard Worker }); 160*61046927SAndroid Build Coastguard Worker for ssa in killed.drain() { 161*61046927SAndroid Build Coastguard Worker live[ssa.file()] -= 1; 162*61046927SAndroid Build Coastguard Worker } 163*61046927SAndroid Build Coastguard Worker 164*61046927SAndroid Build Coastguard Worker // Scalar destinations are allocated last 165*61046927SAndroid Build Coastguard Worker for dst in instr.dsts() { 166*61046927SAndroid Build Coastguard Worker if let Dst::SSA(vec) = dst { 167*61046927SAndroid Build Coastguard Worker if vec.comps() == 1 { 168*61046927SAndroid Build Coastguard Worker live[vec[0].file()] += 1; 169*61046927SAndroid Build Coastguard Worker } 170*61046927SAndroid Build Coastguard Worker } 171*61046927SAndroid Build Coastguard Worker } 172*61046927SAndroid Build Coastguard Worker 173*61046927SAndroid Build Coastguard Worker PerRegFile::new_with(|file| { 174*61046927SAndroid Build Coastguard Worker max(0, max(vec_dst_live[file], live[file])) 175*61046927SAndroid Build Coastguard Worker .try_into() 176*61046927SAndroid Build Coastguard Worker .unwrap() 177*61046927SAndroid Build Coastguard Worker }) 178*61046927SAndroid Build Coastguard Worker } 179*61046927SAndroid Build Coastguard Worker } 180*61046927SAndroid Build Coastguard Worker 181*61046927SAndroid Build Coastguard Worker pub trait Liveness { 182*61046927SAndroid Build Coastguard Worker type PerBlock: BlockLiveness; 183*61046927SAndroid Build Coastguard Worker block_live(&self, idx: usize) -> &Self::PerBlock184*61046927SAndroid Build Coastguard Worker fn block_live(&self, idx: usize) -> &Self::PerBlock; 185*61046927SAndroid Build Coastguard Worker calc_max_live(&self, f: &Function) -> PerRegFile<u32>186*61046927SAndroid Build Coastguard Worker fn calc_max_live(&self, f: &Function) -> PerRegFile<u32> { 187*61046927SAndroid Build Coastguard Worker let mut max_live: PerRegFile<u32> = Default::default(); 188*61046927SAndroid Build Coastguard Worker let mut block_live_out: Vec<LiveSet> = Vec::new(); 189*61046927SAndroid Build Coastguard Worker 190*61046927SAndroid Build Coastguard Worker for (bb_idx, bb) in f.blocks.iter().enumerate() { 191*61046927SAndroid Build Coastguard Worker let bl = self.block_live(bb_idx); 192*61046927SAndroid Build Coastguard Worker 193*61046927SAndroid Build Coastguard Worker let mut live = LiveSet::new(); 194*61046927SAndroid Build Coastguard Worker 195*61046927SAndroid Build Coastguard Worker // Predecessors are added block order so we can just grab the first 196*61046927SAndroid Build Coastguard Worker // one (if any) and it will be a block we've processed. 197*61046927SAndroid Build Coastguard Worker if let Some(pred_idx) = f.blocks.pred_indices(bb_idx).first() { 198*61046927SAndroid Build Coastguard Worker let pred_out = &block_live_out[*pred_idx]; 199*61046927SAndroid Build Coastguard Worker for ssa in pred_out.iter() { 200*61046927SAndroid Build Coastguard Worker if bl.is_live_in(ssa) { 201*61046927SAndroid Build Coastguard Worker live.insert(*ssa); 202*61046927SAndroid Build Coastguard Worker } 203*61046927SAndroid Build Coastguard Worker } 204*61046927SAndroid Build Coastguard Worker } 205*61046927SAndroid Build Coastguard Worker 206*61046927SAndroid Build Coastguard Worker for (ip, instr) in bb.instrs.iter().enumerate() { 207*61046927SAndroid Build Coastguard Worker let live_at_instr = live.insert_instr_top_down(ip, instr, bl); 208*61046927SAndroid Build Coastguard Worker max_live = PerRegFile::new_with(|file| { 209*61046927SAndroid Build Coastguard Worker max(max_live[file], live_at_instr[file]) 210*61046927SAndroid Build Coastguard Worker }); 211*61046927SAndroid Build Coastguard Worker 212*61046927SAndroid Build Coastguard Worker if let Op::RegOut(reg_out) = &instr.op { 213*61046927SAndroid Build Coastguard Worker // This should be the last instruction. Everything should 214*61046927SAndroid Build Coastguard Worker // be dead once we've processed it. 215*61046927SAndroid Build Coastguard Worker debug_assert!(live.count(RegFile::GPR) == 0); 216*61046927SAndroid Build Coastguard Worker let num_gprs_out = reg_out.srcs.len().try_into().unwrap(); 217*61046927SAndroid Build Coastguard Worker max_live[RegFile::GPR] = 218*61046927SAndroid Build Coastguard Worker max(max_live[RegFile::GPR], num_gprs_out); 219*61046927SAndroid Build Coastguard Worker } 220*61046927SAndroid Build Coastguard Worker } 221*61046927SAndroid Build Coastguard Worker 222*61046927SAndroid Build Coastguard Worker assert!(block_live_out.len() == bb_idx); 223*61046927SAndroid Build Coastguard Worker block_live_out.push(live); 224*61046927SAndroid Build Coastguard Worker } 225*61046927SAndroid Build Coastguard Worker 226*61046927SAndroid Build Coastguard Worker max_live 227*61046927SAndroid Build Coastguard Worker } 228*61046927SAndroid Build Coastguard Worker } 229*61046927SAndroid Build Coastguard Worker 230*61046927SAndroid Build Coastguard Worker pub struct SimpleBlockLiveness { 231*61046927SAndroid Build Coastguard Worker defs: BitSet, 232*61046927SAndroid Build Coastguard Worker uses: BitSet, 233*61046927SAndroid Build Coastguard Worker last_use: HashMap<u32, usize>, 234*61046927SAndroid Build Coastguard Worker live_in: BitSet, 235*61046927SAndroid Build Coastguard Worker live_out: BitSet, 236*61046927SAndroid Build Coastguard Worker } 237*61046927SAndroid Build Coastguard Worker 238*61046927SAndroid Build Coastguard Worker impl SimpleBlockLiveness { new() -> Self239*61046927SAndroid Build Coastguard Worker fn new() -> Self { 240*61046927SAndroid Build Coastguard Worker Self { 241*61046927SAndroid Build Coastguard Worker defs: BitSet::new(), 242*61046927SAndroid Build Coastguard Worker uses: BitSet::new(), 243*61046927SAndroid Build Coastguard Worker last_use: HashMap::new(), 244*61046927SAndroid Build Coastguard Worker live_in: BitSet::new(), 245*61046927SAndroid Build Coastguard Worker live_out: BitSet::new(), 246*61046927SAndroid Build Coastguard Worker } 247*61046927SAndroid Build Coastguard Worker } 248*61046927SAndroid Build Coastguard Worker add_def(&mut self, ssa: SSAValue)249*61046927SAndroid Build Coastguard Worker fn add_def(&mut self, ssa: SSAValue) { 250*61046927SAndroid Build Coastguard Worker self.defs.insert(ssa.idx().try_into().unwrap()); 251*61046927SAndroid Build Coastguard Worker } 252*61046927SAndroid Build Coastguard Worker add_use(&mut self, ssa: SSAValue, ip: usize)253*61046927SAndroid Build Coastguard Worker fn add_use(&mut self, ssa: SSAValue, ip: usize) { 254*61046927SAndroid Build Coastguard Worker self.uses.insert(ssa.idx().try_into().unwrap()); 255*61046927SAndroid Build Coastguard Worker self.last_use.insert(ssa.idx(), ip); 256*61046927SAndroid Build Coastguard Worker } 257*61046927SAndroid Build Coastguard Worker } 258*61046927SAndroid Build Coastguard Worker 259*61046927SAndroid Build Coastguard Worker impl BlockLiveness for SimpleBlockLiveness { is_live_after_ip(&self, val: &SSAValue, ip: usize) -> bool260*61046927SAndroid Build Coastguard Worker fn is_live_after_ip(&self, val: &SSAValue, ip: usize) -> bool { 261*61046927SAndroid Build Coastguard Worker if self.live_out.get(val.idx().try_into().unwrap()) { 262*61046927SAndroid Build Coastguard Worker true 263*61046927SAndroid Build Coastguard Worker } else { 264*61046927SAndroid Build Coastguard Worker if let Some(last_use_ip) = self.last_use.get(&val.idx()) { 265*61046927SAndroid Build Coastguard Worker *last_use_ip > ip 266*61046927SAndroid Build Coastguard Worker } else { 267*61046927SAndroid Build Coastguard Worker false 268*61046927SAndroid Build Coastguard Worker } 269*61046927SAndroid Build Coastguard Worker } 270*61046927SAndroid Build Coastguard Worker } 271*61046927SAndroid Build Coastguard Worker is_live_in(&self, val: &SSAValue) -> bool272*61046927SAndroid Build Coastguard Worker fn is_live_in(&self, val: &SSAValue) -> bool { 273*61046927SAndroid Build Coastguard Worker self.live_in.get(val.idx().try_into().unwrap()) 274*61046927SAndroid Build Coastguard Worker } 275*61046927SAndroid Build Coastguard Worker is_live_out(&self, val: &SSAValue) -> bool276*61046927SAndroid Build Coastguard Worker fn is_live_out(&self, val: &SSAValue) -> bool { 277*61046927SAndroid Build Coastguard Worker self.live_out.get(val.idx().try_into().unwrap()) 278*61046927SAndroid Build Coastguard Worker } 279*61046927SAndroid Build Coastguard Worker } 280*61046927SAndroid Build Coastguard Worker 281*61046927SAndroid Build Coastguard Worker pub struct SimpleLiveness { 282*61046927SAndroid Build Coastguard Worker ssa_block_ip: HashMap<SSAValue, (usize, usize)>, 283*61046927SAndroid Build Coastguard Worker blocks: Vec<SimpleBlockLiveness>, 284*61046927SAndroid Build Coastguard Worker } 285*61046927SAndroid Build Coastguard Worker 286*61046927SAndroid Build Coastguard Worker impl SimpleLiveness { for_function(func: &Function) -> SimpleLiveness287*61046927SAndroid Build Coastguard Worker pub fn for_function(func: &Function) -> SimpleLiveness { 288*61046927SAndroid Build Coastguard Worker let mut l = SimpleLiveness { 289*61046927SAndroid Build Coastguard Worker ssa_block_ip: HashMap::new(), 290*61046927SAndroid Build Coastguard Worker blocks: Vec::new(), 291*61046927SAndroid Build Coastguard Worker }; 292*61046927SAndroid Build Coastguard Worker let mut live_in = Vec::new(); 293*61046927SAndroid Build Coastguard Worker 294*61046927SAndroid Build Coastguard Worker for (bi, b) in func.blocks.iter().enumerate() { 295*61046927SAndroid Build Coastguard Worker let mut bl = SimpleBlockLiveness::new(); 296*61046927SAndroid Build Coastguard Worker 297*61046927SAndroid Build Coastguard Worker for (ip, instr) in b.instrs.iter().enumerate() { 298*61046927SAndroid Build Coastguard Worker instr.for_each_ssa_use(|ssa| { 299*61046927SAndroid Build Coastguard Worker bl.add_use(*ssa, ip); 300*61046927SAndroid Build Coastguard Worker }); 301*61046927SAndroid Build Coastguard Worker instr.for_each_ssa_def(|ssa| { 302*61046927SAndroid Build Coastguard Worker l.ssa_block_ip.insert(*ssa, (bi, ip)); 303*61046927SAndroid Build Coastguard Worker bl.add_def(*ssa); 304*61046927SAndroid Build Coastguard Worker }); 305*61046927SAndroid Build Coastguard Worker } 306*61046927SAndroid Build Coastguard Worker 307*61046927SAndroid Build Coastguard Worker l.blocks.push(bl); 308*61046927SAndroid Build Coastguard Worker live_in.push(BitSet::new()); 309*61046927SAndroid Build Coastguard Worker } 310*61046927SAndroid Build Coastguard Worker assert!(l.blocks.len() == func.blocks.len()); 311*61046927SAndroid Build Coastguard Worker assert!(live_in.len() == func.blocks.len()); 312*61046927SAndroid Build Coastguard Worker 313*61046927SAndroid Build Coastguard Worker let num_ssa = usize::try_from(func.ssa_alloc.max_idx() + 1).unwrap(); 314*61046927SAndroid Build Coastguard Worker let mut tmp = BitSet::new(); 315*61046927SAndroid Build Coastguard Worker tmp.reserve(num_ssa); 316*61046927SAndroid Build Coastguard Worker 317*61046927SAndroid Build Coastguard Worker let mut to_do = true; 318*61046927SAndroid Build Coastguard Worker while to_do { 319*61046927SAndroid Build Coastguard Worker to_do = false; 320*61046927SAndroid Build Coastguard Worker for (b_idx, bl) in l.blocks.iter_mut().enumerate().rev() { 321*61046927SAndroid Build Coastguard Worker // Compute live-out 322*61046927SAndroid Build Coastguard Worker for sb_idx in func.blocks.succ_indices(b_idx) { 323*61046927SAndroid Build Coastguard Worker to_do |= bl.live_out.union_with(&live_in[*sb_idx]); 324*61046927SAndroid Build Coastguard Worker } 325*61046927SAndroid Build Coastguard Worker 326*61046927SAndroid Build Coastguard Worker tmp.clear(); 327*61046927SAndroid Build Coastguard Worker tmp.set_words(0..num_ssa, |w| { 328*61046927SAndroid Build Coastguard Worker (bl.live_out.get_word(w) | bl.uses.get_word(w)) 329*61046927SAndroid Build Coastguard Worker & !bl.defs.get_word(w) 330*61046927SAndroid Build Coastguard Worker }); 331*61046927SAndroid Build Coastguard Worker 332*61046927SAndroid Build Coastguard Worker to_do |= live_in[b_idx].union_with(&tmp); 333*61046927SAndroid Build Coastguard Worker } 334*61046927SAndroid Build Coastguard Worker } 335*61046927SAndroid Build Coastguard Worker 336*61046927SAndroid Build Coastguard Worker for (bl, b_live_in) in l.blocks.iter_mut().zip(live_in.into_iter()) { 337*61046927SAndroid Build Coastguard Worker bl.live_in = b_live_in; 338*61046927SAndroid Build Coastguard Worker } 339*61046927SAndroid Build Coastguard Worker 340*61046927SAndroid Build Coastguard Worker l 341*61046927SAndroid Build Coastguard Worker } 342*61046927SAndroid Build Coastguard Worker } 343*61046927SAndroid Build Coastguard Worker 344*61046927SAndroid Build Coastguard Worker impl SimpleLiveness { def_block_ip(&self, ssa: &SSAValue) -> (usize, usize)345*61046927SAndroid Build Coastguard Worker pub fn def_block_ip(&self, ssa: &SSAValue) -> (usize, usize) { 346*61046927SAndroid Build Coastguard Worker *self.ssa_block_ip.get(ssa).unwrap() 347*61046927SAndroid Build Coastguard Worker } 348*61046927SAndroid Build Coastguard Worker interferes(&self, a: &SSAValue, b: &SSAValue) -> bool349*61046927SAndroid Build Coastguard Worker pub fn interferes(&self, a: &SSAValue, b: &SSAValue) -> bool { 350*61046927SAndroid Build Coastguard Worker let (ab, ai) = self.def_block_ip(a); 351*61046927SAndroid Build Coastguard Worker let (bb, bi) = self.def_block_ip(b); 352*61046927SAndroid Build Coastguard Worker 353*61046927SAndroid Build Coastguard Worker match ab.cmp(&bb).then(ai.cmp(&bi)) { 354*61046927SAndroid Build Coastguard Worker Ordering::Equal => true, 355*61046927SAndroid Build Coastguard Worker Ordering::Less => self.block_live(bb).is_live_after_ip(a, bi), 356*61046927SAndroid Build Coastguard Worker Ordering::Greater => self.block_live(ab).is_live_after_ip(b, ai), 357*61046927SAndroid Build Coastguard Worker } 358*61046927SAndroid Build Coastguard Worker } 359*61046927SAndroid Build Coastguard Worker } 360*61046927SAndroid Build Coastguard Worker 361*61046927SAndroid Build Coastguard Worker impl Liveness for SimpleLiveness { 362*61046927SAndroid Build Coastguard Worker type PerBlock = SimpleBlockLiveness; 363*61046927SAndroid Build Coastguard Worker block_live(&self, idx: usize) -> &SimpleBlockLiveness364*61046927SAndroid Build Coastguard Worker fn block_live(&self, idx: usize) -> &SimpleBlockLiveness { 365*61046927SAndroid Build Coastguard Worker &self.blocks[idx] 366*61046927SAndroid Build Coastguard Worker } 367*61046927SAndroid Build Coastguard Worker } 368*61046927SAndroid Build Coastguard Worker 369*61046927SAndroid Build Coastguard Worker struct SSAUseDef { 370*61046927SAndroid Build Coastguard Worker defined: bool, 371*61046927SAndroid Build Coastguard Worker uses: Vec<usize>, 372*61046927SAndroid Build Coastguard Worker } 373*61046927SAndroid Build Coastguard Worker 374*61046927SAndroid Build Coastguard Worker impl SSAUseDef { add_def(&mut self)375*61046927SAndroid Build Coastguard Worker fn add_def(&mut self) { 376*61046927SAndroid Build Coastguard Worker self.defined = true; 377*61046927SAndroid Build Coastguard Worker } 378*61046927SAndroid Build Coastguard Worker add_in_block_use(&mut self, use_ip: usize)379*61046927SAndroid Build Coastguard Worker fn add_in_block_use(&mut self, use_ip: usize) { 380*61046927SAndroid Build Coastguard Worker self.uses.push(use_ip); 381*61046927SAndroid Build Coastguard Worker } 382*61046927SAndroid Build Coastguard Worker add_successor_use( &mut self, num_block_instrs: usize, use_ip: usize, ) -> bool383*61046927SAndroid Build Coastguard Worker fn add_successor_use( 384*61046927SAndroid Build Coastguard Worker &mut self, 385*61046927SAndroid Build Coastguard Worker num_block_instrs: usize, 386*61046927SAndroid Build Coastguard Worker use_ip: usize, 387*61046927SAndroid Build Coastguard Worker ) -> bool { 388*61046927SAndroid Build Coastguard Worker // IPs are relative to the start of their block 389*61046927SAndroid Build Coastguard Worker let use_ip = num_block_instrs + use_ip; 390*61046927SAndroid Build Coastguard Worker 391*61046927SAndroid Build Coastguard Worker if let Some(last_use_ip) = self.uses.last_mut() { 392*61046927SAndroid Build Coastguard Worker if *last_use_ip < num_block_instrs { 393*61046927SAndroid Build Coastguard Worker // We've never seen a successor use before 394*61046927SAndroid Build Coastguard Worker self.uses.push(use_ip); 395*61046927SAndroid Build Coastguard Worker true 396*61046927SAndroid Build Coastguard Worker } else if *last_use_ip > use_ip { 397*61046927SAndroid Build Coastguard Worker // Otherwise, we want the minimum next use 398*61046927SAndroid Build Coastguard Worker *last_use_ip = use_ip; 399*61046927SAndroid Build Coastguard Worker true 400*61046927SAndroid Build Coastguard Worker } else { 401*61046927SAndroid Build Coastguard Worker false 402*61046927SAndroid Build Coastguard Worker } 403*61046927SAndroid Build Coastguard Worker } else { 404*61046927SAndroid Build Coastguard Worker self.uses.push(use_ip); 405*61046927SAndroid Build Coastguard Worker true 406*61046927SAndroid Build Coastguard Worker } 407*61046927SAndroid Build Coastguard Worker } 408*61046927SAndroid Build Coastguard Worker } 409*61046927SAndroid Build Coastguard Worker 410*61046927SAndroid Build Coastguard Worker pub struct NextUseBlockLiveness { 411*61046927SAndroid Build Coastguard Worker num_instrs: usize, 412*61046927SAndroid Build Coastguard Worker ssa_map: HashMap<SSAValue, SSAUseDef>, 413*61046927SAndroid Build Coastguard Worker } 414*61046927SAndroid Build Coastguard Worker 415*61046927SAndroid Build Coastguard Worker impl NextUseBlockLiveness { new(num_instrs: usize) -> Self416*61046927SAndroid Build Coastguard Worker fn new(num_instrs: usize) -> Self { 417*61046927SAndroid Build Coastguard Worker Self { 418*61046927SAndroid Build Coastguard Worker num_instrs: num_instrs, 419*61046927SAndroid Build Coastguard Worker ssa_map: HashMap::new(), 420*61046927SAndroid Build Coastguard Worker } 421*61046927SAndroid Build Coastguard Worker } 422*61046927SAndroid Build Coastguard Worker entry_mut(&mut self, ssa: SSAValue) -> &mut SSAUseDef423*61046927SAndroid Build Coastguard Worker fn entry_mut(&mut self, ssa: SSAValue) -> &mut SSAUseDef { 424*61046927SAndroid Build Coastguard Worker self.ssa_map.entry(ssa).or_insert_with(|| SSAUseDef { 425*61046927SAndroid Build Coastguard Worker defined: false, 426*61046927SAndroid Build Coastguard Worker uses: Vec::new(), 427*61046927SAndroid Build Coastguard Worker }) 428*61046927SAndroid Build Coastguard Worker } 429*61046927SAndroid Build Coastguard Worker add_def(&mut self, ssa: SSAValue)430*61046927SAndroid Build Coastguard Worker fn add_def(&mut self, ssa: SSAValue) { 431*61046927SAndroid Build Coastguard Worker self.entry_mut(ssa).add_def(); 432*61046927SAndroid Build Coastguard Worker } 433*61046927SAndroid Build Coastguard Worker add_use(&mut self, ssa: SSAValue, ip: usize)434*61046927SAndroid Build Coastguard Worker fn add_use(&mut self, ssa: SSAValue, ip: usize) { 435*61046927SAndroid Build Coastguard Worker self.entry_mut(ssa).add_in_block_use(ip); 436*61046927SAndroid Build Coastguard Worker } 437*61046927SAndroid Build Coastguard Worker 438*61046927SAndroid Build Coastguard Worker /// Returns an iterator over all the values which are live-in to this block iter_live_in(&self) -> impl Iterator<Item = &SSAValue>439*61046927SAndroid Build Coastguard Worker pub fn iter_live_in(&self) -> impl Iterator<Item = &SSAValue> { 440*61046927SAndroid Build Coastguard Worker self.ssa_map.iter().filter_map(|(ssa, entry)| { 441*61046927SAndroid Build Coastguard Worker if entry.defined || entry.uses.is_empty() { 442*61046927SAndroid Build Coastguard Worker None 443*61046927SAndroid Build Coastguard Worker } else { 444*61046927SAndroid Build Coastguard Worker Some(ssa) 445*61046927SAndroid Build Coastguard Worker } 446*61046927SAndroid Build Coastguard Worker }) 447*61046927SAndroid Build Coastguard Worker } 448*61046927SAndroid Build Coastguard Worker 449*61046927SAndroid Build Coastguard Worker /// Returns the IP of the first use of @val 450*61046927SAndroid Build Coastguard Worker /// 451*61046927SAndroid Build Coastguard Worker /// The returned IP is relative to the start of this block. If the next use 452*61046927SAndroid Build Coastguard Worker /// is in some successor block, the returned IP is relative to the start of 453*61046927SAndroid Build Coastguard Worker /// this block. If @val is not used in this block and is not live-out, None 454*61046927SAndroid Build Coastguard Worker /// is returned. first_use(&self, val: &SSAValue) -> Option<usize>455*61046927SAndroid Build Coastguard Worker pub fn first_use(&self, val: &SSAValue) -> Option<usize> { 456*61046927SAndroid Build Coastguard Worker if let Some(entry) = self.ssa_map.get(val) { 457*61046927SAndroid Build Coastguard Worker entry.uses.first().cloned() 458*61046927SAndroid Build Coastguard Worker } else { 459*61046927SAndroid Build Coastguard Worker None 460*61046927SAndroid Build Coastguard Worker } 461*61046927SAndroid Build Coastguard Worker } 462*61046927SAndroid Build Coastguard Worker 463*61046927SAndroid Build Coastguard Worker /// Returns the IP of the first use of @val which is greater than or equal 464*61046927SAndroid Build Coastguard Worker /// to @ip 465*61046927SAndroid Build Coastguard Worker /// 466*61046927SAndroid Build Coastguard Worker /// All IPs are relative to the start of the block. If the next use is some 467*61046927SAndroid Build Coastguard Worker /// successor block, the returned IP is relative to the start of this block. next_use_after_or_at_ip( &self, val: &SSAValue, ip: usize, ) -> Option<usize>468*61046927SAndroid Build Coastguard Worker pub fn next_use_after_or_at_ip( 469*61046927SAndroid Build Coastguard Worker &self, 470*61046927SAndroid Build Coastguard Worker val: &SSAValue, 471*61046927SAndroid Build Coastguard Worker ip: usize, 472*61046927SAndroid Build Coastguard Worker ) -> Option<usize> { 473*61046927SAndroid Build Coastguard Worker if let Some(entry) = self.ssa_map.get(val) { 474*61046927SAndroid Build Coastguard Worker let i = entry.uses.partition_point(|u| *u < ip); 475*61046927SAndroid Build Coastguard Worker if i < entry.uses.len() { 476*61046927SAndroid Build Coastguard Worker Some(entry.uses[i]) 477*61046927SAndroid Build Coastguard Worker } else { 478*61046927SAndroid Build Coastguard Worker None 479*61046927SAndroid Build Coastguard Worker } 480*61046927SAndroid Build Coastguard Worker } else { 481*61046927SAndroid Build Coastguard Worker None 482*61046927SAndroid Build Coastguard Worker } 483*61046927SAndroid Build Coastguard Worker } 484*61046927SAndroid Build Coastguard Worker } 485*61046927SAndroid Build Coastguard Worker 486*61046927SAndroid Build Coastguard Worker impl BlockLiveness for NextUseBlockLiveness { is_live_after_ip(&self, val: &SSAValue, ip: usize) -> bool487*61046927SAndroid Build Coastguard Worker fn is_live_after_ip(&self, val: &SSAValue, ip: usize) -> bool { 488*61046927SAndroid Build Coastguard Worker if let Some(entry) = self.ssa_map.get(val) { 489*61046927SAndroid Build Coastguard Worker if let Some(last_use_ip) = entry.uses.last() { 490*61046927SAndroid Build Coastguard Worker *last_use_ip > ip 491*61046927SAndroid Build Coastguard Worker } else { 492*61046927SAndroid Build Coastguard Worker false 493*61046927SAndroid Build Coastguard Worker } 494*61046927SAndroid Build Coastguard Worker } else { 495*61046927SAndroid Build Coastguard Worker false 496*61046927SAndroid Build Coastguard Worker } 497*61046927SAndroid Build Coastguard Worker } 498*61046927SAndroid Build Coastguard Worker is_live_in(&self, val: &SSAValue) -> bool499*61046927SAndroid Build Coastguard Worker fn is_live_in(&self, val: &SSAValue) -> bool { 500*61046927SAndroid Build Coastguard Worker if let Some(entry) = self.ssa_map.get(val) { 501*61046927SAndroid Build Coastguard Worker !entry.defined && !entry.uses.is_empty() 502*61046927SAndroid Build Coastguard Worker } else { 503*61046927SAndroid Build Coastguard Worker false 504*61046927SAndroid Build Coastguard Worker } 505*61046927SAndroid Build Coastguard Worker } 506*61046927SAndroid Build Coastguard Worker is_live_out(&self, val: &SSAValue) -> bool507*61046927SAndroid Build Coastguard Worker fn is_live_out(&self, val: &SSAValue) -> bool { 508*61046927SAndroid Build Coastguard Worker if let Some(entry) = self.ssa_map.get(val) { 509*61046927SAndroid Build Coastguard Worker if let Some(last_use_ip) = entry.uses.last() { 510*61046927SAndroid Build Coastguard Worker *last_use_ip >= self.num_instrs 511*61046927SAndroid Build Coastguard Worker } else { 512*61046927SAndroid Build Coastguard Worker false 513*61046927SAndroid Build Coastguard Worker } 514*61046927SAndroid Build Coastguard Worker } else { 515*61046927SAndroid Build Coastguard Worker false 516*61046927SAndroid Build Coastguard Worker } 517*61046927SAndroid Build Coastguard Worker } 518*61046927SAndroid Build Coastguard Worker } 519*61046927SAndroid Build Coastguard Worker 520*61046927SAndroid Build Coastguard Worker /// An implementation of Liveness that tracks next-use IPs for each SSAValue 521*61046927SAndroid Build Coastguard Worker /// 522*61046927SAndroid Build Coastguard Worker /// Along with the usual liveness information, this tracks next-use IPs for each 523*61046927SAndroid Build Coastguard Worker /// SSAValue. Cross-block next-use IPs computed are as per the global next-use 524*61046927SAndroid Build Coastguard Worker /// distance algorithm described in "Register Spilling and Live-Range Splitting 525*61046927SAndroid Build Coastguard Worker /// for SSA-Form Programs" by Braun and Hack. 526*61046927SAndroid Build Coastguard Worker pub struct NextUseLiveness { 527*61046927SAndroid Build Coastguard Worker blocks: Vec<NextUseBlockLiveness>, 528*61046927SAndroid Build Coastguard Worker } 529*61046927SAndroid Build Coastguard Worker 530*61046927SAndroid Build Coastguard Worker impl NextUseLiveness { for_function( func: &Function, files: &RegFileSet, ) -> NextUseLiveness531*61046927SAndroid Build Coastguard Worker pub fn for_function( 532*61046927SAndroid Build Coastguard Worker func: &Function, 533*61046927SAndroid Build Coastguard Worker files: &RegFileSet, 534*61046927SAndroid Build Coastguard Worker ) -> NextUseLiveness { 535*61046927SAndroid Build Coastguard Worker let mut blocks = Vec::new(); 536*61046927SAndroid Build Coastguard Worker for (bi, b) in func.blocks.iter().enumerate() { 537*61046927SAndroid Build Coastguard Worker let mut bl = NextUseBlockLiveness::new(b.instrs.len()); 538*61046927SAndroid Build Coastguard Worker 539*61046927SAndroid Build Coastguard Worker for (ip, instr) in b.instrs.iter().enumerate() { 540*61046927SAndroid Build Coastguard Worker instr.for_each_ssa_use(|ssa| { 541*61046927SAndroid Build Coastguard Worker if files.contains(ssa.file()) { 542*61046927SAndroid Build Coastguard Worker bl.add_use(*ssa, ip); 543*61046927SAndroid Build Coastguard Worker } 544*61046927SAndroid Build Coastguard Worker }); 545*61046927SAndroid Build Coastguard Worker 546*61046927SAndroid Build Coastguard Worker instr.for_each_ssa_def(|ssa| { 547*61046927SAndroid Build Coastguard Worker if files.contains(ssa.file()) { 548*61046927SAndroid Build Coastguard Worker bl.add_def(*ssa); 549*61046927SAndroid Build Coastguard Worker } 550*61046927SAndroid Build Coastguard Worker }); 551*61046927SAndroid Build Coastguard Worker } 552*61046927SAndroid Build Coastguard Worker 553*61046927SAndroid Build Coastguard Worker debug_assert!(bi == blocks.len()); 554*61046927SAndroid Build Coastguard Worker blocks.push(RefCell::new(bl)); 555*61046927SAndroid Build Coastguard Worker } 556*61046927SAndroid Build Coastguard Worker 557*61046927SAndroid Build Coastguard Worker let mut to_do = true; 558*61046927SAndroid Build Coastguard Worker while to_do { 559*61046927SAndroid Build Coastguard Worker to_do = false; 560*61046927SAndroid Build Coastguard Worker for (b_idx, b) in func.blocks.iter().enumerate().rev() { 561*61046927SAndroid Build Coastguard Worker let num_instrs = b.instrs.len(); 562*61046927SAndroid Build Coastguard Worker let mut bl = blocks[b_idx].borrow_mut(); 563*61046927SAndroid Build Coastguard Worker 564*61046927SAndroid Build Coastguard Worker // Compute live-out 565*61046927SAndroid Build Coastguard Worker for sb_idx in func.blocks.succ_indices(b_idx) { 566*61046927SAndroid Build Coastguard Worker if *sb_idx == b_idx { 567*61046927SAndroid Build Coastguard Worker for entry in bl.ssa_map.values_mut() { 568*61046927SAndroid Build Coastguard Worker if entry.defined { 569*61046927SAndroid Build Coastguard Worker continue; 570*61046927SAndroid Build Coastguard Worker } 571*61046927SAndroid Build Coastguard Worker 572*61046927SAndroid Build Coastguard Worker let Some(first_use_ip) = entry.uses.first() else { 573*61046927SAndroid Build Coastguard Worker continue; 574*61046927SAndroid Build Coastguard Worker }; 575*61046927SAndroid Build Coastguard Worker 576*61046927SAndroid Build Coastguard Worker to_do |= entry 577*61046927SAndroid Build Coastguard Worker .add_successor_use(num_instrs, *first_use_ip); 578*61046927SAndroid Build Coastguard Worker } 579*61046927SAndroid Build Coastguard Worker } else { 580*61046927SAndroid Build Coastguard Worker let sbl = blocks[*sb_idx].borrow(); 581*61046927SAndroid Build Coastguard Worker for (ssa, entry) in sbl.ssa_map.iter() { 582*61046927SAndroid Build Coastguard Worker if entry.defined { 583*61046927SAndroid Build Coastguard Worker continue; 584*61046927SAndroid Build Coastguard Worker } 585*61046927SAndroid Build Coastguard Worker 586*61046927SAndroid Build Coastguard Worker let Some(first_use_ip) = entry.uses.first() else { 587*61046927SAndroid Build Coastguard Worker continue; 588*61046927SAndroid Build Coastguard Worker }; 589*61046927SAndroid Build Coastguard Worker 590*61046927SAndroid Build Coastguard Worker to_do |= bl 591*61046927SAndroid Build Coastguard Worker .entry_mut(*ssa) 592*61046927SAndroid Build Coastguard Worker .add_successor_use(num_instrs, *first_use_ip); 593*61046927SAndroid Build Coastguard Worker } 594*61046927SAndroid Build Coastguard Worker } 595*61046927SAndroid Build Coastguard Worker } 596*61046927SAndroid Build Coastguard Worker } 597*61046927SAndroid Build Coastguard Worker } 598*61046927SAndroid Build Coastguard Worker 599*61046927SAndroid Build Coastguard Worker NextUseLiveness { 600*61046927SAndroid Build Coastguard Worker blocks: blocks.into_iter().map(|bl| bl.into_inner()).collect(), 601*61046927SAndroid Build Coastguard Worker } 602*61046927SAndroid Build Coastguard Worker } 603*61046927SAndroid Build Coastguard Worker } 604*61046927SAndroid Build Coastguard Worker 605*61046927SAndroid Build Coastguard Worker impl Liveness for NextUseLiveness { 606*61046927SAndroid Build Coastguard Worker type PerBlock = NextUseBlockLiveness; 607*61046927SAndroid Build Coastguard Worker block_live(&self, idx: usize) -> &NextUseBlockLiveness608*61046927SAndroid Build Coastguard Worker fn block_live(&self, idx: usize) -> &NextUseBlockLiveness { 609*61046927SAndroid Build Coastguard Worker &self.blocks[idx] 610*61046927SAndroid Build Coastguard Worker } 611*61046927SAndroid Build Coastguard Worker } 612