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.
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.
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.
17 pub use self::EntryOrExit
::*;
20 use middle
::cfg
::CFGIndex
;
24 use std
::iter
::repeat
;
26 use syntax
::ast_util
::IdRange
;
28 use syntax
::print
::{pp, pprust}
;
29 use util
::nodemap
::NodeMap
;
31 #[derive(Copy, Clone, Debug)]
32 pub enum EntryOrExit
{
38 pub struct DataFlowContext
<'a
, 'tcx
: 'a
, O
> {
39 tcx
: &'a ty
::ctxt
<'tcx
>,
41 /// a name for the analysis using this dataflow instance
42 analysis_name
: &'
static str,
44 /// the data flow operator
47 /// number of bits to propagate per id
50 /// number of words we will use to store bits_per_id.
51 /// equal to bits_per_id/usize::BITS rounded up.
54 // mapping from node to cfg node index
55 // FIXME (#6298): Shouldn't this go with CFG?
56 nodeid_to_index
: NodeMap
<Vec
<CFGIndex
>>,
58 // Bit sets per cfg node. The following three fields (`gens`, `kills`,
59 // and `on_entry`) all have the same structure. For each id in
60 // `id_range`, there is a range of words equal to `words_per_id`.
61 // So, to access the bits for any given id, you take a slice of
62 // the full vector (see the method `compute_id_range()`).
64 /// bits generated as we exit the cfg node. Updated by `add_gen()`.
67 /// bits killed as we exit the cfg node, or non-locally jump over
68 /// it. Updated by `add_kill(KillFrom::ScopeEnd)`.
69 scope_kills
: Vec
<usize>,
71 /// bits killed as we exit the cfg node directly; if it is jumped
72 /// over, e.g. via `break`, the kills are not reflected in the
73 /// jump's effects. Updated by `add_kill(KillFrom::Execution)`.
74 action_kills
: Vec
<usize>,
76 /// bits that are valid on entry to the cfg node. Updated by
81 pub trait BitwiseOperator
{
82 /// Joins two predecessor bits together, typically either `|` or `&`
83 fn join(&self, succ
: usize, pred
: usize) -> usize;
86 /// Parameterization for the precise form of data flow that is used.
87 pub trait DataFlowOperator
: BitwiseOperator
{
88 /// Specifies the initial value for each bit in the `on_entry` set
89 fn initial_value(&self) -> bool
;
92 struct PropagationContext
<'a
, 'b
: 'a
, 'tcx
: 'b
, O
: 'a
> {
93 dfcx
: &'a
mut DataFlowContext
<'b
, 'tcx
, O
>,
97 fn get_cfg_indices
<'a
>(id
: ast
::NodeId
, index
: &'a NodeMap
<Vec
<CFGIndex
>>) -> &'a
[CFGIndex
] {
98 let opt_indices
= index
.get(&id
);
99 opt_indices
.map(|v
| &v
[..]).unwrap_or(&[])
102 impl<'a
, 'tcx
, O
:DataFlowOperator
> DataFlowContext
<'a
, 'tcx
, O
> {
103 fn has_bitset_for_nodeid(&self, n
: ast
::NodeId
) -> bool
{
104 assert
!(n
!= ast
::DUMMY_NODE_ID
);
105 self.nodeid_to_index
.contains_key(&n
)
109 impl<'a
, 'tcx
, O
:DataFlowOperator
> pprust
::PpAnn
for DataFlowContext
<'a
, 'tcx
, O
> {
111 ps
: &mut pprust
::State
,
112 node
: pprust
::AnnNode
) -> io
::Result
<()> {
113 let id
= match node
{
114 pprust
::NodeIdent(_
) | pprust
::NodeName(_
) => 0,
115 pprust
::NodeExpr(expr
) => expr
.id
,
116 pprust
::NodeBlock(blk
) => blk
.id
,
117 pprust
::NodeItem(_
) | pprust
::NodeSubItem(_
) => 0,
118 pprust
::NodePat(pat
) => pat
.id
121 if !self.has_bitset_for_nodeid(id
) {
125 assert
!(self.bits_per_id
> 0);
126 let indices
= get_cfg_indices(id
, &self.nodeid_to_index
);
127 for &cfgidx
in indices
{
128 let (start
, end
) = self.compute_id_range(cfgidx
);
129 let on_entry
= &self.on_entry
[start
.. end
];
130 let entry_str
= bits_to_string(on_entry
);
132 let gens
= &self.gens
[start
.. end
];
133 let gens_str
= if gens
.iter().any(|&u
| u
!= 0) {
134 format
!(" gen: {}", bits_to_string(gens
))
139 let action_kills
= &self.action_kills
[start
.. end
];
140 let action_kills_str
= if action_kills
.iter().any(|&u
| u
!= 0) {
141 format
!(" action_kill: {}", bits_to_string(action_kills
))
146 let scope_kills
= &self.scope_kills
[start
.. end
];
147 let scope_kills_str
= if scope_kills
.iter().any(|&u
| u
!= 0) {
148 format
!(" scope_kill: {}", bits_to_string(scope_kills
))
153 try
!(ps
.synth_comment(
154 format
!("id {}: {}{}{}{}", id
, entry_str
,
155 gens_str
, action_kills_str
, scope_kills_str
)));
156 try
!(pp
::space(&mut ps
.s
));
162 fn build_nodeid_to_index(decl
: Option
<&ast
::FnDecl
>,
163 cfg
: &cfg
::CFG
) -> NodeMap
<Vec
<CFGIndex
>> {
164 let mut index
= NodeMap();
166 // FIXME (#6298): Would it be better to fold formals from decl
167 // into cfg itself? i.e. introduce a fn-based flow-graph in
168 // addition to the current block-based flow-graph, rather than
169 // have to put traversals like this here?
172 Some(decl
) => add_entries_from_fn_decl(&mut index
, decl
, cfg
.entry
)
175 cfg
.graph
.each_node(|node_idx
, node
| {
176 if let cfg
::CFGNodeData
::AST(id
) = node
.data
{
177 index
.entry(id
).or_insert(vec
![]).push(node_idx
);
184 fn add_entries_from_fn_decl(index
: &mut NodeMap
<Vec
<CFGIndex
>>,
187 //! add mappings from the ast nodes for the formal bindings to
188 //! the entry-node in the graph.
191 index
: &'a
mut NodeMap
<Vec
<CFGIndex
>>,
193 let mut formals
= Formals { entry: entry, index: index }
;
194 visit
::walk_fn_decl(&mut formals
, decl
);
195 impl<'a
, 'v
> visit
::Visitor
<'v
> for Formals
<'a
> {
196 fn visit_pat(&mut self, p
: &ast
::Pat
) {
197 self.index
.entry(p
.id
).or_insert(vec
![]).push(self.entry
);
198 visit
::walk_pat(self, p
)
204 /// Flag used by `add_kill` to indicate whether the provided kill
205 /// takes effect only when control flows directly through the node in
206 /// question, or if the kill's effect is associated with any
207 /// control-flow directly through or indirectly over the node.
208 #[derive(Copy, Clone, PartialEq, Debug)]
210 /// A `ScopeEnd` kill is one that takes effect when any control
211 /// flow goes over the node. A kill associated with the end of the
212 /// scope of a variable declaration `let x;` is an example of a
216 /// An `Execution` kill is one that takes effect only when control
217 /// flow goes through the node to completion. A kill associated
218 /// with an assignment statement `x = expr;` is an example of an
219 /// `Execution` kill.
223 impl<'a
, 'tcx
, O
:DataFlowOperator
> DataFlowContext
<'a
, 'tcx
, O
> {
224 pub fn new(tcx
: &'a ty
::ctxt
<'tcx
>,
225 analysis_name
: &'
static str,
226 decl
: Option
<&ast
::FnDecl
>,
230 bits_per_id
: usize) -> DataFlowContext
<'a
, 'tcx
, O
> {
231 let words_per_id
= (bits_per_id
+ usize::BITS
- 1) / usize::BITS
;
232 let num_nodes
= cfg
.graph
.all_nodes().len();
234 debug
!("DataFlowContext::new(analysis_name: {}, id_range={:?}, \
235 bits_per_id={}, words_per_id={}) \
237 analysis_name
, id_range
, bits_per_id
, words_per_id
,
240 let entry
= if oper
.initial_value() { usize::MAX }
else {0}
;
242 let zeroes
: Vec
<_
> = repeat(0).take(num_nodes
* words_per_id
).collect();
243 let gens
: Vec
<_
> = zeroes
.clone();
244 let kills1
: Vec
<_
> = zeroes
.clone();
245 let kills2
: Vec
<_
> = zeroes
;
246 let on_entry
: Vec
<_
> = repeat(entry
).take(num_nodes
* words_per_id
).collect();
248 let nodeid_to_index
= build_nodeid_to_index(decl
, cfg
);
252 analysis_name
: analysis_name
,
253 words_per_id
: words_per_id
,
254 nodeid_to_index
: nodeid_to_index
,
255 bits_per_id
: bits_per_id
,
258 action_kills
: kills1
,
264 pub fn add_gen(&mut self, id
: ast
::NodeId
, bit
: usize) {
265 //! Indicates that `id` generates `bit`
266 debug
!("{} add_gen(id={}, bit={})",
267 self.analysis_name
, id
, bit
);
268 assert
!(self.nodeid_to_index
.contains_key(&id
));
269 assert
!(self.bits_per_id
> 0);
271 let indices
= get_cfg_indices(id
, &self.nodeid_to_index
);
272 for &cfgidx
in indices
{
273 let (start
, end
) = self.compute_id_range(cfgidx
);
274 let gens
= &mut self.gens
[start
.. end
];
279 pub fn add_kill(&mut self, kind
: KillFrom
, id
: ast
::NodeId
, bit
: usize) {
280 //! Indicates that `id` kills `bit`
281 debug
!("{} add_kill(id={}, bit={})",
282 self.analysis_name
, id
, bit
);
283 assert
!(self.nodeid_to_index
.contains_key(&id
));
284 assert
!(self.bits_per_id
> 0);
286 let indices
= get_cfg_indices(id
, &self.nodeid_to_index
);
287 for &cfgidx
in indices
{
288 let (start
, end
) = self.compute_id_range(cfgidx
);
289 let kills
= match kind
{
290 KillFrom
::Execution
=> &mut self.action_kills
[start
.. end
],
291 KillFrom
::ScopeEnd
=> &mut self.scope_kills
[start
.. end
],
297 fn apply_gen_kill(&self, cfgidx
: CFGIndex
, bits
: &mut [usize]) {
298 //! Applies the gen and kill sets for `cfgidx` to `bits`
299 debug
!("{} apply_gen_kill(cfgidx={:?}, bits={}) [before]",
300 self.analysis_name
, cfgidx
, mut_bits_to_string(bits
));
301 assert
!(self.bits_per_id
> 0);
303 let (start
, end
) = self.compute_id_range(cfgidx
);
304 let gens
= &self.gens
[start
.. end
];
305 bitwise(bits
, gens
, &Union
);
306 let kills
= &self.action_kills
[start
.. end
];
307 bitwise(bits
, kills
, &Subtract
);
308 let kills
= &self.scope_kills
[start
.. end
];
309 bitwise(bits
, kills
, &Subtract
);
311 debug
!("{} apply_gen_kill(cfgidx={:?}, bits={}) [after]",
312 self.analysis_name
, cfgidx
, mut_bits_to_string(bits
));
315 fn compute_id_range(&self, cfgidx
: CFGIndex
) -> (usize, usize) {
316 let n
= cfgidx
.node_id();
317 let start
= n
* self.words_per_id
;
318 let end
= start
+ self.words_per_id
;
320 assert
!(start
< self.gens
.len());
321 assert
!(end
<= self.gens
.len());
322 assert
!(self.gens
.len() == self.action_kills
.len());
323 assert
!(self.gens
.len() == self.scope_kills
.len());
324 assert
!(self.gens
.len() == self.on_entry
.len());
330 pub fn each_bit_on_entry
<F
>(&self, id
: ast
::NodeId
, mut f
: F
) -> bool
where
331 F
: FnMut(usize) -> bool
,
333 //! Iterates through each bit that is set on entry to `id`.
334 //! Only useful after `propagate()` has been called.
335 if !self.has_bitset_for_nodeid(id
) {
338 let indices
= get_cfg_indices(id
, &self.nodeid_to_index
);
339 for &cfgidx
in indices
{
340 if !self.each_bit_for_node(Entry
, cfgidx
, |i
| f(i
)) {
347 pub fn each_bit_for_node
<F
>(&self, e
: EntryOrExit
, cfgidx
: CFGIndex
, f
: F
) -> bool
where
348 F
: FnMut(usize) -> bool
,
350 //! Iterates through each bit that is set on entry/exit to `cfgidx`.
351 //! Only useful after `propagate()` has been called.
353 if self.bits_per_id
== 0 {
354 // Skip the surprisingly common degenerate case. (Note
355 // compute_id_range requires self.words_per_id > 0.)
359 let (start
, end
) = self.compute_id_range(cfgidx
);
360 let on_entry
= &self.on_entry
[start
.. end
];
362 let slice
= match e
{
365 let mut t
= on_entry
.to_vec();
366 self.apply_gen_kill(cfgidx
, &mut t
);
371 debug
!("{} each_bit_for_node({:?}, cfgidx={:?}) bits={}",
372 self.analysis_name
, e
, cfgidx
, bits_to_string(slice
));
373 self.each_bit(slice
, f
)
376 pub fn each_gen_bit
<F
>(&self, id
: ast
::NodeId
, mut f
: F
) -> bool
where
377 F
: FnMut(usize) -> bool
,
379 //! Iterates through each bit in the gen set for `id`.
380 if !self.has_bitset_for_nodeid(id
) {
384 if self.bits_per_id
== 0 {
385 // Skip the surprisingly common degenerate case. (Note
386 // compute_id_range requires self.words_per_id > 0.)
390 let indices
= get_cfg_indices(id
, &self.nodeid_to_index
);
391 for &cfgidx
in indices
{
392 let (start
, end
) = self.compute_id_range(cfgidx
);
393 let gens
= &self.gens
[start
.. end
];
394 debug
!("{} each_gen_bit(id={}, gens={})",
395 self.analysis_name
, id
, bits_to_string(gens
));
396 if !self.each_bit(gens
, |i
| f(i
)) {
403 fn each_bit
<F
>(&self, words
: &[usize], mut f
: F
) -> bool
where
404 F
: FnMut(usize) -> bool
,
406 //! Helper for iterating over the bits in a bit set.
407 //! Returns false on the first call to `f` that returns false;
408 //! if all calls to `f` return true, then returns true.
410 for (word_index
, &word
) in words
.iter().enumerate() {
412 let base_index
= word_index
* usize::BITS
;
413 for offset
in 0..usize::BITS
{
414 let bit
= 1 << offset
;
415 if (word
& bit
) != 0 {
416 // NB: we round up the total number of bits
417 // that we store in any given bit set so that
418 // it is an even multiple of usize::BITS. This
419 // means that there may be some stray bits at
420 // the end that do not correspond to any
421 // actual value. So before we callback, check
422 // whether the bit_index is greater than the
423 // actual value the user specified and stop
425 let bit_index
= base_index
+ offset
as usize;
426 if bit_index
>= self.bits_per_id
{
428 } else if !f(bit_index
) {
438 pub fn add_kills_from_flow_exits(&mut self, cfg
: &cfg
::CFG
) {
439 //! Whenever you have a `break` or `continue` statement, flow
440 //! exits through any number of enclosing scopes on its way to
441 //! the new destination. This function infers the kill bits of
442 //! those control operators based on the kill bits associated
443 //! with those scopes.
445 //! This is usually called (if it is called at all), after
446 //! all add_gen and add_kill calls, but before propagate.
448 debug
!("{} add_kills_from_flow_exits", self.analysis_name
);
449 if self.bits_per_id
== 0 {
450 // Skip the surprisingly common degenerate case. (Note
451 // compute_id_range requires self.words_per_id > 0.)
454 cfg
.graph
.each_edge(|_edge_index
, edge
| {
455 let flow_exit
= edge
.source();
456 let (start
, end
) = self.compute_id_range(flow_exit
);
457 let mut orig_kills
= self.scope_kills
[start
.. end
].to_vec();
459 let mut changed
= false;
460 for &node_id
in &edge
.data
.exiting_scopes
{
461 let opt_cfg_idx
= self.nodeid_to_index
.get(&node_id
);
464 for &cfg_idx
in indices
{
465 let (start
, end
) = self.compute_id_range(cfg_idx
);
466 let kills
= &self.scope_kills
[start
.. end
];
467 if bitwise(&mut orig_kills
, kills
, &Union
) {
468 debug
!("scope exits: scope id={} \
469 (node={:?} of {:?}) added killset: {}",
470 node_id
, cfg_idx
, indices
,
471 bits_to_string(kills
));
477 debug
!("{} add_kills_from_flow_exits flow_exit={:?} \
478 no cfg_idx for exiting_scope={}",
479 self.analysis_name
, flow_exit
, node_id
);
485 let bits
= &mut self.scope_kills
[start
.. end
];
486 debug
!("{} add_kills_from_flow_exits flow_exit={:?} bits={} [before]",
487 self.analysis_name
, flow_exit
, mut_bits_to_string(bits
));
488 bits
.clone_from_slice(&orig_kills
[..]);
489 debug
!("{} add_kills_from_flow_exits flow_exit={:?} bits={} [after]",
490 self.analysis_name
, flow_exit
, mut_bits_to_string(bits
));
497 impl<'a
, 'tcx
, O
:DataFlowOperator
+Clone
+'
static> DataFlowContext
<'a
, 'tcx
, O
> {
498 // ^^^^^^^^^^^^^ only needed for pretty printing
499 pub fn propagate(&mut self, cfg
: &cfg
::CFG
, blk
: &ast
::Block
) {
500 //! Performs the data flow analysis.
502 if self.bits_per_id
== 0 {
503 // Optimize the surprisingly common degenerate case.
508 let words_per_id
= self.words_per_id
;
509 let mut propcx
= PropagationContext
{
514 let mut temp
: Vec
<_
> = repeat(0).take(words_per_id
).collect();
515 while propcx
.changed
{
516 propcx
.changed
= false;
517 propcx
.reset(&mut temp
);
518 propcx
.walk_cfg(cfg
, &mut temp
);
522 debug
!("Dataflow result for {}:", self.analysis_name
);
524 let mut v
= Vec
::new();
525 self.pretty_print_to(box &mut v
, blk
).unwrap();
526 println
!("{}", String
::from_utf8(v
).unwrap());
531 fn pretty_print_to
<'b
>(&self, wr
: Box
<io
::Write
+ 'b
>,
532 blk
: &ast
::Block
) -> io
::Result
<()> {
533 let mut ps
= pprust
::rust_printer_annotated(wr
, self);
534 try
!(ps
.cbox(pprust
::indent_unit
));
536 try
!(ps
.print_block(blk
));
541 impl<'a
, 'b
, 'tcx
, O
:DataFlowOperator
> PropagationContext
<'a
, 'b
, 'tcx
, O
> {
542 fn walk_cfg(&mut self,
544 in_out
: &mut [usize]) {
545 debug
!("DataFlowContext::walk_cfg(in_out={}) {}",
546 bits_to_string(in_out
), self.dfcx
.analysis_name
);
547 assert
!(self.dfcx
.bits_per_id
> 0);
549 cfg
.graph
.each_node(|node_index
, node
| {
550 debug
!("DataFlowContext::walk_cfg idx={:?} id={} begin in_out={}",
551 node_index
, node
.data
.id(), bits_to_string(in_out
));
553 let (start
, end
) = self.dfcx
.compute_id_range(node_index
);
555 // Initialize local bitvector with state on-entry.
556 in_out
.clone_from_slice(&self.dfcx
.on_entry
[start
.. end
]);
558 // Compute state on-exit by applying transfer function to
560 self.dfcx
.apply_gen_kill(node_index
, in_out
);
562 // Propagate state on-exit from node into its successors.
563 self.propagate_bits_into_graph_successors_of(in_out
, cfg
, node_index
);
564 true // continue to next node
568 fn reset(&mut self, bits
: &mut [usize]) {
569 let e
= if self.dfcx
.oper
.initial_value() {usize::MAX}
else {0}
;
575 fn propagate_bits_into_graph_successors_of(&mut self,
579 for (_
, edge
) in cfg
.graph
.outgoing_edges(cfgidx
) {
580 self.propagate_bits_into_entry_set_for(pred_bits
, edge
);
584 fn propagate_bits_into_entry_set_for(&mut self,
586 edge
: &cfg
::CFGEdge
) {
587 let source
= edge
.source();
588 let cfgidx
= edge
.target();
589 debug
!("{} propagate_bits_into_entry_set_for(pred_bits={}, {:?} to {:?})",
590 self.dfcx
.analysis_name
, bits_to_string(pred_bits
), source
, cfgidx
);
591 assert
!(self.dfcx
.bits_per_id
> 0);
593 let (start
, end
) = self.dfcx
.compute_id_range(cfgidx
);
595 // (scoping mutable borrow of self.dfcx.on_entry)
596 let on_entry
= &mut self.dfcx
.on_entry
[start
.. end
];
597 bitwise(on_entry
, pred_bits
, &self.dfcx
.oper
)
600 debug
!("{} changed entry set for {:?} to {}",
601 self.dfcx
.analysis_name
, cfgidx
,
602 bits_to_string(&self.dfcx
.on_entry
[start
.. end
]));
608 fn mut_bits_to_string(words
: &mut [usize]) -> String
{
609 bits_to_string(words
)
612 fn bits_to_string(words
: &[usize]) -> String
{
613 let mut result
= String
::new();
616 // Note: this is a little endian printout of bytes.
620 for _
in 0..usize::BYTES
{
622 result
.push_str(&format
!("{:02x}", v
& 0xFF));
632 fn bitwise
<Op
:BitwiseOperator
>(out_vec
: &mut [usize],
635 assert_eq
!(out_vec
.len(), in_vec
.len());
636 let mut changed
= false;
637 for (out_elt
, in_elt
) in out_vec
.iter_mut().zip(in_vec
) {
638 let old_val
= *out_elt
;
639 let new_val
= op
.join(old_val
, *in_elt
);
641 changed
|= old_val
!= new_val
;
646 fn set_bit(words
: &mut [usize], bit
: usize) -> bool
{
647 debug
!("set_bit: words={} bit={}",
648 mut_bits_to_string(words
), bit_str(bit
));
649 let word
= bit
/ usize::BITS
;
650 let bit_in_word
= bit
% usize::BITS
;
651 let bit_mask
= 1 << bit_in_word
;
652 debug
!("word={} bit_in_word={} bit_mask={}", word
, bit_in_word
, word
);
653 let oldv
= words
[word
];
654 let newv
= oldv
| bit_mask
;
659 fn bit_str(bit
: usize) -> String
{
661 let lobits
= 1 << (bit
& 0xFF);
662 format
!("[{}:{}-{:02x}]", bit
, byte
, lobits
)
666 impl BitwiseOperator
for Union
{
667 fn join(&self, a
: usize, b
: usize) -> usize { a | b }
670 impl BitwiseOperator
for Subtract
{
671 fn join(&self, a
: usize, b
: usize) -> usize { a & !b }