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