2014-01-25 20:37:51 +13:00
|
|
|
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
2013-03-15 15:24:24 -04:00
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
|
|
|
|
2014-11-25 21:17:11 -05:00
|
|
|
//! A module for propagating forward dataflow information. The analysis
|
|
|
|
//! assumes that the items to be propagated can be represented as bits
|
|
|
|
//! and thus uses bitvectors. Your job is simply to specify the so-called
|
|
|
|
//! GEN and KILL bits for each expression.
|
2013-03-15 15:24:24 -04:00
|
|
|
|
2016-03-22 17:30:57 +02:00
|
|
|
use cfg;
|
|
|
|
use cfg::CFGIndex;
|
|
|
|
use ty::TyCtxt;
|
2015-02-26 21:00:43 -08:00
|
|
|
use std::io;
|
2016-01-15 10:07:52 -08:00
|
|
|
use std::mem;
|
2015-02-09 16:33:19 -08:00
|
|
|
use std::usize;
|
2013-03-15 15:24:24 -04:00
|
|
|
use syntax::ast;
|
2015-07-31 00:04:06 -07:00
|
|
|
use syntax::print::pp;
|
2015-09-14 21:58:20 +12:00
|
|
|
use syntax::print::pprust::PrintState;
|
2014-02-28 14:34:26 -08:00
|
|
|
use util::nodemap::NodeMap;
|
2016-03-29 08:50:44 +03:00
|
|
|
use hir;
|
2016-03-29 12:12:01 +03:00
|
|
|
use hir::intravisit::{self, IdRange};
|
2016-03-29 08:50:44 +03:00
|
|
|
use hir::print as pprust;
|
2015-07-31 00:04:06 -07:00
|
|
|
|
2013-03-15 15:24:24 -04:00
|
|
|
|
2015-03-30 09:38:44 -04:00
|
|
|
#[derive(Copy, Clone, Debug)]
|
librustc: Make `Copy` opt-in.
This change makes the compiler no longer infer whether types (structures
and enumerations) implement the `Copy` trait (and thus are implicitly
copyable). Rather, you must implement `Copy` yourself via `impl Copy for
MyType {}`.
A new warning has been added, `missing_copy_implementations`, to warn
you if a non-generic public type has been added that could have
implemented `Copy` but didn't.
For convenience, you may *temporarily* opt out of this behavior by using
`#![feature(opt_out_copy)]`. Note though that this feature gate will never be
accepted and will be removed by the time that 1.0 is released, so you should
transition your code away from using it.
This breaks code like:
#[deriving(Show)]
struct Point2D {
x: int,
y: int,
}
fn main() {
let mypoint = Point2D {
x: 1,
y: 1,
};
let otherpoint = mypoint;
println!("{}{}", mypoint, otherpoint);
}
Change this code to:
#[deriving(Show)]
struct Point2D {
x: int,
y: int,
}
impl Copy for Point2D {}
fn main() {
let mypoint = Point2D {
x: 1,
y: 1,
};
let otherpoint = mypoint;
println!("{}{}", mypoint, otherpoint);
}
This is the backwards-incompatible part of #13231.
Part of RFC #3.
[breaking-change]
2014-12-05 17:01:33 -08:00
|
|
|
pub enum EntryOrExit {
|
|
|
|
Entry,
|
|
|
|
Exit,
|
|
|
|
}
|
|
|
|
|
2015-01-03 22:54:18 -05:00
|
|
|
#[derive(Clone)]
|
2014-04-22 15:56:37 +03:00
|
|
|
pub struct DataFlowContext<'a, 'tcx: 'a, O> {
|
2016-02-29 23:36:51 +00:00
|
|
|
tcx: &'a TyCtxt<'tcx>,
|
2013-03-15 15:24:24 -04:00
|
|
|
|
2014-05-21 14:49:16 +02:00
|
|
|
/// a name for the analysis using this dataflow instance
|
|
|
|
analysis_name: &'static str,
|
|
|
|
|
2013-03-15 15:24:24 -04:00
|
|
|
/// the data flow operator
|
2014-03-28 10:05:27 -07:00
|
|
|
oper: O,
|
2013-03-15 15:24:24 -04:00
|
|
|
|
|
|
|
/// number of bits to propagate per id
|
2015-03-25 17:06:52 -07:00
|
|
|
bits_per_id: usize,
|
2013-03-15 15:24:24 -04:00
|
|
|
|
|
|
|
/// number of words we will use to store bits_per_id.
|
2015-02-09 16:33:19 -08:00
|
|
|
/// equal to bits_per_id/usize::BITS rounded up.
|
2015-03-25 17:06:52 -07:00
|
|
|
words_per_id: usize,
|
2013-03-15 15:24:24 -04:00
|
|
|
|
2014-05-21 14:49:16 +02:00
|
|
|
// mapping from node to cfg node index
|
|
|
|
// FIXME (#6298): Shouldn't this go with CFG?
|
2015-02-19 20:36:25 +01:00
|
|
|
nodeid_to_index: NodeMap<Vec<CFGIndex>>,
|
2013-06-13 10:07:34 -07:00
|
|
|
|
2014-05-21 14:49:16 +02:00
|
|
|
// Bit sets per cfg node. The following three fields (`gens`, `kills`,
|
2013-03-15 15:24:24 -04:00
|
|
|
// and `on_entry`) all have the same structure. For each id in
|
|
|
|
// `id_range`, there is a range of words equal to `words_per_id`.
|
|
|
|
// So, to access the bits for any given id, you take a slice of
|
|
|
|
// the full vector (see the method `compute_id_range()`).
|
|
|
|
|
2014-05-21 14:49:16 +02:00
|
|
|
/// bits generated as we exit the cfg node. Updated by `add_gen()`.
|
2015-03-25 17:06:52 -07:00
|
|
|
gens: Vec<usize>,
|
2013-03-15 15:24:24 -04:00
|
|
|
|
2015-04-11 18:42:33 +02:00
|
|
|
/// bits killed as we exit the cfg node, or non-locally jump over
|
|
|
|
/// it. Updated by `add_kill(KillFrom::ScopeEnd)`.
|
|
|
|
scope_kills: Vec<usize>,
|
|
|
|
|
|
|
|
/// bits killed as we exit the cfg node directly; if it is jumped
|
|
|
|
/// over, e.g. via `break`, the kills are not reflected in the
|
|
|
|
/// jump's effects. Updated by `add_kill(KillFrom::Execution)`.
|
|
|
|
action_kills: Vec<usize>,
|
2013-03-15 15:24:24 -04:00
|
|
|
|
2014-05-21 14:49:16 +02:00
|
|
|
/// bits that are valid on entry to the cfg node. Updated by
|
2013-03-15 15:24:24 -04:00
|
|
|
/// `propagate()`.
|
2015-03-25 17:06:52 -07:00
|
|
|
on_entry: Vec<usize>,
|
2014-03-28 10:05:27 -07:00
|
|
|
}
|
2013-03-15 15:24:24 -04:00
|
|
|
|
2014-05-21 14:49:16 +02:00
|
|
|
pub trait BitwiseOperator {
|
|
|
|
/// Joins two predecessor bits together, typically either `|` or `&`
|
2015-03-25 17:06:52 -07:00
|
|
|
fn join(&self, succ: usize, pred: usize) -> usize;
|
2014-05-21 14:49:16 +02:00
|
|
|
}
|
|
|
|
|
2013-03-15 15:24:24 -04:00
|
|
|
/// Parameterization for the precise form of data flow that is used.
|
2014-05-21 14:49:16 +02:00
|
|
|
pub trait DataFlowOperator : BitwiseOperator {
|
2013-03-15 15:24:24 -04:00
|
|
|
/// Specifies the initial value for each bit in the `on_entry` set
|
|
|
|
fn initial_value(&self) -> bool;
|
|
|
|
}
|
|
|
|
|
2014-04-22 15:56:37 +03:00
|
|
|
struct PropagationContext<'a, 'b: 'a, 'tcx: 'b, O: 'a> {
|
|
|
|
dfcx: &'a mut DataFlowContext<'b, 'tcx, O>,
|
2014-08-27 21:46:52 -04:00
|
|
|
changed: bool
|
|
|
|
}
|
|
|
|
|
2015-02-19 20:36:25 +01:00
|
|
|
fn get_cfg_indices<'a>(id: ast::NodeId, index: &'a NodeMap<Vec<CFGIndex>>) -> &'a [CFGIndex] {
|
|
|
|
let opt_indices = index.get(&id);
|
|
|
|
opt_indices.map(|v| &v[..]).unwrap_or(&[])
|
2014-05-21 14:49:16 +02:00
|
|
|
}
|
|
|
|
|
2014-04-22 15:56:37 +03:00
|
|
|
impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
|
2014-07-02 17:50:18 +02:00
|
|
|
fn has_bitset_for_nodeid(&self, n: ast::NodeId) -> bool {
|
2014-05-21 14:49:16 +02:00
|
|
|
assert!(n != ast::DUMMY_NODE_ID);
|
2014-07-17 14:28:03 +02:00
|
|
|
self.nodeid_to_index.contains_key(&n)
|
2014-05-21 14:49:16 +02:00
|
|
|
}
|
2014-03-08 21:36:22 +01:00
|
|
|
}
|
2013-03-15 15:24:24 -04:00
|
|
|
|
2014-04-22 15:56:37 +03:00
|
|
|
impl<'a, 'tcx, O:DataFlowOperator> pprust::PpAnn for DataFlowContext<'a, 'tcx, O> {
|
2014-03-16 20:58:11 +02:00
|
|
|
fn pre(&self,
|
2014-03-17 22:27:37 -07:00
|
|
|
ps: &mut pprust::State,
|
2015-02-26 21:00:43 -08:00
|
|
|
node: pprust::AnnNode) -> io::Result<()> {
|
2014-03-16 20:58:11 +02:00
|
|
|
let id = match node {
|
2015-09-23 20:04:49 +03:00
|
|
|
pprust::NodeName(_) => 0,
|
2014-03-16 20:58:11 +02:00
|
|
|
pprust::NodeExpr(expr) => expr.id,
|
|
|
|
pprust::NodeBlock(blk) => blk.id,
|
2015-03-24 14:52:55 +13:00
|
|
|
pprust::NodeItem(_) | pprust::NodeSubItem(_) => 0,
|
2014-03-16 20:58:11 +02:00
|
|
|
pprust::NodePat(pat) => pat.id
|
2013-08-29 15:24:33 -07:00
|
|
|
};
|
|
|
|
|
2015-02-19 20:36:25 +01:00
|
|
|
if !self.has_bitset_for_nodeid(id) {
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
|
|
|
|
assert!(self.bits_per_id > 0);
|
|
|
|
let indices = get_cfg_indices(id, &self.nodeid_to_index);
|
|
|
|
for &cfgidx in indices {
|
2014-07-17 15:36:38 +02:00
|
|
|
let (start, end) = self.compute_id_range(cfgidx);
|
2015-01-17 16:15:52 -08:00
|
|
|
let on_entry = &self.on_entry[start.. end];
|
2014-06-21 03:39:03 -07:00
|
|
|
let entry_str = bits_to_string(on_entry);
|
2013-08-29 15:24:33 -07:00
|
|
|
|
2015-01-17 16:15:52 -08:00
|
|
|
let gens = &self.gens[start.. end];
|
2013-08-29 15:24:33 -07:00
|
|
|
let gens_str = if gens.iter().any(|&u| u != 0) {
|
2014-06-21 03:39:03 -07:00
|
|
|
format!(" gen: {}", bits_to_string(gens))
|
2013-08-29 15:24:33 -07:00
|
|
|
} else {
|
2014-05-25 03:17:19 -07:00
|
|
|
"".to_string()
|
2013-08-29 15:24:33 -07:00
|
|
|
};
|
|
|
|
|
2015-04-11 18:42:33 +02:00
|
|
|
let action_kills = &self.action_kills[start .. end];
|
|
|
|
let action_kills_str = if action_kills.iter().any(|&u| u != 0) {
|
|
|
|
format!(" action_kill: {}", bits_to_string(action_kills))
|
|
|
|
} else {
|
|
|
|
"".to_string()
|
|
|
|
};
|
|
|
|
|
|
|
|
let scope_kills = &self.scope_kills[start .. end];
|
|
|
|
let scope_kills_str = if scope_kills.iter().any(|&u| u != 0) {
|
|
|
|
format!(" scope_kill: {}", bits_to_string(scope_kills))
|
2013-08-29 15:24:33 -07:00
|
|
|
} else {
|
2014-05-25 03:17:19 -07:00
|
|
|
"".to_string()
|
2013-08-29 15:24:33 -07:00
|
|
|
};
|
|
|
|
|
2016-03-22 22:01:37 -05:00
|
|
|
ps.synth_comment(
|
2015-04-11 18:42:33 +02:00
|
|
|
format!("id {}: {}{}{}{}", id, entry_str,
|
2016-03-22 22:01:37 -05:00
|
|
|
gens_str, action_kills_str, scope_kills_str))?;
|
|
|
|
pp::space(&mut ps.s)?;
|
2013-08-29 15:24:33 -07:00
|
|
|
}
|
2014-01-29 18:42:19 -08:00
|
|
|
Ok(())
|
2013-08-29 15:24:33 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
fn build_nodeid_to_index(decl: Option<&hir::FnDecl>,
|
2015-02-19 20:36:25 +01:00
|
|
|
cfg: &cfg::CFG) -> NodeMap<Vec<CFGIndex>> {
|
2015-01-16 14:27:43 -08:00
|
|
|
let mut index = NodeMap();
|
2014-05-21 14:49:16 +02:00
|
|
|
|
|
|
|
// FIXME (#6298): Would it be better to fold formals from decl
|
|
|
|
// into cfg itself? i.e. introduce a fn-based flow-graph in
|
|
|
|
// addition to the current block-based flow-graph, rather than
|
|
|
|
// have to put traversals like this here?
|
|
|
|
match decl {
|
|
|
|
None => {}
|
|
|
|
Some(decl) => add_entries_from_fn_decl(&mut index, decl, cfg.entry)
|
|
|
|
}
|
|
|
|
|
|
|
|
cfg.graph.each_node(|node_idx, node| {
|
2015-02-19 20:36:25 +01:00
|
|
|
if let cfg::CFGNodeData::AST(id) = node.data {
|
2015-03-20 13:43:01 -04:00
|
|
|
index.entry(id).or_insert(vec![]).push(node_idx);
|
2014-05-21 14:49:16 +02:00
|
|
|
}
|
|
|
|
true
|
|
|
|
});
|
|
|
|
|
|
|
|
return index;
|
|
|
|
|
2015-02-19 20:36:25 +01:00
|
|
|
fn add_entries_from_fn_decl(index: &mut NodeMap<Vec<CFGIndex>>,
|
2015-07-31 00:04:06 -07:00
|
|
|
decl: &hir::FnDecl,
|
2014-05-21 14:49:16 +02:00
|
|
|
entry: CFGIndex) {
|
|
|
|
//! add mappings from the ast nodes for the formal bindings to
|
|
|
|
//! the entry-node in the graph.
|
|
|
|
struct Formals<'a> {
|
|
|
|
entry: CFGIndex,
|
2015-02-19 20:36:25 +01:00
|
|
|
index: &'a mut NodeMap<Vec<CFGIndex>>,
|
2014-05-21 14:49:16 +02:00
|
|
|
}
|
|
|
|
let mut formals = Formals { entry: entry, index: index };
|
2015-11-17 17:51:44 -05:00
|
|
|
intravisit::walk_fn_decl(&mut formals, decl);
|
|
|
|
impl<'a, 'v> intravisit::Visitor<'v> for Formals<'a> {
|
2015-07-31 00:04:06 -07:00
|
|
|
fn visit_pat(&mut self, p: &hir::Pat) {
|
2015-03-20 13:43:01 -04:00
|
|
|
self.index.entry(p.id).or_insert(vec![]).push(self.entry);
|
2015-11-17 17:51:44 -05:00
|
|
|
intravisit::walk_pat(self, p)
|
2014-05-21 14:49:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-11 18:42:33 +02:00
|
|
|
/// Flag used by `add_kill` to indicate whether the provided kill
|
|
|
|
/// takes effect only when control flows directly through the node in
|
|
|
|
/// question, or if the kill's effect is associated with any
|
|
|
|
/// control-flow directly through or indirectly over the node.
|
|
|
|
#[derive(Copy, Clone, PartialEq, Debug)]
|
|
|
|
pub enum KillFrom {
|
|
|
|
/// A `ScopeEnd` kill is one that takes effect when any control
|
|
|
|
/// flow goes over the node. A kill associated with the end of the
|
|
|
|
/// scope of a variable declaration `let x;` is an example of a
|
|
|
|
/// `ScopeEnd` kill.
|
|
|
|
ScopeEnd,
|
|
|
|
|
|
|
|
/// An `Execution` kill is one that takes effect only when control
|
|
|
|
/// flow goes through the node to completion. A kill associated
|
|
|
|
/// with an assignment statement `x = expr;` is an example of an
|
|
|
|
/// `Execution` kill.
|
|
|
|
Execution,
|
|
|
|
}
|
|
|
|
|
2014-04-22 15:56:37 +03:00
|
|
|
impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
|
2016-02-29 23:36:51 +00:00
|
|
|
pub fn new(tcx: &'a TyCtxt<'tcx>,
|
2014-05-21 14:49:16 +02:00
|
|
|
analysis_name: &'static str,
|
2015-07-31 00:04:06 -07:00
|
|
|
decl: Option<&hir::FnDecl>,
|
2014-05-21 14:49:16 +02:00
|
|
|
cfg: &cfg::CFG,
|
2013-03-15 15:24:24 -04:00
|
|
|
oper: O,
|
2014-01-09 15:05:33 +02:00
|
|
|
id_range: IdRange,
|
2015-03-25 17:06:52 -07:00
|
|
|
bits_per_id: usize) -> DataFlowContext<'a, 'tcx, O> {
|
2016-01-15 10:07:52 -08:00
|
|
|
let usize_bits = mem::size_of::<usize>() * 8;
|
|
|
|
let words_per_id = (bits_per_id + usize_bits - 1) / usize_bits;
|
2014-07-17 14:28:03 +02:00
|
|
|
let num_nodes = cfg.graph.all_nodes().len();
|
2013-03-15 15:24:24 -04:00
|
|
|
|
2014-12-20 00:09:35 -08:00
|
|
|
debug!("DataFlowContext::new(analysis_name: {}, id_range={:?}, \
|
2014-10-15 02:25:34 -04:00
|
|
|
bits_per_id={}, words_per_id={}) \
|
2014-07-17 14:28:03 +02:00
|
|
|
num_nodes: {}",
|
|
|
|
analysis_name, id_range, bits_per_id, words_per_id,
|
|
|
|
num_nodes);
|
|
|
|
|
2015-02-09 16:33:19 -08:00
|
|
|
let entry = if oper.initial_value() { usize::MAX } else {0};
|
2013-03-15 15:24:24 -04:00
|
|
|
|
2015-07-08 22:52:55 +02:00
|
|
|
let zeroes = vec![0; num_nodes * words_per_id];
|
|
|
|
let gens = zeroes.clone();
|
|
|
|
let kills1 = zeroes.clone();
|
|
|
|
let kills2 = zeroes;
|
|
|
|
let on_entry = vec![entry; num_nodes * words_per_id];
|
2013-03-15 15:24:24 -04:00
|
|
|
|
2014-05-21 14:49:16 +02:00
|
|
|
let nodeid_to_index = build_nodeid_to_index(decl, cfg);
|
|
|
|
|
2013-03-15 15:24:24 -04:00
|
|
|
DataFlowContext {
|
|
|
|
tcx: tcx,
|
2014-05-21 14:49:16 +02:00
|
|
|
analysis_name: analysis_name,
|
2013-03-15 15:24:24 -04:00
|
|
|
words_per_id: words_per_id,
|
2014-05-21 14:49:16 +02:00
|
|
|
nodeid_to_index: nodeid_to_index,
|
2013-03-15 15:24:24 -04:00
|
|
|
bits_per_id: bits_per_id,
|
|
|
|
oper: oper,
|
|
|
|
gens: gens,
|
2015-04-11 18:42:33 +02:00
|
|
|
action_kills: kills1,
|
|
|
|
scope_kills: kills2,
|
2013-03-15 15:24:24 -04:00
|
|
|
on_entry: on_entry
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-25 17:06:52 -07:00
|
|
|
pub fn add_gen(&mut self, id: ast::NodeId, bit: usize) {
|
2013-03-15 15:24:24 -04:00
|
|
|
//! Indicates that `id` generates `bit`
|
2014-11-17 11:29:38 -08:00
|
|
|
debug!("{} add_gen(id={}, bit={})",
|
Ensure dataflow of a proc never looks at blocks from closed-over context.
Details: in a program like:
```
type T = proc(int) -> int; /* 4 */
pub fn outer(captured /* pat 16 */: T) -> T {
(proc(x /* pat 23 */) {
((captured /* 29 */).foo((x /* 30 */)) /* 28 */)
} /* block 27 */ /* 20 */)
} /* block 19 */ /* 12 */
```
the `captured` arg is moved from the outer fn into the inner proc (id=20).
The old dataflow analysis for flowed_move_data_moves, when looking at
the inner proc, would attempt to add a kill bit for `captured` at the
end of its scope; the problem is that it thought the end of the
`captured` arg's scope was the outer fn (id=12), even though at that
point in the analysis, the `captured` arg's scope should now be
restricted to the proc itself (id=20).
This patch fixes handling of upvars so that dataflow of a fn/proc
should never attempts to add a gen or kill bit to any NodeId outside
of the current fn/proc. It accomplishes this by adding an `LpUpvar`
variant to `borrowck::LoanPath`, so for cases like `captured` above
will carry both their original `var_id`, as before, as well as the
`NodeId` for the closure that is capturing them.
As a drive-by fix to another occurrence of a similar bug that
nikomatsakis pointed out to me earlier, this also fixes
`gather_loans::compute_kill_scope` so that it computes the kill scope
of the `captured` arg to be block 27; that is, the block for the proc
itself (id=20).
(This is an updated version that generalizes the new loan path variant
to cover all upvars, and thus renamed the variant from `LpCopiedUpvar`
to just `LpUpvar`.)
2014-06-13 17:19:29 +02:00
|
|
|
self.analysis_name, id, bit);
|
|
|
|
assert!(self.nodeid_to_index.contains_key(&id));
|
2014-07-17 15:36:38 +02:00
|
|
|
assert!(self.bits_per_id > 0);
|
|
|
|
|
2015-02-19 20:36:25 +01:00
|
|
|
let indices = get_cfg_indices(id, &self.nodeid_to_index);
|
|
|
|
for &cfgidx in indices {
|
|
|
|
let (start, end) = self.compute_id_range(cfgidx);
|
|
|
|
let gens = &mut self.gens[start.. end];
|
|
|
|
set_bit(gens, bit);
|
|
|
|
}
|
2013-03-15 15:24:24 -04:00
|
|
|
}
|
|
|
|
|
2015-04-11 18:42:33 +02:00
|
|
|
pub fn add_kill(&mut self, kind: KillFrom, id: ast::NodeId, bit: usize) {
|
2013-03-15 15:24:24 -04:00
|
|
|
//! Indicates that `id` kills `bit`
|
2014-11-17 11:29:38 -08:00
|
|
|
debug!("{} add_kill(id={}, bit={})",
|
Ensure dataflow of a proc never looks at blocks from closed-over context.
Details: in a program like:
```
type T = proc(int) -> int; /* 4 */
pub fn outer(captured /* pat 16 */: T) -> T {
(proc(x /* pat 23 */) {
((captured /* 29 */).foo((x /* 30 */)) /* 28 */)
} /* block 27 */ /* 20 */)
} /* block 19 */ /* 12 */
```
the `captured` arg is moved from the outer fn into the inner proc (id=20).
The old dataflow analysis for flowed_move_data_moves, when looking at
the inner proc, would attempt to add a kill bit for `captured` at the
end of its scope; the problem is that it thought the end of the
`captured` arg's scope was the outer fn (id=12), even though at that
point in the analysis, the `captured` arg's scope should now be
restricted to the proc itself (id=20).
This patch fixes handling of upvars so that dataflow of a fn/proc
should never attempts to add a gen or kill bit to any NodeId outside
of the current fn/proc. It accomplishes this by adding an `LpUpvar`
variant to `borrowck::LoanPath`, so for cases like `captured` above
will carry both their original `var_id`, as before, as well as the
`NodeId` for the closure that is capturing them.
As a drive-by fix to another occurrence of a similar bug that
nikomatsakis pointed out to me earlier, this also fixes
`gather_loans::compute_kill_scope` so that it computes the kill scope
of the `captured` arg to be block 27; that is, the block for the proc
itself (id=20).
(This is an updated version that generalizes the new loan path variant
to cover all upvars, and thus renamed the variant from `LpCopiedUpvar`
to just `LpUpvar`.)
2014-06-13 17:19:29 +02:00
|
|
|
self.analysis_name, id, bit);
|
|
|
|
assert!(self.nodeid_to_index.contains_key(&id));
|
2014-07-17 15:36:38 +02:00
|
|
|
assert!(self.bits_per_id > 0);
|
|
|
|
|
2015-02-19 20:36:25 +01:00
|
|
|
let indices = get_cfg_indices(id, &self.nodeid_to_index);
|
|
|
|
for &cfgidx in indices {
|
|
|
|
let (start, end) = self.compute_id_range(cfgidx);
|
2015-04-11 18:42:33 +02:00
|
|
|
let kills = match kind {
|
|
|
|
KillFrom::Execution => &mut self.action_kills[start.. end],
|
|
|
|
KillFrom::ScopeEnd => &mut self.scope_kills[start.. end],
|
|
|
|
};
|
2015-02-19 20:36:25 +01:00
|
|
|
set_bit(kills, bit);
|
|
|
|
}
|
2013-03-15 15:24:24 -04:00
|
|
|
}
|
|
|
|
|
2015-03-25 17:06:52 -07:00
|
|
|
fn apply_gen_kill(&self, cfgidx: CFGIndex, bits: &mut [usize]) {
|
2014-07-02 17:50:18 +02:00
|
|
|
//! Applies the gen and kill sets for `cfgidx` to `bits`
|
2014-12-20 00:09:35 -08:00
|
|
|
debug!("{} apply_gen_kill(cfgidx={:?}, bits={}) [before]",
|
2014-06-21 03:39:03 -07:00
|
|
|
self.analysis_name, cfgidx, mut_bits_to_string(bits));
|
2014-07-17 15:36:38 +02:00
|
|
|
assert!(self.bits_per_id > 0);
|
2013-03-15 15:24:24 -04:00
|
|
|
|
2014-07-17 15:36:38 +02:00
|
|
|
let (start, end) = self.compute_id_range(cfgidx);
|
2015-01-17 16:15:52 -08:00
|
|
|
let gens = &self.gens[start.. end];
|
2014-07-02 17:50:18 +02:00
|
|
|
bitwise(bits, gens, &Union);
|
2015-04-11 18:42:33 +02:00
|
|
|
let kills = &self.action_kills[start.. end];
|
|
|
|
bitwise(bits, kills, &Subtract);
|
|
|
|
let kills = &self.scope_kills[start.. end];
|
2014-07-02 17:50:18 +02:00
|
|
|
bitwise(bits, kills, &Subtract);
|
|
|
|
|
2014-12-20 00:09:35 -08:00
|
|
|
debug!("{} apply_gen_kill(cfgidx={:?}, bits={}) [after]",
|
2014-07-02 17:50:18 +02:00
|
|
|
self.analysis_name, cfgidx, mut_bits_to_string(bits));
|
|
|
|
}
|
|
|
|
|
2015-03-25 17:06:52 -07:00
|
|
|
fn compute_id_range(&self, cfgidx: CFGIndex) -> (usize, usize) {
|
2014-07-17 15:36:38 +02:00
|
|
|
let n = cfgidx.node_id();
|
2014-05-21 14:49:16 +02:00
|
|
|
let start = n * self.words_per_id;
|
2013-03-15 15:24:24 -04:00
|
|
|
let end = start + self.words_per_id;
|
2013-06-13 10:07:34 -07:00
|
|
|
|
|
|
|
assert!(start < self.gens.len());
|
|
|
|
assert!(end <= self.gens.len());
|
2015-04-11 18:42:33 +02:00
|
|
|
assert!(self.gens.len() == self.action_kills.len());
|
|
|
|
assert!(self.gens.len() == self.scope_kills.len());
|
2013-06-13 10:07:34 -07:00
|
|
|
assert!(self.gens.len() == self.on_entry.len());
|
|
|
|
|
2013-03-15 15:24:24 -04:00
|
|
|
(start, end)
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-02-19 20:36:25 +01:00
|
|
|
pub fn each_bit_on_entry<F>(&self, id: ast::NodeId, mut f: F) -> bool where
|
2015-03-25 17:06:52 -07:00
|
|
|
F: FnMut(usize) -> bool,
|
2014-12-08 20:26:43 -05:00
|
|
|
{
|
2013-06-13 10:07:34 -07:00
|
|
|
//! Iterates through each bit that is set on entry to `id`.
|
|
|
|
//! Only useful after `propagate()` has been called.
|
2014-07-02 17:50:18 +02:00
|
|
|
if !self.has_bitset_for_nodeid(id) {
|
2013-06-13 10:07:34 -07:00
|
|
|
return true;
|
|
|
|
}
|
2015-02-19 20:36:25 +01:00
|
|
|
let indices = get_cfg_indices(id, &self.nodeid_to_index);
|
|
|
|
for &cfgidx in indices {
|
2015-11-24 13:06:12 +01:00
|
|
|
if !self.each_bit_for_node(EntryOrExit::Entry, cfgidx, |i| f(i)) {
|
2015-02-19 20:36:25 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
2014-07-02 17:50:18 +02:00
|
|
|
}
|
|
|
|
|
2014-12-08 20:26:43 -05:00
|
|
|
pub fn each_bit_for_node<F>(&self, e: EntryOrExit, cfgidx: CFGIndex, f: F) -> bool where
|
2015-03-25 17:06:52 -07:00
|
|
|
F: FnMut(usize) -> bool,
|
2014-12-08 20:26:43 -05:00
|
|
|
{
|
2014-07-02 17:50:18 +02:00
|
|
|
//! Iterates through each bit that is set on entry/exit to `cfgidx`.
|
|
|
|
//! Only useful after `propagate()` has been called.
|
2014-07-17 15:36:38 +02:00
|
|
|
|
|
|
|
if self.bits_per_id == 0 {
|
|
|
|
// Skip the surprisingly common degenerate case. (Note
|
|
|
|
// compute_id_range requires self.words_per_id > 0.)
|
2014-07-02 17:50:18 +02:00
|
|
|
return true;
|
|
|
|
}
|
2014-07-17 15:36:38 +02:00
|
|
|
|
|
|
|
let (start, end) = self.compute_id_range(cfgidx);
|
2015-01-17 16:15:52 -08:00
|
|
|
let on_entry = &self.on_entry[start.. end];
|
2014-07-02 17:50:18 +02:00
|
|
|
let temp_bits;
|
|
|
|
let slice = match e {
|
2015-11-24 13:06:12 +01:00
|
|
|
EntryOrExit::Entry => on_entry,
|
|
|
|
EntryOrExit::Exit => {
|
2014-07-16 22:37:28 +02:00
|
|
|
let mut t = on_entry.to_vec();
|
2015-02-01 21:53:25 -05:00
|
|
|
self.apply_gen_kill(cfgidx, &mut t);
|
2014-07-02 17:50:18 +02:00
|
|
|
temp_bits = t;
|
2015-02-18 14:48:57 -05:00
|
|
|
&temp_bits[..]
|
2014-07-02 17:50:18 +02:00
|
|
|
}
|
|
|
|
};
|
2014-12-20 00:09:35 -08:00
|
|
|
debug!("{} each_bit_for_node({:?}, cfgidx={:?}) bits={}",
|
2014-07-02 17:50:18 +02:00
|
|
|
self.analysis_name, e, cfgidx, bits_to_string(slice));
|
|
|
|
self.each_bit(slice, f)
|
2013-06-13 10:07:34 -07:00
|
|
|
}
|
|
|
|
|
2015-02-19 20:36:25 +01:00
|
|
|
pub fn each_gen_bit<F>(&self, id: ast::NodeId, mut f: F) -> bool where
|
2015-03-25 17:06:52 -07:00
|
|
|
F: FnMut(usize) -> bool,
|
2014-12-08 20:26:43 -05:00
|
|
|
{
|
2013-06-13 10:07:34 -07:00
|
|
|
//! Iterates through each bit in the gen set for `id`.
|
2014-07-02 17:50:18 +02:00
|
|
|
if !self.has_bitset_for_nodeid(id) {
|
2013-06-13 10:07:34 -07:00
|
|
|
return true;
|
|
|
|
}
|
2014-07-17 15:36:38 +02:00
|
|
|
|
|
|
|
if self.bits_per_id == 0 {
|
|
|
|
// Skip the surprisingly common degenerate case. (Note
|
|
|
|
// compute_id_range requires self.words_per_id > 0.)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-02-19 20:36:25 +01:00
|
|
|
let indices = get_cfg_indices(id, &self.nodeid_to_index);
|
|
|
|
for &cfgidx in indices {
|
|
|
|
let (start, end) = self.compute_id_range(cfgidx);
|
|
|
|
let gens = &self.gens[start.. end];
|
|
|
|
debug!("{} each_gen_bit(id={}, gens={})",
|
|
|
|
self.analysis_name, id, bits_to_string(gens));
|
|
|
|
if !self.each_bit(gens, |i| f(i)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
2013-06-13 10:07:34 -07:00
|
|
|
}
|
|
|
|
|
2015-03-25 17:06:52 -07:00
|
|
|
fn each_bit<F>(&self, words: &[usize], mut f: F) -> bool where
|
|
|
|
F: FnMut(usize) -> bool,
|
2014-12-08 20:26:43 -05:00
|
|
|
{
|
2013-05-03 13:08:08 -04:00
|
|
|
//! Helper for iterating over the bits in a bit set.
|
2014-07-17 15:36:38 +02:00
|
|
|
//! Returns false on the first call to `f` that returns false;
|
|
|
|
//! if all calls to `f` return true, then returns true.
|
2013-05-03 13:08:08 -04:00
|
|
|
|
2016-01-15 10:07:52 -08:00
|
|
|
let usize_bits = mem::size_of::<usize>() * 8;
|
2013-08-03 12:45:23 -04:00
|
|
|
for (word_index, &word) in words.iter().enumerate() {
|
2013-05-03 13:08:08 -04:00
|
|
|
if word != 0 {
|
2016-01-15 10:07:52 -08:00
|
|
|
let base_index = word_index * usize_bits;
|
|
|
|
for offset in 0..usize_bits {
|
2013-05-03 13:08:08 -04:00
|
|
|
let bit = 1 << offset;
|
|
|
|
if (word & bit) != 0 {
|
|
|
|
// NB: we round up the total number of bits
|
|
|
|
// that we store in any given bit set so that
|
2015-02-09 16:33:19 -08:00
|
|
|
// it is an even multiple of usize::BITS. This
|
2013-05-03 13:08:08 -04:00
|
|
|
// means that there may be some stray bits at
|
|
|
|
// the end that do not correspond to any
|
|
|
|
// actual value. So before we callback, check
|
|
|
|
// whether the bit_index is greater than the
|
|
|
|
// actual value the user specified and stop
|
|
|
|
// iterating if so.
|
2015-02-19 21:05:35 -08:00
|
|
|
let bit_index = base_index + offset as usize;
|
2013-05-03 13:08:08 -04:00
|
|
|
if bit_index >= self.bits_per_id {
|
|
|
|
return true;
|
|
|
|
} else if !f(bit_index) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2014-05-21 14:49:16 +02:00
|
|
|
|
|
|
|
pub fn add_kills_from_flow_exits(&mut self, cfg: &cfg::CFG) {
|
|
|
|
//! Whenever you have a `break` or `continue` statement, flow
|
|
|
|
//! exits through any number of enclosing scopes on its way to
|
|
|
|
//! the new destination. This function infers the kill bits of
|
|
|
|
//! those control operators based on the kill bits associated
|
|
|
|
//! with those scopes.
|
|
|
|
//!
|
|
|
|
//! This is usually called (if it is called at all), after
|
|
|
|
//! all add_gen and add_kill calls, but before propagate.
|
|
|
|
|
2014-11-17 11:29:38 -08:00
|
|
|
debug!("{} add_kills_from_flow_exits", self.analysis_name);
|
2014-05-21 14:49:16 +02:00
|
|
|
if self.bits_per_id == 0 {
|
|
|
|
// Skip the surprisingly common degenerate case. (Note
|
|
|
|
// compute_id_range requires self.words_per_id > 0.)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
cfg.graph.each_edge(|_edge_index, edge| {
|
|
|
|
let flow_exit = edge.source();
|
|
|
|
let (start, end) = self.compute_id_range(flow_exit);
|
2015-04-11 18:42:33 +02:00
|
|
|
let mut orig_kills = self.scope_kills[start.. end].to_vec();
|
2014-05-21 14:49:16 +02:00
|
|
|
|
|
|
|
let mut changed = false;
|
2015-01-31 12:20:46 -05:00
|
|
|
for &node_id in &edge.data.exiting_scopes {
|
2015-02-19 20:36:25 +01:00
|
|
|
let opt_cfg_idx = self.nodeid_to_index.get(&node_id);
|
2014-05-21 14:49:16 +02:00
|
|
|
match opt_cfg_idx {
|
2015-02-19 20:36:25 +01:00
|
|
|
Some(indices) => {
|
|
|
|
for &cfg_idx in indices {
|
|
|
|
let (start, end) = self.compute_id_range(cfg_idx);
|
2015-04-11 18:42:33 +02:00
|
|
|
let kills = &self.scope_kills[start.. end];
|
2015-02-19 20:36:25 +01:00
|
|
|
if bitwise(&mut orig_kills, kills, &Union) {
|
2015-04-11 18:42:33 +02:00
|
|
|
debug!("scope exits: scope id={} \
|
|
|
|
(node={:?} of {:?}) added killset: {}",
|
|
|
|
node_id, cfg_idx, indices,
|
|
|
|
bits_to_string(kills));
|
2015-02-19 20:36:25 +01:00
|
|
|
changed = true;
|
|
|
|
}
|
2014-05-21 14:49:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
None => {
|
2014-12-20 00:09:35 -08:00
|
|
|
debug!("{} add_kills_from_flow_exits flow_exit={:?} \
|
2014-10-15 02:25:34 -04:00
|
|
|
no cfg_idx for exiting_scope={}",
|
2014-05-21 14:49:16 +02:00
|
|
|
self.analysis_name, flow_exit, node_id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if changed {
|
2015-04-11 18:42:33 +02:00
|
|
|
let bits = &mut self.scope_kills[start.. end];
|
2014-12-20 00:09:35 -08:00
|
|
|
debug!("{} add_kills_from_flow_exits flow_exit={:?} bits={} [before]",
|
2014-06-21 03:39:03 -07:00
|
|
|
self.analysis_name, flow_exit, mut_bits_to_string(bits));
|
2016-02-23 19:25:43 +01:00
|
|
|
bits.copy_from_slice(&orig_kills[..]);
|
2014-12-20 00:09:35 -08:00
|
|
|
debug!("{} add_kills_from_flow_exits flow_exit={:?} bits={} [after]",
|
2014-06-21 03:39:03 -07:00
|
|
|
self.analysis_name, flow_exit, mut_bits_to_string(bits));
|
2014-05-21 14:49:16 +02:00
|
|
|
}
|
|
|
|
true
|
|
|
|
});
|
|
|
|
}
|
2013-03-15 15:24:24 -04:00
|
|
|
}
|
|
|
|
|
2014-04-22 15:56:37 +03:00
|
|
|
impl<'a, 'tcx, O:DataFlowOperator+Clone+'static> DataFlowContext<'a, 'tcx, O> {
|
|
|
|
// ^^^^^^^^^^^^^ only needed for pretty printing
|
2015-07-31 00:04:06 -07:00
|
|
|
pub fn propagate(&mut self, cfg: &cfg::CFG, blk: &hir::Block) {
|
2013-03-15 15:24:24 -04:00
|
|
|
//! Performs the data flow analysis.
|
|
|
|
|
|
|
|
if self.bits_per_id == 0 {
|
|
|
|
// Optimize the surprisingly common degenerate case.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-07-02 12:47:32 -07:00
|
|
|
{
|
2014-06-13 20:48:09 -07:00
|
|
|
let words_per_id = self.words_per_id;
|
2013-07-02 12:47:32 -07:00
|
|
|
let mut propcx = PropagationContext {
|
2014-03-06 05:07:47 +02:00
|
|
|
dfcx: &mut *self,
|
2013-07-02 12:47:32 -07:00
|
|
|
changed: true
|
|
|
|
};
|
2013-03-15 15:24:24 -04:00
|
|
|
|
2015-07-08 22:52:55 +02:00
|
|
|
let mut temp = vec![0; words_per_id];
|
2013-07-02 12:47:32 -07:00
|
|
|
while propcx.changed {
|
|
|
|
propcx.changed = false;
|
2015-02-01 21:53:25 -05:00
|
|
|
propcx.reset(&mut temp);
|
|
|
|
propcx.walk_cfg(cfg, &mut temp);
|
2013-07-02 12:47:32 -07:00
|
|
|
}
|
2013-03-15 15:24:24 -04:00
|
|
|
}
|
|
|
|
|
2014-11-17 11:29:38 -08:00
|
|
|
debug!("Dataflow result for {}:", self.analysis_name);
|
2013-10-21 13:08:31 -07:00
|
|
|
debug!("{}", {
|
2015-02-26 21:00:43 -08:00
|
|
|
let mut v = Vec::new();
|
|
|
|
self.pretty_print_to(box &mut v, blk).unwrap();
|
2016-01-25 09:59:52 +01:00
|
|
|
String::from_utf8(v).unwrap()
|
2013-03-15 15:24:24 -04:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2015-02-26 21:00:43 -08:00
|
|
|
fn pretty_print_to<'b>(&self, wr: Box<io::Write + 'b>,
|
2015-07-31 00:04:06 -07:00
|
|
|
blk: &hir::Block) -> io::Result<()> {
|
2015-11-17 17:51:44 -05:00
|
|
|
let mut ps = pprust::rust_printer_annotated(wr, self, None);
|
2016-03-22 22:01:37 -05:00
|
|
|
ps.cbox(pprust::indent_unit)?;
|
|
|
|
ps.ibox(0)?;
|
|
|
|
ps.print_block(blk)?;
|
2014-03-16 20:58:11 +02:00
|
|
|
pp::eof(&mut ps.s)
|
2013-03-15 15:24:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-22 15:56:37 +03:00
|
|
|
impl<'a, 'b, 'tcx, O:DataFlowOperator> PropagationContext<'a, 'b, 'tcx, O> {
|
2014-05-21 14:49:16 +02:00
|
|
|
fn walk_cfg(&mut self,
|
|
|
|
cfg: &cfg::CFG,
|
2015-03-25 17:06:52 -07:00
|
|
|
in_out: &mut [usize]) {
|
2014-11-17 11:29:38 -08:00
|
|
|
debug!("DataFlowContext::walk_cfg(in_out={}) {}",
|
2014-06-21 03:39:03 -07:00
|
|
|
bits_to_string(in_out), self.dfcx.analysis_name);
|
2014-07-17 15:36:38 +02:00
|
|
|
assert!(self.dfcx.bits_per_id > 0);
|
|
|
|
|
2014-05-21 14:49:16 +02:00
|
|
|
cfg.graph.each_node(|node_index, node| {
|
2014-12-20 00:09:35 -08:00
|
|
|
debug!("DataFlowContext::walk_cfg idx={:?} id={} begin in_out={}",
|
2015-02-19 15:27:25 +01:00
|
|
|
node_index, node.data.id(), bits_to_string(in_out));
|
2014-05-21 14:49:16 +02:00
|
|
|
|
|
|
|
let (start, end) = self.dfcx.compute_id_range(node_index);
|
|
|
|
|
|
|
|
// Initialize local bitvector with state on-entry.
|
2016-02-23 19:25:43 +01:00
|
|
|
in_out.copy_from_slice(&self.dfcx.on_entry[start.. end]);
|
2014-05-21 14:49:16 +02:00
|
|
|
|
|
|
|
// Compute state on-exit by applying transfer function to
|
|
|
|
// state on-entry.
|
|
|
|
self.dfcx.apply_gen_kill(node_index, in_out);
|
|
|
|
|
|
|
|
// Propagate state on-exit from node into its successors.
|
|
|
|
self.propagate_bits_into_graph_successors_of(in_out, cfg, node_index);
|
|
|
|
true // continue to next node
|
2013-11-21 15:42:55 -08:00
|
|
|
});
|
2013-03-15 15:24:24 -04:00
|
|
|
}
|
|
|
|
|
2015-03-25 17:06:52 -07:00
|
|
|
fn reset(&mut self, bits: &mut [usize]) {
|
2015-02-09 16:33:19 -08:00
|
|
|
let e = if self.dfcx.oper.initial_value() {usize::MAX} else {0};
|
2015-01-31 20:02:00 -05:00
|
|
|
for b in bits {
|
2014-05-16 10:45:16 -07:00
|
|
|
*b = e;
|
|
|
|
}
|
2013-03-15 15:24:24 -04:00
|
|
|
}
|
|
|
|
|
2014-05-21 14:49:16 +02:00
|
|
|
fn propagate_bits_into_graph_successors_of(&mut self,
|
2015-03-25 17:06:52 -07:00
|
|
|
pred_bits: &[usize],
|
2014-05-21 14:49:16 +02:00
|
|
|
cfg: &cfg::CFG,
|
|
|
|
cfgidx: CFGIndex) {
|
2015-04-07 06:12:13 -04:00
|
|
|
for (_, edge) in cfg.graph.outgoing_edges(cfgidx) {
|
2014-05-21 14:49:16 +02:00
|
|
|
self.propagate_bits_into_entry_set_for(pred_bits, edge);
|
2015-04-07 06:12:13 -04:00
|
|
|
}
|
2013-03-15 15:24:24 -04:00
|
|
|
}
|
|
|
|
|
2014-05-21 14:49:16 +02:00
|
|
|
fn propagate_bits_into_entry_set_for(&mut self,
|
2015-03-25 17:06:52 -07:00
|
|
|
pred_bits: &[usize],
|
2014-05-21 14:49:16 +02:00
|
|
|
edge: &cfg::CFGEdge) {
|
|
|
|
let source = edge.source();
|
|
|
|
let cfgidx = edge.target();
|
2014-12-20 00:09:35 -08:00
|
|
|
debug!("{} propagate_bits_into_entry_set_for(pred_bits={}, {:?} to {:?})",
|
2014-06-21 03:39:03 -07:00
|
|
|
self.dfcx.analysis_name, bits_to_string(pred_bits), source, cfgidx);
|
2014-07-17 15:36:38 +02:00
|
|
|
assert!(self.dfcx.bits_per_id > 0);
|
|
|
|
|
2014-05-21 14:49:16 +02:00
|
|
|
let (start, end) = self.dfcx.compute_id_range(cfgidx);
|
|
|
|
let changed = {
|
|
|
|
// (scoping mutable borrow of self.dfcx.on_entry)
|
2015-01-17 16:15:52 -08:00
|
|
|
let on_entry = &mut self.dfcx.on_entry[start.. end];
|
2014-05-21 14:49:16 +02:00
|
|
|
bitwise(on_entry, pred_bits, &self.dfcx.oper)
|
2013-03-15 15:24:24 -04:00
|
|
|
};
|
|
|
|
if changed {
|
2014-12-20 00:09:35 -08:00
|
|
|
debug!("{} changed entry set for {:?} to {}",
|
2014-05-21 14:49:16 +02:00
|
|
|
self.dfcx.analysis_name, cfgidx,
|
2015-01-17 16:15:52 -08:00
|
|
|
bits_to_string(&self.dfcx.on_entry[start.. end]));
|
2013-03-15 15:24:24 -04:00
|
|
|
self.changed = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-25 17:06:52 -07:00
|
|
|
fn mut_bits_to_string(words: &mut [usize]) -> String {
|
2014-06-21 03:39:03 -07:00
|
|
|
bits_to_string(words)
|
2013-03-15 15:24:24 -04:00
|
|
|
}
|
|
|
|
|
2015-03-25 17:06:52 -07:00
|
|
|
fn bits_to_string(words: &[usize]) -> String {
|
2014-05-22 16:57:53 -07:00
|
|
|
let mut result = String::new();
|
2013-03-15 15:24:24 -04:00
|
|
|
let mut sep = '[';
|
|
|
|
|
|
|
|
// Note: this is a little endian printout of bytes.
|
|
|
|
|
2015-01-31 12:20:46 -05:00
|
|
|
for &word in words {
|
2013-03-15 15:24:24 -04:00
|
|
|
let mut v = word;
|
2016-01-15 10:07:52 -08:00
|
|
|
for _ in 0..mem::size_of::<usize>() {
|
2014-10-14 23:05:01 -07:00
|
|
|
result.push(sep);
|
2015-02-20 14:08:14 -05:00
|
|
|
result.push_str(&format!("{:02x}", v & 0xFF));
|
2013-03-15 15:24:24 -04:00
|
|
|
v >>= 8;
|
|
|
|
sep = '-';
|
|
|
|
}
|
|
|
|
}
|
2014-10-14 23:05:01 -07:00
|
|
|
result.push(']');
|
2014-05-09 18:45:36 -07:00
|
|
|
return result
|
2013-03-15 15:24:24 -04:00
|
|
|
}
|
|
|
|
|
2013-06-18 14:45:18 -07:00
|
|
|
#[inline]
|
2015-03-25 17:06:52 -07:00
|
|
|
fn bitwise<Op:BitwiseOperator>(out_vec: &mut [usize],
|
|
|
|
in_vec: &[usize],
|
2014-05-21 14:49:16 +02:00
|
|
|
op: &Op) -> bool {
|
2013-03-15 15:24:24 -04:00
|
|
|
assert_eq!(out_vec.len(), in_vec.len());
|
|
|
|
let mut changed = false;
|
2015-06-10 17:22:20 +01:00
|
|
|
for (out_elt, in_elt) in out_vec.iter_mut().zip(in_vec) {
|
2013-08-07 20:19:15 +02:00
|
|
|
let old_val = *out_elt;
|
2014-05-21 14:49:16 +02:00
|
|
|
let new_val = op.join(old_val, *in_elt);
|
2013-08-07 20:19:15 +02:00
|
|
|
*out_elt = new_val;
|
2014-02-18 13:40:25 +01:00
|
|
|
changed |= old_val != new_val;
|
2013-03-15 15:24:24 -04:00
|
|
|
}
|
2013-08-01 18:35:46 -04:00
|
|
|
changed
|
2013-03-15 15:24:24 -04:00
|
|
|
}
|
|
|
|
|
2015-03-25 17:06:52 -07:00
|
|
|
fn set_bit(words: &mut [usize], bit: usize) -> bool {
|
2013-10-21 13:08:31 -07:00
|
|
|
debug!("set_bit: words={} bit={}",
|
2014-06-21 03:39:03 -07:00
|
|
|
mut_bits_to_string(words), bit_str(bit));
|
2016-01-15 10:07:52 -08:00
|
|
|
let usize_bits = mem::size_of::<usize>() * 8;
|
|
|
|
let word = bit / usize_bits;
|
|
|
|
let bit_in_word = bit % usize_bits;
|
2013-03-15 15:24:24 -04:00
|
|
|
let bit_mask = 1 << bit_in_word;
|
2016-01-25 14:34:34 +01:00
|
|
|
debug!("word={} bit_in_word={} bit_mask={}", word, bit_in_word, bit_mask);
|
2013-03-15 15:24:24 -04:00
|
|
|
let oldv = words[word];
|
|
|
|
let newv = oldv | bit_mask;
|
|
|
|
words[word] = newv;
|
|
|
|
oldv != newv
|
|
|
|
}
|
|
|
|
|
2015-03-25 17:06:52 -07:00
|
|
|
fn bit_str(bit: usize) -> String {
|
2013-03-15 15:24:24 -04:00
|
|
|
let byte = bit >> 8;
|
2015-01-25 10:58:43 +00:00
|
|
|
let lobits = 1 << (bit & 0xFF);
|
2014-05-27 20:44:58 -07:00
|
|
|
format!("[{}:{}-{:02x}]", bit, byte, lobits)
|
2013-03-15 15:24:24 -04:00
|
|
|
}
|
2014-05-21 14:49:16 +02:00
|
|
|
|
|
|
|
struct Union;
|
|
|
|
impl BitwiseOperator for Union {
|
2015-03-25 17:06:52 -07:00
|
|
|
fn join(&self, a: usize, b: usize) -> usize { a | b }
|
2014-05-21 14:49:16 +02:00
|
|
|
}
|
|
|
|
struct Subtract;
|
|
|
|
impl BitwiseOperator for Subtract {
|
2015-03-25 17:06:52 -07:00
|
|
|
fn join(&self, a: usize, b: usize) -> usize { a & !b }
|
2014-05-21 14:49:16 +02:00
|
|
|
}
|