Introduce fast insertion at extremities to IntervalSet.
This commit is contained in:
committed by
Camille Gillot
parent
bea625f327
commit
2ff92e83af
@@ -140,6 +140,49 @@ impl<I: Idx> IntervalSet<I> {
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Specialized version of `insert` when we know that the inserted point is *before* any
|
||||||
|
/// contained.
|
||||||
|
pub fn prepend(&mut self, point: I) {
|
||||||
|
let point = point.index() as u32;
|
||||||
|
|
||||||
|
if let Some((first_start, _)) = self.map.first_mut() {
|
||||||
|
assert!(point < *first_start);
|
||||||
|
if point + 1 == *first_start {
|
||||||
|
*first_start = point;
|
||||||
|
} else {
|
||||||
|
self.map.insert(0, (point, point));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// If the map is empty, push is faster than insert.
|
||||||
|
self.map.push((point, point));
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_assert!(
|
||||||
|
self.check_invariants(),
|
||||||
|
"wrong intervals after prepend {point:?} to {self:?}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Specialized version of `insert` when we know that the inserted point is *after* any
|
||||||
|
/// contained.
|
||||||
|
pub fn append(&mut self, point: I) {
|
||||||
|
let point = point.index() as u32;
|
||||||
|
|
||||||
|
if let Some((_, last_end)) = self.map.last_mut()
|
||||||
|
&& let _ = assert!(*last_end < point)
|
||||||
|
&& point == *last_end + 1
|
||||||
|
{
|
||||||
|
*last_end = point;
|
||||||
|
} else {
|
||||||
|
self.map.push((point, point));
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_assert!(
|
||||||
|
self.check_invariants(),
|
||||||
|
"wrong intervals after append {point:?} to {self:?}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn contains(&self, needle: I) -> bool {
|
pub fn contains(&self, needle: I) -> bool {
|
||||||
let needle = needle.index() as u32;
|
let needle = needle.index() as u32;
|
||||||
let Some(last) = self.map.partition_point(|r| r.0 <= needle).checked_sub(1) else {
|
let Some(last) = self.map.partition_point(|r| r.0 <= needle).checked_sub(1) else {
|
||||||
@@ -325,6 +368,14 @@ impl<R: Idx, C: Step + Idx> SparseIntervalMatrix<R, C> {
|
|||||||
self.ensure_row(row).insert(point)
|
self.ensure_row(row).insert(point)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn prepend(&mut self, row: R, point: C) {
|
||||||
|
self.ensure_row(row).prepend(point)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn append(&mut self, row: R, point: C) {
|
||||||
|
self.ensure_row(row).append(point)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn contains(&self, row: R, point: C) -> bool {
|
pub fn contains(&self, row: R, point: C) -> bool {
|
||||||
self.row(row).is_some_and(|r| r.contains(point))
|
self.row(row).is_some_and(|r| r.contains(point))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use rustc_index::interval::SparseIntervalMatrix;
|
|||||||
use rustc_index::{Idx, IndexVec};
|
use rustc_index::{Idx, IndexVec};
|
||||||
use rustc_middle::mir::{self, BasicBlock, Body, Location};
|
use rustc_middle::mir::{self, BasicBlock, Body, Location};
|
||||||
|
|
||||||
use crate::framework::{Analysis, Results, ResultsVisitor, visit_results};
|
use crate::framework::{Analysis, Direction, Results, ResultsVisitor, visit_results};
|
||||||
|
|
||||||
/// Maps between a `Location` and a `PointIndex` (and vice versa).
|
/// Maps between a `Location` and a `PointIndex` (and vice versa).
|
||||||
pub struct DenseLocationMap {
|
pub struct DenseLocationMap {
|
||||||
@@ -105,27 +105,47 @@ where
|
|||||||
N: Idx,
|
N: Idx,
|
||||||
A: Analysis<'tcx, Domain = DenseBitSet<N>>,
|
A: Analysis<'tcx, Domain = DenseBitSet<N>>,
|
||||||
{
|
{
|
||||||
let values = SparseIntervalMatrix::new(elements.num_points());
|
let mut values = SparseIntervalMatrix::new(elements.num_points());
|
||||||
let mut visitor = Visitor { elements, values };
|
let reachable_blocks = mir::traversal::reachable_as_bitset(body);
|
||||||
visit_results(
|
if A::Direction::IS_BACKWARD {
|
||||||
body,
|
// Iterate blocks in decreasing order, to visit locations in decreasing order. This
|
||||||
body.basic_blocks.reverse_postorder().iter().copied(),
|
// allows to use the more efficient `prepend` method to interval sets.
|
||||||
&mut analysis,
|
let callback = |state: &DenseBitSet<N>, location| {
|
||||||
&results,
|
let point = elements.point_from_location(location);
|
||||||
&mut visitor,
|
// Use internal iterator manually as it is much more efficient.
|
||||||
);
|
state.iter().for_each(|node| values.prepend(node, point));
|
||||||
visitor.values
|
};
|
||||||
|
let mut visitor = Visitor { callback };
|
||||||
|
visit_results(
|
||||||
|
body,
|
||||||
|
// Note the `.rev()`.
|
||||||
|
body.basic_blocks.indices().filter(|&bb| reachable_blocks.contains(bb)).rev(),
|
||||||
|
&mut analysis,
|
||||||
|
&results,
|
||||||
|
&mut visitor,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// Iterate blocks in increasing order, to visit locations in increasing order. This
|
||||||
|
// allows to use the more efficient `append` method to interval sets.
|
||||||
|
let callback = |state: &DenseBitSet<N>, location| {
|
||||||
|
let point = elements.point_from_location(location);
|
||||||
|
// Use internal iterator manually as it is much more efficient.
|
||||||
|
state.iter().for_each(|node| values.append(node, point));
|
||||||
|
};
|
||||||
|
let mut visitor = Visitor { callback };
|
||||||
|
visit_results(body, reachable_blocks.iter(), &mut analysis, &results, &mut visitor);
|
||||||
|
}
|
||||||
|
values
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Visitor<'a, N: Idx> {
|
struct Visitor<F> {
|
||||||
elements: &'a DenseLocationMap,
|
callback: F,
|
||||||
values: SparseIntervalMatrix<N, PointIndex>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx, A, N> ResultsVisitor<'tcx, A> for Visitor<'_, N>
|
impl<'tcx, A, F> ResultsVisitor<'tcx, A> for Visitor<F>
|
||||||
where
|
where
|
||||||
A: Analysis<'tcx, Domain = DenseBitSet<N>>,
|
A: Analysis<'tcx>,
|
||||||
N: Idx,
|
F: FnMut(&A::Domain, Location),
|
||||||
{
|
{
|
||||||
fn visit_after_primary_statement_effect<'mir>(
|
fn visit_after_primary_statement_effect<'mir>(
|
||||||
&mut self,
|
&mut self,
|
||||||
@@ -134,11 +154,7 @@ where
|
|||||||
_statement: &'mir mir::Statement<'tcx>,
|
_statement: &'mir mir::Statement<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
) {
|
) {
|
||||||
let point = self.elements.point_from_location(location);
|
(self.callback)(state, location);
|
||||||
// Use internal iterator manually as it is much more efficient.
|
|
||||||
state.iter().for_each(|node| {
|
|
||||||
self.values.insert(node, point);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_after_primary_terminator_effect<'mir>(
|
fn visit_after_primary_terminator_effect<'mir>(
|
||||||
@@ -148,10 +164,6 @@ where
|
|||||||
_terminator: &'mir mir::Terminator<'tcx>,
|
_terminator: &'mir mir::Terminator<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
) {
|
) {
|
||||||
let point = self.elements.point_from_location(location);
|
(self.callback)(state, location);
|
||||||
// Use internal iterator manually as it is much more efficient.
|
|
||||||
state.iter().for_each(|node| {
|
|
||||||
self.values.insert(node, point);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user