Skip to content

Commit 7a20a3f

Browse files
committed
change to use an O(1) data structure for looking up point indices
Converting a `RegionElementIndex` to a `Location` is O(n) though could trivially be O(log n), but we don't do it that much anyhow -- just on error and debugging.
1 parent 77663a6 commit 7a20a3f

File tree

2 files changed

+77
-21
lines changed

2 files changed

+77
-21
lines changed

src/librustc_mir/borrow_check/nll/region_infer/mod.rs

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -107,16 +107,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
107107
let num_region_variables = var_origins.len();
108108
let num_universal_regions = universal_regions.len();
109109

110-
let mut points = Vec::new();
111-
for (block, block_data) in mir.basic_blocks().iter_enumerated() {
112-
for statement_index in 0..block_data.statements.len() + 1 {
113-
points.push(Location {
114-
block,
115-
statement_index,
116-
});
117-
}
118-
}
119-
let elements = &Rc::new(RegionValueElements::new(points, num_universal_regions));
110+
let elements = &Rc::new(RegionValueElements::new(mir, num_universal_regions));
120111

121112
// Create a RegionDefinition for each inference variable.
122113
let definitions = var_origins

src/librustc_mir/borrow_check/nll/region_infer/values.rs

Lines changed: 76 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,66 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
111
use std::rc::Rc;
212
use rustc_data_structures::bitvec::BitMatrix;
313
use rustc_data_structures::indexed_vec::Idx;
4-
use rustc::mir::Location;
14+
use rustc_data_structures::indexed_vec::IndexVec;
15+
use rustc::mir::{BasicBlock, Location, Mir};
516
use rustc::ty::RegionVid;
617

718
/// Maps between the various kinds of elements of a region value to
819
/// the internal indices that w use.
920
pub(super) struct RegionValueElements {
10-
points: Vec<Location>,
21+
/// For each basic block, how many points are contained within?
22+
statements_before_block: IndexVec<BasicBlock, usize>,
23+
num_points: usize,
1124
num_universal_regions: usize,
1225
}
1326

1427
impl RegionValueElements {
15-
pub(super) fn new(points: Vec<Location>, num_universal_regions: usize) -> Self {
28+
pub(super) fn new(mir: &Mir<'_>, num_universal_regions: usize) -> Self {
29+
let mut num_points = 0;
30+
let statements_before_block =
31+
mir.basic_blocks()
32+
.iter()
33+
.map(|block_data| {
34+
let v = num_points;
35+
num_points += block_data.statements.len() + 1;
36+
v
37+
})
38+
.collect();
39+
40+
debug!("RegionValueElements(num_universal_regions={:?})", num_universal_regions);
41+
debug!("RegionValueElements: statements_before_block={:#?}", statements_before_block);
42+
debug!("RegionValueElements: num_points={:#?}", num_points);
43+
1644
Self {
17-
points,
45+
statements_before_block,
1846
num_universal_regions,
47+
num_points,
1948
}
2049
}
2150

51+
/// Total number of element indices that exist.
52+
pub(super) fn num_elements(&self) -> usize {
53+
self.num_points + self.num_universal_regions
54+
}
55+
2256
/// Converts an element of a region value into a `RegionElementIndex`.
2357
pub(super) fn index<T: ToElementIndex>(&self, elem: T) -> RegionElementIndex {
2458
elem.to_element_index(self)
2559
}
2660

2761
/// Iterates over the `RegionElementIndex` for all points in the CFG.
2862
pub(super) fn all_point_indices<'a>(&'a self) -> impl Iterator<Item = RegionElementIndex> + 'a {
29-
(0..self.points.len()).map(move |i| RegionElementIndex::new(i + self.num_universal_regions))
63+
(0..self.num_points).map(move |i| RegionElementIndex::new(i + self.num_universal_regions))
3064
}
3165

3266
/// Iterates over the `RegionElementIndex` for all points in the CFG.
@@ -36,10 +70,42 @@ impl RegionValueElements {
3670

3771
/// Converts a particular `RegionElementIndex` to the `RegionElement` it represents.
3872
pub(super) fn to_element(&self, i: RegionElementIndex) -> RegionElement {
73+
debug!("to_element(i={:?})", i);
74+
3975
if let Some(r) = self.to_universal_region(i) {
4076
RegionElement::UniversalRegion(r)
4177
} else {
42-
RegionElement::Location(self.points[i.index() - self.num_universal_regions])
78+
let point_index = i.index() - self.num_universal_regions;
79+
80+
// Find the basic block. We have a vector with the
81+
// starting index of the statement in each block. Imagine
82+
// we have statement #22, and we have a vector like:
83+
//
84+
// [0, 10, 20]
85+
//
86+
// In that case, this represents point_index 2 of
87+
// basic block BB2. We know this because BB0 accounts for
88+
// 0..10, BB1 accounts for 11..20, and BB2 accounts for
89+
// 20...
90+
//
91+
// To compute this, we could do a binary search, but
92+
// because I am lazy we instead iterate through to find
93+
// the last point where the "first index" (0, 10, or 20)
94+
// was less than the statement index (22). In our case, this will
95+
// be (BB2, 20).
96+
//
97+
// Nit: we could do a binary search here but I'm too lazy.
98+
let (block, &first_index) =
99+
self.statements_before_block
100+
.iter_enumerated()
101+
.filter(|(_, first_index)| **first_index <= point_index)
102+
.last()
103+
.unwrap();
104+
105+
RegionElement::Location(Location {
106+
block,
107+
statement_index: point_index - first_index,
108+
})
43109
}
44110
}
45111

@@ -85,8 +151,9 @@ pub(super) trait ToElementIndex {
85151

86152
impl ToElementIndex for Location {
87153
fn to_element_index(self, elements: &RegionValueElements) -> RegionElementIndex {
88-
let index = elements.points.binary_search(&self).unwrap();
89-
RegionElementIndex::new(index + elements.num_universal_regions)
154+
let Location { block, statement_index } = self;
155+
let start_index = elements.statements_before_block[block];
156+
RegionElementIndex::new(elements.num_universal_regions + start_index + statement_index)
90157
}
91158
}
92159

@@ -120,11 +187,9 @@ impl RegionValues {
120187
"universal regions are a subset of the region variables"
121188
);
122189

123-
let num_columns = elements.points.len() + elements.num_universal_regions;
124-
125190
Self {
126191
elements: elements.clone(),
127-
matrix: BitMatrix::new(num_region_variables, num_columns),
192+
matrix: BitMatrix::new(num_region_variables, elements.num_elements()),
128193
}
129194
}
130195

0 commit comments

Comments
 (0)