Skip to content

rustc: map node ids through a table that ensures bitset indexes in dataflow are dense #7146

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/librustc/middle/borrowck/check_loans.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,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;
Expand Down Expand Up @@ -135,7 +135,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;
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/middle/borrowck/move_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -505,7 +505,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) {
Expand Down Expand Up @@ -561,7 +561,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;
Expand Down
91 changes: 71 additions & 20 deletions src/librustc/middle/dataflow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,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;
Expand All @@ -38,16 +39,16 @@ pub struct DataFlowContext<O> {
/// 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,

/// number of words we will use to store bits_per_id.
/// 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<ast::node_id,uint>,

// 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`.
Expand Down Expand Up @@ -109,19 +110,17 @@ impl<O:DataFlowOperator> DataFlowContext<O> {
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
Expand Down Expand Up @@ -150,7 +149,7 @@ impl<O:DataFlowOperator> DataFlowContext<O> {
}
}

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]",
Expand All @@ -165,7 +164,7 @@ impl<O:DataFlowOperator> DataFlowContext<O> {
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);
Expand All @@ -175,18 +174,56 @@ impl<O:DataFlowOperator> DataFlowContext<O> {
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);
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)
}

let relative_id = absolute_id - self.id_range.min;
let start = (relative_id as uint) * self.words_per_id;
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;

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(&self,
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`.
Expand All @@ -199,7 +236,7 @@ impl<O:DataFlowOperator> DataFlowContext<O> {
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`.
Expand All @@ -211,6 +248,20 @@ impl<O:DataFlowOperator> DataFlowContext<O> {
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 {
Expand Down Expand Up @@ -286,8 +337,8 @@ impl<O:DataFlowOperator+Copy+'static> DataFlowContext<O> {
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);

Expand Down