From 4a8a552b4961d7a1dbc4592902c62d0426b0140f Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Mon, 17 Jun 2019 19:01:16 -0700 Subject: [PATCH] Add DataflowResultsCursor --- src/librustc_mir/dataflow/mod.rs | 94 ++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/src/librustc_mir/dataflow/mod.rs b/src/librustc_mir/dataflow/mod.rs index 80f65a9c8d04..fccd1fdf8f2e 100644 --- a/src/librustc_mir/dataflow/mod.rs +++ b/src/librustc_mir/dataflow/mod.rs @@ -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>, +{ + flow_state: FlowAtLocation<'tcx, BD, DR>, + + // The statement (or terminator) whose effect has been reconstructed in + // flow_state. + curr_loc: Option, + + 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>, +{ + 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(&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>,