diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index bf6aa800d20f4..afd4318288e54 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -89,12 +89,13 @@ use std::borrow::Cow; use either::Either; use itertools::Itertools as _; use rustc_abi::{self as abi, BackendRepr, FIRST_VARIANT, FieldIdx, Primitive, Size, VariantIdx}; +use rustc_arena::DroplessArena; use rustc_const_eval::const_eval::DummyMachine; use rustc_const_eval::interpret::{ ImmTy, Immediate, InterpCx, MemPlaceMeta, MemoryKind, OpTy, Projectable, Scalar, intern_const_alloc_for_constprop, }; -use rustc_data_structures::fx::{FxIndexSet, MutableValues}; +use rustc_data_structures::fx::{FxHashMap, FxIndexSet, MutableValues}; use rustc_data_structures::graph::dominators::Dominators; use rustc_hir::def::DefKind; use rustc_index::bit_set::DenseBitSet; @@ -127,7 +128,9 @@ impl<'tcx> crate::MirPass<'tcx> for GVN { // Clone dominators because we need them while mutating the body. let dominators = body.basic_blocks.dominators().clone(); - let mut state = VnState::new(tcx, body, typing_env, &ssa, dominators, &body.local_decls); + let arena = DroplessArena::default(); + let mut state = + VnState::new(tcx, body, typing_env, &ssa, dominators, &body.local_decls, &arena); for local in body.args_iter().filter(|&local| ssa.is_ssa(local)) { let opaque = state.new_opaque(body.local_decls[local].ty); @@ -161,8 +164,16 @@ enum AddressKind { Address(RawPtrKind), } -#[derive(Debug, PartialEq, Eq, Hash)] -enum Value<'tcx> { +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +enum AddressBase { + /// This address is based on this local. + Local(Local), + /// This address is based on the deref of this pointer. + Deref(VnIndex), +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +enum Value<'a, 'tcx> { // Root values. /// Used to represent values we know nothing about. /// The `usize` is a counter incremented by `new_opaque`. @@ -177,7 +188,7 @@ enum Value<'tcx> { }, /// An aggregate value, either tuple/closure/struct/enum. /// This does not contain unions, as we cannot reason with the value. - Aggregate(VariantIdx, Vec), + Aggregate(VariantIdx, &'a [VnIndex]), /// A raw pointer aggregate built from a thin pointer and metadata. RawPtr { /// Thin pointer component. This is field 0 in MIR. @@ -189,7 +200,10 @@ enum Value<'tcx> { Repeat(VnIndex, ty::Const<'tcx>), /// The address of a place. Address { - place: Place<'tcx>, + base: AddressBase, + // We do not use a plain `Place` as we want to be able to reason about indices. + // This does not contain any `Deref` projection. + projection: &'a [ProjectionElem>], kind: AddressKind, /// Give each borrow and pointer a different provenance, so we don't merge them. provenance: usize, @@ -213,7 +227,7 @@ enum Value<'tcx> { }, } -struct VnState<'body, 'tcx> { +struct VnState<'body, 'a, 'tcx> { tcx: TyCtxt<'tcx>, ecx: InterpCx<'tcx, DummyMachine>, local_decls: &'body LocalDecls<'tcx>, @@ -221,9 +235,12 @@ struct VnState<'body, 'tcx> { /// Value stored in each local. locals: IndexVec>, /// Locals that are assigned that value. - // This vector does not hold all the values of `VnIndex` that we create. - rev_locals: IndexVec>, - values: FxIndexSet<(Value<'tcx>, Ty<'tcx>)>, + // This vector holds the locals that are SSA. + rev_locals_ssa: IndexVec>, + // This map holds the locals that are not SSA. This map is cleared at the end of each block. + // Therefore, we do not need a location, the local always appears before the current location. + rev_locals_non_ssa: FxHashMap>, + values: FxIndexSet<(Value<'a, 'tcx>, Ty<'tcx>)>, /// Values evaluated as constants if possible. evaluated: IndexVec>>, /// Counter to generate different values. @@ -233,9 +250,10 @@ struct VnState<'body, 'tcx> { ssa: &'body SsaLocals, dominators: Dominators, reused_locals: DenseBitSet, + arena: &'a DroplessArena, } -impl<'body, 'tcx> VnState<'body, 'tcx> { +impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> { fn new( tcx: TyCtxt<'tcx>, body: &Body<'tcx>, @@ -243,6 +261,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { ssa: &'body SsaLocals, dominators: Dominators, local_decls: &'body LocalDecls<'tcx>, + arena: &'a DroplessArena, ) -> Self { // Compute a rough estimate of the number of values in the body from the number of // statements. This is meant to reduce the number of allocations, but it's all right if @@ -256,8 +275,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { ecx: InterpCx::new(tcx, DUMMY_SP, typing_env, DummyMachine), local_decls, is_coroutine: body.coroutine.is_some(), - locals: IndexVec::from_elem(None, local_decls), - rev_locals: IndexVec::with_capacity(num_values), + locals: IndexVec::from_elem(None, &body.local_decls), + rev_locals_ssa: IndexVec::with_capacity(num_values), + rev_locals_non_ssa: FxHashMap::default(), values: FxIndexSet::with_capacity_and_hasher(num_values, Default::default()), evaluated: IndexVec::with_capacity(num_values), next_opaque: 1, @@ -265,6 +285,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { ssa, dominators, reused_locals: DenseBitSet::new_empty(local_decls.len()), + arena, } } @@ -273,7 +294,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } #[instrument(level = "trace", skip(self), ret)] - fn insert(&mut self, ty: Ty<'tcx>, value: Value<'tcx>) -> VnIndex { + fn insert(&mut self, ty: Ty<'tcx>, value: Value<'a, 'tcx>) -> VnIndex { let (index, new) = self.values.insert_full((value, ty)); let index = VnIndex::from_usize(index); if new { @@ -281,7 +302,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let evaluated = self.eval_to_const(index); let _index = self.evaluated.push(evaluated); debug_assert_eq!(index, _index); - let _index = self.rev_locals.push(SmallVec::new()); + let _index = self.rev_locals_ssa.push(Default::default()); debug_assert_eq!(index, _index); } index @@ -303,7 +324,12 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { /// Create a new `Value::Address` distinct from all the others. #[instrument(level = "trace", skip(self), ret)] - fn new_pointer(&mut self, place: Place<'tcx>, kind: AddressKind) -> VnIndex { + fn new_pointer( + &mut self, + place: Place<'tcx>, + kind: AddressKind, + location: Location, + ) -> Option { let pty = place.ty(self.local_decls, self.tcx).ty; let ty = match kind { AddressKind::Ref(bk) => { @@ -311,13 +337,31 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } AddressKind::Address(mutbl) => Ty::new_ptr(self.tcx, pty, mutbl.to_mutbl_lossy()), }; - let value = Value::Address { place, kind, provenance: self.next_opaque() }; - self.insert(ty, value) + + let mut projection = place.projection.iter(); + let base = if place.is_indirect_first_projection() { + let base = self.local(place.local); + // Skip the initial `Deref`. + projection.next(); + AddressBase::Deref(base) + } else { + AddressBase::Local(place.local) + }; + // Do not try evaluating inside `Index`, this has been done by `simplify_place_value`. + let projection = self + .arena + .try_alloc_from_iter( + projection + .map(|proj| proj.try_map(|value| Some(self.local(value)), |ty| ty).ok_or(())), + ) + .ok()?; + let value = Value::Address { base, projection, kind, provenance: self.next_opaque() }; + Some(self.insert(ty, value)) } #[inline] - fn get(&self, index: VnIndex) -> &Value<'tcx> { - &self.values.get_index(index.as_usize()).unwrap().0 + fn get(&self, index: VnIndex) -> Value<'a, 'tcx> { + self.values.get_index(index.as_usize()).unwrap().0 } #[inline] @@ -325,12 +369,49 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { self.values.get_index(index.as_usize()).unwrap().1 } - /// Record that `local` is assigned `value`. `local` must be SSA. + /// Record that `local` is assigned `value`. #[instrument(level = "trace", skip(self))] fn assign(&mut self, local: Local, value: VnIndex) { - debug_assert!(self.ssa.is_ssa(local)); self.locals[local] = Some(value); - self.rev_locals[value].push(local); + if self.ssa.is_ssa(local) { + self.rev_locals_ssa[value].push(local); + } else { + self.rev_locals_non_ssa.entry(value).or_default().push(local); + } + } + + /// Return the value assigned to a local, or assign an opaque value and return it. + #[instrument(level = "trace", skip(self), ret)] + fn local(&mut self, local: Local) -> VnIndex { + if let Some(value) = self.locals[local] { + return value; + } + let value = self.new_opaque(self.local_decls[local].ty); + self.locals[local] = Some(value); + self.rev_locals_non_ssa.entry(value).or_default().push(local); + value + } + + #[instrument(level = "trace", skip(self))] + fn discard_place(&mut self, place: Place<'tcx>) { + let discard_local = |this: &mut Self, local| { + if this.ssa.is_ssa(local) { + return; + } + if let Some(value) = this.locals[local].take() { + this.rev_locals_non_ssa.entry(value).or_default().retain(|l| *l != local); + } + }; + if place.is_indirect_first_projection() { + // Non-local mutation maybe invalidate deref. + self.invalidate_derefs(); + // Remove stored value from borrowed locals. + for local in self.ssa.borrowed_locals().iter() { + discard_local(self, local); + } + } else { + discard_local(self, place.local); + } } fn insert_constant(&mut self, value: Const<'tcx>) -> VnIndex { @@ -362,8 +443,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { self.insert(ty, Value::Constant { value, disambiguator: 0 }) } - fn insert_tuple(&mut self, ty: Ty<'tcx>, values: Vec) -> VnIndex { - self.insert(ty, Value::Aggregate(VariantIdx::ZERO, values)) + fn insert_tuple(&mut self, ty: Ty<'tcx>, values: &[VnIndex]) -> VnIndex { + self.insert(ty, Value::Aggregate(VariantIdx::ZERO, self.arena.alloc_slice(values))) } fn insert_deref(&mut self, ty: Ty<'tcx>, value: VnIndex) -> VnIndex { @@ -389,7 +470,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } else { return None; }; - let op = match *self.get(value) { + let op = match self.get(value) { _ if ty.is_zst() => ImmTy::uninit(ty).into(), Opaque(_) => return None, @@ -453,14 +534,15 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let elem = elem.try_map(|_| None, |()| ty.ty)?; self.ecx.project(base, elem).discard_err()? } - Address { place, kind: _, provenance: _ } => { - if !place.is_indirect_first_projection() { - return None; - } - let local = self.locals[place.local]?; - let pointer = self.evaluated[local].as_ref()?; + Address { base, projection, .. } => { + debug_assert!(!projection.contains(&ProjectionElem::Deref)); + let pointer = match base { + AddressBase::Deref(pointer) => self.evaluated[pointer].as_ref()?, + // We have no stack to point to. + AddressBase::Local(_) => return None, + }; let mut mplace = self.ecx.deref_pointer(pointer).discard_err()?; - for elem in place.projection.iter().skip(1) { + for elem in projection { // `Index` by constants should have been replaced by `ConstantIndex` by // `simplify_place_projection`. let elem = elem.try_map(|_| None, |ty| ty)?; @@ -584,32 +666,68 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { Some(op) } + /// Represent the *value* we obtain by dereferencing an `Address` value. + #[instrument(level = "trace", skip(self), ret)] + fn dereference_address( + &mut self, + base: AddressBase, + projection: &[ProjectionElem>], + ) -> Option { + let (mut place_ty, mut value) = match base { + // The base is a local, so we take the local's value and project from it. + AddressBase::Local(local) => { + let local = self.local(local); + let place_ty = PlaceTy::from_ty(self.ty(local)); + (place_ty, local) + } + // The base is a pointer's deref, so we introduce the implicit deref. + AddressBase::Deref(reborrow) => { + let place_ty = PlaceTy::from_ty(self.ty(reborrow)); + self.project(place_ty, reborrow, ProjectionElem::Deref)? + } + }; + for &proj in projection { + (place_ty, value) = self.project(place_ty, value, proj)?; + } + Some(value) + } + + #[instrument(level = "trace", skip(self), ret)] fn project( &mut self, place_ty: PlaceTy<'tcx>, value: VnIndex, - proj: PlaceElem<'tcx>, - from_non_ssa_index: &mut bool, + proj: ProjectionElem>, ) -> Option<(PlaceTy<'tcx>, VnIndex)> { let projection_ty = place_ty.projection_ty(self.tcx, proj); - let proj = match proj { - ProjectionElem::Deref => { - if let Some(Mutability::Not) = place_ty.ty.ref_mutability() - && projection_ty.ty.is_freeze(self.tcx, self.typing_env()) - { - // An immutable borrow `_x` always points to the same value for the - // lifetime of the borrow, so we can merge all instances of `*_x`. - return Some((projection_ty, self.insert_deref(projection_ty.ty, value))); - } else { - return None; - } + let proj = proj.try_map(Some, |_| ())?; + + if let ProjectionElem::Deref = proj + // An immutable borrow `_x` always points to the same value for the + // lifetime of the borrow, so we can merge all instances of `*_x`. + && !(place_ty.ty.ref_mutability() == Some(Mutability::Not) + && projection_ty.ty.is_freeze(self.tcx, self.typing_env())) + { + return None; + } + + match (proj, self.get(value)) { + (ProjectionElem::Deref, Value::Address { base, projection, .. }) + if let Some(deref) = self.dereference_address(base, projection) => + { + return Some((projection_ty, deref)); } - ProjectionElem::Downcast(name, index) => ProjectionElem::Downcast(name, index), - ProjectionElem::Field(f, _) => { - if let Value::Aggregate(_, fields) = self.get(value) { - return Some((projection_ty, fields[f.as_usize()])); - } else if let Value::Projection(outer_value, ProjectionElem::Downcast(_, read_variant)) = self.get(value) - && let Value::Aggregate(written_variant, fields) = self.get(*outer_value) + (ProjectionElem::Deref, _) => { + return Some((projection_ty, self.insert_deref(projection_ty.ty, value))); + } + (ProjectionElem::Field(f, _), Value::Aggregate(_, fields)) => { + return Some((projection_ty, fields[f.as_usize()])); + } + ( + ProjectionElem::Field(f, _), + Value::Projection(outer_value, ProjectionElem::Downcast(_, read_variant)), + ) => { + if let Value::Aggregate(written_variant, fields) = self.get(outer_value) // This pass is not aware of control-flow, so we do not know whether the // replacement we are doing is actually reachable. We could be in any arm of // ``` @@ -629,41 +747,30 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { { return Some((projection_ty, fields[f.as_usize()])); } - ProjectionElem::Field(f, ()) } - ProjectionElem::Index(idx) => { - if let Value::Repeat(inner, _) = self.get(value) { - *from_non_ssa_index |= self.locals[idx].is_none(); - return Some((projection_ty, *inner)); - } - let idx = self.locals[idx]?; - ProjectionElem::Index(idx) + (ProjectionElem::Index(_), Value::Repeat(inner, _)) => { + return Some((projection_ty, inner)); } - ProjectionElem::ConstantIndex { offset, min_length, from_end } => { - match self.get(value) { - Value::Repeat(inner, _) => { - return Some((projection_ty, *inner)); - } - Value::Aggregate(_, operands) => { - let offset = if from_end { - operands.len() - offset as usize - } else { - offset as usize - }; - let value = operands.get(offset).copied()?; - return Some((projection_ty, value)); - } - _ => {} - }; - ProjectionElem::ConstantIndex { offset, min_length, from_end } + (ProjectionElem::ConstantIndex { .. }, Value::Repeat(inner, _)) => { + return Some((projection_ty, inner)); } - ProjectionElem::Subslice { from, to, from_end } => { - ProjectionElem::Subslice { from, to, from_end } + ( + ProjectionElem::ConstantIndex { offset, from_end: false, .. }, + Value::Aggregate(_, operands), + ) => { + let value = operands.get(offset as usize).copied()?; + return Some((projection_ty, value)); } - ProjectionElem::OpaqueCast(_) => ProjectionElem::OpaqueCast(()), - ProjectionElem::Subtype(_) => ProjectionElem::Subtype(()), - ProjectionElem::UnwrapUnsafeBinder(_) => ProjectionElem::UnwrapUnsafeBinder(()), - }; + ( + ProjectionElem::ConstantIndex { offset, from_end: true, .. }, + Value::Aggregate(_, operands), + ) => { + let offset = operands.len().checked_sub(offset as usize)?; + let value = operands[offset]; + return Some((projection_ty, value)); + } + _ => {} + } let value = self.insert(projection_ty.ty, Value::Projection(value, proj)); Some((projection_ty, value)) @@ -675,7 +782,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { // If the projection is indirect, we treat the local as a value, so can replace it with // another local. if place.is_indirect_first_projection() - && let Some(base) = self.locals[place.local] + && let base = self.local(place.local) && let Some(new_local) = self.try_as_local(base, location) && place.local != new_local { @@ -687,9 +794,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { for i in 0..projection.len() { let elem = projection[i]; - if let ProjectionElem::Index(idx_local) = elem - && let Some(idx) = self.locals[idx_local] - { + if let ProjectionElem::Index(idx_local) = elem { + let idx = self.local(idx_local); if let Some(offset) = self.evaluated[idx].as_ref() && let Some(offset) = self.ecx.read_target_usize(offset).discard_err() && let Some(min_length) = offset.checked_add(1) @@ -715,37 +821,20 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { /// Represent the *value* which would be read from `place`, and point `place` to a preexisting /// place with the same value (if that already exists). #[instrument(level = "trace", skip(self), ret)] - fn simplify_place_value( + fn compute_place_value( &mut self, - place: &mut Place<'tcx>, + place: Place<'tcx>, location: Location, - ) -> Option { - self.simplify_place_projection(place, location); - + ) -> Result> { // Invariant: `place` and `place_ref` point to the same value, even if they point to // different memory locations. let mut place_ref = place.as_ref(); // Invariant: `value` holds the value up-to the `index`th projection excluded. - let mut value = self.locals[place.local]?; + let mut value = self.local(place.local); // Invariant: `value` has type `place_ty`, with optional downcast variant if needed. let mut place_ty = PlaceTy::from_ty(self.local_decls[place.local].ty); - let mut from_non_ssa_index = false; for (index, proj) in place.projection.iter().enumerate() { - if let Value::Projection(pointer, ProjectionElem::Deref) = *self.get(value) - && let Value::Address { place: mut pointee, kind, .. } = *self.get(pointer) - && let AddressKind::Ref(BorrowKind::Shared) = kind - && let Some(v) = self.simplify_place_value(&mut pointee, location) - { - value = v; - // `pointee` holds a `Place`, so `ProjectionElem::Index` holds a `Local`. - // That local is SSA, but we otherwise have no guarantee on that local's value at - // the current location compared to its value where `pointee` was borrowed. - if pointee.projection.iter().all(|elem| !matches!(elem, ProjectionElem::Index(_))) { - place_ref = - pointee.project_deeper(&place.projection[index..], self.tcx).as_ref(); - } - } if let Some(local) = self.try_as_local(value, location) { // Both `local` and `Place { local: place.local, projection: projection[..index] }` // hold the same value. Therefore, following place holds the value in the original @@ -753,36 +842,50 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { place_ref = PlaceRef { local, projection: &place.projection[index..] }; } - (place_ty, value) = self.project(place_ty, value, proj, &mut from_non_ssa_index)?; + let Some(proj) = proj.try_map(|value| Some(self.local(value)), |ty| ty) else { + return Err(place_ref); + }; + let Some(ty_and_value) = self.project(place_ty, value, proj) else { + return Err(place_ref); + }; + (place_ty, value) = ty_and_value; } - if let Value::Projection(pointer, ProjectionElem::Deref) = *self.get(value) - && let Value::Address { place: mut pointee, kind, .. } = *self.get(pointer) - && let AddressKind::Ref(BorrowKind::Shared) = kind - && let Some(v) = self.simplify_place_value(&mut pointee, location) - { - value = v; - // `pointee` holds a `Place`, so `ProjectionElem::Index` holds a `Local`. - // That local is SSA, but we otherwise have no guarantee on that local's value at - // the current location compared to its value where `pointee` was borrowed. - if pointee.projection.iter().all(|elem| !matches!(elem, ProjectionElem::Index(_))) { - place_ref = pointee.project_deeper(&[], self.tcx).as_ref(); - } - } - if let Some(new_local) = self.try_as_local(value, location) { - place_ref = PlaceRef { local: new_local, projection: &[] }; - } else if from_non_ssa_index { - // If access to non-SSA locals is unavoidable, bail out. - return None; - } + Ok(value) + } - if place_ref.local != place.local || place_ref.projection.len() < place.projection.len() { - // By the invariant on `place_ref`. - *place = place_ref.project_deeper(&[], self.tcx); - self.reused_locals.insert(place_ref.local); - } + /// Represent the *value* which would be read from `place`, and point `place` to a preexisting + /// place with the same value (if that already exists). + #[instrument(level = "trace", skip(self), ret)] + fn simplify_place_value( + &mut self, + place: &mut Place<'tcx>, + location: Location, + ) -> Option { + self.simplify_place_projection(place, location); - Some(value) + match self.compute_place_value(*place, location) { + Ok(value) => { + if let Some(new_place) = self.try_as_place(value, location, true) + && (new_place.local != place.local + || new_place.projection.len() < place.projection.len()) + { + *place = new_place; + self.reused_locals.insert(new_place.local); + } + Some(value) + } + Err(place_ref) => { + if place_ref.local != place.local + || place_ref.projection.len() < place.projection.len() + { + // By the invariant on `place_ref`. + *place = place_ref.project_deeper(&[], self.tcx); + self.reused_locals.insert(place_ref.local); + } + None + } + } } #[instrument(level = "trace", skip(self), ret)] @@ -806,7 +909,6 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { #[instrument(level = "trace", skip(self), ret)] fn simplify_rvalue( &mut self, - lhs: &Place<'tcx>, rvalue: &mut Rvalue<'tcx>, location: Location, ) -> Option { @@ -826,14 +928,14 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { Value::Repeat(op, amount) } Rvalue::NullaryOp(op, ty) => Value::NullaryOp(op, ty), - Rvalue::Aggregate(..) => return self.simplify_aggregate(lhs, rvalue, location), + Rvalue::Aggregate(..) => return self.simplify_aggregate(rvalue, location), Rvalue::Ref(_, borrow_kind, ref mut place) => { self.simplify_place_projection(place, location); - return Some(self.new_pointer(*place, AddressKind::Ref(borrow_kind))); + return self.new_pointer(*place, AddressKind::Ref(borrow_kind), location); } Rvalue::RawPtr(mutbl, ref mut place) => { self.simplify_place_projection(place, location); - return Some(self.new_pointer(*place, AddressKind::Address(mutbl))); + return self.new_pointer(*place, AddressKind::Address(mutbl), location); } Rvalue::WrapUnsafeBinder(ref mut op, _) => { let value = self.simplify_operand(op, location)?; @@ -869,7 +971,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { fn simplify_discriminant(&mut self, place: VnIndex) -> Option { let enum_ty = self.ty(place); if enum_ty.is_enum() - && let Value::Aggregate(variant, _) = *self.get(place) + && let Value::Aggregate(variant, _) = self.get(place) { let discr = self.ecx.discriminant_for_variant(enum_ty, variant).discard_err()?; return Some(self.insert_scalar(discr.layout.ty, discr.to_scalar())); @@ -901,11 +1003,11 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { fields: &[VnIndex], ) -> Option { let Some(&first_field) = fields.first() else { return None }; - let Value::Projection(copy_from_value, _) = *self.get(first_field) else { return None }; + let Value::Projection(copy_from_value, _) = self.get(first_field) else { return None }; // All fields must correspond one-to-one and come from the same aggregate value. if fields.iter().enumerate().any(|(index, &v)| { - if let Value::Projection(pointer, ProjectionElem::Field(from_index, _)) = *self.get(v) + if let Value::Projection(pointer, ProjectionElem::Field(from_index, _)) = self.get(v) && copy_from_value == pointer && from_index.index() == index { @@ -917,7 +1019,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } let mut copy_from_local_value = copy_from_value; - if let Value::Projection(pointer, proj) = *self.get(copy_from_value) + if let Value::Projection(pointer, proj) = self.get(copy_from_value) && let ProjectionElem::Downcast(_, read_variant) = proj { if variant_index == read_variant { @@ -935,7 +1037,6 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { fn simplify_aggregate( &mut self, - lhs: &Place<'tcx>, rvalue: &mut Rvalue<'tcx>, location: Location, ) -> Option { @@ -962,13 +1063,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } } - let fields: Vec<_> = field_ops - .iter_mut() - .map(|op| { - self.simplify_operand(op, location) - .unwrap_or_else(|| self.new_opaque(op.ty(self.local_decls, self.tcx))) - }) - .collect(); + let fields = self.arena.alloc_from_iter(field_ops.iter_mut().map(|op| { + self.simplify_operand(op, location) + .unwrap_or_else(|| self.new_opaque(op.ty(self.local_decls, self.tcx))) + })); let variant_index = match *kind { AggregateKind::Array(..) | AggregateKind::Tuple => { @@ -989,12 +1087,12 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let mut was_updated = false; while let Value::Cast { kind: CastKind::PtrToPtr, value: cast_value } = self.get(pointer) - && let ty::RawPtr(from_pointee_ty, from_mtbl) = self.ty(*cast_value).kind() + && let ty::RawPtr(from_pointee_ty, from_mtbl) = self.ty(cast_value).kind() && let ty::RawPtr(_, output_mtbl) = ty.kind() && from_mtbl == output_mtbl && from_pointee_ty.is_sized(self.tcx, self.typing_env()) { - pointer = *cast_value; + pointer = cast_value; was_updated = true; } @@ -1018,15 +1116,6 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } if let Some(value) = self.simplify_aggregate_to_copy(ty, variant_index, &fields) { - // Allow introducing places with non-constant offsets, as those are still better than - // reconstructing an aggregate. But avoid creating `*a = copy (*b)`, as they might be - // aliases resulting in overlapping assignments. - let allow_complex_projection = - lhs.projection[..].iter().all(PlaceElem::is_stable_offset); - if let Some(place) = self.try_as_place(value, location, allow_complex_projection) { - self.reused_locals.insert(place.local); - *rvalue = Rvalue::Use(Operand::Copy(place)); - } return Some(value); } @@ -1059,20 +1148,18 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { // To allow things like `*mut (?A, ?T)` <-> `*mut (?B, ?T)`, // it's fine to get a projection as the type. Value::Cast { kind: CastKind::PtrToPtr, value: inner } - if self.pointers_have_same_metadata(self.ty(*inner), arg_ty) => + if self.pointers_have_same_metadata(self.ty(inner), arg_ty) => { - arg_index = *inner; + arg_index = inner; was_updated = true; continue; } // `&mut *p`, `&raw *p`, etc don't change metadata. - Value::Address { place, kind: _, provenance: _ } - if let PlaceRef { local, projection: [PlaceElem::Deref] } = - place.as_ref() - && let Some(local_index) = self.locals[local] => + Value::Address { base: AddressBase::Deref(reborrowed), projection, .. } + if projection.is_empty() => { - arg_index = local_index; + arg_index = reborrowed; was_updated = true; continue; } @@ -1088,15 +1175,15 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } let value = match (op, self.get(arg_index)) { - (UnOp::Not, Value::UnaryOp(UnOp::Not, inner)) => return Some(*inner), - (UnOp::Neg, Value::UnaryOp(UnOp::Neg, inner)) => return Some(*inner), + (UnOp::Not, Value::UnaryOp(UnOp::Not, inner)) => return Some(inner), + (UnOp::Neg, Value::UnaryOp(UnOp::Neg, inner)) => return Some(inner), (UnOp::Not, Value::BinaryOp(BinOp::Eq, lhs, rhs)) => { - Value::BinaryOp(BinOp::Ne, *lhs, *rhs) + Value::BinaryOp(BinOp::Ne, lhs, rhs) } (UnOp::Not, Value::BinaryOp(BinOp::Ne, lhs, rhs)) => { - Value::BinaryOp(BinOp::Eq, *lhs, *rhs) + Value::BinaryOp(BinOp::Eq, lhs, rhs) } - (UnOp::PtrMetadata, Value::RawPtr { metadata, .. }) => return Some(*metadata), + (UnOp::PtrMetadata, Value::RawPtr { metadata, .. }) => return Some(metadata), // We have an unsizing cast, which assigns the length to wide pointer metadata. ( UnOp::PtrMetadata, @@ -1105,7 +1192,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { value: inner, }, ) if let ty::Slice(..) = arg_ty.builtin_deref(true).unwrap().kind() - && let ty::Array(_, len) = self.ty(*inner).builtin_deref(true).unwrap().kind() => + && let ty::Array(_, len) = self.ty(inner).builtin_deref(true).unwrap().kind() => { return Some(self.insert_constant(Const::Ty(self.tcx.types.usize, *len))); } @@ -1138,12 +1225,12 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { && lhs_ty.is_any_ptr() && let Value::Cast { kind: CastKind::PtrToPtr, value: lhs_value } = self.get(lhs) && let Value::Cast { kind: CastKind::PtrToPtr, value: rhs_value } = self.get(rhs) - && let lhs_from = self.ty(*lhs_value) - && lhs_from == self.ty(*rhs_value) + && let lhs_from = self.ty(lhs_value) + && lhs_from == self.ty(rhs_value) && self.pointers_have_same_metadata(lhs_from, lhs_ty) { - lhs = *lhs_value; - rhs = *rhs_value; + lhs = lhs_value; + rhs = rhs_value; if let Some(lhs_op) = self.try_as_operand(lhs, location) && let Some(rhs_op) = self.try_as_operand(rhs, location) { @@ -1277,7 +1364,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { if op.is_overflowing() { let ty = Ty::new_tup(self.tcx, &[self.ty(result), self.tcx.types.bool]); let false_val = self.insert_bool(false); - Some(self.insert_tuple(ty, vec![result, false_val])) + Some(self.insert_tuple(ty, &[result, false_val])) } else { Some(result) } @@ -1330,11 +1417,11 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { && let ty::RawPtr(to_pointee, _) = to.kind() && to_pointee.is_sized(self.tcx, self.typing_env()) { - from = self.ty(*pointer); - value = *pointer; + from = self.ty(pointer); + value = pointer; was_updated_this_iteration = true; if from == to { - return Some(*pointer); + return Some(pointer); } } @@ -1343,7 +1430,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { if let Transmute = kind && let Value::Aggregate(variant_idx, field_values) = self.get(value) && let Some((field_idx, field_ty)) = - self.value_is_all_in_one_field(from, *variant_idx) + self.value_is_all_in_one_field(from, variant_idx) { from = field_ty; value = field_values[field_idx.as_usize()]; @@ -1354,7 +1441,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } // Various cast-then-cast cases can be simplified. - if let Value::Cast { kind: inner_kind, value: inner_value } = *self.get(value) { + if let Value::Cast { kind: inner_kind, value: inner_value } = self.get(value) { let inner_from = self.ty(inner_value); let new_kind = match (inner_kind, kind) { // Even if there's a narrowing cast in here that's fine, because @@ -1418,9 +1505,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { // The length information is stored in the wide pointer. // Reborrowing copies length information from one pointer to the other. - while let Value::Address { place: borrowed, .. } = self.get(inner) - && let [PlaceElem::Deref] = borrowed.projection[..] - && let Some(borrowed) = self.locals[borrowed.local] + while let Value::Address { base: AddressBase::Deref(borrowed), projection, .. } = + self.get(inner) + && projection.is_empty() { inner = borrowed; } @@ -1428,7 +1515,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { // We have an unsizing cast, which assigns the length to wide pointer metadata. if let Value::Cast { kind, value: from } = self.get(inner) && let CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize, _) = kind - && let Some(from) = self.ty(*from).builtin_deref(true) + && let Some(from) = self.ty(from).builtin_deref(true) && let ty::Array(_, len) = from.kind() && let Some(to) = self.ty(inner).builtin_deref(true) && let ty::Slice(..) = to.kind() @@ -1586,7 +1673,7 @@ fn op_to_prop_const<'tcx>( None } -impl<'tcx> VnState<'_, 'tcx> { +impl<'tcx> VnState<'_, '_, 'tcx> { /// If either [`Self::try_as_constant`] as [`Self::try_as_place`] succeeds, /// returns that result as an [`Operand`]. fn try_as_operand(&mut self, index: VnIndex, location: Location) -> Option> { @@ -1605,7 +1692,7 @@ impl<'tcx> VnState<'_, 'tcx> { // This was already constant in MIR, do not change it. If the constant is not // deterministic, adding an additional mention of it in MIR will not give the same value as // the former mention. - if let Value::Constant { value, disambiguator: 0 } = *self.get(index) { + if let Value::Constant { value, disambiguator: 0 } = self.get(index) { debug_assert!(value.is_deterministic()); return Some(ConstOperand { span: DUMMY_SP, user_ty: None, const_: value }); } @@ -1649,7 +1736,7 @@ impl<'tcx> VnState<'_, 'tcx> { // If we are here, we failed to find a local, and we already have a `Deref`. // Trying to add projections will only result in an ill-formed place. return None; - } else if let Value::Projection(pointer, proj) = *self.get(index) + } else if let Value::Projection(pointer, proj) = self.get(index) && (allow_complex_projection || proj.is_stable_offset()) && let Some(proj) = self.try_as_place_elem(self.ty(index), proj, loc) { @@ -1664,24 +1751,39 @@ impl<'tcx> VnState<'_, 'tcx> { /// If there is a local which is assigned `index`, and its assignment strictly dominates `loc`, /// return it. If you used this local, add it to `reused_locals` to remove storage statements. fn try_as_local(&mut self, index: VnIndex, loc: Location) -> Option { - let other = self.rev_locals.get(index)?; - other - .iter() - .find(|&&other| self.ssa.assignment_dominates(&self.dominators, other, loc)) - .copied() + if let Some(ssa) = self.rev_locals_ssa.get(index) + && let Some(other) = ssa + .iter() + .find(|&&other| self.ssa.assignment_dominates(&self.dominators, other, loc)) + { + Some(*other) + } else if let Some(non_ssa) = self.rev_locals_non_ssa.get(&index) { + non_ssa.first().copied() + } else { + None + } } } -impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> { +impl<'tcx> MutVisitor<'tcx> for VnState<'_, '_, 'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } + fn visit_basic_block_data(&mut self, block: BasicBlock, bbdata: &mut BasicBlockData<'tcx>) { + self.rev_locals_non_ssa.clear(); + for local in self.locals.indices() { + if !self.ssa.is_ssa(local) { + self.locals[local] = None; + } + } + self.super_basic_block_data(block, bbdata); + } + fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) { self.simplify_place_projection(place, location); - if context.is_mutating_use() && place.is_indirect() { - // Non-local mutation maybe invalidate deref. - self.invalidate_derefs(); + if context.is_mutating_use() { + self.discard_place(*place); } self.super_place(place, context, location); } @@ -1699,26 +1801,30 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> { ) { self.simplify_place_projection(lhs, location); - let value = self.simplify_rvalue(lhs, rvalue, location); + let value = self.simplify_rvalue(rvalue, location); if let Some(value) = value { + // Allow introducing places with non-constant offsets, as those are still better than + // reconstructing an aggregate. But avoid creating `*a = copy (*b)`, as they might be + // aliases resulting in overlapping assignments. + let allow_complex_projection = + lhs.projection[..].iter().all(PlaceElem::is_stable_offset); + if let Some(const_) = self.try_as_constant(value) { *rvalue = Rvalue::Use(Operand::Constant(Box::new(const_))); - } else if let Some(place) = self.try_as_place(value, location, false) + } else if let Some(place) = self.try_as_place(value, location, allow_complex_projection) && *rvalue != Rvalue::Use(Operand::Move(place)) && *rvalue != Rvalue::Use(Operand::Copy(place)) + // Avoid introducing overlapping assignments to the same local. + && place.local != lhs.local { *rvalue = Rvalue::Use(Operand::Copy(place)); self.reused_locals.insert(place.local); } } - if lhs.is_indirect() { - // Non-local mutation maybe invalidate deref. - self.invalidate_derefs(); - } + self.discard_place(*lhs); if let Some(local) = lhs.as_local() - && self.ssa.is_ssa(local) && let rvalue_ty = rvalue.ty(self.local_decls, self.tcx) // FIXME(#112651) `rvalue` may have a subtype to `local`. We can only mark // `local` as reusable if we have an exact type match. @@ -1730,14 +1836,13 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> { } fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Location) { - if let Terminator { kind: TerminatorKind::Call { destination, .. }, .. } = terminator { - if let Some(local) = destination.as_local() - && self.ssa.is_ssa(local) - { - let ty = self.local_decls[local].ty; - let opaque = self.new_opaque(ty); - self.assign(local, opaque); - } + self.super_terminator(terminator, location); + if let Terminator { kind: TerminatorKind::Call { destination, .. }, .. } = terminator + && let Some(local) = destination.as_local() + { + let ty = self.local_decls[local].ty; + let opaque = self.new_opaque(ty); + self.assign(local, opaque); } // Function calls and ASM may invalidate (nested) derefs. We must handle them carefully. // Currently, only preserving derefs for trivial terminators like SwitchInt and Goto. @@ -1748,7 +1853,6 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> { if !safe_to_preserve_derefs { self.invalidate_derefs(); } - self.super_terminator(terminator, location); } } diff --git a/tests/coverage/closure.cov-map b/tests/coverage/closure.cov-map index ee8934f0a846f..608792564245c 100644 --- a/tests/coverage/closure.cov-map +++ b/tests/coverage/closure.cov-map @@ -74,24 +74,22 @@ Number of file 0 mappings: 66 - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 -Function name: closure::main::{closure#0} -Raw bytes (51): 0x[01, 01, 01, 01, 05, 09, 01, 28, 05, 00, 06, 01, 01, 0d, 00, 1a, 01, 00, 1d, 00, 1e, 01, 01, 0c, 00, 14, 05, 00, 15, 02, 0a, 02, 02, 09, 00, 0a, 01, 01, 09, 00, 17, 01, 00, 18, 00, 20, 01, 01, 05, 00, 06] +Function name: closure::main::{closure#0} (unused) +Raw bytes (49): 0x[01, 01, 00, 09, 00, 28, 05, 00, 06, 00, 01, 0d, 00, 1a, 00, 00, 1d, 00, 1e, 00, 01, 0c, 00, 14, 00, 00, 15, 02, 0a, 00, 02, 09, 00, 0a, 00, 01, 09, 00, 17, 00, 00, 18, 00, 20, 00, 01, 05, 00, 06] Number of files: 1 - file 0 => $DIR/closure.rs -Number of expressions: 1 -- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +Number of expressions: 0 Number of file 0 mappings: 9 -- Code(Counter(0)) at (prev + 40, 5) to (start + 0, 6) -- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 26) -- Code(Counter(0)) at (prev + 0, 29) to (start + 0, 30) -- Code(Counter(0)) at (prev + 1, 12) to (start + 0, 20) -- Code(Counter(1)) at (prev + 0, 21) to (start + 2, 10) -- Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 10) - = (c0 - c1) -- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 23) -- Code(Counter(0)) at (prev + 0, 24) to (start + 0, 32) -- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 6) -Highest counter ID seen: c1 +- Code(Zero) at (prev + 40, 5) to (start + 0, 6) +- Code(Zero) at (prev + 1, 13) to (start + 0, 26) +- Code(Zero) at (prev + 0, 29) to (start + 0, 30) +- Code(Zero) at (prev + 1, 12) to (start + 0, 20) +- Code(Zero) at (prev + 0, 21) to (start + 2, 10) +- Code(Zero) at (prev + 2, 9) to (start + 0, 10) +- Code(Zero) at (prev + 1, 9) to (start + 0, 23) +- Code(Zero) at (prev + 0, 24) to (start + 0, 32) +- Code(Zero) at (prev + 1, 5) to (start + 0, 6) +Highest counter ID seen: (none) Function name: closure::main::{closure#10} (unused) Raw bytes (25): 0x[01, 01, 00, 04, 00, 9b, 01, 07, 00, 08, 00, 00, 09, 00, 11, 00, 00, 12, 00, 1e, 00, 00, 20, 00, 21] @@ -199,24 +197,22 @@ Number of file 0 mappings: 7 - Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10) Highest counter ID seen: c1 -Function name: closure::main::{closure#18} -Raw bytes (51): 0x[01, 01, 01, 01, 05, 09, 01, 19, 0d, 00, 0e, 01, 01, 15, 00, 22, 01, 00, 25, 00, 26, 01, 01, 14, 00, 1c, 05, 00, 1d, 02, 12, 02, 02, 11, 00, 12, 01, 01, 11, 00, 1f, 01, 00, 20, 00, 28, 01, 01, 0d, 00, 0e] +Function name: closure::main::{closure#18} (unused) +Raw bytes (49): 0x[01, 01, 00, 09, 00, 19, 0d, 00, 0e, 00, 01, 15, 00, 22, 00, 00, 25, 00, 26, 00, 01, 14, 00, 1c, 00, 00, 1d, 02, 12, 00, 02, 11, 00, 12, 00, 01, 11, 00, 1f, 00, 00, 20, 00, 28, 00, 01, 0d, 00, 0e] Number of files: 1 - file 0 => $DIR/closure.rs -Number of expressions: 1 -- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +Number of expressions: 0 Number of file 0 mappings: 9 -- Code(Counter(0)) at (prev + 25, 13) to (start + 0, 14) -- Code(Counter(0)) at (prev + 1, 21) to (start + 0, 34) -- Code(Counter(0)) at (prev + 0, 37) to (start + 0, 38) -- Code(Counter(0)) at (prev + 1, 20) to (start + 0, 28) -- Code(Counter(1)) at (prev + 0, 29) to (start + 2, 18) -- Code(Expression(0, Sub)) at (prev + 2, 17) to (start + 0, 18) - = (c0 - c1) -- Code(Counter(0)) at (prev + 1, 17) to (start + 0, 31) -- Code(Counter(0)) at (prev + 0, 32) to (start + 0, 40) -- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 14) -Highest counter ID seen: c1 +- Code(Zero) at (prev + 25, 13) to (start + 0, 14) +- Code(Zero) at (prev + 1, 21) to (start + 0, 34) +- Code(Zero) at (prev + 0, 37) to (start + 0, 38) +- Code(Zero) at (prev + 1, 20) to (start + 0, 28) +- Code(Zero) at (prev + 0, 29) to (start + 2, 18) +- Code(Zero) at (prev + 2, 17) to (start + 0, 18) +- Code(Zero) at (prev + 1, 17) to (start + 0, 31) +- Code(Zero) at (prev + 0, 32) to (start + 0, 40) +- Code(Zero) at (prev + 1, 13) to (start + 0, 14) +Highest counter ID seen: (none) Function name: closure::main::{closure#19} Raw bytes (51): 0x[01, 01, 01, 01, 05, 09, 01, 43, 0d, 00, 0e, 01, 01, 15, 00, 22, 01, 00, 25, 00, 26, 01, 01, 14, 00, 1c, 05, 00, 1d, 02, 12, 02, 02, 11, 00, 12, 01, 01, 11, 00, 1f, 01, 00, 20, 00, 28, 01, 01, 0d, 00, 0e] diff --git a/tests/coverage/issue-83601.cov-map b/tests/coverage/issue-83601.cov-map index d1d751ff24b86..e42b5591c0fb3 100644 --- a/tests/coverage/issue-83601.cov-map +++ b/tests/coverage/issue-83601.cov-map @@ -1,30 +1,22 @@ Function name: issue_83601::main -Raw bytes (76): 0x[01, 01, 01, 05, 09, 0e, 01, 06, 01, 00, 0a, 01, 01, 09, 00, 0c, 01, 00, 0f, 00, 15, 01, 01, 05, 00, 0f, 05, 01, 09, 00, 0c, 05, 00, 0f, 00, 15, 05, 01, 05, 00, 0f, 02, 01, 05, 00, 0d, 02, 00, 0e, 00, 14, 02, 01, 05, 00, 0d, 02, 00, 0e, 00, 14, 02, 01, 05, 00, 0d, 02, 00, 0e, 00, 14, 02, 01, 01, 00, 02] +Raw bytes (74): 0x[01, 01, 00, 0e, 01, 06, 01, 00, 0a, 01, 01, 09, 00, 0c, 01, 00, 0f, 00, 15, 01, 01, 05, 00, 0f, 01, 01, 09, 00, 0c, 01, 00, 0f, 00, 15, 01, 01, 05, 00, 0f, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 14, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 14, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 14, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/issue-83601.rs -Number of expressions: 1 -- expression 0 operands: lhs = Counter(1), rhs = Counter(2) +Number of expressions: 0 Number of file 0 mappings: 14 - Code(Counter(0)) at (prev + 6, 1) to (start + 0, 10) - Code(Counter(0)) at (prev + 1, 9) to (start + 0, 12) - Code(Counter(0)) at (prev + 0, 15) to (start + 0, 21) - Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) -- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 12) -- Code(Counter(1)) at (prev + 0, 15) to (start + 0, 21) -- Code(Counter(1)) at (prev + 1, 5) to (start + 0, 15) -- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 13) - = (c1 - c2) -- Code(Expression(0, Sub)) at (prev + 0, 14) to (start + 0, 20) - = (c1 - c2) -- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 13) - = (c1 - c2) -- Code(Expression(0, Sub)) at (prev + 0, 14) to (start + 0, 20) - = (c1 - c2) -- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 13) - = (c1 - c2) -- Code(Expression(0, Sub)) at (prev + 0, 14) to (start + 0, 20) - = (c1 - c2) -- Code(Expression(0, Sub)) at (prev + 1, 1) to (start + 0, 2) - = (c1 - c2) -Highest counter ID seen: c1 +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 12) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 21) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 20) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 20) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 20) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: c0 diff --git a/tests/coverage/issue-84561.cov-map b/tests/coverage/issue-84561.cov-map index 2b643ea599ed0..e5bb1afdcc263 100644 --- a/tests/coverage/issue-84561.cov-map +++ b/tests/coverage/issue-84561.cov-map @@ -73,20 +73,20 @@ Number of file 0 mappings: 4 Highest counter ID seen: c0 Function name: issue_84561::test3 -Raw bytes (409): 0x[01, 01, 0a, 0d, 11, 0d, 15, 0d, 19, 1d, 21, 29, 2d, 25, 29, 25, 29, 25, 29, 27, 31, 29, 2d, 4d, 01, 08, 01, 00, 0b, 01, 01, 09, 00, 10, 01, 00, 13, 00, 2e, 01, 01, 09, 00, 0c, 01, 00, 0f, 00, 15, 01, 01, 05, 00, 0f, 05, 01, 09, 00, 0c, 05, 00, 0f, 00, 15, 05, 01, 05, 00, 0f, 09, 01, 05, 00, 0d, 09, 00, 0e, 00, 14, 09, 01, 05, 00, 0d, 09, 00, 0e, 00, 14, 09, 01, 05, 00, 0d, 09, 00, 0e, 00, 14, 09, 02, 05, 00, 0f, 09, 01, 05, 00, 0f, 09, 01, 05, 00, 0f, 09, 01, 09, 00, 0c, 09, 00, 0f, 00, 15, 09, 01, 05, 00, 0f, 0d, 01, 05, 00, 0f, 0d, 01, 05, 00, 0f, 00, 00, 20, 00, 30, 0d, 01, 05, 00, 0d, 0d, 00, 0e, 00, 14, 0d, 01, 05, 00, 0d, 0d, 00, 0e, 00, 14, 0d, 02, 05, 00, 0f, 00, 00, 20, 00, 24, 00, 00, 29, 00, 30, 00, 00, 33, 00, 41, 00, 00, 4b, 00, 5a, 0d, 01, 05, 00, 0f, 00, 05, 09, 00, 0d, 00, 03, 09, 00, 10, 00, 02, 0d, 00, 1b, 00, 02, 0d, 00, 1c, 0d, 04, 09, 00, 10, 0d, 00, 13, 00, 2e, 0d, 02, 05, 00, 0f, 0d, 04, 05, 00, 0f, 0d, 04, 05, 00, 0f, 0d, 04, 09, 00, 0c, 0d, 00, 0f, 00, 15, 0d, 01, 05, 00, 0f, 0d, 04, 08, 00, 0f, 11, 01, 09, 00, 13, 02, 05, 09, 00, 13, 0d, 05, 08, 00, 0f, 15, 01, 09, 00, 13, 00, 03, 0d, 00, 1d, 06, 03, 09, 00, 13, 00, 03, 0d, 00, 1d, 0d, 03, 05, 00, 0f, 0d, 01, 0c, 00, 13, 19, 01, 0d, 00, 13, 0a, 02, 0d, 00, 13, 1d, 04, 05, 00, 0f, 1d, 02, 0c, 00, 13, 21, 01, 0d, 00, 13, 0e, 02, 0d, 00, 13, 27, 03, 05, 00, 0f, 25, 01, 0c, 00, 13, 29, 01, 0d, 00, 17, 29, 04, 0d, 00, 13, 1e, 02, 0d, 00, 17, 1e, 01, 14, 00, 1b, 00, 01, 15, 00, 1b, 1e, 02, 15, 00, 1b, 2d, 04, 0d, 00, 13, 22, 03, 09, 00, 19, 31, 02, 05, 00, 0f, 31, 03, 09, 00, 22, 00, 02, 05, 00, 0f, 00, 03, 09, 00, 2c, 00, 02, 01, 00, 02] +Raw bytes (409): 0x[01, 01, 0a, 01, 05, 01, 09, 01, 0d, 11, 15, 1d, 21, 19, 1d, 19, 1d, 19, 1d, 27, 25, 1d, 21, 4d, 01, 08, 01, 00, 0b, 01, 01, 09, 00, 10, 01, 00, 13, 00, 2e, 01, 01, 09, 00, 0c, 01, 00, 0f, 00, 15, 01, 01, 05, 00, 0f, 01, 01, 09, 00, 0c, 01, 00, 0f, 00, 15, 01, 01, 05, 00, 0f, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 14, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 14, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 14, 01, 02, 05, 00, 0f, 01, 01, 05, 00, 0f, 01, 01, 05, 00, 0f, 01, 01, 09, 00, 0c, 01, 00, 0f, 00, 15, 01, 01, 05, 00, 0f, 01, 01, 05, 00, 0f, 01, 01, 05, 00, 0f, 00, 00, 20, 00, 30, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 14, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 14, 01, 02, 05, 00, 0f, 00, 00, 20, 00, 24, 00, 00, 29, 00, 30, 00, 00, 33, 00, 41, 00, 00, 4b, 00, 5a, 01, 01, 05, 00, 0f, 00, 05, 09, 00, 0d, 00, 03, 09, 00, 10, 00, 02, 0d, 00, 1b, 00, 02, 0d, 00, 1c, 01, 04, 09, 00, 10, 01, 00, 13, 00, 2e, 01, 02, 05, 00, 0f, 01, 04, 05, 00, 0f, 01, 04, 05, 00, 0f, 01, 04, 09, 00, 0c, 01, 00, 0f, 00, 15, 01, 01, 05, 00, 0f, 01, 04, 08, 00, 0f, 05, 01, 09, 00, 13, 02, 05, 09, 00, 13, 01, 05, 08, 00, 0f, 09, 01, 09, 00, 13, 00, 03, 0d, 00, 1d, 06, 03, 09, 00, 13, 00, 03, 0d, 00, 1d, 01, 03, 05, 00, 0f, 01, 01, 0c, 00, 13, 0d, 01, 0d, 00, 13, 0a, 02, 0d, 00, 13, 11, 04, 05, 00, 0f, 11, 02, 0c, 00, 13, 15, 01, 0d, 00, 13, 0e, 02, 0d, 00, 13, 27, 03, 05, 00, 0f, 19, 01, 0c, 00, 13, 1d, 01, 0d, 00, 17, 1d, 04, 0d, 00, 13, 1e, 02, 0d, 00, 17, 1e, 01, 14, 00, 1b, 00, 01, 15, 00, 1b, 1e, 02, 15, 00, 1b, 21, 04, 0d, 00, 13, 22, 03, 09, 00, 19, 25, 02, 05, 00, 0f, 25, 03, 09, 00, 22, 00, 02, 05, 00, 0f, 00, 03, 09, 00, 2c, 00, 02, 01, 00, 02] Number of files: 1 - file 0 => $DIR/issue-84561.rs Number of expressions: 10 -- expression 0 operands: lhs = Counter(3), rhs = Counter(4) -- expression 1 operands: lhs = Counter(3), rhs = Counter(5) -- expression 2 operands: lhs = Counter(3), rhs = Counter(6) -- expression 3 operands: lhs = Counter(7), rhs = Counter(8) -- expression 4 operands: lhs = Counter(10), rhs = Counter(11) -- expression 5 operands: lhs = Counter(9), rhs = Counter(10) -- expression 6 operands: lhs = Counter(9), rhs = Counter(10) -- expression 7 operands: lhs = Counter(9), rhs = Counter(10) -- expression 8 operands: lhs = Expression(9, Add), rhs = Counter(12) -- expression 9 operands: lhs = Counter(10), rhs = Counter(11) +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(0), rhs = Counter(2) +- expression 2 operands: lhs = Counter(0), rhs = Counter(3) +- expression 3 operands: lhs = Counter(4), rhs = Counter(5) +- expression 4 operands: lhs = Counter(7), rhs = Counter(8) +- expression 5 operands: lhs = Counter(6), rhs = Counter(7) +- expression 6 operands: lhs = Counter(6), rhs = Counter(7) +- expression 7 operands: lhs = Counter(6), rhs = Counter(7) +- expression 8 operands: lhs = Expression(9, Add), rhs = Counter(9) +- expression 9 operands: lhs = Counter(7), rhs = Counter(8) Number of file 0 mappings: 77 - Code(Counter(0)) at (prev + 8, 1) to (start + 0, 11) - Code(Counter(0)) at (prev + 1, 9) to (start + 0, 16) @@ -94,85 +94,85 @@ Number of file 0 mappings: 77 - Code(Counter(0)) at (prev + 1, 9) to (start + 0, 12) - Code(Counter(0)) at (prev + 0, 15) to (start + 0, 21) - Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) -- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 12) -- Code(Counter(1)) at (prev + 0, 15) to (start + 0, 21) -- Code(Counter(1)) at (prev + 1, 5) to (start + 0, 15) -- Code(Counter(2)) at (prev + 1, 5) to (start + 0, 13) -- Code(Counter(2)) at (prev + 0, 14) to (start + 0, 20) -- Code(Counter(2)) at (prev + 1, 5) to (start + 0, 13) -- Code(Counter(2)) at (prev + 0, 14) to (start + 0, 20) -- Code(Counter(2)) at (prev + 1, 5) to (start + 0, 13) -- Code(Counter(2)) at (prev + 0, 14) to (start + 0, 20) -- Code(Counter(2)) at (prev + 2, 5) to (start + 0, 15) -- Code(Counter(2)) at (prev + 1, 5) to (start + 0, 15) -- Code(Counter(2)) at (prev + 1, 5) to (start + 0, 15) -- Code(Counter(2)) at (prev + 1, 9) to (start + 0, 12) -- Code(Counter(2)) at (prev + 0, 15) to (start + 0, 21) -- Code(Counter(2)) at (prev + 1, 5) to (start + 0, 15) -- Code(Counter(3)) at (prev + 1, 5) to (start + 0, 15) -- Code(Counter(3)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 12) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 21) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 20) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 20) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 20) +- Code(Counter(0)) at (prev + 2, 5) to (start + 0, 15) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 12) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 21) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) - Code(Zero) at (prev + 0, 32) to (start + 0, 48) -- Code(Counter(3)) at (prev + 1, 5) to (start + 0, 13) -- Code(Counter(3)) at (prev + 0, 14) to (start + 0, 20) -- Code(Counter(3)) at (prev + 1, 5) to (start + 0, 13) -- Code(Counter(3)) at (prev + 0, 14) to (start + 0, 20) -- Code(Counter(3)) at (prev + 2, 5) to (start + 0, 15) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 20) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 20) +- Code(Counter(0)) at (prev + 2, 5) to (start + 0, 15) - Code(Zero) at (prev + 0, 32) to (start + 0, 36) - Code(Zero) at (prev + 0, 41) to (start + 0, 48) - Code(Zero) at (prev + 0, 51) to (start + 0, 65) - Code(Zero) at (prev + 0, 75) to (start + 0, 90) -- Code(Counter(3)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) - Code(Zero) at (prev + 5, 9) to (start + 0, 13) - Code(Zero) at (prev + 3, 9) to (start + 0, 16) - Code(Zero) at (prev + 2, 13) to (start + 0, 27) - Code(Zero) at (prev + 2, 13) to (start + 0, 28) -- Code(Counter(3)) at (prev + 4, 9) to (start + 0, 16) -- Code(Counter(3)) at (prev + 0, 19) to (start + 0, 46) -- Code(Counter(3)) at (prev + 2, 5) to (start + 0, 15) -- Code(Counter(3)) at (prev + 4, 5) to (start + 0, 15) -- Code(Counter(3)) at (prev + 4, 5) to (start + 0, 15) -- Code(Counter(3)) at (prev + 4, 9) to (start + 0, 12) -- Code(Counter(3)) at (prev + 0, 15) to (start + 0, 21) -- Code(Counter(3)) at (prev + 1, 5) to (start + 0, 15) -- Code(Counter(3)) at (prev + 4, 8) to (start + 0, 15) -- Code(Counter(4)) at (prev + 1, 9) to (start + 0, 19) +- Code(Counter(0)) at (prev + 4, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 0, 19) to (start + 0, 46) +- Code(Counter(0)) at (prev + 2, 5) to (start + 0, 15) +- Code(Counter(0)) at (prev + 4, 5) to (start + 0, 15) +- Code(Counter(0)) at (prev + 4, 5) to (start + 0, 15) +- Code(Counter(0)) at (prev + 4, 9) to (start + 0, 12) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 21) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(0)) at (prev + 4, 8) to (start + 0, 15) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 19) - Code(Expression(0, Sub)) at (prev + 5, 9) to (start + 0, 19) - = (c3 - c4) -- Code(Counter(3)) at (prev + 5, 8) to (start + 0, 15) -- Code(Counter(5)) at (prev + 1, 9) to (start + 0, 19) + = (c0 - c1) +- Code(Counter(0)) at (prev + 5, 8) to (start + 0, 15) +- Code(Counter(2)) at (prev + 1, 9) to (start + 0, 19) - Code(Zero) at (prev + 3, 13) to (start + 0, 29) - Code(Expression(1, Sub)) at (prev + 3, 9) to (start + 0, 19) - = (c3 - c5) + = (c0 - c2) - Code(Zero) at (prev + 3, 13) to (start + 0, 29) -- Code(Counter(3)) at (prev + 3, 5) to (start + 0, 15) -- Code(Counter(3)) at (prev + 1, 12) to (start + 0, 19) -- Code(Counter(6)) at (prev + 1, 13) to (start + 0, 19) +- Code(Counter(0)) at (prev + 3, 5) to (start + 0, 15) +- Code(Counter(0)) at (prev + 1, 12) to (start + 0, 19) +- Code(Counter(3)) at (prev + 1, 13) to (start + 0, 19) - Code(Expression(2, Sub)) at (prev + 2, 13) to (start + 0, 19) - = (c3 - c6) -- Code(Counter(7)) at (prev + 4, 5) to (start + 0, 15) -- Code(Counter(7)) at (prev + 2, 12) to (start + 0, 19) -- Code(Counter(8)) at (prev + 1, 13) to (start + 0, 19) + = (c0 - c3) +- Code(Counter(4)) at (prev + 4, 5) to (start + 0, 15) +- Code(Counter(4)) at (prev + 2, 12) to (start + 0, 19) +- Code(Counter(5)) at (prev + 1, 13) to (start + 0, 19) - Code(Expression(3, Sub)) at (prev + 2, 13) to (start + 0, 19) - = (c7 - c8) + = (c4 - c5) - Code(Expression(9, Add)) at (prev + 3, 5) to (start + 0, 15) - = (c10 + c11) -- Code(Counter(9)) at (prev + 1, 12) to (start + 0, 19) -- Code(Counter(10)) at (prev + 1, 13) to (start + 0, 23) -- Code(Counter(10)) at (prev + 4, 13) to (start + 0, 19) + = (c7 + c8) +- Code(Counter(6)) at (prev + 1, 12) to (start + 0, 19) +- Code(Counter(7)) at (prev + 1, 13) to (start + 0, 23) +- Code(Counter(7)) at (prev + 4, 13) to (start + 0, 19) - Code(Expression(7, Sub)) at (prev + 2, 13) to (start + 0, 23) - = (c9 - c10) + = (c6 - c7) - Code(Expression(7, Sub)) at (prev + 1, 20) to (start + 0, 27) - = (c9 - c10) + = (c6 - c7) - Code(Zero) at (prev + 1, 21) to (start + 0, 27) - Code(Expression(7, Sub)) at (prev + 2, 21) to (start + 0, 27) - = (c9 - c10) -- Code(Counter(11)) at (prev + 4, 13) to (start + 0, 19) + = (c6 - c7) +- Code(Counter(8)) at (prev + 4, 13) to (start + 0, 19) - Code(Expression(8, Sub)) at (prev + 3, 9) to (start + 0, 25) - = ((c10 + c11) - c12) -- Code(Counter(12)) at (prev + 2, 5) to (start + 0, 15) -- Code(Counter(12)) at (prev + 3, 9) to (start + 0, 34) + = ((c7 + c8) - c9) +- Code(Counter(9)) at (prev + 2, 5) to (start + 0, 15) +- Code(Counter(9)) at (prev + 3, 9) to (start + 0, 34) - Code(Zero) at (prev + 2, 5) to (start + 0, 15) - Code(Zero) at (prev + 3, 9) to (start + 0, 44) - Code(Zero) at (prev + 2, 1) to (start + 0, 2) -Highest counter ID seen: c12 +Highest counter ID seen: c9 diff --git a/tests/mir-opt/const_prop/boxes.main.GVN.panic-abort.diff b/tests/mir-opt/const_prop/boxes.main.GVN.panic-abort.diff index f43c0cca9ad28..6f33229ce7a27 100644 --- a/tests/mir-opt/const_prop/boxes.main.GVN.panic-abort.diff +++ b/tests/mir-opt/const_prop/boxes.main.GVN.panic-abort.diff @@ -30,16 +30,21 @@ } bb1: { - StorageLive(_7); +- StorageLive(_7); ++ nop; _7 = ShallowInitBox(move _6, i32); _8 = copy ((_7.0: std::ptr::Unique).0: std::ptr::NonNull) as *const i32 (Transmute); (*_8) = const 42_i32; - _3 = move _7; - StorageDead(_7); - _9 = copy ((_3.0: std::ptr::Unique).0: std::ptr::NonNull) as *const i32 (Transmute); - _2 = copy (*_9); +- _3 = move _7; +- StorageDead(_7); +- _9 = copy ((_3.0: std::ptr::Unique).0: std::ptr::NonNull) as *const i32 (Transmute); +- _2 = copy (*_9); - _1 = Add(move _2, const 0_i32); - StorageDead(_2); ++ _3 = copy _7; ++ nop; ++ _9 = copy _8; ++ _2 = copy (*_8); + _1 = copy _2; + nop; drop(_3) -> [return: bb2, unwind unreachable]; diff --git a/tests/mir-opt/const_prop/boxes.main.GVN.panic-unwind.diff b/tests/mir-opt/const_prop/boxes.main.GVN.panic-unwind.diff index 2c903b6d85349..008f3d96962f9 100644 --- a/tests/mir-opt/const_prop/boxes.main.GVN.panic-unwind.diff +++ b/tests/mir-opt/const_prop/boxes.main.GVN.panic-unwind.diff @@ -30,16 +30,21 @@ } bb1: { - StorageLive(_7); +- StorageLive(_7); ++ nop; _7 = ShallowInitBox(move _6, i32); _8 = copy ((_7.0: std::ptr::Unique).0: std::ptr::NonNull) as *const i32 (Transmute); (*_8) = const 42_i32; - _3 = move _7; - StorageDead(_7); - _9 = copy ((_3.0: std::ptr::Unique).0: std::ptr::NonNull) as *const i32 (Transmute); - _2 = copy (*_9); +- _3 = move _7; +- StorageDead(_7); +- _9 = copy ((_3.0: std::ptr::Unique).0: std::ptr::NonNull) as *const i32 (Transmute); +- _2 = copy (*_9); - _1 = Add(move _2, const 0_i32); - StorageDead(_2); ++ _3 = copy _7; ++ nop; ++ _9 = copy _8; ++ _2 = copy (*_8); + _1 = copy _2; + nop; drop(_3) -> [return: bb2, unwind: bb3]; diff --git a/tests/mir-opt/const_prop/discriminant.main.GVN.32bit.diff b/tests/mir-opt/const_prop/discriminant.main.GVN.32bit.diff index 2543cf6257d43..57ef2724feb7a 100644 --- a/tests/mir-opt/const_prop/discriminant.main.GVN.32bit.diff +++ b/tests/mir-opt/const_prop/discriminant.main.GVN.32bit.diff @@ -15,7 +15,8 @@ bb0: { StorageLive(_1); - StorageLive(_2); +- StorageLive(_2); ++ nop; StorageLive(_3); - _3 = Option::::Some(const true); - _4 = discriminant(_3); @@ -41,8 +42,10 @@ } bb4: { - _1 = Add(move _2, const 0_i32); - StorageDead(_2); +- _1 = Add(move _2, const 0_i32); +- StorageDead(_2); ++ _1 = copy _2; ++ nop; StorageDead(_3); _0 = const (); StorageDead(_1); diff --git a/tests/mir-opt/const_prop/discriminant.main.GVN.64bit.diff b/tests/mir-opt/const_prop/discriminant.main.GVN.64bit.diff index 2543cf6257d43..57ef2724feb7a 100644 --- a/tests/mir-opt/const_prop/discriminant.main.GVN.64bit.diff +++ b/tests/mir-opt/const_prop/discriminant.main.GVN.64bit.diff @@ -15,7 +15,8 @@ bb0: { StorageLive(_1); - StorageLive(_2); +- StorageLive(_2); ++ nop; StorageLive(_3); - _3 = Option::::Some(const true); - _4 = discriminant(_3); @@ -41,8 +42,10 @@ } bb4: { - _1 = Add(move _2, const 0_i32); - StorageDead(_2); +- _1 = Add(move _2, const 0_i32); +- StorageDead(_2); ++ _1 = copy _2; ++ nop; StorageDead(_3); _0 = const (); StorageDead(_1); diff --git a/tests/mir-opt/const_prop/discriminant.rs b/tests/mir-opt/const_prop/discriminant.rs index aa169eb4e3699..e9c1e50794343 100644 --- a/tests/mir-opt/const_prop/discriminant.rs +++ b/tests/mir-opt/const_prop/discriminant.rs @@ -20,6 +20,6 @@ fn main() { // CHECK: [[tmp]] = const 10_i32; // CHECK: goto -> bb4; // CHECK: bb4: { - // CHECK: {{_.*}} = Add(move [[tmp]], const 0_i32); + // CHECK: {{_.*}} = copy [[tmp]]; let x = (if let Some(true) = Some(true) { 42 } else { 10 }) + 0; } diff --git a/tests/mir-opt/const_prop/mutable_variable.main.GVN.diff b/tests/mir-opt/const_prop/mutable_variable.main.GVN.diff index cc25b6caf90d9..009b71044bd44 100644 --- a/tests/mir-opt/const_prop/mutable_variable.main.GVN.diff +++ b/tests/mir-opt/const_prop/mutable_variable.main.GVN.diff @@ -17,7 +17,8 @@ _1 = const 42_i32; _1 = const 99_i32; StorageLive(_2); - _2 = copy _1; +- _2 = copy _1; ++ _2 = const 99_i32; _0 = const (); StorageDead(_2); StorageDead(_1); diff --git a/tests/mir-opt/const_prop/mutable_variable.rs b/tests/mir-opt/const_prop/mutable_variable.rs index 3aa1b1bcd2181..e86048e90b990 100644 --- a/tests/mir-opt/const_prop/mutable_variable.rs +++ b/tests/mir-opt/const_prop/mutable_variable.rs @@ -7,7 +7,7 @@ fn main() { // CHECK: debug y => [[y:_.*]]; // CHECK: [[x]] = const 42_i32; // CHECK: [[x]] = const 99_i32; - // CHECK: [[y]] = copy [[x]]; + // CHECK: [[y]] = const 99_i32; let mut x = 42; x = 99; let y = x; diff --git a/tests/mir-opt/const_prop/mutable_variable_no_prop.main.GVN.diff b/tests/mir-opt/const_prop/mutable_variable_no_prop.main.GVN.diff index 3f8dc12f4ae57..5feecdbeff29f 100644 --- a/tests/mir-opt/const_prop/mutable_variable_no_prop.main.GVN.diff +++ b/tests/mir-opt/const_prop/mutable_variable_no_prop.main.GVN.diff @@ -19,17 +19,21 @@ StorageLive(_1); _1 = const 42_u32; StorageLive(_2); - StorageLive(_3); +- StorageLive(_3); ++ nop; StorageLive(_4); _4 = const {ALLOC0: *mut u32}; _3 = copy (*_4); - _1 = move _3; - StorageDead(_3); +- _1 = move _3; +- StorageDead(_3); ++ _1 = copy _3; ++ nop; StorageDead(_4); _2 = const (); StorageDead(_2); StorageLive(_5); - _5 = copy _1; +- _5 = copy _1; ++ _5 = copy _3; _0 = const (); StorageDead(_5); StorageDead(_1); diff --git a/tests/mir-opt/const_prop/mutable_variable_no_prop.rs b/tests/mir-opt/const_prop/mutable_variable_no_prop.rs index 66af5bf1d5d40..8f3ba8ec846da 100644 --- a/tests/mir-opt/const_prop/mutable_variable_no_prop.rs +++ b/tests/mir-opt/const_prop/mutable_variable_no_prop.rs @@ -10,8 +10,8 @@ fn main() { // CHECK: debug y => [[y:_.*]]; // CHECK: [[x]] = const 42_u32; // CHECK: [[tmp:_.*]] = copy (*{{_.*}}); - // CHECK: [[x]] = move [[tmp]]; - // CHECK: [[y]] = copy [[x]]; + // CHECK: [[x]] = copy [[tmp]]; + // CHECK: [[y]] = copy [[tmp]]; let mut x = 42; unsafe { x = STATIC; diff --git a/tests/mir-opt/gvn.dereference_indexing.GVN.panic-abort.diff b/tests/mir-opt/gvn.dereference_indexing.GVN.panic-abort.diff index 9bdcc2f108a6a..1a07638cbafea 100644 --- a/tests/mir-opt/gvn.dereference_indexing.GVN.panic-abort.diff +++ b/tests/mir-opt/gvn.dereference_indexing.GVN.panic-abort.diff @@ -43,7 +43,8 @@ + nop; StorageLive(_8); StorageLive(_9); - _9 = copy (*_3); +- _9 = copy (*_3); ++ _9 = copy _1[_4]; _8 = opaque::(move _9) -> [return: bb2, unwind unreachable]; } diff --git a/tests/mir-opt/gvn.dereference_indexing.GVN.panic-unwind.diff b/tests/mir-opt/gvn.dereference_indexing.GVN.panic-unwind.diff index f38bc51adc480..6e67b66e783c4 100644 --- a/tests/mir-opt/gvn.dereference_indexing.GVN.panic-unwind.diff +++ b/tests/mir-opt/gvn.dereference_indexing.GVN.panic-unwind.diff @@ -43,7 +43,8 @@ + nop; StorageLive(_8); StorageLive(_9); - _9 = copy (*_3); +- _9 = copy (*_3); ++ _9 = copy _1[_4]; _8 = opaque::(move _9) -> [return: bb2, unwind continue]; } diff --git a/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff b/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff index f3f631956374d..3cce35d34e90d 100644 --- a/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff +++ b/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff @@ -8,10 +8,10 @@ let mut _3: fn(u8) -> u8; let _5: (); let mut _6: fn(u8) -> u8; - let mut _9: {closure@$DIR/gvn.rs:617:19: 617:21}; + let mut _9: {closure@$DIR/gvn.rs:620:19: 620:21}; let _10: (); let mut _11: fn(); - let mut _13: {closure@$DIR/gvn.rs:617:19: 617:21}; + let mut _13: {closure@$DIR/gvn.rs:620:19: 620:21}; let _14: (); let mut _15: fn(); scope 1 { @@ -19,7 +19,7 @@ let _4: fn(u8) -> u8; scope 2 { debug g => _4; - let _7: {closure@$DIR/gvn.rs:617:19: 617:21}; + let _7: {closure@$DIR/gvn.rs:620:19: 620:21}; scope 3 { debug closure => _7; let _8: fn(); @@ -62,16 +62,16 @@ StorageDead(_6); StorageDead(_5); - StorageLive(_7); -- _7 = {closure@$DIR/gvn.rs:617:19: 617:21}; +- _7 = {closure@$DIR/gvn.rs:620:19: 620:21}; - StorageLive(_8); + nop; -+ _7 = const ZeroSized: {closure@$DIR/gvn.rs:617:19: 617:21}; ++ _7 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21}; + nop; StorageLive(_9); - _9 = copy _7; - _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast)); -+ _9 = const ZeroSized: {closure@$DIR/gvn.rs:617:19: 617:21}; -+ _8 = const ZeroSized: {closure@$DIR/gvn.rs:617:19: 617:21} as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast)); ++ _9 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21}; ++ _8 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21} as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast)); StorageDead(_9); StorageLive(_10); StorageLive(_11); @@ -88,8 +88,8 @@ StorageLive(_13); - _13 = copy _7; - _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast)); -+ _13 = const ZeroSized: {closure@$DIR/gvn.rs:617:19: 617:21}; -+ _12 = const ZeroSized: {closure@$DIR/gvn.rs:617:19: 617:21} as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast)); ++ _13 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21}; ++ _12 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21} as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast)); StorageDead(_13); StorageLive(_14); StorageLive(_15); diff --git a/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff b/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff index 029e736a97952..d85aca040fe67 100644 --- a/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff +++ b/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff @@ -8,10 +8,10 @@ let mut _3: fn(u8) -> u8; let _5: (); let mut _6: fn(u8) -> u8; - let mut _9: {closure@$DIR/gvn.rs:617:19: 617:21}; + let mut _9: {closure@$DIR/gvn.rs:620:19: 620:21}; let _10: (); let mut _11: fn(); - let mut _13: {closure@$DIR/gvn.rs:617:19: 617:21}; + let mut _13: {closure@$DIR/gvn.rs:620:19: 620:21}; let _14: (); let mut _15: fn(); scope 1 { @@ -19,7 +19,7 @@ let _4: fn(u8) -> u8; scope 2 { debug g => _4; - let _7: {closure@$DIR/gvn.rs:617:19: 617:21}; + let _7: {closure@$DIR/gvn.rs:620:19: 620:21}; scope 3 { debug closure => _7; let _8: fn(); @@ -62,16 +62,16 @@ StorageDead(_6); StorageDead(_5); - StorageLive(_7); -- _7 = {closure@$DIR/gvn.rs:617:19: 617:21}; +- _7 = {closure@$DIR/gvn.rs:620:19: 620:21}; - StorageLive(_8); + nop; -+ _7 = const ZeroSized: {closure@$DIR/gvn.rs:617:19: 617:21}; ++ _7 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21}; + nop; StorageLive(_9); - _9 = copy _7; - _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast)); -+ _9 = const ZeroSized: {closure@$DIR/gvn.rs:617:19: 617:21}; -+ _8 = const ZeroSized: {closure@$DIR/gvn.rs:617:19: 617:21} as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast)); ++ _9 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21}; ++ _8 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21} as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast)); StorageDead(_9); StorageLive(_10); StorageLive(_11); @@ -88,8 +88,8 @@ StorageLive(_13); - _13 = copy _7; - _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast)); -+ _13 = const ZeroSized: {closure@$DIR/gvn.rs:617:19: 617:21}; -+ _12 = const ZeroSized: {closure@$DIR/gvn.rs:617:19: 617:21} as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast)); ++ _13 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21}; ++ _12 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21} as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast)); StorageDead(_13); StorageLive(_14); StorageLive(_15); diff --git a/tests/mir-opt/gvn.rs b/tests/mir-opt/gvn.rs index 98f94fbf0b146..eb60e996adfcd 100644 --- a/tests/mir-opt/gvn.rs +++ b/tests/mir-opt/gvn.rs @@ -99,12 +99,14 @@ fn subexpression_elimination(x: u64, y: u64, mut z: u64) { opaque((x * y) - y); opaque((x * y) - y); - // We cannot substitute through an immutable reference. + // We can substitute through an immutable reference. + // But we prefer using a SSA local rather than a borrowed one. // CHECK: [[ref:_.*]] = &_3; - // CHECK: [[deref:_.*]] = copy (*[[ref]]); + // CHECK: [[deref:_.*]] = copy _3; // CHECK: [[addref:_.*]] = Add(move [[deref]], copy _1); // CHECK: opaque::(move [[addref]]) - // CHECK: [[deref2:_.*]] = copy (*[[ref]]); + // But `_3` is not SSA so we cannot merge the values in two different blocks. + // CHECK: [[deref2:_.*]] = copy _3; // CHECK: [[addref2:_.*]] = Add(move [[deref2]], copy _1); // CHECK: opaque::(move [[addref2]]) let a = &z; @@ -141,13 +143,14 @@ fn subexpression_elimination(x: u64, y: u64, mut z: u64) { // We still cannot substitute again, and never with the earlier computations. // Important: `e` is not `a`! - // CHECK: [[ref2:_.*]] = &_3; - // CHECK: [[deref2:_.*]] = copy (*[[ref2]]); - // CHECK: [[addref2:_.*]] = Add(move [[deref2]], copy _1); - // CHECK: opaque::(move [[addref2]]) - // CHECK: [[deref3:_.*]] = copy (*[[ref2]]); + // CHECK: [[ref3:_.*]] = &_3; + // CHECK: [[deref3:_.*]] = copy _3; // CHECK: [[addref3:_.*]] = Add(move [[deref3]], copy _1); // CHECK: opaque::(move [[addref3]]) + // And `_3` is not SSA so we cannot merge the values in two different blocks. + // CHECK: [[deref4:_.*]] = copy _3; + // CHECK: [[addref4:_.*]] = Add(move [[deref4]], copy _1); + // CHECK: opaque::(move [[addref4]]) let e = &z; opaque(*e + x); opaque(*e + x); @@ -1065,8 +1068,8 @@ fn dereference_indexing(array: [u8; 2], index: usize) { &array[i] }; - // CHECK-NOT: [{{.*}}] - // CHECK: [[tmp:_.*]] = copy (*[[a]]); + // CHECK-NOT: StorageDead([[i]]); + // CHECK: [[tmp:_.*]] = copy _1[[[i]]]; // CHECK: opaque::(move [[tmp]]) opaque(*a); } diff --git a/tests/mir-opt/gvn.subexpression_elimination.GVN.panic-abort.diff b/tests/mir-opt/gvn.subexpression_elimination.GVN.panic-abort.diff index e872e011542b3..0a17eba07087b 100644 --- a/tests/mir-opt/gvn.subexpression_elimination.GVN.panic-abort.diff +++ b/tests/mir-opt/gvn.subexpression_elimination.GVN.panic-abort.diff @@ -760,7 +760,8 @@ StorageLive(_127); StorageLive(_128); StorageLive(_129); - _129 = copy (*_126); +- _129 = copy (*_126); ++ _129 = copy _3; StorageLive(_130); _130 = copy _1; - _128 = Add(move _129, move _130); @@ -776,7 +777,8 @@ StorageLive(_131); StorageLive(_132); StorageLive(_133); - _133 = copy (*_126); +- _133 = copy (*_126); ++ _133 = copy _3; StorageLive(_134); _134 = copy _1; - _132 = Add(move _133, move _134); @@ -901,7 +903,8 @@ StorageLive(_164); StorageLive(_165); StorageLive(_166); - _166 = copy (*_163); +- _166 = copy (*_163); ++ _166 = copy _3; StorageLive(_167); _167 = copy _1; - _165 = Add(move _166, move _167); @@ -917,7 +920,8 @@ StorageLive(_168); StorageLive(_169); StorageLive(_170); - _170 = copy (*_163); +- _170 = copy (*_163); ++ _170 = copy _3; StorageLive(_171); _171 = copy _1; - _169 = Add(move _170, move _171); diff --git a/tests/mir-opt/gvn.subexpression_elimination.GVN.panic-unwind.diff b/tests/mir-opt/gvn.subexpression_elimination.GVN.panic-unwind.diff index 3996dab27a343..d12a8aaca419d 100644 --- a/tests/mir-opt/gvn.subexpression_elimination.GVN.panic-unwind.diff +++ b/tests/mir-opt/gvn.subexpression_elimination.GVN.panic-unwind.diff @@ -760,7 +760,8 @@ StorageLive(_127); StorageLive(_128); StorageLive(_129); - _129 = copy (*_126); +- _129 = copy (*_126); ++ _129 = copy _3; StorageLive(_130); _130 = copy _1; - _128 = Add(move _129, move _130); @@ -776,7 +777,8 @@ StorageLive(_131); StorageLive(_132); StorageLive(_133); - _133 = copy (*_126); +- _133 = copy (*_126); ++ _133 = copy _3; StorageLive(_134); _134 = copy _1; - _132 = Add(move _133, move _134); @@ -901,7 +903,8 @@ StorageLive(_164); StorageLive(_165); StorageLive(_166); - _166 = copy (*_163); +- _166 = copy (*_163); ++ _166 = copy _3; StorageLive(_167); _167 = copy _1; - _165 = Add(move _166, move _167); @@ -917,7 +920,8 @@ StorageLive(_168); StorageLive(_169); StorageLive(_170); - _170 = copy (*_163); +- _170 = copy (*_163); ++ _170 = copy _3; StorageLive(_171); _171 = copy _1; - _169 = Add(move _170, move _171); diff --git a/tests/mir-opt/gvn_copy_aggregate.all_copy_use_changed.GVN.diff b/tests/mir-opt/gvn_copy_aggregate.all_copy_use_changed.GVN.diff index dc65cccb7bd6e..4368fa5b93d50 100644 --- a/tests/mir-opt/gvn_copy_aggregate.all_copy_use_changed.GVN.diff +++ b/tests/mir-opt/gvn_copy_aggregate.all_copy_use_changed.GVN.diff @@ -25,24 +25,28 @@ StorageLive(_2); _2 = copy ((*_1).0: i32); ((*_1).0: i32) = const 1_i32; - StorageLive(_3); +- StorageLive(_3); ++ nop; _3 = copy ((*_1).0: i32); - _2 = move _3; - StorageDead(_3); +- _2 = move _3; +- StorageDead(_3); - StorageLive(_4); ++ _2 = copy _3; ++ nop; + nop; _4 = copy ((*_1).1: u64); - StorageLive(_5); + nop; _5 = copy ((*_1).2: [i8; 3]); StorageLive(_6); - _6 = copy _2; +- _6 = copy _2; ++ _6 = copy _3; StorageLive(_7); _7 = copy _4; StorageLive(_8); _8 = copy _5; - _0 = AllCopy { a: move _6, b: move _7, c: move _8 }; -+ _0 = AllCopy { a: move _6, b: copy _4, c: copy _5 }; ++ _0 = AllCopy { a: copy _3, b: copy _4, c: copy _5 }; StorageDead(_8); StorageDead(_7); StorageDead(_6); diff --git a/tests/mir-opt/gvn_copy_aggregate.all_copy_use_changed_2.GVN.diff b/tests/mir-opt/gvn_copy_aggregate.all_copy_use_changed_2.GVN.diff index 08a4a078adcb4..4b7c2b7d7fc42 100644 --- a/tests/mir-opt/gvn_copy_aggregate.all_copy_use_changed_2.GVN.diff +++ b/tests/mir-opt/gvn_copy_aggregate.all_copy_use_changed_2.GVN.diff @@ -31,18 +31,22 @@ + nop; _4 = copy ((*_1).2: [i8; 3]); ((*_1).0: i32) = const 1_i32; - StorageLive(_5); +- StorageLive(_5); ++ nop; _5 = copy ((*_1).0: i32); - _2 = move _5; - StorageDead(_5); +- _2 = move _5; +- StorageDead(_5); ++ _2 = copy _5; ++ nop; StorageLive(_6); - _6 = copy _2; +- _6 = copy _2; ++ _6 = copy _5; StorageLive(_7); _7 = copy _3; StorageLive(_8); _8 = copy _4; - _0 = AllCopy { a: move _6, b: move _7, c: move _8 }; -+ _0 = AllCopy { a: move _6, b: copy _3, c: copy _4 }; ++ _0 = AllCopy { a: copy _5, b: copy _3, c: copy _4 }; StorageDead(_8); StorageDead(_7); StorageDead(_6); diff --git a/tests/mir-opt/gvn_copy_moves.fn0.GVN.diff b/tests/mir-opt/gvn_copy_moves.fn0.GVN.diff index c364da7a3cc68..c882f617f3836 100644 --- a/tests/mir-opt/gvn_copy_moves.fn0.GVN.diff +++ b/tests/mir-opt/gvn_copy_moves.fn0.GVN.diff @@ -17,7 +17,7 @@ _3 = (copy _2,); _4 = copy _3; - _5 = fn1(move (_3.0: [u128; 6]), copy _4) -> [return: bb1, unwind unreachable]; -+ _5 = fn1(copy (_3.0: [u128; 6]), copy _3) -> [return: bb1, unwind unreachable]; ++ _5 = fn1(copy _2, copy _3) -> [return: bb1, unwind unreachable]; } bb1: { diff --git a/tests/mir-opt/gvn_copy_moves.fn2.GVN.diff b/tests/mir-opt/gvn_copy_moves.fn2.GVN.diff new file mode 100644 index 0000000000000..37b471418fbb2 --- /dev/null +++ b/tests/mir-opt/gvn_copy_moves.fn2.GVN.diff @@ -0,0 +1,27 @@ +- // MIR for `fn2` before GVN ++ // MIR for `fn2` after GVN + + fn fn2() -> () { + let mut _0: (); + let mut _1: usize; + let mut _2: [u128; 6]; + let mut _3: ([u128; 6],); + let mut _4: ([u128; 6],); + let mut _5: (); + + bb0: { + _1 = const 1_usize; + _2 = [const 42_u128; 6]; + _3 = (copy _2,); +- _2[_1] = const 1_u128; ++ _2[1 of 2] = const 1_u128; + _4 = copy _3; +- _5 = fn1(move (_3.0: [u128; 6]), copy _4) -> [return: bb1, unwind unreachable]; ++ _5 = fn1(copy (_3.0: [u128; 6]), copy _3) -> [return: bb1, unwind unreachable]; + } + + bb1: { + return; + } + } + diff --git a/tests/mir-opt/gvn_copy_moves.rs b/tests/mir-opt/gvn_copy_moves.rs index b1fe2caf3a143..c72c1709f69c4 100644 --- a/tests/mir-opt/gvn_copy_moves.rs +++ b/tests/mir-opt/gvn_copy_moves.rs @@ -20,7 +20,7 @@ fn fn0() { // CHECK-NEXT: _2[1 of 2] = const 1_u128; // CHECK-NEXT: _3 = (copy _2,); // CHECK-NEXT: _4 = copy _3; - // CHECK-NEXT: _5 = fn1(copy (_3.0: [u128; 6]), copy _3) + // CHECK-NEXT: _5 = fn1(copy _2, copy _3) a = 1_usize; b = [42; 6]; b[a] = 1; @@ -39,8 +39,40 @@ fn fn1(a: [u128; 6], mut b: ([u128; 6],)) { b.0 = [0; 6]; } +// Like `fn0` but we assign to `b` after copying the value to `c`. +#[custom_mir(dialect = "runtime", phase = "initial")] +fn fn2() { + // CHECK-LABEL: fn fn2( + mir! { + let a: usize; + let b: [u128; 6]; + let c: ([u128; 6],); + let d: ([u128; 6],); + let x: (); + { + // CHECK: bb0: { + // CHECK-NEXT: _1 = const 1_usize; + // CHECK-NEXT: _2 = [const 42_u128; 6]; + // CHECK-NEXT: _3 = (copy _2,); + // CHECK-NEXT: _2[1 of 2] = const 1_u128; + // CHECK-NEXT: _4 = copy _3; + // CHECK-NEXT: _5 = fn1(copy (_3.0: [u128; 6]), copy _3) + a = 1_usize; + b = [42; 6]; + c = (b,); + b[a] = 1; + d = c; + Call(x = fn1(Move(c.0), d), ReturnTo(bb1), UnwindUnreachable()) + } + bb1 = { + Return() + } + } +} + fn main() { fn0(); } // EMIT_MIR gvn_copy_moves.fn0.GVN.diff +// EMIT_MIR gvn_copy_moves.fn2.GVN.diff diff --git a/tests/mir-opt/gvn_repeat.index_place.GVN.diff b/tests/mir-opt/gvn_repeat.index_place.GVN.diff new file mode 100644 index 0000000000000..1eb7e9015cc3f --- /dev/null +++ b/tests/mir-opt/gvn_repeat.index_place.GVN.diff @@ -0,0 +1,15 @@ +- // MIR for `index_place` before GVN ++ // MIR for `index_place` after GVN + + fn index_place(_1: usize, _2: usize, _3: [i32; 5]) -> i32 { + let mut _0: i32; + let mut _4: &i32; + + bb0: { + _4 = &_3[_1]; + _1 = copy _2; + _0 = copy (*_4); + return; + } + } + diff --git a/tests/mir-opt/gvn_repeat.repeat_place.GVN.diff b/tests/mir-opt/gvn_repeat.repeat_place.GVN.diff index e490925bc119e..4cb7d3d9aee43 100644 --- a/tests/mir-opt/gvn_repeat.repeat_place.GVN.diff +++ b/tests/mir-opt/gvn_repeat.repeat_place.GVN.diff @@ -10,7 +10,8 @@ _4 = [copy (*_3); 5]; _5 = &_4[_1]; _1 = copy _2; - _0 = copy (*_5); +- _0 = copy (*_5); ++ _0 = copy (*_3); return; } } diff --git a/tests/mir-opt/gvn_repeat.rs b/tests/mir-opt/gvn_repeat.rs index bbbb2a7ccbaf5..730378d825983 100644 --- a/tests/mir-opt/gvn_repeat.rs +++ b/tests/mir-opt/gvn_repeat.rs @@ -6,12 +6,28 @@ use std::intrinsics::mir::*; +// EMIT_MIR gvn_repeat.index_place.GVN.diff +#[custom_mir(dialect = "runtime")] +pub fn index_place(mut idx1: usize, idx2: usize, array: [i32; 5]) -> i32 { + // CHECK-LABEL: fn index_place( + // CHECK: let mut [[ELEM:.*]]: &i32; + // CHECK: _0 = copy (*[[ELEM]]) + mir! { + let elem; + { + elem = &array[idx1]; + idx1 = idx2; + RET = *elem; + Return() + } + } +} + // EMIT_MIR gvn_repeat.repeat_place.GVN.diff #[custom_mir(dialect = "runtime")] pub fn repeat_place(mut idx1: usize, idx2: usize, val: &i32) -> i32 { // CHECK-LABEL: fn repeat_place( - // CHECK: let mut [[ELEM:.*]]: &i32; - // CHECK: _0 = copy (*[[ELEM]]) + // CHECK: _0 = copy (*_3) mir! { let array; let elem; @@ -29,7 +45,7 @@ pub fn repeat_place(mut idx1: usize, idx2: usize, val: &i32) -> i32 { #[custom_mir(dialect = "runtime")] pub fn repeat_local(mut idx1: usize, idx2: usize, val: i32) -> i32 { // CHECK-LABEL: fn repeat_local( - // CHECK: _0 = copy _3 + // CHECK: _0 = copy _3; mir! { let array; let elem; @@ -44,6 +60,7 @@ pub fn repeat_local(mut idx1: usize, idx2: usize, val: i32) -> i32 { } fn main() { + assert_eq!(index_place(0, 5, [0; 5]), 0); assert_eq!(repeat_place(0, 5, &0), 0); assert_eq!(repeat_local(0, 5, 0), 0); } diff --git a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir index 72b39a7f6a87b..967232e79914b 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir @@ -180,8 +180,6 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } bb4: { - StorageLive(_32); - StorageLive(_29); StorageLive(_30); StorageLive(_27); StorageLive(_14); @@ -252,8 +250,6 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { bb10: { StorageDead(_27); StorageDead(_30); - StorageDead(_29); - StorageDead(_32); StorageDead(_11); StorageDead(_12); StorageDead(_13); @@ -285,8 +281,8 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { _28 = copy ((_27 as Some).0: &T); StorageDead(_27); _29 = copy _13; - _30 = AddWithOverflow(copy _13, const 1_usize); - assert(!move (_30.1: bool), "attempt to compute `{} + {}`, which would overflow", copy _13, const 1_usize) -> [success: bb14, unwind unreachable]; + _30 = AddWithOverflow(copy _29, const 1_usize); + assert(!move (_30.1: bool), "attempt to compute `{} + {}`, which would overflow", copy _29, const 1_usize) -> [success: bb14, unwind unreachable]; } bb14: { @@ -296,20 +292,18 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { _32 = Option::<(usize, &T)>::Some(move _31); StorageDead(_31); StorageDead(_30); - StorageDead(_29); _33 = copy (((_32 as Some).0: (usize, &T)).0: usize); _34 = copy (((_32 as Some).0: (usize, &T)).1: &T); StorageLive(_35); _35 = &_2; StorageLive(_36); - _36 = (copy _33, copy _34); + _36 = copy ((_32 as Some).0: (usize, &T)); _37 = >::call(move _35, move _36) -> [return: bb15, unwind unreachable]; } bb15: { StorageDead(_36); StorageDead(_35); - StorageDead(_32); goto -> bb4; } }