Add DataflowResultsCursor

This commit is contained in:
Tyler Mandry 2019-06-17 19:01:16 -07:00
parent 7262e64f53
commit 4a8a552b49

View file

@ -344,6 +344,100 @@ pub(crate) trait DataflowResultsConsumer<'a, 'tcx: 'a> {
fn body(&self) -> &'a Body<'tcx>;
}
/// Allows iterating dataflow results in a flexible and reasonably fast way.
#[derive(Clone)]
pub struct DataflowResultsCursor<'mir, 'tcx, BD, DR>
where
BD: BitDenotation<'tcx>,
DR: Borrow<DataflowResults<'tcx, BD>>,
{
flow_state: FlowAtLocation<'tcx, BD, DR>,
// The statement (or terminator) whose effect has been reconstructed in
// flow_state.
curr_loc: Option<Location>,
body: &'mir Body<'tcx>,
}
pub type DataflowResultsRefCursor<'mir, 'tcx, 'flow, BD> =
DataflowResultsCursor<'mir, 'tcx, BD, &'flow DataflowResults<'tcx, BD>>;
impl<'mir, 'tcx, BD, DR> DataflowResultsCursor<'mir, 'tcx, BD, DR>
where
BD: BitDenotation<'tcx>,
DR: Borrow<DataflowResults<'tcx, BD>>,
{
pub fn new(result: DR, body: &'mir Body<'tcx>) -> Self {
DataflowResultsCursor {
flow_state: FlowAtLocation::new(result),
curr_loc: None,
body,
}
}
/// Seek to the given location in MIR. This method is fast if you are
/// traversing your MIR statements in order.
///
/// After calling `seek`, the current state will reflect all effects up to
/// and including the `before_statement_effect` of the statement at location
/// `loc`. The `statement_effect` of the statement at `loc` will be
/// available as the current effect (see e.g. `each_gen_bit`).
///
/// If `loc.statement_index` equals the number of statements in the block,
/// we will reconstruct the terminator effect in the same way as described
/// above.
pub fn seek(&mut self, loc: Location) {
if self.curr_loc.map(|cur| loc == cur).unwrap_or(false) {
return;
}
let start_index;
let should_reset = match self.curr_loc {
None => true,
Some(cur)
if loc.block != cur.block || loc.statement_index < cur.statement_index => true,
_ => false,
};
if should_reset {
self.flow_state.reset_to_entry_of(loc.block);
start_index = 0;
} else {
let curr_loc = self.curr_loc.unwrap();
start_index = curr_loc.statement_index;
// Apply the effect from the last seek to the current state.
self.flow_state.apply_local_effect(curr_loc);
}
for stmt in start_index..loc.statement_index {
let mut stmt_loc = loc;
stmt_loc.statement_index = stmt;
self.flow_state.reconstruct_statement_effect(stmt_loc);
self.flow_state.apply_local_effect(stmt_loc);
}
if loc.statement_index == self.body[loc.block].statements.len() {
self.flow_state.reconstruct_terminator_effect(loc);
} else {
self.flow_state.reconstruct_statement_effect(loc);
}
self.curr_loc = Some(loc);
}
/// Return whether the current state contains bit `x`.
pub fn contains(&self, x: BD::Idx) -> bool {
self.flow_state.contains(x)
}
/// Iterate over each `gen` bit in the current effect (invoke `seek` first).
pub fn each_gen_bit<F>(&self, f: F)
where
F: FnMut(BD::Idx),
{
self.flow_state.each_gen_bit(f)
}
}
pub fn state_for_location<'tcx, T: BitDenotation<'tcx>>(loc: Location,
analysis: &T,
result: &DataflowResults<'tcx, T>,