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