1 // Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! A nice wrapper to consume dataflow results at several CFG
14 use rustc::mir::{BasicBlock, Location};
15 use rustc_data_structures::bitvec::BitIter;
16 use rustc_data_structures::indexed_set::{HybridIdxSet, IdxSet};
18 use dataflow::{BitDenotation, BlockSets, DataflowResults};
19 use dataflow::move_paths::{HasMoveData, MovePathIndex};
23 /// A trait for "cartesian products" of multiple FlowAtLocation.
25 /// There's probably a way to auto-impl this, but I think
26 /// it is cleaner to have manual visitor impls.
27 pub trait FlowsAtLocation {
28 /// Reset the state bitvector to represent the entry to block `bb`.
29 fn reset_to_entry_of(&mut self, bb: BasicBlock);
31 /// Reset the state bitvector to represent the exit of the
32 /// terminator of block `bb`.
34 /// **Important:** In the case of a `Call` terminator, these
35 /// effects do *not* include the result of storing the destination
36 /// of the call, since that is edge-dependent (in other words, the
37 /// effects don't apply to the unwind edge).
38 fn reset_to_exit_of(&mut self, bb: BasicBlock);
40 /// Build gen + kill sets for statement at `loc`.
42 /// Note that invoking this method alone does not change the
43 /// `curr_state` -- you must invoke `apply_local_effect`
45 fn reconstruct_statement_effect(&mut self, loc: Location);
47 /// Build gen + kill sets for terminator for `loc`.
49 /// Note that invoking this method alone does not change the
50 /// `curr_state` -- you must invoke `apply_local_effect`
52 fn reconstruct_terminator_effect(&mut self, loc: Location);
54 /// Apply current gen + kill sets to `flow_state`.
56 /// (`loc` parameters can be ignored if desired by
57 /// client. For the terminator, the `stmt_idx` will be the number
58 /// of statements in the block.)
59 fn apply_local_effect(&mut self, loc: Location);
62 /// Represents the state of dataflow at a particular
63 /// CFG location, both before and after it is
66 /// Data flow results are typically computed only as basic block
67 /// boundaries. A `FlowInProgress` allows you to reconstruct the
68 /// effects at any point in the control-flow graph by starting with
69 /// the state at the start of the basic block (`reset_to_entry_of`)
70 /// and then replaying the effects of statements and terminators
71 /// (e.g. via `reconstruct_statement_effect` and
72 /// `reconstruct_terminator_effect`; don't forget to call
73 /// `apply_local_effect`).
74 pub struct FlowAtLocation<BD>
78 base_results: DataflowResults<BD>,
79 curr_state: IdxSet<BD::Idx>,
80 stmt_gen: HybridIdxSet<BD::Idx>,
81 stmt_kill: HybridIdxSet<BD::Idx>,
84 impl<BD> FlowAtLocation<BD>
88 /// Iterate over each bit set in the current state.
89 pub fn each_state_bit<F>(&self, f: F)
93 self.curr_state.iter().for_each(f)
96 /// Iterate over each `gen` bit in the current effect (invoke
97 /// `reconstruct_statement_effect` or
98 /// `reconstruct_terminator_effect` first).
99 pub fn each_gen_bit<F>(&self, f: F)
103 self.stmt_gen.iter().for_each(f)
106 pub fn new(results: DataflowResults<BD>) -> Self {
107 let bits_per_block = results.sets().bits_per_block();
108 let curr_state = IdxSet::new_empty(bits_per_block);
109 let stmt_gen = HybridIdxSet::new_empty(bits_per_block);
110 let stmt_kill = HybridIdxSet::new_empty(bits_per_block);
112 base_results: results,
113 curr_state: curr_state,
115 stmt_kill: stmt_kill,
119 /// Access the underlying operator.
120 pub fn operator(&self) -> &BD {
121 self.base_results.operator()
124 pub fn contains(&self, x: &BD::Idx) -> bool {
125 self.curr_state.contains(x)
128 /// Returns an iterator over the elements present in the current state.
129 pub fn iter_incoming(&self) -> iter::Peekable<BitIter<BD::Idx>> {
130 self.curr_state.iter().peekable()
133 /// Creates a clone of the current state and applies the local
134 /// effects to the clone (leaving the state of self intact).
135 /// Invokes `f` with an iterator over the resulting state.
136 pub fn with_iter_outgoing<F>(&self, f: F)
138 F: FnOnce(BitIter<BD::Idx>),
140 let mut curr_state = self.curr_state.clone();
141 curr_state.union(&self.stmt_gen);
142 curr_state.subtract(&self.stmt_kill);
143 f(curr_state.iter());
147 impl<BD> FlowsAtLocation for FlowAtLocation<BD>
148 where BD: BitDenotation
150 fn reset_to_entry_of(&mut self, bb: BasicBlock) {
151 self.curr_state.overwrite(self.base_results.sets().on_entry_set_for(bb.index()));
154 fn reset_to_exit_of(&mut self, bb: BasicBlock) {
155 self.reset_to_entry_of(bb);
156 self.curr_state.union(self.base_results.sets().gen_set_for(bb.index()));
157 self.curr_state.subtract(self.base_results.sets().kill_set_for(bb.index()));
160 fn reconstruct_statement_effect(&mut self, loc: Location) {
161 self.stmt_gen.clear();
162 self.stmt_kill.clear();
164 let mut sets = BlockSets {
165 on_entry: &mut self.curr_state,
166 gen_set: &mut self.stmt_gen,
167 kill_set: &mut self.stmt_kill,
171 .before_statement_effect(&mut sets, loc);
173 self.apply_local_effect(loc);
175 let mut sets = BlockSets {
176 on_entry: &mut self.curr_state,
177 gen_set: &mut self.stmt_gen,
178 kill_set: &mut self.stmt_kill,
182 .statement_effect(&mut sets, loc);
185 fn reconstruct_terminator_effect(&mut self, loc: Location) {
186 self.stmt_gen.clear();
187 self.stmt_kill.clear();
189 let mut sets = BlockSets {
190 on_entry: &mut self.curr_state,
191 gen_set: &mut self.stmt_gen,
192 kill_set: &mut self.stmt_kill,
196 .before_terminator_effect(&mut sets, loc);
198 self.apply_local_effect(loc);
200 let mut sets = BlockSets {
201 on_entry: &mut self.curr_state,
202 gen_set: &mut self.stmt_gen,
203 kill_set: &mut self.stmt_kill,
207 .terminator_effect(&mut sets, loc);
210 fn apply_local_effect(&mut self, _loc: Location) {
211 self.curr_state.union(&self.stmt_gen);
212 self.curr_state.subtract(&self.stmt_kill);
217 impl<'tcx, T> FlowAtLocation<T>
219 T: HasMoveData<'tcx> + BitDenotation<Idx = MovePathIndex>,
221 pub fn has_any_child_of(&self, mpi: T::Idx) -> Option<T::Idx> {
222 // We process `mpi` before the loop below, for two reasons:
223 // - it's a little different from the loop case (we don't traverse its
225 // - ~99% of the time the loop isn't reached, and this code is hot, so
226 // we don't want to allocate `todo` unnecessarily.
227 if self.contains(&mpi) {
230 let move_data = self.operator().move_data();
231 let move_path = &move_data.move_paths[mpi];
232 let mut todo = if let Some(child) = move_path.first_child {
238 while let Some(mpi) = todo.pop() {
239 if self.contains(&mpi) {
242 let move_path = &move_data.move_paths[mpi];
243 if let Some(child) = move_path.first_child {
246 // After we've processed the original `mpi`, we should always
247 // traverse the siblings of any of its children.
248 if let Some(sibling) = move_path.next_sibling {