From cb56ff5a775a8915d2e79cd8c8a0f2992f1a561d Mon Sep 17 00:00:00 2001 From: Niko Matsakis <niko@alum.mit.edu> Date: Tue, 24 Oct 2017 15:39:08 -0400 Subject: [PATCH] reorder liveness to bring the more significant code up top --- src/librustc_mir/util/liveness.rs | 214 +++++++++++++++--------------- 1 file changed, 107 insertions(+), 107 deletions(-) diff --git a/src/librustc_mir/util/liveness.rs b/src/librustc_mir/util/liveness.rs index df7ba3c62fa..514ff2ab830 100644 --- a/src/librustc_mir/util/liveness.rs +++ b/src/librustc_mir/util/liveness.rs @@ -47,6 +47,113 @@ use std::io::{self, Write}; pub type LocalSet = IdxSetBuf<Local>; +// This gives the result of the liveness analysis at the boundary of basic blocks +pub struct LivenessResult { + pub ins: IndexVec<BasicBlock, LocalSet>, + pub outs: IndexVec<BasicBlock, LocalSet>, +} + +pub fn liveness_of_locals<'tcx>(mir: &Mir<'tcx>) -> LivenessResult { + let locals = mir.local_decls.len(); + let def_use: IndexVec<_, _> = mir.basic_blocks().iter().map(|b| { + block(b, locals) + }).collect(); + + let mut ins: IndexVec<_, _> = mir.basic_blocks() + .indices() + .map(|_| LocalSet::new_empty(locals)) + .collect(); + let mut outs = ins.clone(); + + let mut changed = true; + let mut bits = LocalSet::new_empty(locals); + while changed { + changed = false; + + for b in mir.basic_blocks().indices().rev() { + // outs[b] = ∪ {ins of successors} + bits.clear(); + for &successor in mir.basic_blocks()[b].terminator().successors().into_iter() { + bits.union(&ins[successor]); + } + outs[b].clone_from(&bits); + + // bits = use ∪ (bits - def) + def_use[b].apply(&mut bits); + + // update bits on entry and flag if they have changed + if ins[b] != bits { + ins[b].clone_from(&bits); + changed = true; + } + } + } + + LivenessResult { + ins, + outs, + } +} + +impl LivenessResult { + /// Walks backwards through the statements/terminator in the given + /// basic block `block`. At each point within `block`, invokes + /// the callback `op` with the current location and the set of + /// variables that are live on entry to that location. + pub fn simulate_block<'tcx, OP>(&self, + mir: &Mir<'tcx>, + block: BasicBlock, + mut callback: OP) + where OP: FnMut(Location, &LocalSet) + { + let data = &mir[block]; + + // Get a copy of the bits on exit from the block. + let mut bits = self.outs[block].clone(); + + // Start with the maximal statement index -- i.e., right before + // the terminator executes. + let mut statement_index = data.statements.len(); + + // Compute liveness right before terminator and invoke callback. + let terminator_location = Location { block, statement_index }; + let terminator_defs_uses = self.defs_uses(mir, terminator_location, &data.terminator); + terminator_defs_uses.apply(&mut bits); + callback(terminator_location, &bits); + + // Compute liveness before each statement (in rev order) and invoke callback. + for statement in data.statements.iter().rev() { + statement_index -= 1; + let statement_location = Location { block, statement_index }; + let statement_defs_uses = self.defs_uses(mir, statement_location, statement); + statement_defs_uses.apply(&mut bits); + callback(statement_location, &bits); + } + + assert_eq!(bits, self.ins[block]); + } + + fn defs_uses<'tcx, V>(&self, + mir: &Mir<'tcx>, + location: Location, + thing: &V) + -> DefsUses + where V: MirVisitable<'tcx>, + { + let locals = mir.local_decls.len(); + let mut visitor = DefsUses { + defs: LocalSet::new_empty(locals), + uses: LocalSet::new_empty(locals), + }; + + // Visit the various parts of the basic block in reverse. If we go + // forward, the logic in `add_def` and `add_use` would be wrong. + thing.apply(location, &mut visitor); + + visitor + } +} + #[derive(Eq, PartialEq, Clone)] struct DefsUses { defs: LocalSet, @@ -159,113 +266,6 @@ fn block<'tcx>(b: &BasicBlockData<'tcx>, locals: usize) -> DefsUses { visitor } -// This gives the result of the liveness analysis at the boundary of basic blocks -pub struct LivenessResult { - pub ins: IndexVec<BasicBlock, LocalSet>, - pub outs: IndexVec<BasicBlock, LocalSet>, -} - -pub fn liveness_of_locals<'tcx>(mir: &Mir<'tcx>) -> LivenessResult { - let locals = mir.local_decls.len(); - let def_use: IndexVec<_, _> = mir.basic_blocks().iter().map(|b| { - block(b, locals) - }).collect(); - - let mut ins: IndexVec<_, _> = mir.basic_blocks() - .indices() - .map(|_| LocalSet::new_empty(locals)) - .collect(); - let mut outs = ins.clone(); - - let mut changed = true; - let mut bits = LocalSet::new_empty(locals); - while changed { - changed = false; - - for b in mir.basic_blocks().indices().rev() { - // outs[b] = ∪ {ins of successors} - bits.clear(); - for &successor in mir.basic_blocks()[b].terminator().successors().into_iter() { - bits.union(&ins[successor]); - } - outs[b].clone_from(&bits); - - // bits = use ∪ (bits - def) - def_use[b].apply(&mut bits); - - // update bits on entry and flag if they have changed - if ins[b] != bits { - ins[b].clone_from(&bits); - changed = true; - } - } - } - - LivenessResult { - ins, - outs, - } -} - -impl LivenessResult { - /// Walks backwards through the statements/terminator in the given - /// basic block `block`. At each point within `block`, invokes - /// the callback `op` with the current location and the set of - /// variables that are live on entry to that location. - pub fn simulate_block<'tcx, OP>(&self, - mir: &Mir<'tcx>, - block: BasicBlock, - mut callback: OP) - where OP: FnMut(Location, &LocalSet) - { - let data = &mir[block]; - - // Get a copy of the bits on exit from the block. - let mut bits = self.outs[block].clone(); - - // Start with the maximal statement index -- i.e., right before - // the terminator executes. - let mut statement_index = data.statements.len(); - - // Compute liveness right before terminator and invoke callback. - let terminator_location = Location { block, statement_index }; - let terminator_defs_uses = self.defs_uses(mir, terminator_location, &data.terminator); - terminator_defs_uses.apply(&mut bits); - callback(terminator_location, &bits); - - // Compute liveness before each statement (in rev order) and invoke callback. - for statement in data.statements.iter().rev() { - statement_index -= 1; - let statement_location = Location { block, statement_index }; - let statement_defs_uses = self.defs_uses(mir, statement_location, statement); - statement_defs_uses.apply(&mut bits); - callback(statement_location, &bits); - } - - assert_eq!(bits, self.ins[block]); - } - - fn defs_uses<'tcx, V>(&self, - mir: &Mir<'tcx>, - location: Location, - thing: &V) - -> DefsUses - where V: MirVisitable<'tcx>, - { - let locals = mir.local_decls.len(); - let mut visitor = DefsUses { - defs: LocalSet::new_empty(locals), - uses: LocalSet::new_empty(locals), - }; - - // Visit the various parts of the basic block in reverse. If we go - // forward, the logic in `add_def` and `add_use` would be wrong. - thing.apply(location, &mut visitor); - - visitor - } -} - trait MirVisitable<'tcx> { fn apply<V>(&self, location: Location, visitor: &mut V) where V: Visitor<'tcx>;