]> git.proxmox.com Git - rustc.git/blame - src/librustc_borrowck/dataflow.rs
New upstream version 1.34.2+dfsg1
[rustc.git] / src / librustc_borrowck / dataflow.rs
CommitLineData
1a4d82fc
JJ
1//! A module for propagating forward dataflow information. The analysis
2//! assumes that the items to be propagated can be represented as bits
3//! and thus uses bitvectors. Your job is simply to specify the so-called
4//! GEN and KILL bits for each expression.
970d7e83 5
b7449926
XL
6use rustc::cfg;
7use rustc::cfg::CFGIndex;
8use rustc::ty::TyCtxt;
c34b1796 9use std::io;
9cc50fc6 10use std::mem;
85aaf69f 11use std::usize;
b039eaaf 12use syntax::print::pprust::PrintState;
9fa01778 13use log::debug;
3b2f2976 14
8faf50e0 15use rustc_data_structures::graph::implementation::OUTGOING;
3b2f2976 16
b7449926
XL
17use rustc::util::nodemap::FxHashMap;
18use rustc::hir;
9fa01778 19use rustc::hir::intravisit;
b7449926 20use rustc::hir::print as pprust;
e9174d1e 21
1a4d82fc 22
c34b1796 23#[derive(Copy, Clone, Debug)]
1a4d82fc
JJ
24pub enum EntryOrExit {
25 Entry,
26 Exit,
27}
970d7e83 28
1a4d82fc
JJ
29#[derive(Clone)]
30pub struct DataFlowContext<'a, 'tcx: 'a, O> {
a7813a04 31 tcx: TyCtxt<'a, 'tcx, 'tcx>,
1a4d82fc
JJ
32
33 /// a name for the analysis using this dataflow instance
34 analysis_name: &'static str,
970d7e83
LB
35
36 /// the data flow operator
1a4d82fc 37 oper: O,
970d7e83
LB
38
39 /// number of bits to propagate per id
c34b1796 40 bits_per_id: usize,
970d7e83
LB
41
42 /// number of words we will use to store bits_per_id.
85aaf69f 43 /// equal to bits_per_id/usize::BITS rounded up.
c34b1796 44 words_per_id: usize,
970d7e83 45
1a4d82fc
JJ
46 // mapping from node to cfg node index
47 // FIXME (#6298): Shouldn't this go with CFG?
ea8adc8c 48 local_id_to_index: FxHashMap<hir::ItemLocalId, Vec<CFGIndex>>,
970d7e83 49
1a4d82fc 50 // Bit sets per cfg node. The following three fields (`gens`, `kills`,
970d7e83
LB
51 // and `on_entry`) all have the same structure. For each id in
52 // `id_range`, there is a range of words equal to `words_per_id`.
53 // So, to access the bits for any given id, you take a slice of
54 // the full vector (see the method `compute_id_range()`).
55
1a4d82fc 56 /// bits generated as we exit the cfg node. Updated by `add_gen()`.
c34b1796 57 gens: Vec<usize>,
970d7e83 58
9346a6ac
AL
59 /// bits killed as we exit the cfg node, or non-locally jump over
60 /// it. Updated by `add_kill(KillFrom::ScopeEnd)`.
61 scope_kills: Vec<usize>,
62
63 /// bits killed as we exit the cfg node directly; if it is jumped
0731742a 64 /// over, e.g., via `break`, the kills are not reflected in the
9346a6ac
AL
65 /// jump's effects. Updated by `add_kill(KillFrom::Execution)`.
66 action_kills: Vec<usize>,
970d7e83 67
1a4d82fc 68 /// bits that are valid on entry to the cfg node. Updated by
970d7e83 69 /// `propagate()`.
c34b1796 70 on_entry: Vec<usize>,
1a4d82fc
JJ
71}
72
73pub trait BitwiseOperator {
74 /// Joins two predecessor bits together, typically either `|` or `&`
c34b1796 75 fn join(&self, succ: usize, pred: usize) -> usize;
970d7e83
LB
76}
77
78/// Parameterization for the precise form of data flow that is used.
1a4d82fc 79pub trait DataFlowOperator : BitwiseOperator {
970d7e83
LB
80 /// Specifies the initial value for each bit in the `on_entry` set
81 fn initial_value(&self) -> bool;
1a4d82fc 82}
970d7e83 83
9fa01778 84struct PropagationContext<'a, 'b: 'a, 'tcx: 'b, O> {
1a4d82fc
JJ
85 dfcx: &'a mut DataFlowContext<'b, 'tcx, O>,
86 changed: bool
87}
970d7e83 88
ea8adc8c
XL
89fn get_cfg_indices<'a>(id: hir::ItemLocalId,
90 index: &'a FxHashMap<hir::ItemLocalId, Vec<CFGIndex>>)
91 -> &'a [CFGIndex] {
92 index.get(&id).map_or(&[], |v| &v[..])
970d7e83
LB
93}
94
1a4d82fc 95impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
ea8adc8c
XL
96 fn has_bitset_for_local_id(&self, n: hir::ItemLocalId) -> bool {
97 assert!(n != hir::DUMMY_ITEM_LOCAL_ID);
98 self.local_id_to_index.contains_key(&n)
1a4d82fc 99 }
970d7e83
LB
100}
101
1a4d82fc 102impl<'a, 'tcx, O:DataFlowOperator> pprust::PpAnn for DataFlowContext<'a, 'tcx, O> {
9fa01778 103 fn nested(&self, state: &mut pprust::State<'_>, nested: pprust::Nested) -> io::Result<()> {
0731742a 104 pprust::PpAnn::nested(self.tcx.hir(), state, nested)
32a655c1 105 }
1a4d82fc 106 fn pre(&self,
9fa01778
XL
107 ps: &mut pprust::State<'_>,
108 node: pprust::AnnNode<'_>) -> io::Result<()> {
1a4d82fc 109 let id = match node {
b7449926
XL
110 pprust::AnnNode::Name(_) => return Ok(()),
111 pprust::AnnNode::Expr(expr) => expr.hir_id.local_id,
112 pprust::AnnNode::Block(blk) => blk.hir_id.local_id,
113 pprust::AnnNode::Item(_) |
114 pprust::AnnNode::SubItem(_) => return Ok(()),
115 pprust::AnnNode::Pat(pat) => pat.hir_id.local_id
1a4d82fc
JJ
116 };
117
ea8adc8c 118 if !self.has_bitset_for_local_id(id) {
c34b1796
AL
119 return Ok(());
120 }
121
122 assert!(self.bits_per_id > 0);
ea8adc8c 123 let indices = get_cfg_indices(id, &self.local_id_to_index);
c34b1796 124 for &cfgidx in indices {
1a4d82fc 125 let (start, end) = self.compute_id_range(cfgidx);
85aaf69f 126 let on_entry = &self.on_entry[start.. end];
1a4d82fc
JJ
127 let entry_str = bits_to_string(on_entry);
128
85aaf69f 129 let gens = &self.gens[start.. end];
1a4d82fc
JJ
130 let gens_str = if gens.iter().any(|&u| u != 0) {
131 format!(" gen: {}", bits_to_string(gens))
132 } else {
b7449926 133 String::new()
1a4d82fc
JJ
134 };
135
9346a6ac
AL
136 let action_kills = &self.action_kills[start .. end];
137 let action_kills_str = if action_kills.iter().any(|&u| u != 0) {
138 format!(" action_kill: {}", bits_to_string(action_kills))
139 } else {
b7449926 140 String::new()
9346a6ac
AL
141 };
142
143 let scope_kills = &self.scope_kills[start .. end];
144 let scope_kills_str = if scope_kills.iter().any(|&u| u != 0) {
145 format!(" scope_kill: {}", bits_to_string(scope_kills))
1a4d82fc 146 } else {
b7449926 147 String::new()
1a4d82fc 148 };
970d7e83 149
54a0048b 150 ps.synth_comment(
ea8adc8c 151 format!("id {}: {}{}{}{}", id.as_usize(), entry_str,
54a0048b 152 gens_str, action_kills_str, scope_kills_str))?;
041b39d2 153 ps.s.space()?;
1a4d82fc
JJ
154 }
155 Ok(())
156 }
970d7e83
LB
157}
158
ea8adc8c
XL
159fn build_local_id_to_index(body: Option<&hir::Body>,
160 cfg: &cfg::CFG)
161 -> FxHashMap<hir::ItemLocalId, Vec<CFGIndex>> {
0bf4aa26 162 let mut index = FxHashMap::default();
1a4d82fc 163
abe05a73 164 // FIXME(#15020) Would it be better to fold formals from decl
0731742a 165 // into cfg itself? i.e., introduce a fn-based flow-graph in
1a4d82fc
JJ
166 // addition to the current block-based flow-graph, rather than
167 // have to put traversals like this here?
32a655c1
SL
168 if let Some(body) = body {
169 add_entries_from_fn_body(&mut index, body, cfg.entry);
1a4d82fc
JJ
170 }
171
172 cfg.graph.each_node(|node_idx, node| {
c34b1796 173 if let cfg::CFGNodeData::AST(id) = node.data {
b7449926 174 index.entry(id).or_default().push(node_idx);
1a4d82fc
JJ
175 }
176 true
177 });
178
179 return index;
180
9fa01778 181 /// Adds mappings from the ast nodes for the formal bindings to
32a655c1 182 /// the entry-node in the graph.
ea8adc8c 183 fn add_entries_from_fn_body(index: &mut FxHashMap<hir::ItemLocalId, Vec<CFGIndex>>,
32a655c1 184 body: &hir::Body,
1a4d82fc 185 entry: CFGIndex) {
b7449926 186 use rustc::hir::intravisit::Visitor;
32a655c1 187
1a4d82fc
JJ
188 struct Formals<'a> {
189 entry: CFGIndex,
ea8adc8c 190 index: &'a mut FxHashMap<hir::ItemLocalId, Vec<CFGIndex>>,
1a4d82fc
JJ
191 }
192 let mut formals = Formals { entry: entry, index: index };
32a655c1
SL
193 for arg in &body.arguments {
194 formals.visit_pat(&arg.pat);
195 }
196 impl<'a, 'v> Visitor<'v> for Formals<'a> {
476ff2be 197 fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'v> {
32a655c1 198 intravisit::NestedVisitorMap::None
476ff2be
SL
199 }
200
e9174d1e 201 fn visit_pat(&mut self, p: &hir::Pat) {
b7449926 202 self.index.entry(p.hir_id.local_id).or_default().push(self.entry);
92a42be0 203 intravisit::walk_pat(self, p)
1a4d82fc
JJ
204 }
205 }
206 }
970d7e83
LB
207}
208
9346a6ac
AL
209/// Flag used by `add_kill` to indicate whether the provided kill
210/// takes effect only when control flows directly through the node in
211/// question, or if the kill's effect is associated with any
212/// control-flow directly through or indirectly over the node.
213#[derive(Copy, Clone, PartialEq, Debug)]
214pub enum KillFrom {
215 /// A `ScopeEnd` kill is one that takes effect when any control
216 /// flow goes over the node. A kill associated with the end of the
217 /// scope of a variable declaration `let x;` is an example of a
218 /// `ScopeEnd` kill.
219 ScopeEnd,
220
221 /// An `Execution` kill is one that takes effect only when control
222 /// flow goes through the node to completion. A kill associated
223 /// with an assignment statement `x = expr;` is an example of an
224 /// `Execution` kill.
225 Execution,
226}
227
1a4d82fc 228impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
a7813a04 229 pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
1a4d82fc 230 analysis_name: &'static str,
32a655c1 231 body: Option<&hir::Body>,
1a4d82fc 232 cfg: &cfg::CFG,
970d7e83 233 oper: O,
c34b1796 234 bits_per_id: usize) -> DataFlowContext<'a, 'tcx, O> {
9cc50fc6
SL
235 let usize_bits = mem::size_of::<usize>() * 8;
236 let words_per_id = (bits_per_id + usize_bits - 1) / usize_bits;
1a4d82fc
JJ
237 let num_nodes = cfg.graph.all_nodes().len();
238
9fa01778 239 debug!("DataFlowContext::new(analysis_name: {}, \
1a4d82fc
JJ
240 bits_per_id={}, words_per_id={}) \
241 num_nodes: {}",
9fa01778 242 analysis_name, bits_per_id, words_per_id,
1a4d82fc 243 num_nodes);
970d7e83 244
85aaf69f 245 let entry = if oper.initial_value() { usize::MAX } else {0};
970d7e83 246
c1a9b12d
SL
247 let zeroes = vec![0; num_nodes * words_per_id];
248 let gens = zeroes.clone();
249 let kills1 = zeroes.clone();
250 let kills2 = zeroes;
251 let on_entry = vec![entry; num_nodes * words_per_id];
1a4d82fc 252
ea8adc8c 253 let local_id_to_index = build_local_id_to_index(body, cfg);
970d7e83
LB
254
255 DataFlowContext {
041b39d2
XL
256 tcx,
257 analysis_name,
258 words_per_id,
ea8adc8c 259 local_id_to_index,
041b39d2
XL
260 bits_per_id,
261 oper,
262 gens,
9346a6ac
AL
263 action_kills: kills1,
264 scope_kills: kills2,
041b39d2 265 on_entry,
970d7e83
LB
266 }
267 }
268
ea8adc8c 269 pub fn add_gen(&mut self, id: hir::ItemLocalId, bit: usize) {
970d7e83 270 //! Indicates that `id` generates `bit`
ea8adc8c 271 debug!("{} add_gen(id={:?}, bit={})",
1a4d82fc 272 self.analysis_name, id, bit);
ea8adc8c 273 assert!(self.local_id_to_index.contains_key(&id));
1a4d82fc 274 assert!(self.bits_per_id > 0);
970d7e83 275
ea8adc8c 276 let indices = get_cfg_indices(id, &self.local_id_to_index);
c34b1796
AL
277 for &cfgidx in indices {
278 let (start, end) = self.compute_id_range(cfgidx);
279 let gens = &mut self.gens[start.. end];
280 set_bit(gens, bit);
281 }
970d7e83
LB
282 }
283
ea8adc8c 284 pub fn add_kill(&mut self, kind: KillFrom, id: hir::ItemLocalId, bit: usize) {
970d7e83 285 //! Indicates that `id` kills `bit`
ea8adc8c 286 debug!("{} add_kill(id={:?}, bit={})",
1a4d82fc 287 self.analysis_name, id, bit);
ea8adc8c 288 assert!(self.local_id_to_index.contains_key(&id));
1a4d82fc 289 assert!(self.bits_per_id > 0);
970d7e83 290
ea8adc8c 291 let indices = get_cfg_indices(id, &self.local_id_to_index);
c34b1796
AL
292 for &cfgidx in indices {
293 let (start, end) = self.compute_id_range(cfgidx);
9346a6ac
AL
294 let kills = match kind {
295 KillFrom::Execution => &mut self.action_kills[start.. end],
296 KillFrom::ScopeEnd => &mut self.scope_kills[start.. end],
297 };
c34b1796
AL
298 set_bit(kills, bit);
299 }
970d7e83
LB
300 }
301
c34b1796 302 fn apply_gen_kill(&self, cfgidx: CFGIndex, bits: &mut [usize]) {
1a4d82fc
JJ
303 //! Applies the gen and kill sets for `cfgidx` to `bits`
304 debug!("{} apply_gen_kill(cfgidx={:?}, bits={}) [before]",
305 self.analysis_name, cfgidx, mut_bits_to_string(bits));
306 assert!(self.bits_per_id > 0);
970d7e83 307
1a4d82fc 308 let (start, end) = self.compute_id_range(cfgidx);
85aaf69f 309 let gens = &self.gens[start.. end];
1a4d82fc 310 bitwise(bits, gens, &Union);
9346a6ac
AL
311 let kills = &self.action_kills[start.. end];
312 bitwise(bits, kills, &Subtract);
313 let kills = &self.scope_kills[start.. end];
1a4d82fc 314 bitwise(bits, kills, &Subtract);
970d7e83 315
1a4d82fc
JJ
316 debug!("{} apply_gen_kill(cfgidx={:?}, bits={}) [after]",
317 self.analysis_name, cfgidx, mut_bits_to_string(bits));
970d7e83
LB
318 }
319
c34b1796 320 fn compute_id_range(&self, cfgidx: CFGIndex) -> (usize, usize) {
1a4d82fc 321 let n = cfgidx.node_id();
970d7e83
LB
322 let start = n * self.words_per_id;
323 let end = start + self.words_per_id;
970d7e83
LB
324
325 assert!(start < self.gens.len());
326 assert!(end <= self.gens.len());
9346a6ac
AL
327 assert!(self.gens.len() == self.action_kills.len());
328 assert!(self.gens.len() == self.scope_kills.len());
970d7e83
LB
329 assert!(self.gens.len() == self.on_entry.len());
330
331 (start, end)
332 }
333
334
ea8adc8c 335 pub fn each_bit_on_entry<F>(&self, id: hir::ItemLocalId, mut f: F) -> bool where
c34b1796 336 F: FnMut(usize) -> bool,
1a4d82fc 337 {
970d7e83
LB
338 //! Iterates through each bit that is set on entry to `id`.
339 //! Only useful after `propagate()` has been called.
ea8adc8c 340 if !self.has_bitset_for_local_id(id) {
970d7e83
LB
341 return true;
342 }
ea8adc8c 343 let indices = get_cfg_indices(id, &self.local_id_to_index);
c34b1796 344 for &cfgidx in indices {
92a42be0 345 if !self.each_bit_for_node(EntryOrExit::Entry, cfgidx, |i| f(i)) {
c34b1796
AL
346 return false;
347 }
348 }
349 return true;
970d7e83
LB
350 }
351
1a4d82fc 352 pub fn each_bit_for_node<F>(&self, e: EntryOrExit, cfgidx: CFGIndex, f: F) -> bool where
c34b1796 353 F: FnMut(usize) -> bool,
1a4d82fc
JJ
354 {
355 //! Iterates through each bit that is set on entry/exit to `cfgidx`.
970d7e83
LB
356 //! Only useful after `propagate()` has been called.
357
1a4d82fc
JJ
358 if self.bits_per_id == 0 {
359 // Skip the surprisingly common degenerate case. (Note
360 // compute_id_range requires self.words_per_id > 0.)
361 return true;
362 }
363
364 let (start, end) = self.compute_id_range(cfgidx);
85aaf69f 365 let on_entry = &self.on_entry[start.. end];
1a4d82fc
JJ
366 let temp_bits;
367 let slice = match e {
92a42be0
SL
368 EntryOrExit::Entry => on_entry,
369 EntryOrExit::Exit => {
1a4d82fc 370 let mut t = on_entry.to_vec();
85aaf69f 371 self.apply_gen_kill(cfgidx, &mut t);
1a4d82fc 372 temp_bits = t;
85aaf69f 373 &temp_bits[..]
1a4d82fc
JJ
374 }
375 };
376 debug!("{} each_bit_for_node({:?}, cfgidx={:?}) bits={}",
377 self.analysis_name, e, cfgidx, bits_to_string(slice));
378 self.each_bit(slice, f)
970d7e83
LB
379 }
380
ea8adc8c 381 pub fn each_gen_bit<F>(&self, id: hir::ItemLocalId, mut f: F) -> bool where
c34b1796 382 F: FnMut(usize) -> bool,
1a4d82fc 383 {
970d7e83 384 //! Iterates through each bit in the gen set for `id`.
ea8adc8c 385 if !self.has_bitset_for_local_id(id) {
1a4d82fc
JJ
386 return true;
387 }
970d7e83 388
1a4d82fc
JJ
389 if self.bits_per_id == 0 {
390 // Skip the surprisingly common degenerate case. (Note
391 // compute_id_range requires self.words_per_id > 0.)
970d7e83
LB
392 return true;
393 }
1a4d82fc 394
ea8adc8c 395 let indices = get_cfg_indices(id, &self.local_id_to_index);
c34b1796
AL
396 for &cfgidx in indices {
397 let (start, end) = self.compute_id_range(cfgidx);
398 let gens = &self.gens[start.. end];
ea8adc8c 399 debug!("{} each_gen_bit(id={:?}, gens={})",
c34b1796
AL
400 self.analysis_name, id, bits_to_string(gens));
401 if !self.each_bit(gens, |i| f(i)) {
402 return false;
403 }
404 }
405 return true;
970d7e83
LB
406 }
407
c34b1796
AL
408 fn each_bit<F>(&self, words: &[usize], mut f: F) -> bool where
409 F: FnMut(usize) -> bool,
1a4d82fc 410 {
970d7e83 411 //! Helper for iterating over the bits in a bit set.
1a4d82fc
JJ
412 //! Returns false on the first call to `f` that returns false;
413 //! if all calls to `f` return true, then returns true.
970d7e83 414
9cc50fc6 415 let usize_bits = mem::size_of::<usize>() * 8;
1a4d82fc 416 for (word_index, &word) in words.iter().enumerate() {
970d7e83 417 if word != 0 {
9cc50fc6
SL
418 let base_index = word_index * usize_bits;
419 for offset in 0..usize_bits {
970d7e83
LB
420 let bit = 1 << offset;
421 if (word & bit) != 0 {
0731742a 422 // N.B., we round up the total number of bits
970d7e83 423 // that we store in any given bit set so that
85aaf69f 424 // it is an even multiple of usize::BITS. This
970d7e83
LB
425 // means that there may be some stray bits at
426 // the end that do not correspond to any
427 // actual value. So before we callback, check
428 // whether the bit_index is greater than the
429 // actual value the user specified and stop
430 // iterating if so.
c34b1796 431 let bit_index = base_index + offset as usize;
970d7e83
LB
432 if bit_index >= self.bits_per_id {
433 return true;
434 } else if !f(bit_index) {
435 return false;
436 }
437 }
438 }
439 }
440 }
441 return true;
442 }
970d7e83 443
1a4d82fc
JJ
444 pub fn add_kills_from_flow_exits(&mut self, cfg: &cfg::CFG) {
445 //! Whenever you have a `break` or `continue` statement, flow
446 //! exits through any number of enclosing scopes on its way to
447 //! the new destination. This function infers the kill bits of
448 //! those control operators based on the kill bits associated
449 //! with those scopes.
450 //!
451 //! This is usually called (if it is called at all), after
452 //! all add_gen and add_kill calls, but before propagate.
970d7e83 453
1a4d82fc 454 debug!("{} add_kills_from_flow_exits", self.analysis_name);
970d7e83 455 if self.bits_per_id == 0 {
1a4d82fc
JJ
456 // Skip the surprisingly common degenerate case. (Note
457 // compute_id_range requires self.words_per_id > 0.)
970d7e83
LB
458 return;
459 }
1a4d82fc
JJ
460 cfg.graph.each_edge(|_edge_index, edge| {
461 let flow_exit = edge.source();
462 let (start, end) = self.compute_id_range(flow_exit);
9346a6ac 463 let mut orig_kills = self.scope_kills[start.. end].to_vec();
1a4d82fc
JJ
464
465 let mut changed = false;
ea8adc8c
XL
466 for &id in &edge.data.exiting_scopes {
467 let opt_cfg_idx = self.local_id_to_index.get(&id);
1a4d82fc 468 match opt_cfg_idx {
c34b1796
AL
469 Some(indices) => {
470 for &cfg_idx in indices {
471 let (start, end) = self.compute_id_range(cfg_idx);
9346a6ac 472 let kills = &self.scope_kills[start.. end];
c34b1796 473 if bitwise(&mut orig_kills, kills, &Union) {
ea8adc8c 474 debug!("scope exits: scope id={:?} \
9346a6ac 475 (node={:?} of {:?}) added killset: {}",
ea8adc8c 476 id, cfg_idx, indices,
9346a6ac 477 bits_to_string(kills));
c34b1796
AL
478 changed = true;
479 }
1a4d82fc 480 }
970d7e83 481 }
1a4d82fc
JJ
482 None => {
483 debug!("{} add_kills_from_flow_exits flow_exit={:?} \
ea8adc8c
XL
484 no cfg_idx for exiting_scope={:?}",
485 self.analysis_name, flow_exit, id);
970d7e83
LB
486 }
487 }
970d7e83
LB
488 }
489
1a4d82fc 490 if changed {
9346a6ac 491 let bits = &mut self.scope_kills[start.. end];
1a4d82fc
JJ
492 debug!("{} add_kills_from_flow_exits flow_exit={:?} bits={} [before]",
493 self.analysis_name, flow_exit, mut_bits_to_string(bits));
7453a54e 494 bits.copy_from_slice(&orig_kills[..]);
1a4d82fc
JJ
495 debug!("{} add_kills_from_flow_exits flow_exit={:?} bits={} [after]",
496 self.analysis_name, flow_exit, mut_bits_to_string(bits));
970d7e83 497 }
1a4d82fc
JJ
498 true
499 });
500 }
501}
970d7e83 502
1a4d82fc
JJ
503impl<'a, 'tcx, O:DataFlowOperator+Clone+'static> DataFlowContext<'a, 'tcx, O> {
504// ^^^^^^^^^^^^^ only needed for pretty printing
32a655c1 505 pub fn propagate(&mut self, cfg: &cfg::CFG, body: &hir::Body) {
1a4d82fc 506 //! Performs the data flow analysis.
970d7e83 507
1a4d82fc
JJ
508 if self.bits_per_id == 0 {
509 // Optimize the surprisingly common degenerate case.
510 return;
970d7e83
LB
511 }
512
1a4d82fc
JJ
513 {
514 let words_per_id = self.words_per_id;
515 let mut propcx = PropagationContext {
516 dfcx: &mut *self,
517 changed: true
518 };
970d7e83 519
3b2f2976 520 let nodes_po = cfg.graph.nodes_in_postorder(OUTGOING, cfg.entry);
c1a9b12d 521 let mut temp = vec![0; words_per_id];
3b2f2976 522 let mut num_passes = 0;
1a4d82fc 523 while propcx.changed {
3b2f2976 524 num_passes += 1;
1a4d82fc 525 propcx.changed = false;
85aaf69f 526 propcx.reset(&mut temp);
3b2f2976 527 propcx.walk_cfg(cfg, &nodes_po, &mut temp);
970d7e83 528 }
3b2f2976 529 debug!("finished in {} iterations", num_passes);
970d7e83 530 }
970d7e83 531
1a4d82fc 532 debug!("Dataflow result for {}:", self.analysis_name);
32a655c1
SL
533 debug!("{}", pprust::to_string(self, |s| {
534 s.cbox(pprust::indent_unit)?;
535 s.ibox(0)?;
536 s.print_expr(&body.value)
537 }));
970d7e83 538 }
1a4d82fc 539}
970d7e83 540
1a4d82fc
JJ
541impl<'a, 'b, 'tcx, O:DataFlowOperator> PropagationContext<'a, 'b, 'tcx, O> {
542 fn walk_cfg(&mut self,
543 cfg: &cfg::CFG,
3b2f2976 544 nodes_po: &[CFGIndex],
c34b1796 545 in_out: &mut [usize]) {
1a4d82fc
JJ
546 debug!("DataFlowContext::walk_cfg(in_out={}) {}",
547 bits_to_string(in_out), self.dfcx.analysis_name);
548 assert!(self.dfcx.bits_per_id > 0);
970d7e83 549
3b2f2976
XL
550 // Iterate over nodes in reverse postorder
551 for &node_index in nodes_po.iter().rev() {
552 let node = cfg.graph.node(node_index);
ea8adc8c 553 debug!("DataFlowContext::walk_cfg idx={:?} id={:?} begin in_out={}",
c34b1796 554 node_index, node.data.id(), bits_to_string(in_out));
970d7e83 555
1a4d82fc 556 let (start, end) = self.dfcx.compute_id_range(node_index);
970d7e83 557
1a4d82fc 558 // Initialize local bitvector with state on-entry.
7453a54e 559 in_out.copy_from_slice(&self.dfcx.on_entry[start.. end]);
970d7e83 560
1a4d82fc
JJ
561 // Compute state on-exit by applying transfer function to
562 // state on-entry.
563 self.dfcx.apply_gen_kill(node_index, in_out);
970d7e83 564
1a4d82fc
JJ
565 // Propagate state on-exit from node into its successors.
566 self.propagate_bits_into_graph_successors_of(in_out, cfg, node_index);
3b2f2976 567 }
970d7e83
LB
568 }
569
c34b1796 570 fn reset(&mut self, bits: &mut [usize]) {
85aaf69f
SL
571 let e = if self.dfcx.oper.initial_value() {usize::MAX} else {0};
572 for b in bits {
1a4d82fc
JJ
573 *b = e;
574 }
970d7e83
LB
575 }
576
1a4d82fc 577 fn propagate_bits_into_graph_successors_of(&mut self,
c34b1796 578 pred_bits: &[usize],
1a4d82fc
JJ
579 cfg: &cfg::CFG,
580 cfgidx: CFGIndex) {
d9579d0f 581 for (_, edge) in cfg.graph.outgoing_edges(cfgidx) {
1a4d82fc 582 self.propagate_bits_into_entry_set_for(pred_bits, edge);
d9579d0f 583 }
970d7e83
LB
584 }
585
1a4d82fc 586 fn propagate_bits_into_entry_set_for(&mut self,
c34b1796 587 pred_bits: &[usize],
1a4d82fc
JJ
588 edge: &cfg::CFGEdge) {
589 let source = edge.source();
590 let cfgidx = edge.target();
591 debug!("{} propagate_bits_into_entry_set_for(pred_bits={}, {:?} to {:?})",
592 self.dfcx.analysis_name, bits_to_string(pred_bits), source, cfgidx);
593 assert!(self.dfcx.bits_per_id > 0);
594
595 let (start, end) = self.dfcx.compute_id_range(cfgidx);
596 let changed = {
597 // (scoping mutable borrow of self.dfcx.on_entry)
85aaf69f 598 let on_entry = &mut self.dfcx.on_entry[start.. end];
1a4d82fc 599 bitwise(on_entry, pred_bits, &self.dfcx.oper)
970d7e83
LB
600 };
601 if changed {
1a4d82fc
JJ
602 debug!("{} changed entry set for {:?} to {}",
603 self.dfcx.analysis_name, cfgidx,
85aaf69f 604 bits_to_string(&self.dfcx.on_entry[start.. end]));
970d7e83
LB
605 self.changed = true;
606 }
607 }
608}
609
c34b1796 610fn mut_bits_to_string(words: &mut [usize]) -> String {
1a4d82fc 611 bits_to_string(words)
970d7e83
LB
612}
613
c34b1796 614fn bits_to_string(words: &[usize]) -> String {
1a4d82fc 615 let mut result = String::new();
970d7e83
LB
616 let mut sep = '[';
617
618 // Note: this is a little endian printout of bytes.
619
85aaf69f 620 for &word in words {
970d7e83 621 let mut v = word;
9cc50fc6 622 for _ in 0..mem::size_of::<usize>() {
1a4d82fc 623 result.push(sep);
c34b1796 624 result.push_str(&format!("{:02x}", v & 0xFF));
970d7e83
LB
625 v >>= 8;
626 sep = '-';
627 }
628 }
1a4d82fc
JJ
629 result.push(']');
630 return result
970d7e83
LB
631}
632
633#[inline]
c34b1796
AL
634fn bitwise<Op:BitwiseOperator>(out_vec: &mut [usize],
635 in_vec: &[usize],
1a4d82fc 636 op: &Op) -> bool {
970d7e83
LB
637 assert_eq!(out_vec.len(), in_vec.len());
638 let mut changed = false;
62682a34 639 for (out_elt, in_elt) in out_vec.iter_mut().zip(in_vec) {
1a4d82fc
JJ
640 let old_val = *out_elt;
641 let new_val = op.join(old_val, *in_elt);
642 *out_elt = new_val;
643 changed |= old_val != new_val;
970d7e83 644 }
1a4d82fc 645 changed
970d7e83
LB
646}
647
c34b1796 648fn set_bit(words: &mut [usize], bit: usize) -> bool {
1a4d82fc
JJ
649 debug!("set_bit: words={} bit={}",
650 mut_bits_to_string(words), bit_str(bit));
9cc50fc6
SL
651 let usize_bits = mem::size_of::<usize>() * 8;
652 let word = bit / usize_bits;
653 let bit_in_word = bit % usize_bits;
970d7e83 654 let bit_mask = 1 << bit_in_word;
54a0048b 655 debug!("word={} bit_in_word={} bit_mask={}", word, bit_in_word, bit_mask);
970d7e83
LB
656 let oldv = words[word];
657 let newv = oldv | bit_mask;
658 words[word] = newv;
659 oldv != newv
660}
661
c34b1796 662fn bit_str(bit: usize) -> String {
3157f602
XL
663 let byte = bit >> 3;
664 let lobits = 1 << (bit & 0b111);
1a4d82fc 665 format!("[{}:{}-{:02x}]", bit, byte, lobits)
970d7e83
LB
666}
667
1a4d82fc
JJ
668struct Union;
669impl BitwiseOperator for Union {
c34b1796 670 fn join(&self, a: usize, b: usize) -> usize { a | b }
1a4d82fc
JJ
671}
672struct Subtract;
673impl BitwiseOperator for Subtract {
c34b1796 674 fn join(&self, a: usize, b: usize) -> usize { a & !b }
970d7e83 675}