// Copyright 2017 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! A nice wrapper to consume dataflow results at several CFG //! locations. use rustc::mir::{BasicBlock, Location}; use rustc_data_structures::indexed_set::{self, IdxSetBuf}; use rustc_data_structures::indexed_vec::Idx; use dataflow::{BitDenotation, BlockSets, DataflowResults}; use dataflow::move_paths::{HasMoveData, MovePathIndex}; /// A trait for "cartesian products" of multiple FlowAtLocation. /// /// There's probably a way to auto-impl this, but I think /// it is cleaner to have manual visitor impls. pub trait FlowsAtLocation { // reset the state bitvector to represent the entry to block `bb`. fn reset_to_entry_of(&mut self, bb: BasicBlock); // build gen + kill sets for statement at `loc`. fn reconstruct_statement_effect(&mut self, loc: Location); // build gen + kill sets for terminator for `loc`. fn reconstruct_terminator_effect(&mut self, loc: Location); // apply current gen + kill sets to `flow_state`. // // (`bb` and `stmt_idx` parameters can be ignored if desired by // client. For the terminator, the `stmt_idx` will be the number // of statements in the block.) fn apply_local_effect(&mut self, loc: Location); } /// Represents the state of dataflow at a particular /// CFG location, both before and after it is /// executed. pub struct FlowAtLocation where BD: BitDenotation, { base_results: DataflowResults, curr_state: IdxSetBuf, stmt_gen: IdxSetBuf, stmt_kill: IdxSetBuf, } impl FlowAtLocation where BD: BitDenotation, { pub fn each_state_bit(&self, f: F) where F: FnMut(BD::Idx), { self.curr_state .each_bit(self.base_results.operator().bits_per_block(), f) } pub fn each_gen_bit(&self, f: F) where F: FnMut(BD::Idx), { self.stmt_gen .each_bit(self.base_results.operator().bits_per_block(), f) } pub fn new(results: DataflowResults) -> Self { let bits_per_block = results.sets().bits_per_block(); let curr_state = IdxSetBuf::new_empty(bits_per_block); let stmt_gen = IdxSetBuf::new_empty(bits_per_block); let stmt_kill = IdxSetBuf::new_empty(bits_per_block); FlowAtLocation { base_results: results, curr_state: curr_state, stmt_gen: stmt_gen, stmt_kill: stmt_kill, } } pub fn operator(&self) -> &BD { self.base_results.operator() } pub fn contains(&self, x: &BD::Idx) -> bool { self.curr_state.contains(x) } pub fn elems_incoming(&self) -> indexed_set::Elems { let univ = self.base_results.sets().bits_per_block(); self.curr_state.elems(univ) } pub fn with_elems_outgoing(&self, f: F) where F: FnOnce(indexed_set::Elems), { let mut curr_state = self.curr_state.clone(); curr_state.union(&self.stmt_gen); curr_state.subtract(&self.stmt_kill); let univ = self.base_results.sets().bits_per_block(); f(curr_state.elems(univ)); } } impl FlowsAtLocation for FlowAtLocation where BD: BitDenotation { fn reset_to_entry_of(&mut self, bb: BasicBlock) { (*self.curr_state).clone_from(self.base_results.sets().on_entry_set_for(bb.index())); } fn reconstruct_statement_effect(&mut self, loc: Location) { self.stmt_gen.reset_to_empty(); self.stmt_kill.reset_to_empty(); let mut ignored = IdxSetBuf::new_empty(0); let mut sets = BlockSets { on_entry: &mut ignored, gen_set: &mut self.stmt_gen, kill_set: &mut self.stmt_kill, }; self.base_results .operator() .statement_effect(&mut sets, loc); } fn reconstruct_terminator_effect(&mut self, loc: Location) { self.stmt_gen.reset_to_empty(); self.stmt_kill.reset_to_empty(); let mut ignored = IdxSetBuf::new_empty(0); let mut sets = BlockSets { on_entry: &mut ignored, gen_set: &mut self.stmt_gen, kill_set: &mut self.stmt_kill, }; self.base_results .operator() .terminator_effect(&mut sets, loc); } fn apply_local_effect(&mut self, _loc: Location) { self.curr_state.union(&self.stmt_gen); self.curr_state.subtract(&self.stmt_kill); } } impl<'tcx, T> FlowAtLocation where T: HasMoveData<'tcx> + BitDenotation, { pub fn has_any_child_of(&self, mpi: T::Idx) -> Option { let move_data = self.operator().move_data(); let mut todo = vec![mpi]; let mut push_siblings = false; // don't look at siblings of original `mpi`. while let Some(mpi) = todo.pop() { if self.contains(&mpi) { return Some(mpi); } let move_path = &move_data.move_paths[mpi]; if let Some(child) = move_path.first_child { todo.push(child); } if push_siblings { if let Some(sibling) = move_path.next_sibling { todo.push(sibling); } } else { // after we've processed the original `mpi`, we should // always traverse the siblings of any of its // children. push_siblings = true; } } return None; } }