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,
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>;