2014-01-25 01:37:51 -06:00
|
|
|
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
2013-03-15 14:24:24 -05: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.
|
|
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* 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-05-17 17:28:44 -05:00
|
|
|
|
2013-11-11 00:46:32 -06:00
|
|
|
use std::io;
|
2013-06-28 17:32:26 -05:00
|
|
|
use std::uint;
|
|
|
|
use std::vec;
|
|
|
|
use std::hashmap::HashMap;
|
2013-03-15 14:24:24 -05:00
|
|
|
use syntax::ast;
|
|
|
|
use syntax::ast_util;
|
2014-01-09 07:05:33 -06:00
|
|
|
use syntax::ast_util::IdRange;
|
2013-03-15 14:24:24 -05:00
|
|
|
use syntax::print::{pp, pprust};
|
|
|
|
use middle::ty;
|
|
|
|
use middle::typeck;
|
|
|
|
use util::ppaux::Repr;
|
|
|
|
|
2013-07-02 14:47:32 -05:00
|
|
|
#[deriving(Clone)]
|
2013-03-15 14:24:24 -05:00
|
|
|
pub struct DataFlowContext<O> {
|
|
|
|
priv tcx: ty::ctxt,
|
|
|
|
priv method_map: typeck::method_map,
|
|
|
|
|
|
|
|
/// the data flow operator
|
|
|
|
priv oper: O,
|
|
|
|
|
|
|
|
/// number of bits to propagate per id
|
|
|
|
priv bits_per_id: uint,
|
|
|
|
|
|
|
|
/// number of words we will use to store bits_per_id.
|
2014-01-25 01:37:51 -06:00
|
|
|
/// equal to bits_per_id/uint::BITS rounded up.
|
2013-03-15 14:24:24 -05:00
|
|
|
priv words_per_id: uint,
|
|
|
|
|
2013-06-13 12:07:34 -05:00
|
|
|
// mapping from node to bitset index.
|
2013-07-27 03:25:59 -05:00
|
|
|
priv nodeid_to_bitset: HashMap<ast::NodeId,uint>,
|
2013-06-13 12:07:34 -05:00
|
|
|
|
2013-03-15 14:24:24 -05:00
|
|
|
// Bit sets per id. The following three fields (`gens`, `kills`,
|
|
|
|
// 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()`).
|
|
|
|
|
|
|
|
/// bits generated as we exit the scope `id`. Updated by `add_gen()`.
|
|
|
|
priv gens: ~[uint],
|
|
|
|
|
|
|
|
/// bits killed as we exit the scope `id`. Updated by `add_kill()`.
|
|
|
|
priv kills: ~[uint],
|
|
|
|
|
|
|
|
/// bits that are valid on entry to the scope `id`. Updated by
|
|
|
|
/// `propagate()`.
|
|
|
|
priv on_entry: ~[uint]
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Parameterization for the precise form of data flow that is used.
|
|
|
|
pub trait DataFlowOperator {
|
|
|
|
/// Specifies the initial value for each bit in the `on_entry` set
|
|
|
|
fn initial_value(&self) -> bool;
|
|
|
|
|
|
|
|
/// Joins two predecessor bits together, typically either `|` or `&`
|
|
|
|
fn join(&self, succ: uint, pred: uint) -> uint;
|
|
|
|
}
|
|
|
|
|
2013-12-10 01:16:18 -06:00
|
|
|
struct PropagationContext<'a, O> {
|
|
|
|
dfcx: &'a mut DataFlowContext<O>,
|
2013-03-15 14:24:24 -05:00
|
|
|
changed: bool
|
|
|
|
}
|
|
|
|
|
2013-12-10 01:16:18 -06:00
|
|
|
struct LoopScope<'a> {
|
2013-07-27 03:25:59 -05:00
|
|
|
loop_id: ast::NodeId,
|
2013-03-15 14:24:24 -05:00
|
|
|
break_bits: ~[uint]
|
|
|
|
}
|
|
|
|
|
2014-01-09 07:05:33 -06:00
|
|
|
impl<O:DataFlowOperator> pprust::PpAnn for DataFlowContext<O> {
|
2014-01-29 20:42:19 -06:00
|
|
|
fn pre(&self, node: pprust::AnnNode) -> io::IoResult<()> {
|
2013-08-29 17:24:33 -05:00
|
|
|
let (ps, id) = match node {
|
2014-01-09 07:05:33 -06:00
|
|
|
pprust::NodeExpr(ps, expr) => (ps, expr.id),
|
|
|
|
pprust::NodeBlock(ps, blk) => (ps, blk.id),
|
|
|
|
pprust::NodeItem(ps, _) => (ps, 0),
|
|
|
|
pprust::NodePat(ps, pat) => (ps, pat.id)
|
2013-08-29 17:24:33 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
if self.nodeid_to_bitset.contains_key(&id) {
|
|
|
|
let (start, end) = self.compute_id_range_frozen(id);
|
|
|
|
let on_entry = self.on_entry.slice(start, end);
|
|
|
|
let entry_str = bits_to_str(on_entry);
|
|
|
|
|
|
|
|
let gens = self.gens.slice(start, end);
|
|
|
|
let gens_str = if gens.iter().any(|&u| u != 0) {
|
2013-09-28 00:38:08 -05:00
|
|
|
format!(" gen: {}", bits_to_str(gens))
|
2013-08-29 17:24:33 -05:00
|
|
|
} else {
|
|
|
|
~""
|
|
|
|
};
|
|
|
|
|
|
|
|
let kills = self.kills.slice(start, end);
|
|
|
|
let kills_str = if kills.iter().any(|&u| u != 0) {
|
2013-09-28 00:38:08 -05:00
|
|
|
format!(" kill: {}", bits_to_str(kills))
|
2013-08-29 17:24:33 -05:00
|
|
|
} else {
|
|
|
|
~""
|
|
|
|
};
|
|
|
|
|
2013-09-28 00:38:08 -05:00
|
|
|
let comment_str = format!("id {}: {}{}{}",
|
|
|
|
id, entry_str, gens_str, kills_str);
|
2014-01-29 20:42:19 -06:00
|
|
|
if_ok!(pprust::synth_comment(ps, comment_str));
|
|
|
|
if_ok!(pp::space(&mut ps.s));
|
2013-08-29 17:24:33 -05:00
|
|
|
}
|
2014-01-29 20:42:19 -06:00
|
|
|
Ok(())
|
2013-08-29 17:24:33 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-15 14:24:24 -05:00
|
|
|
impl<O:DataFlowOperator> DataFlowContext<O> {
|
|
|
|
pub fn new(tcx: ty::ctxt,
|
|
|
|
method_map: typeck::method_map,
|
|
|
|
oper: O,
|
2014-01-09 07:05:33 -06:00
|
|
|
id_range: IdRange,
|
2013-03-15 14:24:24 -05:00
|
|
|
bits_per_id: uint) -> DataFlowContext<O> {
|
2014-01-25 01:37:51 -06:00
|
|
|
let words_per_id = (bits_per_id + uint::BITS - 1) / uint::BITS;
|
2013-03-15 14:24:24 -05:00
|
|
|
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("DataFlowContext::new(id_range={:?}, bits_per_id={:?}, words_per_id={:?})",
|
2013-03-15 14:24:24 -05:00
|
|
|
id_range, bits_per_id, words_per_id);
|
|
|
|
|
2013-06-13 12:07:34 -05:00
|
|
|
let gens = ~[];
|
|
|
|
let kills = ~[];
|
|
|
|
let on_entry = ~[];
|
2013-03-15 14:24:24 -05:00
|
|
|
|
|
|
|
DataFlowContext {
|
|
|
|
tcx: tcx,
|
|
|
|
method_map: method_map,
|
|
|
|
words_per_id: words_per_id,
|
2013-06-13 12:07:34 -05:00
|
|
|
nodeid_to_bitset: HashMap::new(),
|
2013-03-15 14:24:24 -05:00
|
|
|
bits_per_id: bits_per_id,
|
|
|
|
oper: oper,
|
|
|
|
gens: gens,
|
|
|
|
kills: kills,
|
|
|
|
on_entry: on_entry
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-27 03:25:59 -05:00
|
|
|
pub fn add_gen(&mut self, id: ast::NodeId, bit: uint) {
|
2013-03-15 14:24:24 -05:00
|
|
|
//! Indicates that `id` generates `bit`
|
|
|
|
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("add_gen(id={:?}, bit={:?})", id, bit);
|
2013-03-15 14:24:24 -05:00
|
|
|
let (start, end) = self.compute_id_range(id);
|
|
|
|
{
|
2013-06-27 04:48:50 -05:00
|
|
|
let gens = self.gens.mut_slice(start, end);
|
2013-03-15 14:24:24 -05:00
|
|
|
set_bit(gens, bit);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-27 03:25:59 -05:00
|
|
|
pub fn add_kill(&mut self, id: ast::NodeId, bit: uint) {
|
2013-03-15 14:24:24 -05:00
|
|
|
//! Indicates that `id` kills `bit`
|
|
|
|
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("add_kill(id={:?}, bit={:?})", id, bit);
|
2013-03-15 14:24:24 -05:00
|
|
|
let (start, end) = self.compute_id_range(id);
|
|
|
|
{
|
2013-06-27 04:48:50 -05:00
|
|
|
let kills = self.kills.mut_slice(start, end);
|
2013-03-15 14:24:24 -05:00
|
|
|
set_bit(kills, bit);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-27 03:25:59 -05:00
|
|
|
fn apply_gen_kill(&mut self, id: ast::NodeId, bits: &mut [uint]) {
|
2013-03-15 14:24:24 -05:00
|
|
|
//! Applies the gen and kill sets for `id` to `bits`
|
|
|
|
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("apply_gen_kill(id={:?}, bits={}) [before]",
|
2013-03-15 14:24:24 -05:00
|
|
|
id, mut_bits_to_str(bits));
|
|
|
|
let (start, end) = self.compute_id_range(id);
|
|
|
|
let gens = self.gens.slice(start, end);
|
|
|
|
bitwise(bits, gens, |a, b| a | b);
|
|
|
|
let kills = self.kills.slice(start, end);
|
|
|
|
bitwise(bits, kills, |a, b| a & !b);
|
|
|
|
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("apply_gen_kill(id={:?}, bits={}) [after]",
|
2013-03-15 14:24:24 -05:00
|
|
|
id, mut_bits_to_str(bits));
|
|
|
|
}
|
|
|
|
|
2013-07-27 03:25:59 -05:00
|
|
|
fn apply_kill(&mut self, id: ast::NodeId, bits: &mut [uint]) {
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("apply_kill(id={:?}, bits={}) [before]",
|
2013-03-15 14:24:24 -05:00
|
|
|
id, mut_bits_to_str(bits));
|
|
|
|
let (start, end) = self.compute_id_range(id);
|
|
|
|
let kills = self.kills.slice(start, end);
|
|
|
|
bitwise(bits, kills, |a, b| a & !b);
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("apply_kill(id={:?}, bits={}) [after]",
|
2013-03-15 14:24:24 -05:00
|
|
|
id, mut_bits_to_str(bits));
|
|
|
|
}
|
|
|
|
|
2013-07-27 03:25:59 -05:00
|
|
|
fn compute_id_range_frozen(&self, id: ast::NodeId) -> (uint, uint) {
|
2013-06-13 12:07:34 -05:00
|
|
|
let n = *self.nodeid_to_bitset.get(&id);
|
|
|
|
let start = n * self.words_per_id;
|
|
|
|
let end = start + self.words_per_id;
|
|
|
|
(start, end)
|
|
|
|
}
|
2013-03-15 14:24:24 -05:00
|
|
|
|
2013-07-27 03:25:59 -05:00
|
|
|
fn compute_id_range(&mut self, id: ast::NodeId) -> (uint, uint) {
|
2013-06-13 12:07:34 -05:00
|
|
|
let mut expanded = false;
|
|
|
|
let len = self.nodeid_to_bitset.len();
|
2013-11-21 17:42:55 -06:00
|
|
|
let n = self.nodeid_to_bitset.find_or_insert_with(id, |_| {
|
2013-06-13 12:07:34 -05:00
|
|
|
expanded = true;
|
|
|
|
len
|
2013-11-21 17:42:55 -06:00
|
|
|
});
|
2013-06-13 12:07:34 -05:00
|
|
|
if expanded {
|
2014-01-25 01:37:51 -06:00
|
|
|
let entry = if self.oper.initial_value() { uint::MAX } else {0};
|
2014-01-29 18:20:34 -06:00
|
|
|
for _ in range(0, self.words_per_id) {
|
2013-06-13 12:07:34 -05:00
|
|
|
self.gens.push(0);
|
|
|
|
self.kills.push(0);
|
|
|
|
self.on_entry.push(entry);
|
2014-01-29 18:20:34 -06:00
|
|
|
}
|
2013-06-13 12:07:34 -05:00
|
|
|
}
|
|
|
|
let start = *n * self.words_per_id;
|
2013-03-15 14:24:24 -05:00
|
|
|
let end = start + self.words_per_id;
|
2013-06-13 12:07:34 -05:00
|
|
|
|
|
|
|
assert!(start < self.gens.len());
|
|
|
|
assert!(end <= self.gens.len());
|
|
|
|
assert!(self.gens.len() == self.kills.len());
|
|
|
|
assert!(self.gens.len() == self.on_entry.len());
|
|
|
|
|
2013-03-15 14:24:24 -05:00
|
|
|
(start, end)
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-06-13 12:07:34 -05:00
|
|
|
pub fn each_bit_on_entry_frozen(&self,
|
2013-07-27 03:25:59 -05:00
|
|
|
id: ast::NodeId,
|
2013-11-19 15:22:03 -06:00
|
|
|
f: |uint| -> bool)
|
|
|
|
-> bool {
|
2013-06-13 12:07:34 -05:00
|
|
|
//! Iterates through each bit that is set on entry to `id`.
|
|
|
|
//! Only useful after `propagate()` has been called.
|
|
|
|
if !self.nodeid_to_bitset.contains_key(&id) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
let (start, end) = self.compute_id_range_frozen(id);
|
2013-06-27 04:48:50 -05:00
|
|
|
let on_entry = self.on_entry.slice(start, end);
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("each_bit_on_entry_frozen(id={:?}, on_entry={})",
|
2013-06-13 12:07:34 -05:00
|
|
|
id, bits_to_str(on_entry));
|
|
|
|
self.each_bit(on_entry, f)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn each_bit_on_entry(&mut self,
|
2013-07-27 03:25:59 -05:00
|
|
|
id: ast::NodeId,
|
2013-11-19 15:22:03 -06:00
|
|
|
f: |uint| -> bool)
|
|
|
|
-> bool {
|
2013-05-03 12:08:08 -05:00
|
|
|
//! Iterates through each bit that is set on entry to `id`.
|
|
|
|
//! Only useful after `propagate()` has been called.
|
|
|
|
|
|
|
|
let (start, end) = self.compute_id_range(id);
|
2013-06-27 04:48:50 -05:00
|
|
|
let on_entry = self.on_entry.slice(start, end);
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("each_bit_on_entry(id={:?}, on_entry={})",
|
2013-05-03 12:08:08 -05:00
|
|
|
id, bits_to_str(on_entry));
|
|
|
|
self.each_bit(on_entry, f)
|
|
|
|
}
|
2013-03-15 14:24:24 -05:00
|
|
|
|
2013-11-19 15:22:03 -06:00
|
|
|
pub fn each_gen_bit(&mut self, id: ast::NodeId, f: |uint| -> bool)
|
|
|
|
-> bool {
|
2013-05-03 12:08:08 -05:00
|
|
|
//! Iterates through each bit in the gen set for `id`.
|
2013-03-15 14:24:24 -05:00
|
|
|
|
2013-05-03 12:08:08 -05:00
|
|
|
let (start, end) = self.compute_id_range(id);
|
2013-06-27 04:48:50 -05:00
|
|
|
let gens = self.gens.slice(start, end);
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("each_gen_bit(id={:?}, gens={})",
|
2013-05-03 12:08:08 -05:00
|
|
|
id, bits_to_str(gens));
|
|
|
|
self.each_bit(gens, f)
|
|
|
|
}
|
|
|
|
|
2013-11-19 15:22:03 -06:00
|
|
|
pub fn each_gen_bit_frozen(&self, id: ast::NodeId, f: |uint| -> bool)
|
|
|
|
-> bool {
|
2013-06-13 12:07:34 -05:00
|
|
|
//! Iterates through each bit in the gen set for `id`.
|
|
|
|
if !self.nodeid_to_bitset.contains_key(&id) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
let (start, end) = self.compute_id_range_frozen(id);
|
2013-06-27 04:48:50 -05:00
|
|
|
let gens = self.gens.slice(start, end);
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("each_gen_bit(id={:?}, gens={})",
|
2013-06-13 12:07:34 -05:00
|
|
|
id, bits_to_str(gens));
|
|
|
|
self.each_bit(gens, f)
|
|
|
|
}
|
|
|
|
|
2013-11-19 15:22:03 -06:00
|
|
|
fn each_bit(&self, words: &[uint], f: |uint| -> bool) -> bool {
|
2013-05-03 12:08:08 -05:00
|
|
|
//! Helper for iterating over the bits in a bit set.
|
|
|
|
|
2013-08-03 11:45:23 -05:00
|
|
|
for (word_index, &word) in words.iter().enumerate() {
|
2013-05-03 12:08:08 -05:00
|
|
|
if word != 0 {
|
2014-01-25 01:37:51 -06:00
|
|
|
let base_index = word_index * uint::BITS;
|
|
|
|
for offset in range(0u, uint::BITS) {
|
2013-05-03 12:08:08 -05: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
|
2014-01-25 01:37:51 -06:00
|
|
|
// it is an even multiple of uint::BITS. This
|
2013-05-03 12:08:08 -05: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.
|
|
|
|
let bit_index = base_index + offset;
|
|
|
|
if bit_index >= self.bits_per_id {
|
|
|
|
return true;
|
|
|
|
} else if !f(bit_index) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2013-03-15 14:24:24 -05:00
|
|
|
}
|
|
|
|
|
2013-07-02 14:47:32 -05:00
|
|
|
impl<O:DataFlowOperator+Clone+'static> DataFlowContext<O> {
|
|
|
|
// ^^^^^^^^^^^^^ only needed for pretty printing
|
2013-07-19 00:38:55 -05:00
|
|
|
pub fn propagate(&mut self, blk: &ast::Block) {
|
2013-03-15 14:24:24 -05:00
|
|
|
//! Performs the data flow analysis.
|
|
|
|
|
|
|
|
if self.bits_per_id == 0 {
|
|
|
|
// Optimize the surprisingly common degenerate case.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-07-02 14:47:32 -05:00
|
|
|
{
|
|
|
|
let mut propcx = PropagationContext {
|
|
|
|
dfcx: self,
|
|
|
|
changed: true
|
|
|
|
};
|
2013-03-15 14:24:24 -05:00
|
|
|
|
2013-07-02 14:47:32 -05:00
|
|
|
let mut temp = vec::from_elem(self.words_per_id, 0u);
|
|
|
|
let mut loop_scopes = ~[];
|
2013-03-15 14:24:24 -05:00
|
|
|
|
2013-07-02 14:47:32 -05:00
|
|
|
while propcx.changed {
|
|
|
|
propcx.changed = false;
|
|
|
|
propcx.reset(temp);
|
|
|
|
propcx.walk_block(blk, temp, &mut loop_scopes);
|
|
|
|
}
|
2013-03-15 14:24:24 -05:00
|
|
|
}
|
|
|
|
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("Dataflow result:");
|
|
|
|
debug!("{}", {
|
2014-02-06 16:38:33 -06:00
|
|
|
self.pretty_print_to(~io::stderr(), blk).unwrap();
|
2013-03-15 14:24:24 -05:00
|
|
|
""
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2014-02-06 16:38:33 -06:00
|
|
|
fn pretty_print_to(&self, wr: ~io::Writer,
|
2014-01-29 20:42:19 -06:00
|
|
|
blk: &ast::Block) -> io::IoResult<()> {
|
2014-02-13 23:07:09 -06:00
|
|
|
let mut ps = pprust::rust_printer_annotated(wr, self);
|
2014-01-29 20:42:19 -06:00
|
|
|
if_ok!(pprust::cbox(&mut ps, pprust::indent_unit));
|
|
|
|
if_ok!(pprust::ibox(&mut ps, 0u));
|
|
|
|
if_ok!(pprust::print_block(&mut ps, blk));
|
|
|
|
if_ok!(pp::eof(&mut ps.s));
|
|
|
|
Ok(())
|
2013-03-15 14:24:24 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-10 01:16:18 -06:00
|
|
|
impl<'a, O:DataFlowOperator> PropagationContext<'a, O> {
|
2013-03-15 14:24:24 -05:00
|
|
|
fn tcx(&self) -> ty::ctxt {
|
|
|
|
self.dfcx.tcx
|
|
|
|
}
|
|
|
|
|
|
|
|
fn walk_block(&mut self,
|
2013-07-19 00:38:55 -05:00
|
|
|
blk: &ast::Block,
|
2013-03-15 14:24:24 -05:00
|
|
|
in_out: &mut [uint],
|
|
|
|
loop_scopes: &mut ~[LoopScope]) {
|
2014-02-07 13:36:13 -06:00
|
|
|
debug!("DataFlowContext::walk_block(blk.id={}, in_out={})",
|
|
|
|
blk.id, bits_to_str(in_out));
|
2013-03-15 14:24:24 -05:00
|
|
|
|
2013-07-16 13:08:35 -05:00
|
|
|
self.merge_with_entry_set(blk.id, in_out);
|
2013-03-15 14:24:24 -05:00
|
|
|
|
2013-08-03 11:45:23 -05:00
|
|
|
for &stmt in blk.stmts.iter() {
|
2013-03-15 14:24:24 -05:00
|
|
|
self.walk_stmt(stmt, in_out, loop_scopes);
|
|
|
|
}
|
|
|
|
|
2013-07-16 13:08:35 -05:00
|
|
|
self.walk_opt_expr(blk.expr, in_out, loop_scopes);
|
2013-03-15 14:24:24 -05:00
|
|
|
|
2013-07-16 13:08:35 -05:00
|
|
|
self.dfcx.apply_gen_kill(blk.id, in_out);
|
2013-03-15 14:24:24 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn walk_stmt(&mut self,
|
2013-09-01 20:45:37 -05:00
|
|
|
stmt: @ast::Stmt,
|
2013-03-15 14:24:24 -05:00
|
|
|
in_out: &mut [uint],
|
|
|
|
loop_scopes: &mut ~[LoopScope]) {
|
|
|
|
match stmt.node {
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::StmtDecl(decl, _) => {
|
2013-03-15 14:24:24 -05:00
|
|
|
self.walk_decl(decl, in_out, loop_scopes);
|
|
|
|
}
|
|
|
|
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::StmtExpr(expr, _) | ast::StmtSemi(expr, _) => {
|
2013-03-15 14:24:24 -05:00
|
|
|
self.walk_expr(expr, in_out, loop_scopes);
|
|
|
|
}
|
|
|
|
|
2013-11-28 14:22:53 -06:00
|
|
|
ast::StmtMac(..) => {
|
2013-05-19 00:07:44 -05:00
|
|
|
self.tcx().sess.span_bug(stmt.span, "unexpanded macro");
|
2013-03-15 14:24:24 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn walk_decl(&mut self,
|
2013-09-01 20:45:37 -05:00
|
|
|
decl: @ast::Decl,
|
2013-03-15 14:24:24 -05:00
|
|
|
in_out: &mut [uint],
|
|
|
|
loop_scopes: &mut ~[LoopScope]) {
|
|
|
|
match decl.node {
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::DeclLocal(local) => {
|
2013-07-19 00:38:55 -05:00
|
|
|
self.walk_opt_expr(local.init, in_out, loop_scopes);
|
|
|
|
self.walk_pat(local.pat, in_out, loop_scopes);
|
2013-03-15 14:24:24 -05:00
|
|
|
}
|
|
|
|
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::DeclItem(_) => {}
|
2013-03-15 14:24:24 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn walk_expr(&mut self,
|
2013-09-30 12:37:17 -05:00
|
|
|
expr: &ast::Expr,
|
2013-03-15 14:24:24 -05:00
|
|
|
in_out: &mut [uint],
|
|
|
|
loop_scopes: &mut ~[LoopScope]) {
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("DataFlowContext::walk_expr(expr={}, in_out={})",
|
2014-02-07 13:36:13 -06:00
|
|
|
expr.repr(self.dfcx.tcx), bits_to_str(in_out));
|
2013-03-15 14:24:24 -05:00
|
|
|
|
|
|
|
self.merge_with_entry_set(expr.id, in_out);
|
|
|
|
|
|
|
|
match expr.node {
|
2014-02-07 13:36:13 -06:00
|
|
|
ast::ExprFnBlock(..) | ast::ExprProc(..) => {
|
2013-03-15 14:24:24 -05:00
|
|
|
}
|
|
|
|
|
2013-11-30 16:00:39 -06:00
|
|
|
ast::ExprIf(cond, then, els) => {
|
2013-03-15 14:24:24 -05:00
|
|
|
//
|
|
|
|
// (cond)
|
|
|
|
// |
|
|
|
|
// v
|
|
|
|
// ( )
|
|
|
|
// / \
|
|
|
|
// | |
|
|
|
|
// v v
|
|
|
|
// (then)(els)
|
|
|
|
// | |
|
|
|
|
// v v
|
|
|
|
// ( succ )
|
|
|
|
//
|
|
|
|
self.walk_expr(cond, in_out, loop_scopes);
|
|
|
|
|
2014-02-07 13:36:13 -06:00
|
|
|
let mut then_bits = in_out.to_owned();
|
2013-03-15 14:24:24 -05:00
|
|
|
self.walk_block(then, then_bits, loop_scopes);
|
|
|
|
|
|
|
|
self.walk_opt_expr(els, in_out, loop_scopes);
|
|
|
|
join_bits(&self.dfcx.oper, then_bits, in_out);
|
|
|
|
}
|
|
|
|
|
2013-11-30 16:00:39 -06:00
|
|
|
ast::ExprWhile(cond, blk) => {
|
2013-03-15 14:24:24 -05:00
|
|
|
//
|
|
|
|
// (expr) <--+
|
|
|
|
// | |
|
|
|
|
// v |
|
|
|
|
// +--(cond) |
|
|
|
|
// | | |
|
|
|
|
// | v |
|
|
|
|
// v (blk) ----+
|
|
|
|
// |
|
|
|
|
// <--+ (break)
|
|
|
|
//
|
|
|
|
|
|
|
|
self.walk_expr(cond, in_out, loop_scopes);
|
|
|
|
|
2014-02-07 13:36:13 -06:00
|
|
|
let mut body_bits = in_out.to_owned();
|
2013-03-15 14:24:24 -05:00
|
|
|
loop_scopes.push(LoopScope {
|
|
|
|
loop_id: expr.id,
|
2014-02-07 13:36:13 -06:00
|
|
|
break_bits: in_out.to_owned()
|
2013-03-15 14:24:24 -05:00
|
|
|
});
|
|
|
|
self.walk_block(blk, body_bits, loop_scopes);
|
|
|
|
self.add_to_entry_set(expr.id, body_bits);
|
2013-12-23 09:20:52 -06:00
|
|
|
let new_loop_scope = loop_scopes.pop().unwrap();
|
2013-03-15 14:24:24 -05:00
|
|
|
copy_bits(new_loop_scope.break_bits, in_out);
|
|
|
|
}
|
|
|
|
|
2013-11-28 14:22:53 -06:00
|
|
|
ast::ExprForLoop(..) => fail!("non-desugared expr_for_loop"),
|
2013-07-29 19:25:00 -05:00
|
|
|
|
2013-11-30 16:00:39 -06:00
|
|
|
ast::ExprLoop(blk, _) => {
|
2013-03-15 14:24:24 -05:00
|
|
|
//
|
|
|
|
// (expr) <--+
|
|
|
|
// | |
|
|
|
|
// v |
|
|
|
|
// (blk) ----+
|
|
|
|
// |
|
|
|
|
// <--+ (break)
|
|
|
|
//
|
|
|
|
|
2014-02-07 13:36:13 -06:00
|
|
|
let mut body_bits = in_out.to_owned();
|
2013-03-15 14:24:24 -05:00
|
|
|
self.reset(in_out);
|
|
|
|
loop_scopes.push(LoopScope {
|
|
|
|
loop_id: expr.id,
|
2014-02-07 13:36:13 -06:00
|
|
|
break_bits: in_out.to_owned()
|
2013-03-15 14:24:24 -05:00
|
|
|
});
|
|
|
|
self.walk_block(blk, body_bits, loop_scopes);
|
|
|
|
self.add_to_entry_set(expr.id, body_bits);
|
|
|
|
|
2013-12-23 09:20:52 -06:00
|
|
|
let new_loop_scope = loop_scopes.pop().unwrap();
|
2013-03-15 14:24:24 -05:00
|
|
|
assert_eq!(new_loop_scope.loop_id, expr.id);
|
|
|
|
copy_bits(new_loop_scope.break_bits, in_out);
|
|
|
|
}
|
|
|
|
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::ExprMatch(discr, ref arms) => {
|
2013-03-15 14:24:24 -05:00
|
|
|
//
|
|
|
|
// (discr)
|
|
|
|
// / | \
|
|
|
|
// | | |
|
|
|
|
// v v v
|
|
|
|
// (..arms..)
|
|
|
|
// | | |
|
|
|
|
// v v v
|
|
|
|
// ( succ )
|
|
|
|
//
|
|
|
|
//
|
|
|
|
self.walk_expr(discr, in_out, loop_scopes);
|
|
|
|
|
2014-02-07 13:36:13 -06:00
|
|
|
let mut guards = in_out.to_owned();
|
2013-03-15 14:24:24 -05:00
|
|
|
|
|
|
|
// We know that exactly one arm will be taken, so we
|
|
|
|
// can start out with a blank slate and just union
|
|
|
|
// together the bits from each arm:
|
|
|
|
self.reset(in_out);
|
|
|
|
|
2013-08-03 11:45:23 -05:00
|
|
|
for arm in arms.iter() {
|
2013-03-15 14:24:24 -05:00
|
|
|
// in_out reflects the discr and all guards to date
|
|
|
|
self.walk_opt_expr(arm.guard, guards, loop_scopes);
|
|
|
|
|
|
|
|
// determine the bits for the body and then union
|
|
|
|
// them into `in_out`, which reflects all bodies to date
|
2014-02-07 13:36:13 -06:00
|
|
|
let mut body = guards.to_owned();
|
2013-03-15 14:24:24 -05:00
|
|
|
self.walk_pat_alternatives(arm.pats, body, loop_scopes);
|
2013-11-30 16:00:39 -06:00
|
|
|
self.walk_block(arm.body, body, loop_scopes);
|
2013-03-15 14:24:24 -05:00
|
|
|
join_bits(&self.dfcx.oper, body, in_out);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::ExprRet(o_e) => {
|
2013-03-15 14:24:24 -05:00
|
|
|
self.walk_opt_expr(o_e, in_out, loop_scopes);
|
|
|
|
self.reset(in_out);
|
|
|
|
}
|
|
|
|
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::ExprBreak(label) => {
|
2013-03-15 14:24:24 -05:00
|
|
|
let scope = self.find_scope(expr, label, loop_scopes);
|
|
|
|
self.break_from_to(expr, scope, in_out);
|
|
|
|
self.reset(in_out);
|
|
|
|
}
|
|
|
|
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::ExprAgain(label) => {
|
2013-03-15 14:24:24 -05:00
|
|
|
let scope = self.find_scope(expr, label, loop_scopes);
|
2013-08-03 22:51:29 -05:00
|
|
|
self.pop_scopes(expr, scope, in_out);
|
2014-02-07 13:36:13 -06:00
|
|
|
self.add_to_entry_set(scope.loop_id, in_out);
|
2013-03-15 14:24:24 -05:00
|
|
|
self.reset(in_out);
|
|
|
|
}
|
|
|
|
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::ExprAssign(l, r) |
|
|
|
|
ast::ExprAssignOp(_, _, l, r) => {
|
2013-03-15 14:24:24 -05:00
|
|
|
self.walk_expr(r, in_out, loop_scopes);
|
|
|
|
self.walk_expr(l, in_out, loop_scopes);
|
|
|
|
}
|
|
|
|
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::ExprVec(ref exprs, _) => {
|
2013-03-15 14:24:24 -05:00
|
|
|
self.walk_exprs(*exprs, in_out, loop_scopes)
|
|
|
|
}
|
|
|
|
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::ExprRepeat(l, r, _) => {
|
2013-03-15 14:24:24 -05:00
|
|
|
self.walk_expr(l, in_out, loop_scopes);
|
|
|
|
self.walk_expr(r, in_out, loop_scopes);
|
|
|
|
}
|
|
|
|
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::ExprStruct(_, ref fields, with_expr) => {
|
2013-08-03 11:45:23 -05:00
|
|
|
for field in fields.iter() {
|
2013-07-19 09:24:22 -05:00
|
|
|
self.walk_expr(field.expr, in_out, loop_scopes);
|
2013-03-15 14:24:24 -05:00
|
|
|
}
|
2013-05-22 05:54:35 -05:00
|
|
|
self.walk_opt_expr(with_expr, in_out, loop_scopes);
|
2013-03-15 14:24:24 -05:00
|
|
|
}
|
|
|
|
|
2014-02-14 02:28:32 -06:00
|
|
|
ast::ExprCall(f, ref args) => {
|
2014-01-27 06:18:36 -06:00
|
|
|
self.walk_expr(f, in_out, loop_scopes);
|
|
|
|
self.walk_call(f.id, expr.id, *args, in_out, loop_scopes);
|
2013-03-15 14:24:24 -05:00
|
|
|
}
|
|
|
|
|
2014-02-14 02:28:32 -06:00
|
|
|
ast::ExprMethodCall(callee_id, _, _, ref args) => {
|
2014-01-27 06:18:36 -06:00
|
|
|
self.walk_call(callee_id, expr.id, *args, in_out, loop_scopes);
|
2013-03-15 14:24:24 -05:00
|
|
|
}
|
|
|
|
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::ExprIndex(callee_id, l, r) |
|
|
|
|
ast::ExprBinary(callee_id, _, l, r) if self.is_method_call(expr) => {
|
2014-01-27 06:18:36 -06:00
|
|
|
self.walk_call(callee_id, expr.id, [l, r], in_out, loop_scopes);
|
2013-03-15 14:24:24 -05:00
|
|
|
}
|
|
|
|
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::ExprUnary(callee_id, _, e) if self.is_method_call(expr) => {
|
2014-01-27 06:18:36 -06:00
|
|
|
self.walk_call(callee_id, expr.id, [e], in_out, loop_scopes);
|
2013-03-15 14:24:24 -05:00
|
|
|
}
|
|
|
|
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::ExprTup(ref exprs) => {
|
2013-03-15 14:24:24 -05:00
|
|
|
self.walk_exprs(*exprs, in_out, loop_scopes);
|
|
|
|
}
|
|
|
|
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::ExprBinary(_, op, l, r) if ast_util::lazy_binop(op) => {
|
2013-03-15 14:24:24 -05:00
|
|
|
self.walk_expr(l, in_out, loop_scopes);
|
2014-02-07 13:36:13 -06:00
|
|
|
let temp = in_out.to_owned();
|
2013-03-15 14:24:24 -05:00
|
|
|
self.walk_expr(r, in_out, loop_scopes);
|
|
|
|
join_bits(&self.dfcx.oper, temp, in_out);
|
|
|
|
}
|
|
|
|
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::ExprIndex(_, l, r) |
|
|
|
|
ast::ExprBinary(_, _, l, r) => {
|
2013-03-15 14:24:24 -05:00
|
|
|
self.walk_exprs([l, r], in_out, loop_scopes);
|
|
|
|
}
|
|
|
|
|
2013-08-28 01:12:05 -05:00
|
|
|
ast::ExprLogLevel |
|
2013-11-28 14:22:53 -06:00
|
|
|
ast::ExprLit(..) |
|
2014-01-27 06:18:36 -06:00
|
|
|
ast::ExprPath(..) => {}
|
2013-03-15 14:24:24 -05:00
|
|
|
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::ExprAddrOf(_, e) |
|
|
|
|
ast::ExprCast(e, _) |
|
|
|
|
ast::ExprUnary(_, _, e) |
|
|
|
|
ast::ExprParen(e) |
|
|
|
|
ast::ExprVstore(e, _) |
|
|
|
|
ast::ExprField(e, _, _) => {
|
2013-03-15 14:24:24 -05:00
|
|
|
self.walk_expr(e, in_out, loop_scopes);
|
|
|
|
}
|
|
|
|
|
2013-12-17 18:46:18 -06:00
|
|
|
ast::ExprBox(s, e) => {
|
|
|
|
self.walk_expr(s, in_out, loop_scopes);
|
|
|
|
self.walk_expr(e, in_out, loop_scopes);
|
|
|
|
}
|
|
|
|
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::ExprInlineAsm(ref inline_asm) => {
|
2013-08-03 11:45:23 -05:00
|
|
|
for &(_, expr) in inline_asm.inputs.iter() {
|
2013-03-15 14:24:24 -05:00
|
|
|
self.walk_expr(expr, in_out, loop_scopes);
|
|
|
|
}
|
2013-08-03 11:45:23 -05:00
|
|
|
for &(_, expr) in inline_asm.outputs.iter() {
|
2013-03-15 14:24:24 -05:00
|
|
|
self.walk_expr(expr, in_out, loop_scopes);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-30 16:00:39 -06:00
|
|
|
ast::ExprBlock(blk) => {
|
2013-03-15 14:24:24 -05:00
|
|
|
self.walk_block(blk, in_out, loop_scopes);
|
|
|
|
}
|
|
|
|
|
2013-11-28 14:22:53 -06:00
|
|
|
ast::ExprMac(..) => {
|
2013-05-19 00:07:44 -05:00
|
|
|
self.tcx().sess.span_bug(expr.span, "unexpanded macro");
|
2013-03-15 14:24:24 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
self.dfcx.apply_gen_kill(expr.id, in_out);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn pop_scopes(&mut self,
|
2013-09-30 12:37:17 -05:00
|
|
|
from_expr: &ast::Expr,
|
2013-03-15 14:24:24 -05:00
|
|
|
to_scope: &mut LoopScope,
|
|
|
|
in_out: &mut [uint]) {
|
|
|
|
//! Whenever you have a `break` or a `loop` statement, flow
|
|
|
|
//! exits through any number of enclosing scopes on its
|
|
|
|
//! way to the new destination. This function applies the kill
|
|
|
|
//! sets of those enclosing scopes to `in_out` (those kill sets
|
|
|
|
//! concern items that are going out of scope).
|
|
|
|
|
|
|
|
let tcx = self.tcx();
|
|
|
|
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("pop_scopes(from_expr={}, to_scope={:?}, in_out={})",
|
2013-03-15 14:24:24 -05:00
|
|
|
from_expr.repr(tcx), to_scope.loop_id,
|
2014-02-07 13:36:13 -06:00
|
|
|
bits_to_str(in_out));
|
2013-03-15 14:24:24 -05:00
|
|
|
|
|
|
|
let mut id = from_expr.id;
|
|
|
|
while id != to_scope.loop_id {
|
|
|
|
self.dfcx.apply_kill(id, in_out);
|
|
|
|
|
2014-01-06 06:00:46 -06:00
|
|
|
match tcx.region_maps.opt_encl_scope(id) {
|
2013-03-15 14:24:24 -05:00
|
|
|
Some(i) => { id = i; }
|
|
|
|
None => {
|
|
|
|
tcx.sess.span_bug(
|
|
|
|
from_expr.span,
|
2013-09-28 00:38:08 -05:00
|
|
|
format!("pop_scopes(from_expr={}, to_scope={:?}) \
|
2013-03-15 14:24:24 -05:00
|
|
|
to_scope does not enclose from_expr",
|
|
|
|
from_expr.repr(tcx), to_scope.loop_id));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn break_from_to(&mut self,
|
2013-09-30 12:37:17 -05:00
|
|
|
from_expr: &ast::Expr,
|
2013-03-15 14:24:24 -05:00
|
|
|
to_scope: &mut LoopScope,
|
|
|
|
in_out: &mut [uint]) {
|
|
|
|
self.pop_scopes(from_expr, to_scope, in_out);
|
|
|
|
self.dfcx.apply_kill(from_expr.id, in_out);
|
2014-02-07 13:36:13 -06:00
|
|
|
join_bits(&self.dfcx.oper, in_out, to_scope.break_bits);
|
|
|
|
debug!("break_from_to(from_expr={}, to_scope={}) final break_bits={}",
|
2013-03-15 14:24:24 -05:00
|
|
|
from_expr.repr(self.tcx()),
|
|
|
|
to_scope.loop_id,
|
2014-02-07 13:36:13 -06:00
|
|
|
bits_to_str(in_out));
|
2013-03-15 14:24:24 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn walk_exprs(&mut self,
|
2013-09-01 20:45:37 -05:00
|
|
|
exprs: &[@ast::Expr],
|
2013-03-15 14:24:24 -05:00
|
|
|
in_out: &mut [uint],
|
|
|
|
loop_scopes: &mut ~[LoopScope]) {
|
2013-08-03 11:45:23 -05:00
|
|
|
for &expr in exprs.iter() {
|
2013-03-15 14:24:24 -05:00
|
|
|
self.walk_expr(expr, in_out, loop_scopes);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn walk_opt_expr(&mut self,
|
2013-09-01 20:45:37 -05:00
|
|
|
opt_expr: Option<@ast::Expr>,
|
2013-03-15 14:24:24 -05:00
|
|
|
in_out: &mut [uint],
|
|
|
|
loop_scopes: &mut ~[LoopScope]) {
|
2013-08-03 11:45:23 -05:00
|
|
|
for &expr in opt_expr.iter() {
|
2013-03-15 14:24:24 -05:00
|
|
|
self.walk_expr(expr, in_out, loop_scopes);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn walk_call(&mut self,
|
2013-07-27 03:25:59 -05:00
|
|
|
_callee_id: ast::NodeId,
|
|
|
|
call_id: ast::NodeId,
|
2013-09-01 20:45:37 -05:00
|
|
|
args: &[@ast::Expr],
|
2013-03-15 14:24:24 -05:00
|
|
|
in_out: &mut [uint],
|
|
|
|
loop_scopes: &mut ~[LoopScope]) {
|
|
|
|
self.walk_exprs(args, in_out, loop_scopes);
|
|
|
|
|
2013-05-06 13:02:28 -05:00
|
|
|
// FIXME(#6268) nested method calls
|
2013-03-15 14:24:24 -05:00
|
|
|
// self.merge_with_entry_set(callee_id, in_out);
|
|
|
|
// self.dfcx.apply_gen_kill(callee_id, in_out);
|
|
|
|
|
|
|
|
let return_ty = ty::node_id_to_type(self.tcx(), call_id);
|
|
|
|
let fails = ty::type_is_bot(return_ty);
|
|
|
|
if fails {
|
|
|
|
self.reset(in_out);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn walk_pat(&mut self,
|
2013-09-01 20:45:37 -05:00
|
|
|
pat: @ast::Pat,
|
2013-03-15 14:24:24 -05:00
|
|
|
in_out: &mut [uint],
|
|
|
|
_loop_scopes: &mut ~[LoopScope]) {
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("DataFlowContext::walk_pat(pat={}, in_out={})",
|
2014-02-07 13:36:13 -06:00
|
|
|
pat.repr(self.dfcx.tcx), bits_to_str(in_out));
|
2013-03-15 14:24:24 -05:00
|
|
|
|
2013-11-21 17:42:55 -06:00
|
|
|
ast_util::walk_pat(pat, |p| {
|
2014-02-07 13:36:13 -06:00
|
|
|
debug!(" p.id={} in_out={}", p.id, bits_to_str(in_out));
|
2013-03-15 14:24:24 -05:00
|
|
|
self.merge_with_entry_set(p.id, in_out);
|
|
|
|
self.dfcx.apply_gen_kill(p.id, in_out);
|
2013-08-02 01:17:20 -05:00
|
|
|
true
|
2013-11-21 17:42:55 -06:00
|
|
|
});
|
2013-03-15 14:24:24 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn walk_pat_alternatives(&mut self,
|
2013-09-01 20:45:37 -05:00
|
|
|
pats: &[@ast::Pat],
|
2013-03-15 14:24:24 -05:00
|
|
|
in_out: &mut [uint],
|
|
|
|
loop_scopes: &mut ~[LoopScope]) {
|
|
|
|
if pats.len() == 1 {
|
|
|
|
// Common special case:
|
|
|
|
return self.walk_pat(pats[0], in_out, loop_scopes);
|
|
|
|
}
|
|
|
|
|
|
|
|
// In the general case, the patterns in `pats` are
|
|
|
|
// alternatives, so we must treat this like an N-way select
|
|
|
|
// statement.
|
2014-02-07 13:36:13 -06:00
|
|
|
let initial_state = in_out.to_owned();
|
2013-08-03 11:45:23 -05:00
|
|
|
for &pat in pats.iter() {
|
2013-07-02 14:47:32 -05:00
|
|
|
let mut temp = initial_state.clone();
|
2013-04-30 13:07:26 -05:00
|
|
|
self.walk_pat(pat, temp, loop_scopes);
|
2013-03-15 14:24:24 -05:00
|
|
|
join_bits(&self.dfcx.oper, temp, in_out);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn find_scope<'a>(&self,
|
2013-09-30 12:37:17 -05:00
|
|
|
expr: &ast::Expr,
|
2013-09-10 14:01:44 -05:00
|
|
|
label: Option<ast::Name>,
|
2013-03-15 14:24:24 -05:00
|
|
|
loop_scopes: &'a mut ~[LoopScope]) -> &'a mut LoopScope {
|
|
|
|
let index = match label {
|
|
|
|
None => {
|
|
|
|
let len = loop_scopes.len();
|
|
|
|
len - 1
|
|
|
|
}
|
|
|
|
|
|
|
|
Some(_) => {
|
2013-12-23 13:15:16 -06:00
|
|
|
let def_map = self.tcx().def_map.borrow();
|
|
|
|
match def_map.get().find(&expr.id) {
|
2013-09-01 20:45:37 -05:00
|
|
|
Some(&ast::DefLabel(loop_id)) => {
|
2013-07-04 21:13:26 -05:00
|
|
|
match loop_scopes.iter().position(|l| l.loop_id == loop_id) {
|
2013-03-15 14:24:24 -05:00
|
|
|
Some(i) => i,
|
|
|
|
None => {
|
|
|
|
self.tcx().sess.span_bug(
|
|
|
|
expr.span,
|
2014-02-06 03:38:08 -06:00
|
|
|
format!("no loop scope for id {:?}", loop_id));
|
2013-03-15 14:24:24 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
r => {
|
|
|
|
self.tcx().sess.span_bug(
|
|
|
|
expr.span,
|
2014-02-06 03:38:08 -06:00
|
|
|
format!("bad entry `{:?}` in def_map for label", r));
|
2013-03-15 14:24:24 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
&mut loop_scopes[index]
|
|
|
|
}
|
|
|
|
|
2013-09-30 12:37:17 -05:00
|
|
|
fn is_method_call(&self, expr: &ast::Expr) -> bool {
|
2013-12-21 19:04:42 -06:00
|
|
|
let method_map = self.dfcx.method_map.borrow();
|
|
|
|
method_map.get().contains_key(&expr.id)
|
2013-03-15 14:24:24 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn reset(&mut self, bits: &mut [uint]) {
|
2014-01-25 01:37:51 -06:00
|
|
|
let e = if self.dfcx.oper.initial_value() {uint::MAX} else {0};
|
2013-08-03 11:45:23 -05:00
|
|
|
for b in bits.mut_iter() { *b = e; }
|
2013-03-15 14:24:24 -05:00
|
|
|
}
|
|
|
|
|
2013-07-27 03:25:59 -05:00
|
|
|
fn add_to_entry_set(&mut self, id: ast::NodeId, pred_bits: &[uint]) {
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("add_to_entry_set(id={:?}, pred_bits={})",
|
2013-03-15 14:24:24 -05:00
|
|
|
id, bits_to_str(pred_bits));
|
|
|
|
let (start, end) = self.dfcx.compute_id_range(id);
|
|
|
|
let changed = { // FIXME(#5074) awkward construction
|
2013-06-27 04:48:50 -05:00
|
|
|
let on_entry = self.dfcx.on_entry.mut_slice(start, end);
|
2013-03-15 14:24:24 -05:00
|
|
|
join_bits(&self.dfcx.oper, pred_bits, on_entry)
|
|
|
|
};
|
|
|
|
if changed {
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("changed entry set for {:?} to {}",
|
2013-03-15 14:24:24 -05:00
|
|
|
id, bits_to_str(self.dfcx.on_entry.slice(start, end)));
|
|
|
|
self.changed = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn merge_with_entry_set(&mut self,
|
2013-07-27 03:25:59 -05:00
|
|
|
id: ast::NodeId,
|
2013-03-15 14:24:24 -05:00
|
|
|
pred_bits: &mut [uint]) {
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("merge_with_entry_set(id={:?}, pred_bits={})",
|
2013-03-15 14:24:24 -05:00
|
|
|
id, mut_bits_to_str(pred_bits));
|
|
|
|
let (start, end) = self.dfcx.compute_id_range(id);
|
|
|
|
let changed = { // FIXME(#5074) awkward construction
|
2013-06-27 04:48:50 -05:00
|
|
|
let on_entry = self.dfcx.on_entry.mut_slice(start, end);
|
2014-02-07 13:36:13 -06:00
|
|
|
let changed = join_bits(&self.dfcx.oper, pred_bits, on_entry);
|
|
|
|
copy_bits(on_entry, pred_bits);
|
2013-03-15 14:24:24 -05:00
|
|
|
changed
|
|
|
|
};
|
|
|
|
if changed {
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("changed entry set for {:?} to {}",
|
2013-03-15 14:24:24 -05:00
|
|
|
id, bits_to_str(self.dfcx.on_entry.slice(start, end)));
|
|
|
|
self.changed = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn mut_bits_to_str(words: &mut [uint]) -> ~str {
|
2014-02-07 13:36:13 -06:00
|
|
|
bits_to_str(words)
|
2013-03-15 14:24:24 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn bits_to_str(words: &[uint]) -> ~str {
|
|
|
|
let mut result = ~"";
|
|
|
|
let mut sep = '[';
|
|
|
|
|
|
|
|
// Note: this is a little endian printout of bytes.
|
|
|
|
|
2013-08-03 11:45:23 -05:00
|
|
|
for &word in words.iter() {
|
2013-03-15 14:24:24 -05:00
|
|
|
let mut v = word;
|
2014-01-25 01:37:51 -06:00
|
|
|
for _ in range(0u, uint::BYTES) {
|
2013-06-10 02:42:24 -05:00
|
|
|
result.push_char(sep);
|
2013-09-28 00:38:08 -05:00
|
|
|
result.push_str(format!("{:02x}", v & 0xFF));
|
2013-03-15 14:24:24 -05:00
|
|
|
v >>= 8;
|
|
|
|
sep = '-';
|
|
|
|
}
|
|
|
|
}
|
2013-06-10 02:42:24 -05:00
|
|
|
result.push_char(']');
|
2013-03-15 14:24:24 -05:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn copy_bits(in_vec: &[uint], out_vec: &mut [uint]) -> bool {
|
|
|
|
bitwise(out_vec, in_vec, |_, b| b)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn join_bits<O:DataFlowOperator>(oper: &O,
|
|
|
|
in_vec: &[uint],
|
|
|
|
out_vec: &mut [uint]) -> bool {
|
|
|
|
bitwise(out_vec, in_vec, |a, b| oper.join(a, b))
|
|
|
|
}
|
|
|
|
|
2013-06-18 16:45:18 -05:00
|
|
|
#[inline]
|
2013-11-19 15:22:03 -06:00
|
|
|
fn bitwise(out_vec: &mut [uint], in_vec: &[uint], op: |uint, uint| -> uint)
|
|
|
|
-> bool {
|
2013-03-15 14:24:24 -05:00
|
|
|
assert_eq!(out_vec.len(), in_vec.len());
|
|
|
|
let mut changed = false;
|
2013-08-07 13:19:15 -05:00
|
|
|
for (out_elt, in_elt) in out_vec.mut_iter().zip(in_vec.iter()) {
|
|
|
|
let old_val = *out_elt;
|
|
|
|
let new_val = op(old_val, *in_elt);
|
|
|
|
*out_elt = new_val;
|
2013-03-15 14:24:24 -05:00
|
|
|
changed |= (old_val != new_val);
|
|
|
|
}
|
2013-08-01 17:35:46 -05:00
|
|
|
changed
|
2013-03-15 14:24:24 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn set_bit(words: &mut [uint], bit: uint) -> bool {
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("set_bit: words={} bit={}",
|
2013-03-15 14:24:24 -05:00
|
|
|
mut_bits_to_str(words), bit_str(bit));
|
2014-01-25 01:37:51 -06:00
|
|
|
let word = bit / uint::BITS;
|
|
|
|
let bit_in_word = bit % uint::BITS;
|
2013-03-15 14:24:24 -05:00
|
|
|
let bit_mask = 1 << bit_in_word;
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("word={} bit_in_word={} bit_mask={}", word, bit_in_word, word);
|
2013-03-15 14:24:24 -05:00
|
|
|
let oldv = words[word];
|
|
|
|
let newv = oldv | bit_mask;
|
|
|
|
words[word] = newv;
|
|
|
|
oldv != newv
|
|
|
|
}
|
|
|
|
|
|
|
|
fn bit_str(bit: uint) -> ~str {
|
|
|
|
let byte = bit >> 8;
|
|
|
|
let lobits = 1 << (bit & 0xFF);
|
2013-09-28 00:38:08 -05:00
|
|
|
format!("[{}:{}-{:02x}]", bit, byte, lobits)
|
2013-03-15 14:24:24 -05:00
|
|
|
}
|
|
|
|
|