From 6914ff9d0142a4b1e82f809ebb8de805d8319698 Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Thu, 13 Jun 2013 10:07:34 -0700 Subject: [PATCH] rustc: map node ids through a table that ensures bitset indexes in dataflow are dense --- src/librustc/middle/borrowck/check_loans.rs | 4 +- src/librustc/middle/borrowck/move_data.rs | 4 +- src/librustc/middle/dataflow.rs | 93 ++++++++++++++++----- 3 files changed, 76 insertions(+), 25 deletions(-) diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs index e384d35373e..be87beba778 100644 --- a/src/librustc/middle/borrowck/check_loans.rs +++ b/src/librustc/middle/borrowck/check_loans.rs @@ -82,7 +82,7 @@ impl<'self> CheckLoanCtxt<'self> { //! are issued for future scopes and thus they may have been //! *issued* but not yet be in effect. - for self.dfcx_loans.each_bit_on_entry(scope_id) |loan_index| { + for self.dfcx_loans.each_bit_on_entry_frozen(scope_id) |loan_index| { let loan = &self.all_loans[loan_index]; if !op(loan) { return false; @@ -134,7 +134,7 @@ impl<'self> CheckLoanCtxt<'self> { //! we encounter `scope_id`. let mut result = ~[]; - for self.dfcx_loans.each_gen_bit(scope_id) |loan_index| { + for self.dfcx_loans.each_gen_bit_frozen(scope_id) |loan_index| { result.push(loan_index); } return result; diff --git a/src/librustc/middle/borrowck/move_data.rs b/src/librustc/middle/borrowck/move_data.rs index bd560fca985..d19afd0f5fc 100644 --- a/src/librustc/middle/borrowck/move_data.rs +++ b/src/librustc/middle/borrowck/move_data.rs @@ -504,7 +504,7 @@ impl FlowedMoveData { let opt_loan_path_index = self.move_data.existing_move_path(loan_path); - for self.dfcx_moves.each_bit_on_entry(id) |index| { + for self.dfcx_moves.each_bit_on_entry_frozen(id) |index| { let move = &self.move_data.moves[index]; let moved_path = move.path; if base_indices.contains(&moved_path) { @@ -560,7 +560,7 @@ impl FlowedMoveData { } }; - for self.dfcx_assign.each_bit_on_entry(id) |index| { + for self.dfcx_assign.each_bit_on_entry_frozen(id) |index| { let assignment = &self.move_data.var_assignments[index]; if assignment.path == loan_path_index && !f(assignment) { return false; diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs index 8037bacd3e7..8403b1616f4 100644 --- a/src/librustc/middle/dataflow.rs +++ b/src/librustc/middle/dataflow.rs @@ -22,6 +22,7 @@ use core::cast; use core::io; use core::uint; use core::vec; +use core::hashmap::HashMap; use syntax::ast; use syntax::ast_util; use syntax::ast_util::id_range; @@ -37,9 +38,6 @@ pub struct DataFlowContext { /// the data flow operator priv oper: O, - /// range of ids that appear within the item in question - priv id_range: id_range, - /// number of bits to propagate per id priv bits_per_id: uint, @@ -47,6 +45,9 @@ pub struct DataFlowContext { /// equal to bits_per_id/uint::bits rounded up. priv words_per_id: uint, + // mapping from node to bitset index. + priv nodeid_to_bitset: HashMap, + // 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`. @@ -108,19 +109,17 @@ impl DataFlowContext { debug!("DataFlowContext::new(id_range=%?, bits_per_id=%?, words_per_id=%?)", id_range, bits_per_id, words_per_id); - let len = (id_range.max - id_range.min) as uint * words_per_id; - let gens = vec::from_elem(len, 0); - let kills = vec::from_elem(len, 0); - let elem = if oper.initial_value() {uint::max_value} else {0}; - let on_entry = vec::from_elem(len, elem); + let gens = ~[]; + let kills = ~[]; + let on_entry = ~[]; DataFlowContext { tcx: tcx, method_map: method_map, words_per_id: words_per_id, + nodeid_to_bitset: HashMap::new(), bits_per_id: bits_per_id, oper: oper, - id_range: id_range, gens: gens, kills: kills, on_entry: on_entry @@ -149,7 +148,7 @@ impl DataFlowContext { } } - fn apply_gen_kill(&self, id: ast::node_id, bits: &mut [uint]) { + fn apply_gen_kill(&mut self, id: ast::node_id, bits: &mut [uint]) { //! Applies the gen and kill sets for `id` to `bits` debug!("apply_gen_kill(id=%?, bits=%s) [before]", @@ -164,7 +163,7 @@ impl DataFlowContext { id, mut_bits_to_str(bits)); } - fn apply_kill(&self, id: ast::node_id, bits: &mut [uint]) { + fn apply_kill(&mut self, id: ast::node_id, bits: &mut [uint]) { debug!("apply_kill(id=%?, bits=%s) [before]", id, mut_bits_to_str(bits)); let (start, end) = self.compute_id_range(id); @@ -174,18 +173,56 @@ impl DataFlowContext { id, mut_bits_to_str(bits)); } - fn compute_id_range(&self, absolute_id: ast::node_id) -> (uint, uint) { - assert!(absolute_id >= self.id_range.min); - assert!(absolute_id < self.id_range.max); - - let relative_id = absolute_id - self.id_range.min; - let start = (relative_id as uint) * self.words_per_id; + fn compute_id_range_frozen(&self, id: ast::node_id) -> (uint, uint) { + let n = *self.nodeid_to_bitset.get(&id); + let start = n * self.words_per_id; let end = start + self.words_per_id; (start, end) } + fn compute_id_range(&mut self, id: ast::node_id) -> (uint, uint) { + let mut expanded = false; + let len = self.nodeid_to_bitset.len(); + let n = do self.nodeid_to_bitset.find_or_insert_with(id) |_| { + expanded = true; + len + }; + if expanded { + let entry = if self.oper.initial_value() { uint::max_value } else {0}; + for self.words_per_id.times { + 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; - pub fn each_bit_on_entry(&self, + 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()); + + (start, end) + } + + + pub fn each_bit_on_entry_frozen(&self, + id: ast::node_id, + f: &fn(uint) -> bool) -> bool { + //! 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); + let on_entry = vec::slice(self.on_entry, start, end); + debug!("each_bit_on_entry_frozen(id=%?, on_entry=%s)", + id, bits_to_str(on_entry)); + self.each_bit(on_entry, f) + } + + pub fn each_bit_on_entry(&mut self, id: ast::node_id, f: &fn(uint) -> bool) -> bool { //! Iterates through each bit that is set on entry to `id`. @@ -198,7 +235,7 @@ impl DataFlowContext { self.each_bit(on_entry, f) } - pub fn each_gen_bit(&self, + pub fn each_gen_bit(&mut self, id: ast::node_id, f: &fn(uint) -> bool) -> bool { //! Iterates through each bit in the gen set for `id`. @@ -210,6 +247,20 @@ impl DataFlowContext { self.each_bit(gens, f) } + pub fn each_gen_bit_frozen(&self, + id: ast::node_id, + f: &fn(uint) -> bool) -> bool { + //! 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); + let gens = vec::slice(self.gens, start, end); + debug!("each_gen_bit(id=%?, gens=%s)", + id, bits_to_str(gens)); + self.each_bit(gens, f) + } + fn each_bit(&self, words: &[uint], f: &fn(uint) -> bool) -> bool { @@ -285,8 +336,8 @@ impl DataFlowContext { pprust::node_pat(ps, pat) => (ps, pat.id) }; - if id >= self.id_range.min || id < self.id_range.max { - let (start, end) = self.compute_id_range(id); + if self.nodeid_to_bitset.contains_key(&id) { + let (start, end) = self.compute_id_range_frozen(id); let on_entry = vec::slice(self.on_entry, start, end); let entry_str = bits_to_str(on_entry);