Skip to content

Commit

Permalink
Implement SSA-based reference propagation.
Browse files Browse the repository at this point in the history
  • Loading branch information
cjgillot committed May 9, 2023
1 parent f7b831a commit 3490375
Show file tree
Hide file tree
Showing 21 changed files with 2,668 additions and 80 deletions.
13 changes: 13 additions & 0 deletions compiler/rustc_middle/src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1524,6 +1524,19 @@ impl<V, T> ProjectionElem<V, T> {
}
}

/// Returns `true` if the target of this projection always refers to the same memory region
/// whatever the state of the program.
pub fn is_stable_offset(&self) -> bool {
match self {
Self::Deref | Self::Index(_) => false,
Self::Field(_, _)
| Self::OpaqueCast(_)
| Self::ConstantIndex { .. }
| Self::Subslice { .. }
| Self::Downcast(_, _) => true,
}
}

/// Returns `true` if this is a `Downcast` projection with the given `VariantIdx`.
pub fn is_downcast_to(&self, v: VariantIdx) -> bool {
matches!(*self, Self::Downcast(_, x) if x == v)
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_dataflow/src/impls/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ pub use self::borrowed_locals::borrowed_locals;
pub use self::borrowed_locals::MaybeBorrowedLocals;
pub use self::liveness::MaybeLiveLocals;
pub use self::liveness::MaybeTransitiveLiveLocals;
pub use self::storage_liveness::{MaybeRequiresStorage, MaybeStorageLive};
pub use self::storage_liveness::{MaybeRequiresStorage, MaybeStorageDead, MaybeStorageLive};

/// `MaybeInitializedPlaces` tracks all places that might be
/// initialized upon reaching a particular point in the control flow
Expand Down
66 changes: 66 additions & 0 deletions compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,72 @@ impl<'tcx, 'a> crate::GenKillAnalysis<'tcx> for MaybeStorageLive<'a> {
}
}

#[derive(Clone)]
pub struct MaybeStorageDead {
always_live_locals: BitSet<Local>,
}

impl MaybeStorageDead {
pub fn new(always_live_locals: BitSet<Local>) -> Self {
MaybeStorageDead { always_live_locals }
}
}

impl<'tcx> crate::AnalysisDomain<'tcx> for MaybeStorageDead {
type Domain = BitSet<Local>;

const NAME: &'static str = "maybe_storage_dead";

fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
// bottom = live
BitSet::new_empty(body.local_decls.len())
}

fn initialize_start_block(&self, body: &mir::Body<'tcx>, on_entry: &mut Self::Domain) {
assert_eq!(body.local_decls.len(), self.always_live_locals.domain_size());
for local in body.vars_and_temps_iter() {
if !self.always_live_locals.contains(local) {
on_entry.insert(local);
}
}
}
}

impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeStorageDead {
type Idx = Local;

fn statement_effect(
&self,
trans: &mut impl GenKill<Self::Idx>,
stmt: &mir::Statement<'tcx>,
_: Location,
) {
match stmt.kind {
StatementKind::StorageLive(l) => trans.kill(l),
StatementKind::StorageDead(l) => trans.gen(l),
_ => (),
}
}

fn terminator_effect(
&self,
_trans: &mut impl GenKill<Self::Idx>,
_: &mir::Terminator<'tcx>,
_: Location,
) {
// Terminators have no effect
}

fn call_return_effect(
&self,
_trans: &mut impl GenKill<Self::Idx>,
_block: BasicBlock,
_return_places: CallReturnPlaces<'_, 'tcx>,
) {
// Nothing to do when a call returns successfully
}
}

type BorrowedLocalsResults<'a, 'tcx> = ResultsRefCursor<'a, 'a, 'tcx, MaybeBorrowedLocals>;

/// Dataflow analysis that determines whether each local requires storage at a
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_transform/src/copy_prop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
fn fully_moved_locals(ssa: &SsaLocals, body: &Body<'_>) -> BitSet<Local> {
let mut fully_moved = BitSet::new_filled(body.local_decls.len());

for (_, rvalue) in ssa.assignments(body) {
for (_, rvalue, _) in ssa.assignments(body) {
let (Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) | Rvalue::CopyForDeref(place))
= rvalue
else { continue };
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_mir_transform/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ mod match_branches;
mod multiple_return_terminators;
mod normalize_array_len;
mod nrvo;
mod ref_prop;
mod remove_noop_landing_pads;
mod remove_storage_markers;
mod remove_uninit_drops;
Expand Down Expand Up @@ -559,6 +560,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
&separate_const_switch::SeparateConstSwitch,
&simplify::SimplifyLocals::BeforeConstProp,
&copy_prop::CopyProp,
&ref_prop::ReferencePropagation,
&const_prop::ConstProp,
&dataflow_const_prop::DataflowConstProp,
//
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_transform/src/normalize_array_len.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ fn compute_slice_length<'tcx>(
) -> IndexVec<Local, Option<ty::Const<'tcx>>> {
let mut slice_lengths = IndexVec::from_elem(None, &body.local_decls);

for (local, rvalue) in ssa.assignments(body) {
for (local, rvalue, _) in ssa.assignments(body) {
match rvalue {
Rvalue::Cast(
CastKind::Pointer(ty::adjustment::PointerCast::Unsize),
Expand Down
Loading

0 comments on commit 3490375

Please sign in to comment.