/// equal to bits_per_id/uint::BITS rounded up.
words_per_id: uint,
- // mapping from cfg node index to bitset index.
- index_to_bitset: Vec<Option<uint>>,
-
// mapping from node to cfg node index
// FIXME (#6298): Shouldn't this go with CFG?
nodeid_to_index: NodeMap<CFGIndex>,
impl<'a, O:DataFlowOperator> DataFlowContext<'a, O> {
fn has_bitset_for_nodeid(&self, n: ast::NodeId) -> bool {
assert!(n != ast::DUMMY_NODE_ID);
- match self.nodeid_to_index.find(&n) {
- None => false,
- Some(&cfgidx) => self.has_bitset_for_cfgidx(cfgidx),
- }
- }
- fn has_bitset_for_cfgidx(&self, cfgidx: CFGIndex) -> bool {
- let node_id = cfgidx.node_id();
- node_id < self.index_to_bitset.len() &&
- self.index_to_bitset.get(node_id).is_some()
- }
- fn get_bitset_index(&self, cfgidx: CFGIndex) -> uint {
- let node_id = cfgidx.node_id();
- self.index_to_bitset.get(node_id).unwrap()
- }
- fn get_or_create_bitset_index(&mut self, cfgidx: CFGIndex) -> uint {
- assert!(self.words_per_id > 0);
- let len = self.gens.len() / self.words_per_id;
- let expanded;
- let n;
- if self.index_to_bitset.len() <= cfgidx.node_id() {
- self.index_to_bitset.grow_set(cfgidx.node_id(), &None, Some(len));
- expanded = true;
- n = len;
- } else {
- let entry = self.index_to_bitset.get_mut(cfgidx.node_id());
- match *entry {
- None => {
- *entry = Some(len);
- expanded = true;
- n = len;
- }
- Some(bitidx) => {
- expanded = false;
- n = bitidx;
- }
- }
- }
- if expanded {
- let entry = if self.oper.initial_value() { uint::MAX } else {0};
- for _ in range(0, self.words_per_id) {
- self.gens.push(0);
- self.kills.push(0);
- self.on_entry.push(entry);
- }
- }
-
- let start = n * self.words_per_id;
- let end = start + self.words_per_id;
- let len = self.gens.len();
- assert!(start < len);
- assert!(end <= len);
- n
+ self.nodeid_to_index.contains_key(&n)
}
}
};
if self.has_bitset_for_nodeid(id) {
+ assert!(self.bits_per_id > 0);
let cfgidx = to_cfgidx_or_die(id, &self.nodeid_to_index);
- let (start, end) = self.compute_id_range_frozen(cfgidx);
+ let (start, end) = self.compute_id_range(cfgidx);
let on_entry = self.on_entry.slice(start, end);
let entry_str = bits_to_string(on_entry);
id_range: IdRange,
bits_per_id: uint) -> DataFlowContext<'a, O> {
let words_per_id = (bits_per_id + uint::BITS - 1) / uint::BITS;
+ let num_nodes = cfg.graph.all_nodes().len();
debug!("DataFlowContext::new(analysis_name: {:s}, id_range={:?}, \
- bits_per_id={:?}, words_per_id={:?})",
- analysis_name, id_range, bits_per_id, words_per_id);
+ bits_per_id={:?}, words_per_id={:?}) \
+ num_nodes: {}",
+ analysis_name, id_range, bits_per_id, words_per_id,
+ num_nodes);
- let gens = Vec::new();
- let kills = Vec::new();
- let on_entry = Vec::new();
+ let entry = if oper.initial_value() { uint::MAX } else {0};
+
+ let gens = Vec::from_elem(num_nodes * words_per_id, 0);
+ let kills = Vec::from_elem(num_nodes * words_per_id, 0);
+ let on_entry = Vec::from_elem(num_nodes * words_per_id, entry);
let nodeid_to_index = build_nodeid_to_index(decl, cfg);
tcx: tcx,
analysis_name: analysis_name,
words_per_id: words_per_id,
- index_to_bitset: Vec::new(),
nodeid_to_index: nodeid_to_index,
bits_per_id: bits_per_id,
oper: oper,
debug!("{:s} add_gen(id={:?}, bit={:?})",
self.analysis_name, id, bit);
assert!(self.nodeid_to_index.contains_key(&id));
+ assert!(self.bits_per_id > 0);
+
let cfgidx = to_cfgidx_or_die(id, &self.nodeid_to_index);
let (start, end) = self.compute_id_range(cfgidx);
let gens = self.gens.mut_slice(start, end);
debug!("{:s} add_kill(id={:?}, bit={:?})",
self.analysis_name, id, bit);
assert!(self.nodeid_to_index.contains_key(&id));
+ assert!(self.bits_per_id > 0);
+
let cfgidx = to_cfgidx_or_die(id, &self.nodeid_to_index);
let (start, end) = self.compute_id_range(cfgidx);
let kills = self.kills.mut_slice(start, end);
set_bit(kills, bit);
}
- fn apply_gen_kill(&mut self, cfgidx: CFGIndex, bits: &mut [uint]) {
+ fn apply_gen_kill(&self, cfgidx: CFGIndex, bits: &mut [uint]) {
//! Applies the gen and kill sets for `cfgidx` to `bits`
debug!("{:s} apply_gen_kill(cfgidx={}, bits={}) [before]",
self.analysis_name, cfgidx, mut_bits_to_string(bits));
- let (start, end) = self.compute_id_range(cfgidx);
- let gens = self.gens.slice(start, end);
- bitwise(bits, gens, &Union);
- let kills = self.kills.slice(start, end);
- bitwise(bits, kills, &Subtract);
-
- debug!("{:s} apply_gen_kill(cfgidx={}, bits={}) [after]",
- self.analysis_name, cfgidx, mut_bits_to_string(bits));
- }
+ assert!(self.bits_per_id > 0);
- fn apply_gen_kill_frozen(&self, cfgidx: CFGIndex, bits: &mut [uint]) {
- //! Applies the gen and kill sets for `cfgidx` to `bits`
- //! Only useful after `propagate()` has been called.
- debug!("{:s} apply_gen_kill(cfgidx={}, bits={}) [before]",
- self.analysis_name, cfgidx, mut_bits_to_string(bits));
- let (start, end) = self.compute_id_range_frozen(cfgidx);
+ let (start, end) = self.compute_id_range(cfgidx);
let gens = self.gens.slice(start, end);
bitwise(bits, gens, &Union);
let kills = self.kills.slice(start, end);
self.analysis_name, cfgidx, mut_bits_to_string(bits));
}
- fn compute_id_range_frozen(&self, cfgidx: CFGIndex) -> (uint, uint) {
- let n = self.get_bitset_index(cfgidx);
- let start = n * self.words_per_id;
- let end = start + self.words_per_id;
- (start, end)
- }
-
- fn compute_id_range(&mut self, cfgidx: CFGIndex) -> (uint, uint) {
- let n = self.get_or_create_bitset_index(cfgidx);
+ fn compute_id_range(&self, cfgidx: CFGIndex) -> (uint, uint) {
+ let n = cfgidx.node_id();
let start = n * self.words_per_id;
let end = start + self.words_per_id;
}
- pub fn each_bit_on_entry_frozen(&self,
- id: ast::NodeId,
- f: |uint| -> bool)
- -> bool {
+ pub fn each_bit_on_entry(&self,
+ id: ast::NodeId,
+ f: |uint| -> bool)
+ -> bool {
//! Iterates through each bit that is set on entry to `id`.
//! Only useful after `propagate()` has been called.
if !self.has_bitset_for_nodeid(id) {
-> bool {
//! Iterates through each bit that is set on entry/exit to `cfgidx`.
//! Only useful after `propagate()` has been called.
- if !self.has_bitset_for_cfgidx(cfgidx) {
+
+ if self.bits_per_id == 0 {
+ // Skip the surprisingly common degenerate case. (Note
+ // compute_id_range requires self.words_per_id > 0.)
return true;
}
- let (start, end) = self.compute_id_range_frozen(cfgidx);
+
+ let (start, end) = self.compute_id_range(cfgidx);
let on_entry = self.on_entry.slice(start, end);
let temp_bits;
let slice = match e {
Entry => on_entry,
Exit => {
let mut t = on_entry.to_vec();
- self.apply_gen_kill_frozen(cfgidx, t.as_mut_slice());
+ self.apply_gen_kill(cfgidx, t.as_mut_slice());
temp_bits = t;
temp_bits.as_slice()
}
self.each_bit(slice, f)
}
- pub fn each_gen_bit_frozen(&self, id: ast::NodeId, f: |uint| -> bool)
- -> bool {
+ pub fn each_gen_bit(&self, id: ast::NodeId, f: |uint| -> bool)
+ -> bool {
//! Iterates through each bit in the gen set for `id`.
- //! Only useful after `propagate()` has been called.
if !self.has_bitset_for_nodeid(id) {
return true;
}
+
+ if self.bits_per_id == 0 {
+ // Skip the surprisingly common degenerate case. (Note
+ // compute_id_range requires self.words_per_id > 0.)
+ return true;
+ }
+
let cfgidx = to_cfgidx_or_die(id, &self.nodeid_to_index);
- let (start, end) = self.compute_id_range_frozen(cfgidx);
+ let (start, end) = self.compute_id_range(cfgidx);
let gens = self.gens.slice(start, end);
debug!("{:s} each_gen_bit(id={:?}, gens={})",
self.analysis_name, id, bits_to_string(gens));
fn each_bit(&self, words: &[uint], f: |uint| -> bool) -> bool {
//! Helper for iterating over the bits in a bit set.
+ //! Returns false on the first call to `f` that returns false;
+ //! if all calls to `f` return true, then returns true.
for (word_index, &word) in words.iter().enumerate() {
if word != 0 {
in_out: &mut [uint]) {
debug!("DataFlowContext::walk_cfg(in_out={}) {:s}",
bits_to_string(in_out), self.dfcx.analysis_name);
+ assert!(self.dfcx.bits_per_id > 0);
+
cfg.graph.each_node(|node_index, node| {
debug!("DataFlowContext::walk_cfg idx={} id={} begin in_out={}",
node_index, node.data.id, bits_to_string(in_out));
let cfgidx = edge.target();
debug!("{:s} propagate_bits_into_entry_set_for(pred_bits={}, {} to {})",
self.dfcx.analysis_name, bits_to_string(pred_bits), source, cfgidx);
+ assert!(self.dfcx.bits_per_id > 0);
+
let (start, end) = self.dfcx.compute_id_range(cfgidx);
let changed = {
// (scoping mutable borrow of self.dfcx.on_entry)