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