From 0b0011c5e1cd871932e70cb78e435330341f8967 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Mon, 5 Feb 2024 23:15:49 +0000 Subject: [PATCH 1/2] CopyProp: Propagate moves of constants --- compiler/rustc_mir_transform/src/copy_prop.rs | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_mir_transform/src/copy_prop.rs b/compiler/rustc_mir_transform/src/copy_prop.rs index 0119b95cced97..37505cad0ee27 100644 --- a/compiler/rustc_mir_transform/src/copy_prop.rs +++ b/compiler/rustc_mir_transform/src/copy_prop.rs @@ -1,3 +1,4 @@ +use rustc_data_structures::fx::FxIndexMap; use rustc_index::bit_set::BitSet; use rustc_index::IndexSlice; use rustc_middle::mir::visit::*; @@ -37,6 +38,8 @@ fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let fully_moved = fully_moved_locals(&ssa, body); debug!(?fully_moved); + let const_locals = const_locals(&ssa, body); + debug!(?const_locals); let mut storage_to_remove = BitSet::new_empty(fully_moved.domain_size()); for (local, &head) in ssa.copy_classes().iter_enumerated() { @@ -51,6 +54,7 @@ fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { tcx, copy_classes: ssa.copy_classes(), fully_moved, + const_locals, borrowed_locals, storage_to_remove, } @@ -96,10 +100,28 @@ fn fully_moved_locals(ssa: &SsaLocals, body: &Body<'_>) -> BitSet { fully_moved } +/// Finds all locals that are only assigned to once with a deterministic constant +#[instrument(level = "trace", skip(ssa, body))] +fn const_locals<'body, 'tcx>( + ssa: &'body SsaLocals, + body: &'body Body<'tcx>, +) -> FxIndexMap> { + let mut const_locals = FxIndexMap::default(); + for (local, rvalue, _) in ssa.assignments(body) { + let Rvalue::Use(Operand::Constant(val)) = rvalue else { continue }; + if !val.const_.is_deterministic() { + continue; + } + const_locals.insert(local, **val); + } + const_locals +} + /// Utility to help performing substitution of `*pattern` by `target`. struct Replacer<'a, 'tcx> { tcx: TyCtxt<'tcx>, fully_moved: BitSet, + const_locals: FxIndexMap>, storage_to_remove: BitSet, borrowed_locals: BitSet, copy_classes: &'a IndexSlice, @@ -154,9 +176,14 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> { if let Operand::Move(place) = *operand // A move out of a projection of a copy is equivalent to a copy of the original projection. && !place.is_indirect_first_projection() - && !self.fully_moved.contains(place.local) { - *operand = Operand::Copy(place); + if !self.fully_moved.contains(place.local) { + *operand = Operand::Copy(place); + } else if let Some(local) = place.as_local() + && let Some(val) = self.const_locals.get(&local) + { + *operand = Operand::Constant(Box::new(*val)) + } } self.super_operand(operand, loc); } From cf02fa9f08013fdb26f2c1d8aa3ccac5b03e9390 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Sun, 11 Feb 2024 01:28:58 +0000 Subject: [PATCH 2/2] CopyProp cleanups --- compiler/rustc_mir_transform/src/copy_prop.rs | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_mir_transform/src/copy_prop.rs b/compiler/rustc_mir_transform/src/copy_prop.rs index 37505cad0ee27..bd85b45532478 100644 --- a/compiler/rustc_mir_transform/src/copy_prop.rs +++ b/compiler/rustc_mir_transform/src/copy_prop.rs @@ -48,7 +48,7 @@ fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { } } - let any_replacement = ssa.copy_classes().iter_enumerated().any(|(l, &h)| l != h); + let any_replacement = !storage_to_remove.is_empty() || !const_locals.is_empty(); Replacer { tcx, @@ -79,9 +79,7 @@ fn fully_moved_locals(ssa: &SsaLocals, body: &Body<'_>) -> BitSet { let mut fully_moved = BitSet::new_filled(body.local_decls.len()); for (_, rvalue, _) in ssa.assignments(body) { - let (Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) - | Rvalue::CopyForDeref(place)) = rvalue - else { + let (Rvalue::Use(Operand::Copy(place)) | Rvalue::CopyForDeref(place)) = rvalue else { continue; }; @@ -89,10 +87,7 @@ fn fully_moved_locals(ssa: &SsaLocals, body: &Body<'_>) -> BitSet { if !ssa.is_ssa(rhs) { continue; } - - if let Rvalue::Use(Operand::Copy(_)) | Rvalue::CopyForDeref(_) = rvalue { - fully_moved.remove(rhs); - } + fully_moved.remove(rhs); } ssa.meet_copy_equivalence(&mut fully_moved); @@ -173,11 +168,9 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> { } fn visit_operand(&mut self, operand: &mut Operand<'tcx>, loc: Location) { - if let Operand::Move(place) = *operand + if let Operand::Move(place) = *operand { // A move out of a projection of a copy is equivalent to a copy of the original projection. - && !place.is_indirect_first_projection() - { - if !self.fully_moved.contains(place.local) { + if !place.is_indirect_first_projection() && !self.fully_moved.contains(place.local) { *operand = Operand::Copy(place); } else if let Some(local) = place.as_local() && let Some(val) = self.const_locals.get(&local)