Skip to content

Enable DestinationPropagation by default #142915

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

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
22 changes: 22 additions & 0 deletions compiler/rustc_index/src/bit_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1538,6 +1538,28 @@ impl<R: Idx, C: Idx> BitMatrix<R, C> {
changed != 0
}

/// Adds the bits from col `read` to the bits from col `write`, and
/// returns `true` if anything changed.
pub fn union_cols(&mut self, read: C, write: C) -> bool {
assert!(read.index() < self.num_columns && write.index() < self.num_columns);

let words_per_row = num_words(self.num_columns);
let (read_index, read_mask) = word_index_and_mask(read);
let (write_index, write_mask) = word_index_and_mask(write);

let words = &mut self.words[..];
let mut changed = 0;
for row in 0..self.num_rows {
let write_word = words[row * words_per_row + write_index];
let read_word = (words[row * words_per_row + read_index] & read_mask) != 0;
let new_word = if read_word { write_word | write_mask } else { write_word };
words[row * words_per_row + write_index] = new_word;
// See `bitwise` for the rationale.
changed |= write_word ^ new_word;
}
changed != 0
}

/// Adds the bits from `with` to the bits from row `write`, and
/// returns `true` if anything changed.
pub fn union_row_with(&mut self, with: &DenseBitSet<C>, write: R) -> bool {
Expand Down
51 changes: 51 additions & 0 deletions compiler/rustc_index/src/interval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,49 @@ impl<I: Idx> IntervalSet<I> {
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 {
let needle = needle.index() as u32;
let Some(last) = self.map.partition_point(|r| r.0 <= needle).checked_sub(1) else {
Expand Down Expand Up @@ -325,6 +368,14 @@ impl<R: Idx, C: Step + Idx> SparseIntervalMatrix<R, C> {
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 {
self.row(row).is_some_and(|r| r.contains(point))
}
Expand Down
80 changes: 50 additions & 30 deletions compiler/rustc_mir_dataflow/src/points.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use rustc_index::bit_set::DenseBitSet;
use rustc_index::interval::SparseIntervalMatrix;
use rustc_index::{Idx, IndexVec};
use rustc_index::{Idx, IndexSlice, IndexVec};
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).
pub struct DenseLocationMap {
Expand Down Expand Up @@ -95,37 +95,65 @@ rustc_index::newtype_index! {
}

/// Add points depending on the result of the given dataflow analysis.
pub fn save_as_intervals<'tcx, N, A>(
pub fn save_as_intervals<'tcx, N, M, A>(
elements: &DenseLocationMap,
body: &mir::Body<'tcx>,
relevant: &IndexSlice<N, M>,
mut analysis: A,
results: Results<A::Domain>,
) -> SparseIntervalMatrix<N, PointIndex>
where
N: Idx,
A: Analysis<'tcx, Domain = DenseBitSet<N>>,
M: Idx,
A: Analysis<'tcx, Domain = DenseBitSet<M>>,
{
let values = SparseIntervalMatrix::new(elements.num_points());
let mut visitor = Visitor { elements, values };
visit_results(
body,
body.basic_blocks.reverse_postorder().iter().copied(),
&mut analysis,
&results,
&mut visitor,
);
visitor.values
let mut values = SparseIntervalMatrix::new(elements.num_points());
let reachable_blocks = mir::traversal::reachable_as_bitset(body);
if A::Direction::IS_BACKWARD {
// Iterate blocks in decreasing order, to visit locations in decreasing order. This
// allows to use the more efficient `prepend` method to interval sets.
let callback = |state: &DenseBitSet<M>, location| {
let point = elements.point_from_location(location);
for (relevant, &original) in relevant.iter_enumerated() {
if state.contains(original) {
values.prepend(relevant, point);
}
}
};
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<M>, location| {
let point = elements.point_from_location(location);
for (relevant, &original) in relevant.iter_enumerated() {
if state.contains(original) {
values.append(relevant, point);
}
}
};
let mut visitor = Visitor { callback };
visit_results(body, reachable_blocks.iter(), &mut analysis, &results, &mut visitor);
}
values
}

struct Visitor<'a, N: Idx> {
elements: &'a DenseLocationMap,
values: SparseIntervalMatrix<N, PointIndex>,
struct Visitor<F> {
callback: F,
}

impl<'tcx, A, N> ResultsVisitor<'tcx, A> for Visitor<'_, N>
impl<'tcx, A, F> ResultsVisitor<'tcx, A> for Visitor<F>
where
A: Analysis<'tcx, Domain = DenseBitSet<N>>,
N: Idx,
A: Analysis<'tcx>,
F: FnMut(&A::Domain, Location),
{
fn visit_after_primary_statement_effect<'mir>(
&mut self,
Expand All @@ -134,11 +162,7 @@ where
_statement: &'mir mir::Statement<'tcx>,
location: Location,
) {
let point = self.elements.point_from_location(location);
// Use internal iterator manually as it is much more efficient.
state.iter().for_each(|node| {
self.values.insert(node, point);
});
(self.callback)(state, location);
}

fn visit_after_primary_terminator_effect<'mir>(
Expand All @@ -148,10 +172,6 @@ where
_terminator: &'mir mir::Terminator<'tcx>,
location: Location,
) {
let point = self.elements.point_from_location(location);
// Use internal iterator manually as it is much more efficient.
state.iter().for_each(|node| {
self.values.insert(node, point);
});
(self.callback)(state, location);
}
}
Loading
Loading