reorder liveness to bring the more significant code up top

This commit is contained in:
Niko Matsakis 2017-10-24 15:39:08 -04:00
parent 899c7ad9b2
commit cb56ff5a77

View file

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