diff options
Diffstat (limited to 'compiler/rustc_mir_transform/src')
| -rw-r--r-- | compiler/rustc_mir_transform/src/gvn.rs | 62 | ||||
| -rw-r--r-- | compiler/rustc_mir_transform/src/ref_prop.rs | 39 |
2 files changed, 51 insertions, 50 deletions
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 952da2cdf72..5a13394543b 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -447,26 +447,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { Projection(base, elem) => { let base = self.evaluated[base].as_ref()?; - let elem = match elem { - ProjectionElem::Deref => ProjectionElem::Deref, - ProjectionElem::Downcast(name, read_variant) => { - ProjectionElem::Downcast(name, read_variant) - } - ProjectionElem::Field(f, ()) => ProjectionElem::Field(f, ty.ty), - ProjectionElem::ConstantIndex { offset, min_length, from_end } => { - ProjectionElem::ConstantIndex { offset, min_length, from_end } - } - ProjectionElem::Subslice { from, to, from_end } => { - ProjectionElem::Subslice { from, to, from_end } - } - ProjectionElem::OpaqueCast(()) => ProjectionElem::OpaqueCast(ty.ty), - ProjectionElem::Subtype(()) => ProjectionElem::Subtype(ty.ty), - ProjectionElem::UnwrapUnsafeBinder(()) => { - ProjectionElem::UnwrapUnsafeBinder(ty.ty) - } - // This should have been replaced by a `ConstantIndex` earlier. - ProjectionElem::Index(_) => return None, - }; + // `Index` by constants should have been replaced by `ConstantIndex` by + // `simplify_place_projection`. + let elem = elem.try_map(|_| None, |()| ty.ty)?; self.ecx.project(base, elem).discard_err()? } Address { place, kind: _, provenance: _ } => { @@ -476,13 +459,11 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let local = self.locals[place.local]?; let pointer = self.evaluated[local].as_ref()?; let mut mplace = self.ecx.deref_pointer(pointer).discard_err()?; - for proj in place.projection.iter().skip(1) { - // We have no call stack to associate a local with a value, so we cannot - // interpret indexing. - if matches!(proj, ProjectionElem::Index(_)) { - return None; - } - mplace = self.ecx.project(&mplace, proj).discard_err()?; + for elem in place.projection.iter().skip(1) { + // `Index` by constants should have been replaced by `ConstantIndex` by + // `simplify_place_projection`. + let elem = elem.try_map(|_| None, |ty| ty)?; + mplace = self.ecx.project(&mplace, elem).discard_err()?; } let pointer = mplace.to_ref(&self.ecx); ImmTy::from_immediate(pointer, ty).into() @@ -902,27 +883,14 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { proj: ProjectionElem<VnIndex, ()>, loc: Location, ) -> Option<PlaceElem<'tcx>> { - Some(match proj { - ProjectionElem::Deref => ProjectionElem::Deref, - ProjectionElem::Field(idx, ()) => ProjectionElem::Field(idx, ty), - ProjectionElem::Index(idx) => { - let Some(local) = self.try_as_local(idx, loc) else { - return None; - }; + proj.try_map( + |value| { + let local = self.try_as_local(value, loc)?; self.reused_locals.insert(local); - ProjectionElem::Index(local) - } - ProjectionElem::ConstantIndex { offset, min_length, from_end } => { - ProjectionElem::ConstantIndex { offset, min_length, from_end } - } - ProjectionElem::Subslice { from, to, from_end } => { - ProjectionElem::Subslice { from, to, from_end } - } - ProjectionElem::Downcast(symbol, idx) => ProjectionElem::Downcast(symbol, idx), - ProjectionElem::OpaqueCast(()) => ProjectionElem::OpaqueCast(ty), - ProjectionElem::Subtype(()) => ProjectionElem::Subtype(ty), - ProjectionElem::UnwrapUnsafeBinder(()) => ProjectionElem::UnwrapUnsafeBinder(ty), - }) + Some(local) + }, + |()| ty, + ) } fn simplify_aggregate_to_copy( diff --git a/compiler/rustc_mir_transform/src/ref_prop.rs b/compiler/rustc_mir_transform/src/ref_prop.rs index d1c2d6b508f..6f61215cee2 100644 --- a/compiler/rustc_mir_transform/src/ref_prop.rs +++ b/compiler/rustc_mir_transform/src/ref_prop.rs @@ -79,6 +79,7 @@ impl<'tcx> crate::MirPass<'tcx> for ReferencePropagation { #[instrument(level = "trace", skip(self, tcx, body))] fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { debug!(def_id = ?body.source.def_id()); + move_to_copy_pointers(tcx, body); while propagate_ssa(tcx, body) {} } @@ -87,11 +88,43 @@ impl<'tcx> crate::MirPass<'tcx> for ReferencePropagation { } } +/// The SSA analysis done by [`SsaLocals`] treats [`Operand::Move`] as a read, even though in +/// general [`Operand::Move`] represents pass-by-pointer where the callee can overwrite the +/// pointee (Miri always considers the place deinitialized). CopyProp has a similar trick to +/// turn [`Operand::Move`] into [`Operand::Copy`] when required for an optimization, but in this +/// pass we just turn all moves of pointers into copies because pointers should be by-value anyway. +fn move_to_copy_pointers<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let mut visitor = MoveToCopyVisitor { tcx, local_decls: &body.local_decls }; + for (bb, data) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() { + visitor.visit_basic_block_data(bb, data); + } + + struct MoveToCopyVisitor<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + local_decls: &'a IndexVec<Local, LocalDecl<'tcx>>, + } + + impl<'a, 'tcx> MutVisitor<'tcx> for MoveToCopyVisitor<'a, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn visit_operand(&mut self, operand: &mut Operand<'tcx>, loc: Location) { + if let Operand::Move(place) = *operand { + if place.ty(self.local_decls, self.tcx).ty.is_any_ptr() { + *operand = Operand::Copy(place); + } + } + self.super_operand(operand, loc); + } + } +} + fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool { let typing_env = body.typing_env(tcx); let ssa = SsaLocals::new(tcx, body, typing_env); - let mut replacer = compute_replacement(tcx, body, &ssa); + let mut replacer = compute_replacement(tcx, body, ssa); debug!(?replacer.targets); debug!(?replacer.allowed_replacements); debug!(?replacer.storage_to_remove); @@ -119,7 +152,7 @@ enum Value<'tcx> { fn compute_replacement<'tcx>( tcx: TyCtxt<'tcx>, body: &Body<'tcx>, - ssa: &SsaLocals, + ssa: SsaLocals, ) -> Replacer<'tcx> { let always_live_locals = always_storage_live_locals(body); @@ -138,7 +171,7 @@ fn compute_replacement<'tcx>( // reborrowed references. let mut storage_to_remove = DenseBitSet::new_empty(body.local_decls.len()); - let fully_replaceable_locals = fully_replaceable_locals(ssa); + let fully_replaceable_locals = fully_replaceable_locals(&ssa); // Returns true iff we can use `place` as a pointee. // |
