From 9d999bb035234f2d3eeff38853e262728f9031c6 Mon Sep 17 00:00:00 2001 From: dianqk Date: Mon, 24 Mar 2025 16:55:24 +0800 Subject: [PATCH 1/9] Do not use `for_each_assignment_mut` to iterate over assignment statements `for_each_assignment_mut` can skip assignment statements with side effects, which can result in some assignment statements retrieving outdated value. For example, it may skip a dereference assignment statement. --- compiler/rustc_mir_transform/src/gvn.rs | 77 +++++++++---------- compiler/rustc_mir_transform/src/ssa.rs | 38 --------- ..._simplification.hello.GVN.panic-abort.diff | 3 +- ...simplification.hello.GVN.panic-unwind.diff | 3 +- 4 files changed, 41 insertions(+), 80 deletions(-) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 0a54c780f31e5..2abb4e8b8ce10 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -3,14 +3,16 @@ //! MIR may contain repeated and/or redundant computations. The objective of this pass is to detect //! such redundancies and re-use the already-computed result when possible. //! -//! In a first pass, we compute a symbolic representation of values that are assigned to SSA -//! locals. This symbolic representation is defined by the `Value` enum. Each produced instance of -//! `Value` is interned as a `VnIndex`, which allows us to cheaply compute identical values. -//! //! From those assignments, we construct a mapping `VnIndex -> Vec<(Local, Location)>` of available //! values, the locals in which they are stored, and the assignment location. //! -//! In a second pass, we traverse all (non SSA) assignments `x = rvalue` and operands. For each +//! We traverse all assignments `x = rvalue` and operands. +//! +//! For each SSA one, we compute a symbolic representation of values that are assigned to SSA +//! locals. This symbolic representation is defined by the `Value` enum. Each produced instance of +//! `Value` is interned as a `VnIndex`, which allows us to cheaply compute identical values. +//! +//! For each non-SSA //! one, we compute the `VnIndex` of the rvalue. If this `VnIndex` is associated to a constant, we //! replace the rvalue/operand by that constant. Otherwise, if there is an SSA local `y` //! associated to this `VnIndex`, and if its definition location strictly dominates the assignment @@ -107,7 +109,7 @@ use rustc_span::def_id::DefId; use smallvec::SmallVec; use tracing::{debug, instrument, trace}; -use crate::ssa::{AssignedValue, SsaLocals}; +use crate::ssa::SsaLocals; pub(super) struct GVN; @@ -126,31 +128,11 @@ impl<'tcx> crate::MirPass<'tcx> for GVN { let dominators = body.basic_blocks.dominators().clone(); let mut state = VnState::new(tcx, body, typing_env, &ssa, dominators, &body.local_decls); - ssa.for_each_assignment_mut( - body.basic_blocks.as_mut_preserves_cfg(), - |local, value, location| { - let value = match value { - // We do not know anything of this assigned value. - AssignedValue::Arg | AssignedValue::Terminator => None, - // Try to get some insight. - AssignedValue::Rvalue(rvalue) => { - let value = state.simplify_rvalue(rvalue, location); - // FIXME(#112651) `rvalue` may have a subtype to `local`. We can only mark - // `local` as reusable if we have an exact type match. - if state.local_decls[local].ty != rvalue.ty(state.local_decls, tcx) { - return; - } - value - } - }; - // `next_opaque` is `Some`, so `new_opaque` must return `Some`. - let value = value.or_else(|| state.new_opaque()).unwrap(); - state.assign(local, value); - }, - ); - // Stop creating opaques during replacement as it is useless. - state.next_opaque = None; + for local in body.args_iter().filter(|&local| ssa.is_ssa(local)) { + let opaque = state.new_opaque().unwrap(); + state.assign(local, opaque); + } let reverse_postorder = body.basic_blocks.reverse_postorder().to_vec(); for bb in reverse_postorder { @@ -250,7 +232,6 @@ struct VnState<'body, 'tcx> { locals: IndexVec>, /// Locals that are assigned that value. // This vector does not hold all the values of `VnIndex` that we create. - // It stops at the largest value created in the first phase of collecting assignments. rev_locals: IndexVec>, values: FxIndexSet>, /// Values evaluated as constants if possible. @@ -345,6 +326,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { /// Record that `local` is assigned `value`. `local` must be SSA. #[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); // Only register the value if its type is `Sized`, as we will emit copies of it. @@ -1751,15 +1733,19 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> { if let StatementKind::Assign(box (ref mut lhs, ref mut rvalue)) = stmt.kind { self.simplify_place_projection(lhs, location); - // Do not try to simplify a constant, it's already in canonical shape. - if matches!(rvalue, Rvalue::Use(Operand::Constant(_))) { - return; - } - - let value = lhs - .as_local() - .and_then(|local| self.locals[local]) - .or_else(|| self.simplify_rvalue(rvalue, location)); + let value = self.simplify_rvalue(rvalue, location); + let value = if let Some(local) = lhs.as_local() + && self.ssa.is_ssa(local) + // FIXME(#112651) `rvalue` may have a subtype to `local`. We can only mark + // `local` as reusable if we have an exact type match. + && self.local_decls[local].ty == rvalue.ty(self.local_decls, self.tcx) + { + let value = value.or_else(|| self.new_opaque()).unwrap(); + self.assign(local, value); + Some(value) + } else { + value + }; let Some(value) = value else { return }; if let Some(const_) = self.try_as_constant(value) { @@ -1775,6 +1761,17 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> { } self.super_statement(stmt, location); } + + fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Location) { + if let Terminator { kind: TerminatorKind::Call { destination, .. }, .. } = terminator + && let Some(local) = destination.as_local() + && self.ssa.is_ssa(local) + { + let opaque = self.new_opaque().unwrap(); + self.assign(local, opaque); + } + self.super_terminator(terminator, location); + } } struct StorageRemover<'tcx> { diff --git a/compiler/rustc_mir_transform/src/ssa.rs b/compiler/rustc_mir_transform/src/ssa.rs index 3d512fb064ec4..edd0cabca49a4 100644 --- a/compiler/rustc_mir_transform/src/ssa.rs +++ b/compiler/rustc_mir_transform/src/ssa.rs @@ -32,12 +32,6 @@ pub(super) struct SsaLocals { borrowed_locals: DenseBitSet, } -pub(super) enum AssignedValue<'a, 'tcx> { - Arg, - Rvalue(&'a mut Rvalue<'tcx>), - Terminator, -} - impl SsaLocals { pub(super) fn new<'tcx>( tcx: TyCtxt<'tcx>, @@ -152,38 +146,6 @@ impl SsaLocals { }) } - pub(super) fn for_each_assignment_mut<'tcx>( - &self, - basic_blocks: &mut IndexSlice>, - mut f: impl FnMut(Local, AssignedValue<'_, 'tcx>, Location), - ) { - for &local in &self.assignment_order { - match self.assignments[local] { - Set1::One(DefLocation::Argument) => f( - local, - AssignedValue::Arg, - Location { block: START_BLOCK, statement_index: 0 }, - ), - Set1::One(DefLocation::Assignment(loc)) => { - let bb = &mut basic_blocks[loc.block]; - // `loc` must point to a direct assignment to `local`. - let stmt = &mut bb.statements[loc.statement_index]; - let StatementKind::Assign(box (target, ref mut rvalue)) = stmt.kind else { - bug!() - }; - assert_eq!(target.as_local(), Some(local)); - f(local, AssignedValue::Rvalue(rvalue), loc) - } - Set1::One(DefLocation::CallReturn { call, .. }) => { - let bb = &mut basic_blocks[call]; - let loc = Location { block: call, statement_index: bb.statements.len() }; - f(local, AssignedValue::Terminator, loc) - } - _ => {} - } - } - } - /// Compute the equivalence classes for locals, based on copy statements. /// /// The returned vector maps each local to the one it copies. In the following case: diff --git a/tests/mir-opt/const_prop/control_flow_simplification.hello.GVN.panic-abort.diff b/tests/mir-opt/const_prop/control_flow_simplification.hello.GVN.panic-abort.diff index 886f9a68dd9d1..417406de39b61 100644 --- a/tests/mir-opt/const_prop/control_flow_simplification.hello.GVN.panic-abort.diff +++ b/tests/mir-opt/const_prop/control_flow_simplification.hello.GVN.panic-abort.diff @@ -8,8 +8,9 @@ bb0: { StorageLive(_1); - _1 = const ::NEEDS; +- _1 = const ::NEEDS; - switchInt(move _1) -> [0: bb2, otherwise: bb1]; ++ _1 = const false; + switchInt(const false) -> [0: bb2, otherwise: bb1]; } diff --git a/tests/mir-opt/const_prop/control_flow_simplification.hello.GVN.panic-unwind.diff b/tests/mir-opt/const_prop/control_flow_simplification.hello.GVN.panic-unwind.diff index cc53b213397d8..63ba2c6865f0a 100644 --- a/tests/mir-opt/const_prop/control_flow_simplification.hello.GVN.panic-unwind.diff +++ b/tests/mir-opt/const_prop/control_flow_simplification.hello.GVN.panic-unwind.diff @@ -8,8 +8,9 @@ bb0: { StorageLive(_1); - _1 = const ::NEEDS; +- _1 = const ::NEEDS; - switchInt(move _1) -> [0: bb2, otherwise: bb1]; ++ _1 = const false; + switchInt(const false) -> [0: bb2, otherwise: bb1]; } From 84af55679131e5074b7236fbdd98b12e9012b94e Mon Sep 17 00:00:00 2001 From: dianqk Date: Mon, 24 Mar 2025 16:55:24 +0800 Subject: [PATCH 2/9] `next_opaque` is no longer an `Option` --- compiler/rustc_mir_transform/src/gvn.rs | 69 ++++++++++++------------- 1 file changed, 32 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 2abb4e8b8ce10..42d736cf5f494 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -130,7 +130,7 @@ impl<'tcx> crate::MirPass<'tcx> for GVN { let mut state = VnState::new(tcx, body, typing_env, &ssa, dominators, &body.local_decls); for local in body.args_iter().filter(|&local| ssa.is_ssa(local)) { - let opaque = state.new_opaque().unwrap(); + let opaque = state.new_opaque(); state.assign(local, opaque); } @@ -237,8 +237,7 @@ struct VnState<'body, 'tcx> { /// Values evaluated as constants if possible. evaluated: IndexVec>>, /// Counter to generate different values. - /// This is an option to stop creating opaques during replacement. - next_opaque: Option, + next_opaque: usize, /// Cache the value of the `unsized_locals` features, to avoid fetching it repeatedly in a loop. feature_unsized_locals: bool, ssa: &'body SsaLocals, @@ -270,7 +269,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { rev_locals: IndexVec::with_capacity(num_values), values: FxIndexSet::with_capacity_and_hasher(num_values, Default::default()), evaluated: IndexVec::with_capacity(num_values), - next_opaque: Some(1), + next_opaque: 1, feature_unsized_locals: tcx.features().unsized_locals(), ssa, dominators, @@ -291,32 +290,31 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let evaluated = self.eval_to_const(index); let _index = self.evaluated.push(evaluated); debug_assert_eq!(index, _index); - // No need to push to `rev_locals` if we finished listing assignments. - if self.next_opaque.is_some() { - let _index = self.rev_locals.push(SmallVec::new()); - debug_assert_eq!(index, _index); - } + let _index = self.rev_locals.push(SmallVec::new()); + debug_assert_eq!(index, _index); } index } + fn next_opaque(&mut self) -> usize { + let next_opaque = self.next_opaque; + self.next_opaque += 1; + next_opaque + } + /// Create a new `Value` for which we have no information at all, except that it is distinct /// from all the others. #[instrument(level = "trace", skip(self), ret)] - fn new_opaque(&mut self) -> Option { - let next_opaque = self.next_opaque.as_mut()?; - let value = Value::Opaque(*next_opaque); - *next_opaque += 1; - Some(self.insert(value)) + fn new_opaque(&mut self) -> VnIndex { + let value = Value::Opaque(self.next_opaque()); + self.insert(value) } /// 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) -> Option { - let next_opaque = self.next_opaque.as_mut()?; - let value = Value::Address { place, kind, provenance: *next_opaque }; - *next_opaque += 1; - Some(self.insert(value)) + fn new_pointer(&mut self, place: Place<'tcx>, kind: AddressKind) -> VnIndex { + let value = Value::Address { place, kind, provenance: self.next_opaque() }; + self.insert(value) } fn get(&self, index: VnIndex) -> &Value<'tcx> { @@ -337,21 +335,19 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } } - fn insert_constant(&mut self, value: Const<'tcx>) -> Option { + fn insert_constant(&mut self, value: Const<'tcx>) -> VnIndex { let disambiguator = if value.is_deterministic() { // The constant is deterministic, no need to disambiguate. 0 } else { // Multiple mentions of this constant will yield different values, // so assign a different `disambiguator` to ensure they do not get the same `VnIndex`. - let next_opaque = self.next_opaque.as_mut()?; - let disambiguator = *next_opaque; - *next_opaque += 1; + let disambiguator = self.next_opaque(); // `disambiguator: 0` means deterministic. debug_assert_ne!(disambiguator, 0); disambiguator }; - Some(self.insert(Value::Constant { value, disambiguator })) + self.insert(Value::Constant { value, disambiguator }) } fn insert_bool(&mut self, flag: bool) -> VnIndex { @@ -812,7 +808,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { location: Location, ) -> Option { match *operand { - Operand::Constant(ref constant) => self.insert_constant(constant.const_), + Operand::Constant(ref constant) => Some(self.insert_constant(constant.const_)), Operand::Copy(ref mut place) | Operand::Move(ref mut place) => { let value = self.simplify_place_value(place, location)?; if let Some(const_) = self.try_as_constant(value) { @@ -848,11 +844,11 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { Rvalue::Aggregate(..) => return self.simplify_aggregate(rvalue, location), Rvalue::Ref(_, borrow_kind, ref mut place) => { self.simplify_place_projection(place, location); - return self.new_pointer(*place, AddressKind::Ref(borrow_kind)); + return Some(self.new_pointer(*place, AddressKind::Ref(borrow_kind))); } Rvalue::RawPtr(mutbl, ref mut place) => { self.simplify_place_projection(place, location); - return self.new_pointer(*place, AddressKind::Address(mutbl)); + return Some(self.new_pointer(*place, AddressKind::Address(mutbl))); } Rvalue::WrapUnsafeBinder(ref mut op, ty) => { let value = self.simplify_operand(op, location)?; @@ -1016,7 +1012,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { if is_zst { let ty = rvalue.ty(self.local_decls, tcx); - return self.insert_constant(Const::zero_sized(ty)); + return Some(self.insert_constant(Const::zero_sized(ty))); } } @@ -1045,11 +1041,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } }; - let fields: Option> = field_ops + let mut fields: Vec<_> = field_ops .iter_mut() - .map(|op| self.simplify_operand(op, location).or_else(|| self.new_opaque())) + .map(|op| self.simplify_operand(op, location).unwrap_or_else(|| self.new_opaque())) .collect(); - let mut fields = fields?; if let AggregateTy::RawPtr { data_pointer_ty, output_pointer_ty } = &mut ty { let mut was_updated = false; @@ -1177,7 +1172,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { ) if let ty::Slice(..) = to.builtin_deref(true).unwrap().kind() && let ty::Array(_, len) = from.builtin_deref(true).unwrap().kind() => { - return self.insert_constant(Const::Ty(self.tcx.types.usize, *len)); + return Some(self.insert_constant(Const::Ty(self.tcx.types.usize, *len))); } _ => Value::UnaryOp(op, arg_index), }; @@ -1373,7 +1368,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { if let CastKind::PointerCoercion(ReifyFnPointer | ClosureFnPointer(_), _) = kind { // Each reification of a generic fn may get a different pointer. // Do not try to merge them. - return self.new_opaque(); + return Some(self.new_opaque()); } let mut was_ever_updated = false; @@ -1489,7 +1484,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { // Trivial case: we are fetching a statically known length. let place_ty = place.ty(self.local_decls, self.tcx).ty; if let ty::Array(_, len) = place_ty.kind() { - return self.insert_constant(Const::Ty(self.tcx.types.usize, *len)); + return Some(self.insert_constant(Const::Ty(self.tcx.types.usize, *len))); } let mut inner = self.simplify_place_value(place, location)?; @@ -1511,7 +1506,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { && let Some(to) = to.builtin_deref(true) && let ty::Slice(..) = to.kind() { - return self.insert_constant(Const::Ty(self.tcx.types.usize, *len)); + return Some(self.insert_constant(Const::Ty(self.tcx.types.usize, *len))); } // Fallback: a symbolic `Len`. @@ -1740,7 +1735,7 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> { // `local` as reusable if we have an exact type match. && self.local_decls[local].ty == rvalue.ty(self.local_decls, self.tcx) { - let value = value.or_else(|| self.new_opaque()).unwrap(); + let value = value.unwrap_or_else(|| self.new_opaque()); self.assign(local, value); Some(value) } else { @@ -1767,7 +1762,7 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> { && let Some(local) = destination.as_local() && self.ssa.is_ssa(local) { - let opaque = self.new_opaque().unwrap(); + let opaque = self.new_opaque(); self.assign(local, opaque); } self.super_terminator(terminator, location); From 7830406df1232c59f82d870c218901b8643701bb Mon Sep 17 00:00:00 2001 From: dianqk Date: Mon, 24 Mar 2025 16:55:24 +0800 Subject: [PATCH 3/9] Invalidate all dereferences for non-local assignments --- compiler/rustc_data_structures/src/fx.rs | 2 + compiler/rustc_mir_transform/src/gvn.rs | 38 +++++++++++++++---- ..._aggregate_to_copy_miscompile.foo.GVN.diff | 8 ++-- 3 files changed, 35 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_data_structures/src/fx.rs b/compiler/rustc_data_structures/src/fx.rs index 80e72250470c0..f0db9623b674e 100644 --- a/compiler/rustc_data_structures/src/fx.rs +++ b/compiler/rustc_data_structures/src/fx.rs @@ -9,6 +9,8 @@ pub type FxIndexSet = indexmap::IndexSet>; pub type IndexEntry<'a, K, V> = indexmap::map::Entry<'a, K, V>; pub type IndexOccupiedEntry<'a, K, V> = indexmap::map::OccupiedEntry<'a, K, V>; +pub use indexmap::set::MutableValues; + #[macro_export] macro_rules! define_id_collections { ($map_name:ident, $set_name:ident, $entry_name:ident, $key:ty) => { diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 42d736cf5f494..944c21eab407d 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -93,7 +93,7 @@ use rustc_const_eval::interpret::{ ImmTy, Immediate, InterpCx, MemPlaceMeta, MemoryKind, OpTy, Projectable, Scalar, intern_const_alloc_for_constprop, }; -use rustc_data_structures::fx::FxIndexSet; +use rustc_data_structures::fx::{FxIndexSet, MutableValues}; use rustc_data_structures::graph::dominators::Dominators; use rustc_hir::def::DefKind; use rustc_index::bit_set::DenseBitSet; @@ -238,6 +238,8 @@ struct VnState<'body, 'tcx> { evaluated: IndexVec>>, /// Counter to generate different values. next_opaque: usize, + /// Cache the deref values. + derefs: Vec, /// Cache the value of the `unsized_locals` features, to avoid fetching it repeatedly in a loop. feature_unsized_locals: bool, ssa: &'body SsaLocals, @@ -270,6 +272,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { values: FxIndexSet::with_capacity_and_hasher(num_values, Default::default()), evaluated: IndexVec::with_capacity(num_values), next_opaque: 1, + derefs: Vec::new(), feature_unsized_locals: tcx.features().unsized_locals(), ssa, dominators, @@ -368,6 +371,19 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { self.insert(Value::Aggregate(AggregateTy::Tuple, VariantIdx::ZERO, values)) } + fn insert_deref(&mut self, value: VnIndex) -> VnIndex { + let value = self.insert(Value::Projection(value, ProjectionElem::Deref)); + self.derefs.push(value); + value + } + + fn invalidate_derefs(&mut self) { + for deref in std::mem::take(&mut self.derefs) { + let opaque = self.next_opaque(); + *self.values.get_index_mut2(deref.index()).unwrap() = Value::Opaque(opaque); + } + } + #[instrument(level = "trace", skip(self), ret)] fn eval_to_const(&mut self, value: VnIndex) -> Option> { use Value::*; @@ -634,7 +650,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { { // An immutable borrow `_x` always points to the same value for the // lifetime of the borrow, so we can merge all instances of `*_x`. - ProjectionElem::Deref + return Some(self.insert_deref(value)); } else { return None; } @@ -1739,6 +1755,8 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> { self.assign(local, value); Some(value) } else { + // Non-local assignments maybe invalidate deref. + self.invalidate_derefs(); value }; let Some(value) = value else { return }; @@ -1758,12 +1776,16 @@ 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 - && let Some(local) = destination.as_local() - && self.ssa.is_ssa(local) - { - let opaque = self.new_opaque(); - self.assign(local, opaque); + if let Terminator { kind: TerminatorKind::Call { destination, .. }, .. } = terminator { + if let Some(local) = destination.as_local() + && self.ssa.is_ssa(local) + { + let opaque = self.new_opaque(); + self.assign(local, opaque); + } + // Function calls maybe invalidate nested deref, and non-local assignments maybe invalidate deref. + // Currently, no distinction is made between these two cases. + self.invalidate_derefs(); } self.super_terminator(terminator, location); } diff --git a/tests/mir-opt/simplify_aggregate_to_copy_miscompile.foo.GVN.diff b/tests/mir-opt/simplify_aggregate_to_copy_miscompile.foo.GVN.diff index 22d4277ee4515..2efc4ef56044a 100644 --- a/tests/mir-opt/simplify_aggregate_to_copy_miscompile.foo.GVN.diff +++ b/tests/mir-opt/simplify_aggregate_to_copy_miscompile.foo.GVN.diff @@ -19,8 +19,7 @@ } bb0: { -- StorageLive(_2); -+ nop; + StorageLive(_2); StorageLive(_3); StorageLive(_4); _4 = &_1; @@ -50,13 +49,12 @@ StorageLive(_9); _9 = copy _6; - _0 = Option::::Some(move _9); -+ _0 = copy (*_2); ++ _0 = Option::::Some(copy _6); StorageDead(_9); - StorageDead(_6); + nop; StorageDead(_4); -- StorageDead(_2); -+ nop; + StorageDead(_2); return; } From 7e0463fe93b7fec40e564fb1312296ed608ce837 Mon Sep 17 00:00:00 2001 From: dianqk Date: Mon, 24 Mar 2025 16:55:24 +0800 Subject: [PATCH 4/9] Revert "comment out the old tests instead of adjusting them" This reverts commit 906f66fb4c22daa8a6f97e5c048e9f6ab3fd9051. --- tests/coverage/closure.cov-map | 18 +++++------ .../const_prop/read_immutable_static.rs | 3 +- tests/mir-opt/const_prop/ref_deref_project.rs | 3 +- tests/mir-opt/const_prop/slice_len.rs | 5 ++- .../gvn.fn_pointers.GVN.panic-abort.diff | 18 +++++------ .../gvn.fn_pointers.GVN.panic-unwind.diff | 18 +++++------ tests/mir-opt/gvn.rs | 31 +++++++++++-------- .../pre-codegen/deref_nested_borrows.rs | 1 - 8 files changed, 48 insertions(+), 49 deletions(-) diff --git a/tests/coverage/closure.cov-map b/tests/coverage/closure.cov-map index 2d784ba09b60a..640f98956840d 100644 --- a/tests/coverage/closure.cov-map +++ b/tests/coverage/closure.cov-map @@ -140,19 +140,17 @@ Number of file 0 mappings: 6 - Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10) Highest counter ID seen: c1 -Function name: closure::main::{closure#18} -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 19, 0d, 02, 1c, 05, 02, 1d, 02, 12, 02, 02, 11, 00, 12, 01, 01, 11, 01, 0e] +Function name: closure::main::{closure#18} (unused) +Raw bytes (24): 0x[01, 01, 00, 04, 00, 19, 0d, 02, 1c, 00, 02, 1d, 02, 12, 00, 02, 11, 00, 12, 00, 01, 11, 01, 0e] Number of files: 1 - file 0 => global file 1 -Number of expressions: 1 -- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +Number of expressions: 0 Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 25, 13) to (start + 2, 28) -- Code(Counter(1)) at (prev + 2, 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 + 1, 14) -Highest counter ID seen: c1 +- Code(Zero) at (prev + 25, 13) to (start + 2, 28) +- Code(Zero) at (prev + 2, 29) to (start + 2, 18) +- Code(Zero) at (prev + 2, 17) to (start + 0, 18) +- Code(Zero) at (prev + 1, 17) to (start + 1, 14) +Highest counter ID seen: (none) Function name: closure::main::{closure#19} Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 43, 0d, 02, 1c, 05, 02, 1d, 02, 12, 02, 02, 11, 00, 12, 01, 01, 11, 01, 0e] diff --git a/tests/mir-opt/const_prop/read_immutable_static.rs b/tests/mir-opt/const_prop/read_immutable_static.rs index 98ba76fb7655a..f88e4b3de939f 100644 --- a/tests/mir-opt/const_prop/read_immutable_static.rs +++ b/tests/mir-opt/const_prop/read_immutable_static.rs @@ -6,7 +6,6 @@ static FOO: u8 = 2; fn main() { // CHECK-LABEL: fn main( // CHECK: debug x => [[x:_.*]]; - // Disabled due to - // COM: CHECK: [[x]] = const 4_u8; + // CHECK-NOT: [[x]] = const 4_u8; let x = FOO + FOO; } diff --git a/tests/mir-opt/const_prop/ref_deref_project.rs b/tests/mir-opt/const_prop/ref_deref_project.rs index 31108e1a57f51..813b4ae47455c 100644 --- a/tests/mir-opt/const_prop/ref_deref_project.rs +++ b/tests/mir-opt/const_prop/ref_deref_project.rs @@ -5,7 +5,6 @@ fn main() { // CHECK-LABEL: fn main( // CHECK: debug a => [[a:_.*]]; - // Disabled due to - // COM: CHECK: [[a]] = const 5_i32; + // CHECK-NOT: [[a]] = const 5_i32; let a = *(&(4, 5).1); } diff --git a/tests/mir-opt/const_prop/slice_len.rs b/tests/mir-opt/const_prop/slice_len.rs index 498e09fbb65c3..eb86e28408a34 100644 --- a/tests/mir-opt/const_prop/slice_len.rs +++ b/tests/mir-opt/const_prop/slice_len.rs @@ -8,8 +8,7 @@ fn main() { // CHECK-LABEL: fn main( // CHECK: debug a => [[a:_.*]]; // CHECK: [[slice:_.*]] = copy {{.*}} as &[u32] (PointerCoercion(Unsize, AsCast)); - // Disabled due to - // COM: CHECK: assert(const true, - // COM: CHECK: [[a]] = const 2_u32; + // CHECK-NOT: assert(const true, + // CHECK-NOT: [[a]] = const 2_u32; let a = (&[1u32, 2, 3] as &[u32])[1]; } 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 7f99b83d937dd..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:615:19: 615: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:615:19: 615: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:615:19: 615: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:615:19: 615:21}; +- _7 = {closure@$DIR/gvn.rs:620:19: 620:21}; - StorageLive(_8); + nop; -+ _7 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615: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:615:19: 615:21}; -+ _8 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615: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:615:19: 615:21}; -+ _12 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615: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 06dd0502f30f2..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:615:19: 615: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:615:19: 615: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:615:19: 615: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:615:19: 615:21}; +- _7 = {closure@$DIR/gvn.rs:620:19: 620:21}; - StorageLive(_8); + nop; -+ _7 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615: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:615:19: 615:21}; -+ _8 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615: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:615:19: 615:21}; -+ _12 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615: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 c895a5792595e..be97470ebb17e 100644 --- a/tests/mir-opt/gvn.rs +++ b/tests/mir-opt/gvn.rs @@ -100,17 +100,18 @@ fn subexpression_elimination(x: u64, y: u64, mut z: u64) { opaque((x * y) - y); // We cannot substitute through an immutable reference. - // (Disabled due to ) // CHECK: [[ref:_.*]] = &_3; // CHECK: [[deref:_.*]] = copy (*[[ref]]); - // COM: CHECK: [[addref:_.*]] = Add(copy [[deref]], copy _1); - // COM: CHECK: opaque::(copy [[addref]]) - // COM: CHECK: opaque::(copy [[addref]]) + // CHECK: [[addref:_.*]] = Add(move [[deref]], copy _1); + // CHECK: opaque::(move [[addref]]) + // CHECK: [[deref2:_.*]] = copy (*[[ref]]); + // CHECK: [[addref2:_.*]] = Add(move [[deref2]], copy _1); + // CHECK: opaque::(move [[addref2]]) let a = &z; opaque(*a + x); opaque(*a + x); - // And certainly not through a mutable reference or a pointer. + // But not through a mutable reference or a pointer. // CHECK: [[mut:_.*]] = &mut _3; // CHECK: [[addmut:_.*]] = Add( // CHECK: opaque::(move [[addmut]]) @@ -142,9 +143,11 @@ fn subexpression_elimination(x: u64, y: u64, mut z: u64) { // Important: `e` is not `a`! // CHECK: [[ref2:_.*]] = &_3; // CHECK: [[deref2:_.*]] = copy (*[[ref2]]); - // COM: CHECK: [[addref2:_.*]] = Add(copy [[deref2]], copy _1); - // COM: CHECK: opaque::(copy [[addref2]]) - // COM: CHECK: opaque::(copy [[addref2]]) + // CHECK: [[addref2:_.*]] = Add(move [[deref2]], copy _1); + // CHECK: opaque::(move [[addref2]]) + // CHECK: [[deref3:_.*]] = copy (*[[ref2]]); + // CHECK: [[addref3:_.*]] = Add(move [[deref3]], copy _1); + // CHECK: opaque::(move [[addref3]]) let e = &z; opaque(*e + x); opaque(*e + x); @@ -499,8 +502,9 @@ fn dereferences(t: &mut u32, u: &impl Copy, s: &S) { // Do not reuse dereferences of `&Freeze`. // CHECK: [[ref:_.*]] = &(*_1); // CHECK: [[st7:_.*]] = copy (*[[ref]]); - // COM: CHECK: opaque::(copy [[st7]]) - // COM: CHECK: opaque::(copy [[st7]]) + // CHECK: opaque::(move [[st7]]) + // CHECK: [[st8:_.*]] = copy (*[[ref]]); + // CHECK: opaque::(move [[st8]]) let z = &*t; opaque(*z); opaque(*z); @@ -519,8 +523,9 @@ fn dereferences(t: &mut u32, u: &impl Copy, s: &S) { // `*s` is not Copy, but `(*s).0` is, but we still cannot reuse. // CHECK: [[st10:_.*]] = copy ((*_3).0: u32); - // COM: CHECK: opaque::(copy [[st10]]) - // COM: CHECK: opaque::(copy [[st10]]) + // CHECK: opaque::(move [[st10]]) + // CHECK: [[st11:_.*]] = copy ((*_3).0: u32); + // CHECK: opaque::(move [[st11]]) opaque(s.0); opaque(s.0); } @@ -737,7 +742,7 @@ fn borrowed(x: T) { // CHECK: bb1: { // CHECK-NEXT: _0 = opaque::(copy _1) // CHECK: bb2: { - // COM: CHECK-NEXT: _0 = opaque::(copy _1) + // CHECK-NEXT: _0 = opaque::(copy (*_3)) mir! { { let a = x; diff --git a/tests/mir-opt/pre-codegen/deref_nested_borrows.rs b/tests/mir-opt/pre-codegen/deref_nested_borrows.rs index 4f70ec36bc925..738cd981ae674 100644 --- a/tests/mir-opt/pre-codegen/deref_nested_borrows.rs +++ b/tests/mir-opt/pre-codegen/deref_nested_borrows.rs @@ -1,4 +1,3 @@ -//! Regression test for // EMIT_MIR_FOR_EACH_PANIC_STRATEGY fn src(x: &&u8) -> bool { From fefb0dba824d7a98bbceba63e434279ff7377a45 Mon Sep 17 00:00:00 2001 From: dianqk Date: Mon, 24 Mar 2025 16:55:24 +0800 Subject: [PATCH 5/9] Partially revert "Do not unify dereferences in GVN." This reverts commit 917dd826286bd85e26310e4db4a125d4038c277e. --- compiler/rustc_mir_transform/src/gvn.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 944c21eab407d..a93fdff5817c4 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -642,9 +642,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let proj = match proj { ProjectionElem::Deref => { let ty = place.ty(self.local_decls, self.tcx).ty; - // unsound: https://github.com/rust-lang/rust/issues/130853 - if self.tcx.sess.opts.unstable_opts.unsound_mir_opts - && let Some(Mutability::Not) = ty.ref_mutability() + if let Some(Mutability::Not) = ty.ref_mutability() && let Some(pointee_ty) = ty.builtin_deref(true) && pointee_ty.is_freeze(self.tcx, self.typing_env()) { From 1787789fe5b1eb9f37e72abaff933cd38f68e813 Mon Sep 17 00:00:00 2001 From: dianqk Date: Mon, 24 Mar 2025 16:55:24 +0800 Subject: [PATCH 6/9] Bless tests --- tests/coverage/closure.cov-map | 18 +- tests/coverage/issue-84561.cov-map | 163 +++++------- .../read_immutable_static.main.GVN.diff | 14 +- .../const_prop/read_immutable_static.rs | 2 +- .../const_prop/ref_deref.main.GVN.diff | 3 +- .../ref_deref_project.main.GVN.diff | 3 +- tests/mir-opt/const_prop/ref_deref_project.rs | 2 +- .../slice_len.main.GVN.32bit.panic-abort.diff | 2 +- ...slice_len.main.GVN.32bit.panic-unwind.diff | 2 +- .../slice_len.main.GVN.64bit.panic-abort.diff | 2 +- ...slice_len.main.GVN.64bit.panic-unwind.diff | 2 +- tests/mir-opt/const_prop/slice_len.rs | 4 +- .../mir-opt/gvn.borrowed.GVN.panic-abort.diff | 3 +- .../gvn.borrowed.GVN.panic-unwind.diff | 3 +- tests/mir-opt/gvn.rs | 2 +- tests/mir-opt/gvn.slices.GVN.panic-abort.diff | 38 +-- .../mir-opt/gvn.slices.GVN.panic-unwind.diff | 38 +-- .../gvn_uninhabited.f.GVN.panic-abort.diff | 15 +- .../gvn_uninhabited.f.GVN.panic-unwind.diff | 15 +- ...variant_a-{closure#0}.PreCodegen.after.mir | 238 ++++++++---------- ...variant_b-{closure#0}.PreCodegen.after.mir | 54 ++-- 21 files changed, 301 insertions(+), 322 deletions(-) diff --git a/tests/coverage/closure.cov-map b/tests/coverage/closure.cov-map index 640f98956840d..2d784ba09b60a 100644 --- a/tests/coverage/closure.cov-map +++ b/tests/coverage/closure.cov-map @@ -140,17 +140,19 @@ Number of file 0 mappings: 6 - Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10) Highest counter ID seen: c1 -Function name: closure::main::{closure#18} (unused) -Raw bytes (24): 0x[01, 01, 00, 04, 00, 19, 0d, 02, 1c, 00, 02, 1d, 02, 12, 00, 02, 11, 00, 12, 00, 01, 11, 01, 0e] +Function name: closure::main::{closure#18} +Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 19, 0d, 02, 1c, 05, 02, 1d, 02, 12, 02, 02, 11, 00, 12, 01, 01, 11, 01, 0e] Number of files: 1 - file 0 => global file 1 -Number of expressions: 0 +Number of expressions: 1 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 -- Code(Zero) at (prev + 25, 13) to (start + 2, 28) -- Code(Zero) at (prev + 2, 29) to (start + 2, 18) -- Code(Zero) at (prev + 2, 17) to (start + 0, 18) -- Code(Zero) at (prev + 1, 17) to (start + 1, 14) -Highest counter ID seen: (none) +- Code(Counter(0)) at (prev + 25, 13) to (start + 2, 28) +- Code(Counter(1)) at (prev + 2, 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 + 1, 14) +Highest counter ID seen: c1 Function name: closure::main::{closure#19} Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 43, 0d, 02, 1c, 05, 02, 1d, 02, 12, 02, 02, 11, 00, 12, 01, 01, 11, 01, 0e] diff --git a/tests/coverage/issue-84561.cov-map b/tests/coverage/issue-84561.cov-map index 3bd4e7d2a3666..47e2922a805ac 100644 --- a/tests/coverage/issue-84561.cov-map +++ b/tests/coverage/issue-84561.cov-map @@ -59,109 +59,80 @@ Number of file 0 mappings: 1 Highest counter ID seen: c0 Function name: issue_84561::test3 -Raw bytes (315): 0x[01, 01, 1b, 1d, 21, 25, 29, 21, 25, 2d, 31, 21, 17, 25, 2d, 41, 45, 49, 4d, 51, 55, 33, 51, 49, 4d, 33, 37, 49, 4d, 51, 59, 55, 59, 55, 59, 47, 5d, 55, 59, 61, 65, 71, 75, 69, 6d, 69, 6d, 69, 6d, 63, 79, 71, 75, 79, 7d, 7d, 81, 01, 33, 01, 08, 01, 03, 0f, 05, 04, 09, 01, 0f, 09, 02, 05, 04, 0f, 0d, 05, 05, 00, 0f, 11, 01, 05, 00, 0f, 15, 01, 09, 01, 0f, 19, 02, 05, 00, 0f, 1d, 01, 05, 00, 0f, 02, 00, 20, 00, 30, 21, 01, 05, 03, 0f, 25, 03, 20, 00, 30, 29, 00, 33, 00, 41, 06, 00, 4b, 00, 5a, 0a, 01, 05, 00, 0f, 2d, 05, 09, 03, 10, 31, 05, 0d, 00, 1b, 0e, 02, 0d, 00, 1c, 12, 04, 09, 02, 0f, 35, 06, 05, 00, 0f, 39, 04, 05, 00, 0f, 3d, 04, 09, 01, 0f, 41, 05, 08, 00, 0f, 45, 01, 09, 00, 13, 1a, 05, 09, 00, 13, 33, 05, 08, 00, 0f, 51, 01, 09, 00, 13, 22, 03, 0d, 00, 1d, 26, 03, 09, 00, 13, 2e, 03, 0d, 00, 1d, 47, 03, 05, 00, 0f, 47, 01, 0c, 00, 13, 5d, 01, 0d, 00, 13, 42, 02, 0d, 00, 13, 61, 04, 05, 02, 13, 65, 03, 0d, 00, 13, 4a, 02, 0d, 00, 13, 63, 03, 05, 00, 0f, 69, 01, 0c, 00, 13, 6d, 01, 0d, 00, 17, 71, 04, 0d, 00, 13, 5a, 02, 0d, 00, 17, 5a, 01, 14, 00, 1b, 00, 01, 15, 00, 1b, 5a, 02, 15, 00, 1b, 75, 04, 0d, 00, 13, 5e, 03, 09, 00, 19, 79, 02, 05, 00, 0f, 66, 03, 09, 00, 22, 7d, 02, 05, 00, 0f, 6a, 03, 09, 00, 2c, 81, 01, 02, 01, 00, 02] +Raw bytes (279): 0x[01, 01, 0a, 0d, 11, 0d, 15, 0d, 19, 1d, 21, 29, 2d, 25, 29, 25, 29, 25, 29, 27, 31, 29, 2d, 33, 01, 08, 01, 03, 0f, 05, 04, 09, 01, 0f, 09, 02, 05, 04, 0f, 09, 05, 05, 00, 0f, 09, 01, 05, 00, 0f, 09, 01, 09, 01, 0f, 0d, 02, 05, 00, 0f, 0d, 01, 05, 00, 0f, 00, 00, 20, 00, 30, 0d, 01, 05, 03, 0f, 00, 03, 20, 00, 30, 00, 00, 33, 00, 41, 00, 00, 4b, 00, 5a, 0d, 01, 05, 00, 0f, 00, 05, 09, 03, 10, 00, 05, 0d, 00, 1b, 00, 02, 0d, 00, 1c, 0d, 04, 09, 02, 0f, 0d, 06, 05, 00, 0f, 0d, 04, 05, 00, 0f, 0d, 04, 09, 01, 0f, 0d, 05, 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, 02, 13, 21, 03, 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] Number of files: 1 - file 0 => global file 1 -Number of expressions: 27 -- expression 0 operands: lhs = Counter(7), rhs = Counter(8) -- expression 1 operands: lhs = Counter(9), rhs = Counter(10) -- expression 2 operands: lhs = Counter(8), rhs = Counter(9) -- expression 3 operands: lhs = Counter(11), rhs = Counter(12) -- expression 4 operands: lhs = Counter(8), rhs = Expression(5, Add) -- expression 5 operands: lhs = Counter(9), rhs = Counter(11) -- expression 6 operands: lhs = Counter(16), rhs = Counter(17) -- expression 7 operands: lhs = Counter(18), rhs = Counter(19) -- expression 8 operands: lhs = Counter(20), rhs = Counter(21) -- expression 9 operands: lhs = Expression(12, Add), rhs = Counter(20) -- expression 10 operands: lhs = Counter(18), rhs = Counter(19) -- expression 11 operands: lhs = Expression(12, Add), rhs = Expression(13, Add) -- expression 12 operands: lhs = Counter(18), rhs = Counter(19) -- expression 13 operands: lhs = Counter(20), rhs = Counter(22) -- expression 14 operands: lhs = Counter(21), rhs = Counter(22) -- expression 15 operands: lhs = Counter(21), rhs = Counter(22) -- expression 16 operands: lhs = Expression(17, Add), rhs = Counter(23) -- expression 17 operands: lhs = Counter(21), rhs = Counter(22) -- expression 18 operands: lhs = Counter(24), rhs = Counter(25) -- expression 19 operands: lhs = Counter(28), rhs = Counter(29) -- expression 20 operands: lhs = Counter(26), rhs = Counter(27) -- expression 21 operands: lhs = Counter(26), rhs = Counter(27) -- expression 22 operands: lhs = Counter(26), rhs = Counter(27) -- expression 23 operands: lhs = Expression(24, Add), rhs = Counter(30) -- expression 24 operands: lhs = Counter(28), rhs = Counter(29) -- expression 25 operands: lhs = Counter(30), rhs = Counter(31) -- expression 26 operands: lhs = Counter(31), rhs = Counter(32) +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) Number of file 0 mappings: 51 - Code(Counter(0)) at (prev + 8, 1) to (start + 3, 15) - Code(Counter(1)) at (prev + 4, 9) to (start + 1, 15) - Code(Counter(2)) at (prev + 2, 5) to (start + 4, 15) -- Code(Counter(3)) at (prev + 5, 5) to (start + 0, 15) -- Code(Counter(4)) at (prev + 1, 5) to (start + 0, 15) -- Code(Counter(5)) at (prev + 1, 9) to (start + 1, 15) -- Code(Counter(6)) at (prev + 2, 5) to (start + 0, 15) -- Code(Counter(7)) at (prev + 1, 5) to (start + 0, 15) -- Code(Expression(0, Sub)) at (prev + 0, 32) to (start + 0, 48) +- Code(Counter(2)) at (prev + 5, 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 + 1, 15) +- Code(Counter(3)) at (prev + 2, 5) to (start + 0, 15) +- Code(Counter(3)) 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 + 3, 15) +- Code(Zero) at (prev + 3, 32) 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(Zero) at (prev + 5, 9) to (start + 3, 16) +- Code(Zero) at (prev + 5, 13) to (start + 0, 27) +- Code(Zero) at (prev + 2, 13) to (start + 0, 28) +- Code(Counter(3)) at (prev + 4, 9) to (start + 2, 15) +- Code(Counter(3)) at (prev + 6, 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 + 1, 15) +- Code(Counter(3)) at (prev + 5, 8) to (start + 0, 15) +- Code(Counter(4)) 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) +- Code(Zero) at (prev + 3, 13) to (start + 0, 29) +- Code(Expression(1, Sub)) at (prev + 3, 9) to (start + 0, 19) + = (c3 - c5) +- 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(Expression(2, Sub)) at (prev + 2, 13) to (start + 0, 19) + = (c3 - c6) +- Code(Counter(7)) at (prev + 4, 5) to (start + 2, 19) +- Code(Counter(8)) at (prev + 3, 13) to (start + 0, 19) +- Code(Expression(3, Sub)) at (prev + 2, 13) to (start + 0, 19) = (c7 - c8) -- Code(Counter(8)) at (prev + 1, 5) to (start + 3, 15) -- Code(Counter(9)) at (prev + 3, 32) to (start + 0, 48) -- Code(Counter(10)) at (prev + 0, 51) to (start + 0, 65) -- Code(Expression(1, Sub)) at (prev + 0, 75) to (start + 0, 90) +- 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) +- Code(Expression(7, Sub)) at (prev + 2, 13) to (start + 0, 23) + = (c9 - c10) +- Code(Expression(7, Sub)) at (prev + 1, 20) to (start + 0, 27) = (c9 - c10) -- Code(Expression(2, Sub)) at (prev + 1, 5) to (start + 0, 15) - = (c8 - c9) -- Code(Counter(11)) at (prev + 5, 9) to (start + 3, 16) -- Code(Counter(12)) at (prev + 5, 13) to (start + 0, 27) -- Code(Expression(3, Sub)) at (prev + 2, 13) to (start + 0, 28) - = (c11 - c12) -- Code(Expression(4, Sub)) at (prev + 4, 9) to (start + 2, 15) - = (c8 - (c9 + c11)) -- Code(Counter(13)) at (prev + 6, 5) to (start + 0, 15) -- Code(Counter(14)) at (prev + 4, 5) to (start + 0, 15) -- Code(Counter(15)) at (prev + 4, 9) to (start + 1, 15) -- Code(Counter(16)) at (prev + 5, 8) to (start + 0, 15) -- Code(Counter(17)) at (prev + 1, 9) to (start + 0, 19) -- Code(Expression(6, Sub)) at (prev + 5, 9) to (start + 0, 19) - = (c16 - c17) -- Code(Expression(12, Add)) at (prev + 5, 8) to (start + 0, 15) - = (c18 + c19) -- Code(Counter(20)) at (prev + 1, 9) to (start + 0, 19) -- Code(Expression(8, Sub)) at (prev + 3, 13) to (start + 0, 29) - = (c20 - c21) -- Code(Expression(9, Sub)) at (prev + 3, 9) to (start + 0, 19) - = ((c18 + c19) - c20) -- Code(Expression(11, Sub)) at (prev + 3, 13) to (start + 0, 29) - = ((c18 + c19) - (c20 + c22)) -- Code(Expression(17, Add)) at (prev + 3, 5) to (start + 0, 15) - = (c21 + c22) -- Code(Expression(17, Add)) at (prev + 1, 12) to (start + 0, 19) - = (c21 + c22) -- Code(Counter(23)) at (prev + 1, 13) to (start + 0, 19) -- Code(Expression(16, Sub)) at (prev + 2, 13) to (start + 0, 19) - = ((c21 + c22) - c23) -- Code(Counter(24)) at (prev + 4, 5) to (start + 2, 19) -- Code(Counter(25)) at (prev + 3, 13) to (start + 0, 19) -- Code(Expression(18, Sub)) at (prev + 2, 13) to (start + 0, 19) - = (c24 - c25) -- Code(Expression(24, Add)) at (prev + 3, 5) to (start + 0, 15) - = (c28 + c29) -- Code(Counter(26)) at (prev + 1, 12) to (start + 0, 19) -- Code(Counter(27)) at (prev + 1, 13) to (start + 0, 23) -- Code(Counter(28)) at (prev + 4, 13) to (start + 0, 19) -- Code(Expression(22, Sub)) at (prev + 2, 13) to (start + 0, 23) - = (c26 - c27) -- Code(Expression(22, Sub)) at (prev + 1, 20) to (start + 0, 27) - = (c26 - c27) - Code(Zero) at (prev + 1, 21) to (start + 0, 27) -- Code(Expression(22, Sub)) at (prev + 2, 21) to (start + 0, 27) - = (c26 - c27) -- Code(Counter(29)) at (prev + 4, 13) to (start + 0, 19) -- Code(Expression(23, Sub)) at (prev + 3, 9) to (start + 0, 25) - = ((c28 + c29) - c30) -- Code(Counter(30)) at (prev + 2, 5) to (start + 0, 15) -- Code(Expression(25, Sub)) at (prev + 3, 9) to (start + 0, 34) - = (c30 - c31) -- Code(Counter(31)) at (prev + 2, 5) to (start + 0, 15) -- Code(Expression(26, Sub)) at (prev + 3, 9) to (start + 0, 44) - = (c31 - c32) -- Code(Counter(32)) at (prev + 2, 1) to (start + 0, 2) -Highest counter ID seen: c32 +- 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) +- 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) +- 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 diff --git a/tests/mir-opt/const_prop/read_immutable_static.main.GVN.diff b/tests/mir-opt/const_prop/read_immutable_static.main.GVN.diff index 23928337bf77f..8df262b351f12 100644 --- a/tests/mir-opt/const_prop/read_immutable_static.main.GVN.diff +++ b/tests/mir-opt/const_prop/read_immutable_static.main.GVN.diff @@ -14,19 +14,23 @@ bb0: { StorageLive(_1); - StorageLive(_2); +- StorageLive(_2); - StorageLive(_3); ++ nop; + nop; _3 = const {ALLOC0: &u8}; - _2 = copy (*_3); +- _2 = copy (*_3); ++ _2 = const 2_u8; StorageLive(_4); StorageLive(_5); _5 = const {ALLOC0: &u8}; - _4 = copy (*_5); -+ _4 = copy (*_3); - _1 = Add(move _2, move _4); +- _1 = Add(move _2, move _4); ++ _4 = const 2_u8; ++ _1 = const 4_u8; StorageDead(_4); - StorageDead(_2); +- StorageDead(_2); ++ nop; StorageDead(_5); - StorageDead(_3); + nop; diff --git a/tests/mir-opt/const_prop/read_immutable_static.rs b/tests/mir-opt/const_prop/read_immutable_static.rs index f88e4b3de939f..05fec2f3303b0 100644 --- a/tests/mir-opt/const_prop/read_immutable_static.rs +++ b/tests/mir-opt/const_prop/read_immutable_static.rs @@ -6,6 +6,6 @@ static FOO: u8 = 2; fn main() { // CHECK-LABEL: fn main( // CHECK: debug x => [[x:_.*]]; - // CHECK-NOT: [[x]] = const 4_u8; + // CHECK: [[x]] = const 4_u8; let x = FOO + FOO; } diff --git a/tests/mir-opt/const_prop/ref_deref.main.GVN.diff b/tests/mir-opt/const_prop/ref_deref.main.GVN.diff index 4477b4b005baf..b9e269266b0b1 100644 --- a/tests/mir-opt/const_prop/ref_deref.main.GVN.diff +++ b/tests/mir-opt/const_prop/ref_deref.main.GVN.diff @@ -16,7 +16,8 @@ StorageLive(_2); _4 = const main::promoted[0]; _2 = &(*_4); - _1 = copy (*_2); +- _1 = copy (*_2); ++ _1 = const 4_i32; StorageDead(_2); _0 = const (); StorageDead(_1); diff --git a/tests/mir-opt/const_prop/ref_deref_project.main.GVN.diff b/tests/mir-opt/const_prop/ref_deref_project.main.GVN.diff index bbfd70bea1684..dcc13c9251c41 100644 --- a/tests/mir-opt/const_prop/ref_deref_project.main.GVN.diff +++ b/tests/mir-opt/const_prop/ref_deref_project.main.GVN.diff @@ -16,7 +16,8 @@ StorageLive(_2); _4 = const main::promoted[0]; _2 = &((*_4).1: i32); - _1 = copy (*_2); +- _1 = copy (*_2); ++ _1 = const 5_i32; StorageDead(_2); _0 = const (); StorageDead(_1); diff --git a/tests/mir-opt/const_prop/ref_deref_project.rs b/tests/mir-opt/const_prop/ref_deref_project.rs index 813b4ae47455c..5a48a887f93d7 100644 --- a/tests/mir-opt/const_prop/ref_deref_project.rs +++ b/tests/mir-opt/const_prop/ref_deref_project.rs @@ -5,6 +5,6 @@ fn main() { // CHECK-LABEL: fn main( // CHECK: debug a => [[a:_.*]]; - // CHECK-NOT: [[a]] = const 5_i32; + // CHECK: [[a]] = const 5_i32; let a = *(&(4, 5).1); } diff --git a/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-abort.diff index 0798b30392956..d6e81debccd81 100644 --- a/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-abort.diff @@ -40,7 +40,7 @@ bb1: { - _1 = copy (*_2)[_6]; -+ _1 = copy (*_2)[1 of 2]; ++ _1 = const 2_u32; StorageDead(_6); StorageDead(_4); StorageDead(_2); diff --git a/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-unwind.diff index c0b3d4d321902..6713e531892ae 100644 --- a/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-unwind.diff @@ -40,7 +40,7 @@ bb1: { - _1 = copy (*_2)[_6]; -+ _1 = copy (*_2)[1 of 2]; ++ _1 = const 2_u32; StorageDead(_6); StorageDead(_4); StorageDead(_2); diff --git a/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-abort.diff index 0798b30392956..d6e81debccd81 100644 --- a/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-abort.diff @@ -40,7 +40,7 @@ bb1: { - _1 = copy (*_2)[_6]; -+ _1 = copy (*_2)[1 of 2]; ++ _1 = const 2_u32; StorageDead(_6); StorageDead(_4); StorageDead(_2); diff --git a/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-unwind.diff index c0b3d4d321902..6713e531892ae 100644 --- a/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-unwind.diff @@ -40,7 +40,7 @@ bb1: { - _1 = copy (*_2)[_6]; -+ _1 = copy (*_2)[1 of 2]; ++ _1 = const 2_u32; StorageDead(_6); StorageDead(_4); StorageDead(_2); diff --git a/tests/mir-opt/const_prop/slice_len.rs b/tests/mir-opt/const_prop/slice_len.rs index eb86e28408a34..ebd3c9e792dca 100644 --- a/tests/mir-opt/const_prop/slice_len.rs +++ b/tests/mir-opt/const_prop/slice_len.rs @@ -8,7 +8,7 @@ fn main() { // CHECK-LABEL: fn main( // CHECK: debug a => [[a:_.*]]; // CHECK: [[slice:_.*]] = copy {{.*}} as &[u32] (PointerCoercion(Unsize, AsCast)); - // CHECK-NOT: assert(const true, - // CHECK-NOT: [[a]] = const 2_u32; + // CHECK: assert(const true, + // CHECK: [[a]] = const 2_u32; let a = (&[1u32, 2, 3] as &[u32])[1]; } diff --git a/tests/mir-opt/gvn.borrowed.GVN.panic-abort.diff b/tests/mir-opt/gvn.borrowed.GVN.panic-abort.diff index acbea13642c1f..b0702696e1871 100644 --- a/tests/mir-opt/gvn.borrowed.GVN.panic-abort.diff +++ b/tests/mir-opt/gvn.borrowed.GVN.panic-abort.diff @@ -18,7 +18,8 @@ } bb2: { - _0 = opaque::(copy (*_3)) -> [return: bb3, unwind unreachable]; +- _0 = opaque::(copy (*_3)) -> [return: bb3, unwind unreachable]; ++ _0 = opaque::(copy _1) -> [return: bb3, unwind unreachable]; } bb3: { diff --git a/tests/mir-opt/gvn.borrowed.GVN.panic-unwind.diff b/tests/mir-opt/gvn.borrowed.GVN.panic-unwind.diff index ba080bfdb07a9..fe05d4deeede9 100644 --- a/tests/mir-opt/gvn.borrowed.GVN.panic-unwind.diff +++ b/tests/mir-opt/gvn.borrowed.GVN.panic-unwind.diff @@ -18,7 +18,8 @@ } bb2: { - _0 = opaque::(copy (*_3)) -> [return: bb3, unwind continue]; +- _0 = opaque::(copy (*_3)) -> [return: bb3, unwind continue]; ++ _0 = opaque::(copy _1) -> [return: bb3, unwind continue]; } bb3: { diff --git a/tests/mir-opt/gvn.rs b/tests/mir-opt/gvn.rs index be97470ebb17e..6ef320c90de12 100644 --- a/tests/mir-opt/gvn.rs +++ b/tests/mir-opt/gvn.rs @@ -742,7 +742,7 @@ fn borrowed(x: T) { // CHECK: bb1: { // CHECK-NEXT: _0 = opaque::(copy _1) // CHECK: bb2: { - // CHECK-NEXT: _0 = opaque::(copy (*_3)) + // CHECK-NEXT: _0 = opaque::(copy _1) mir! { { let a = x; diff --git a/tests/mir-opt/gvn.slices.GVN.panic-abort.diff b/tests/mir-opt/gvn.slices.GVN.panic-abort.diff index 43efcbdfb1e4b..e8e99b44e721b 100644 --- a/tests/mir-opt/gvn.slices.GVN.panic-abort.diff +++ b/tests/mir-opt/gvn.slices.GVN.panic-abort.diff @@ -111,8 +111,9 @@ StorageLive(_7); StorageLive(_8); - StorageLive(_9); +- StorageLive(_10); ++ nop; + nop; - StorageLive(_10); StorageLive(_11); _11 = &(*_1); _10 = core::str::::as_ptr(move _11) -> [return: bb3, unwind unreachable]; @@ -122,8 +123,9 @@ StorageDead(_11); _9 = &_10; - StorageLive(_12); +- StorageLive(_13); ++ nop; + nop; - StorageLive(_13); StorageLive(_14); - _14 = &(*_4); + _14 = &(*_1); @@ -148,11 +150,12 @@ StorageLive(_17); StorageLive(_18); - _18 = copy (*_15); -+ _18 = copy (*_9); ++ _18 = copy _10; StorageLive(_19); - _19 = copy (*_16); -+ _19 = copy (*_12); - _17 = Eq(move _18, move _19); +- _17 = Eq(move _18, move _19); ++ _19 = copy _13; ++ _17 = Eq(copy _10, copy _13); switchInt(move _17) -> [0: bb6, otherwise: bb5]; } @@ -163,8 +166,10 @@ StorageDead(_17); StorageDead(_16); StorageDead(_15); - StorageDead(_13); - StorageDead(_10); +- StorageDead(_13); +- StorageDead(_10); ++ nop; ++ nop; StorageDead(_8); StorageDead(_7); - StorageLive(_29); @@ -213,8 +218,9 @@ StorageLive(_33); StorageLive(_34); - StorageLive(_35); +- StorageLive(_36); ++ nop; + nop; - StorageLive(_36); StorageLive(_37); _37 = &(*_1); _36 = core::str::::as_ptr(move _37) -> [return: bb8, unwind unreachable]; @@ -224,8 +230,9 @@ StorageDead(_37); _35 = &_36; - StorageLive(_38); +- StorageLive(_39); ++ nop; + nop; - StorageLive(_39); StorageLive(_40); _40 = &(*_29); _39 = core::slice::::as_ptr(move _40) -> [return: bb9, unwind unreachable]; @@ -249,11 +256,12 @@ StorageLive(_43); StorageLive(_44); - _44 = copy (*_41); -+ _44 = copy (*_35); ++ _44 = copy _36; StorageLive(_45); - _45 = copy (*_42); -+ _45 = copy (*_38); - _43 = Eq(move _44, move _45); +- _43 = Eq(move _44, move _45); ++ _45 = copy _39; ++ _43 = Eq(copy _36, copy _39); switchInt(move _43) -> [0: bb11, otherwise: bb10]; } @@ -264,8 +272,10 @@ StorageDead(_43); StorageDead(_42); StorageDead(_41); - StorageDead(_39); - StorageDead(_36); +- StorageDead(_39); +- StorageDead(_36); ++ nop; ++ nop; StorageDead(_34); StorageDead(_33); _0 = const (); diff --git a/tests/mir-opt/gvn.slices.GVN.panic-unwind.diff b/tests/mir-opt/gvn.slices.GVN.panic-unwind.diff index 8572f538c0ff7..4296d4d4a5945 100644 --- a/tests/mir-opt/gvn.slices.GVN.panic-unwind.diff +++ b/tests/mir-opt/gvn.slices.GVN.panic-unwind.diff @@ -111,8 +111,9 @@ StorageLive(_7); StorageLive(_8); - StorageLive(_9); +- StorageLive(_10); ++ nop; + nop; - StorageLive(_10); StorageLive(_11); _11 = &(*_1); _10 = core::str::::as_ptr(move _11) -> [return: bb3, unwind continue]; @@ -122,8 +123,9 @@ StorageDead(_11); _9 = &_10; - StorageLive(_12); +- StorageLive(_13); ++ nop; + nop; - StorageLive(_13); StorageLive(_14); - _14 = &(*_4); + _14 = &(*_1); @@ -148,11 +150,12 @@ StorageLive(_17); StorageLive(_18); - _18 = copy (*_15); -+ _18 = copy (*_9); ++ _18 = copy _10; StorageLive(_19); - _19 = copy (*_16); -+ _19 = copy (*_12); - _17 = Eq(move _18, move _19); +- _17 = Eq(move _18, move _19); ++ _19 = copy _13; ++ _17 = Eq(copy _10, copy _13); switchInt(move _17) -> [0: bb6, otherwise: bb5]; } @@ -163,8 +166,10 @@ StorageDead(_17); StorageDead(_16); StorageDead(_15); - StorageDead(_13); - StorageDead(_10); +- StorageDead(_13); +- StorageDead(_10); ++ nop; ++ nop; StorageDead(_8); StorageDead(_7); - StorageLive(_29); @@ -213,8 +218,9 @@ StorageLive(_33); StorageLive(_34); - StorageLive(_35); +- StorageLive(_36); ++ nop; + nop; - StorageLive(_36); StorageLive(_37); _37 = &(*_1); _36 = core::str::::as_ptr(move _37) -> [return: bb8, unwind continue]; @@ -224,8 +230,9 @@ StorageDead(_37); _35 = &_36; - StorageLive(_38); +- StorageLive(_39); ++ nop; + nop; - StorageLive(_39); StorageLive(_40); _40 = &(*_29); _39 = core::slice::::as_ptr(move _40) -> [return: bb9, unwind continue]; @@ -249,11 +256,12 @@ StorageLive(_43); StorageLive(_44); - _44 = copy (*_41); -+ _44 = copy (*_35); ++ _44 = copy _36; StorageLive(_45); - _45 = copy (*_42); -+ _45 = copy (*_38); - _43 = Eq(move _44, move _45); +- _43 = Eq(move _44, move _45); ++ _45 = copy _39; ++ _43 = Eq(copy _36, copy _39); switchInt(move _43) -> [0: bb11, otherwise: bb10]; } @@ -264,8 +272,10 @@ StorageDead(_43); StorageDead(_42); StorageDead(_41); - StorageDead(_39); - StorageDead(_36); +- StorageDead(_39); +- StorageDead(_36); ++ nop; ++ nop; StorageDead(_34); StorageDead(_33); _0 = const (); diff --git a/tests/mir-opt/gvn_uninhabited.f.GVN.panic-abort.diff b/tests/mir-opt/gvn_uninhabited.f.GVN.panic-abort.diff index 881b629803a34..a3e4796d088e4 100644 --- a/tests/mir-opt/gvn_uninhabited.f.GVN.panic-abort.diff +++ b/tests/mir-opt/gvn_uninhabited.f.GVN.panic-abort.diff @@ -17,15 +17,16 @@ StorageLive(_3); _5 = const f::promoted[0]; _3 = &(*_5); - _2 = copy ((*_3).1: E); -- StorageLive(_1); -+ nop; - _1 = copy ((_2 as A).1: u32); +- _2 = copy ((*_3).1: E); ++ _2 = const Scalar(0x00000000): E; + StorageLive(_1); +- _1 = copy ((_2 as A).1: u32); ++ _1 = const 0_u32; StorageDead(_3); StorageDead(_2); - _0 = copy _1; -- StorageDead(_1); -+ nop; +- _0 = copy _1; ++ _0 = const 0_u32; + StorageDead(_1); return; } } diff --git a/tests/mir-opt/gvn_uninhabited.f.GVN.panic-unwind.diff b/tests/mir-opt/gvn_uninhabited.f.GVN.panic-unwind.diff index 881b629803a34..a3e4796d088e4 100644 --- a/tests/mir-opt/gvn_uninhabited.f.GVN.panic-unwind.diff +++ b/tests/mir-opt/gvn_uninhabited.f.GVN.panic-unwind.diff @@ -17,15 +17,16 @@ StorageLive(_3); _5 = const f::promoted[0]; _3 = &(*_5); - _2 = copy ((*_3).1: E); -- StorageLive(_1); -+ nop; - _1 = copy ((_2 as A).1: u32); +- _2 = copy ((*_3).1: E); ++ _2 = const Scalar(0x00000000): E; + StorageLive(_1); +- _1 = copy ((_2 as A).1: u32); ++ _1 = const 0_u32; StorageDead(_3); StorageDead(_2); - _0 = copy _1; -- StorageDead(_1); -+ nop; +- _0 = copy _1; ++ _0 = const 0_u32; + StorageDead(_1); return; } } diff --git a/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir index 5a269717f8297..cbdd194afd3ab 100644 --- a/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir @@ -4,70 +4,65 @@ fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:7:25: 7:39}, _2 let mut _0: bool; let mut _3: &(usize, usize, usize, usize); let _4: &usize; - let mut _5: &(usize, usize, usize, usize); + let _5: &usize; let _6: &usize; - let mut _7: &(usize, usize, usize, usize); - let _8: &usize; - let mut _9: &(usize, usize, usize, usize); - let _10: &usize; - let mut _11: &&usize; - let _12: &usize; - let mut _13: &&usize; - let mut _16: bool; - let mut _17: &&usize; - let _18: &usize; - let mut _19: &&usize; - let mut _22: bool; - let mut _23: &&usize; - let _24: &usize; - let mut _25: &&usize; - let mut _28: bool; - let mut _29: &&usize; - let _30: &usize; - let mut _31: &&usize; + let _7: &usize; + let mut _8: &&usize; + let _9: &usize; + let mut _10: &&usize; + let mut _13: bool; + let mut _14: &&usize; + let _15: &usize; + let mut _16: &&usize; + let mut _19: bool; + let mut _20: &&usize; + let _21: &usize; + let mut _22: &&usize; + let mut _23: bool; + let mut _24: &&usize; + let _25: &usize; + let mut _26: &&usize; scope 1 { debug a => _4; - debug b => _6; - debug c => _8; - debug d => _10; + debug b => _5; + debug c => _6; + debug d => _7; scope 2 (inlined std::cmp::impls::::le) { - debug self => _11; - debug other => _13; + debug self => _8; + debug other => _10; scope 3 (inlined std::cmp::impls::::le) { debug self => _4; - debug other => _8; - let mut _14: usize; - let mut _15: usize; + debug other => _6; + let mut _11: usize; + let mut _12: usize; } } scope 4 (inlined std::cmp::impls::::le) { - debug self => _17; - debug other => _19; + debug self => _14; + debug other => _16; scope 5 (inlined std::cmp::impls::::le) { - debug self => _10; - debug other => _6; - let mut _20: usize; - let mut _21: usize; + debug self => _7; + debug other => _5; + let mut _17: usize; + let mut _18: usize; } } scope 6 (inlined std::cmp::impls::::le) { - debug self => _23; - debug other => _25; + debug self => _20; + debug other => _22; scope 7 (inlined std::cmp::impls::::le) { - debug self => _8; + debug self => _6; debug other => _4; - let mut _26: usize; - let mut _27: usize; } } scope 8 (inlined std::cmp::impls::::le) { - debug self => _29; - debug other => _31; + debug self => _24; + debug other => _26; scope 9 (inlined std::cmp::impls::::le) { - debug self => _6; - debug other => _10; - let mut _32: usize; - let mut _33: usize; + debug self => _5; + debug other => _7; + let mut _27: usize; + let mut _28: usize; } } } @@ -75,129 +70,116 @@ fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:7:25: 7:39}, _2 bb0: { _3 = copy (*_2); _4 = &((*_3).0: usize); - _5 = copy (*_2); - _6 = &((*_5).1: usize); - _7 = copy (*_2); - _8 = &((*_7).2: usize); - _9 = copy (*_2); - _10 = &((*_9).3: usize); - StorageLive(_16); - StorageLive(_11); - _11 = &_4; + _5 = &((*_3).1: usize); + _6 = &((*_3).2: usize); + _7 = &((*_3).3: usize); StorageLive(_13); - StorageLive(_12); - _12 = copy _8; - _13 = &_12; - StorageLive(_14); - _14 = copy ((*_3).0: usize); - StorageLive(_15); - _15 = copy ((*_7).2: usize); - _16 = Le(move _14, move _15); - StorageDead(_15); - StorageDead(_14); - switchInt(move _16) -> [0: bb1, otherwise: bb2]; + StorageLive(_8); + _8 = &_4; + StorageLive(_10); + StorageLive(_9); + _9 = copy _6; + _10 = &_9; + _11 = copy ((*_3).0: usize); + _12 = copy ((*_3).2: usize); + _13 = Le(copy _11, copy _12); + switchInt(move _13) -> [0: bb1, otherwise: bb2]; } bb1: { - StorageDead(_12); - StorageDead(_13); - StorageDead(_11); + StorageDead(_9); + StorageDead(_10); + StorageDead(_8); goto -> bb4; } bb2: { - StorageDead(_12); - StorageDead(_13); - StorageDead(_11); - StorageLive(_22); - StorageLive(_17); - _17 = &_10; + StorageDead(_9); + StorageDead(_10); + StorageDead(_8); StorageLive(_19); + StorageLive(_14); + _14 = &_7; + StorageLive(_16); + StorageLive(_15); + _15 = copy _5; + _16 = &_15; + StorageLive(_17); + _17 = copy ((*_3).3: usize); StorageLive(_18); - _18 = copy _6; - _19 = &_18; - StorageLive(_20); - _20 = copy ((*_9).3: usize); - StorageLive(_21); - _21 = copy ((*_5).1: usize); - _22 = Le(move _20, move _21); - StorageDead(_21); - StorageDead(_20); - switchInt(move _22) -> [0: bb3, otherwise: bb8]; + _18 = copy ((*_3).1: usize); + _19 = Le(move _17, move _18); + StorageDead(_18); + StorageDead(_17); + switchInt(move _19) -> [0: bb3, otherwise: bb8]; } bb3: { - StorageDead(_18); - StorageDead(_19); - StorageDead(_17); + StorageDead(_15); + StorageDead(_16); + StorageDead(_14); goto -> bb4; } bb4: { - StorageLive(_28); StorageLive(_23); - _23 = &_8; - StorageLive(_25); - StorageLive(_24); - _24 = copy _4; - _25 = &_24; - StorageLive(_26); - _26 = copy ((*_7).2: usize); - StorageLive(_27); - _27 = copy ((*_3).0: usize); - _28 = Le(move _26, move _27); - StorageDead(_27); - StorageDead(_26); - switchInt(move _28) -> [0: bb5, otherwise: bb6]; + StorageLive(_20); + _20 = &_6; + StorageLive(_22); + StorageLive(_21); + _21 = copy _4; + _22 = &_21; + _23 = Le(copy _12, copy _11); + switchInt(move _23) -> [0: bb5, otherwise: bb6]; } bb5: { - StorageDead(_24); - StorageDead(_25); - StorageDead(_23); + StorageDead(_21); + StorageDead(_22); + StorageDead(_20); _0 = const false; goto -> bb7; } bb6: { - StorageDead(_24); + StorageDead(_21); + StorageDead(_22); + StorageDead(_20); + StorageLive(_24); + _24 = &_5; + StorageLive(_26); + StorageLive(_25); + _25 = copy _7; + _26 = &_25; + StorageLive(_27); + _27 = copy ((*_3).1: usize); + StorageLive(_28); + _28 = copy ((*_3).3: usize); + _0 = Le(move _27, move _28); + StorageDead(_28); + StorageDead(_27); StorageDead(_25); - StorageDead(_23); - StorageLive(_29); - _29 = &_6; - StorageLive(_31); - StorageLive(_30); - _30 = copy _10; - _31 = &_30; - StorageLive(_32); - _32 = copy ((*_5).1: usize); - StorageLive(_33); - _33 = copy ((*_9).3: usize); - _0 = Le(move _32, move _33); - StorageDead(_33); - StorageDead(_32); - StorageDead(_30); - StorageDead(_31); - StorageDead(_29); + StorageDead(_26); + StorageDead(_24); goto -> bb7; } bb7: { - StorageDead(_28); + StorageDead(_23); goto -> bb9; } bb8: { - StorageDead(_18); - StorageDead(_19); - StorageDead(_17); + StorageDead(_15); + StorageDead(_16); + StorageDead(_14); _0 = const true; goto -> bb9; } bb9: { - StorageDead(_22); - StorageDead(_16); + StorageDead(_19); + StorageDead(_13); return; } } diff --git a/tests/mir-opt/pre-codegen/slice_filter.variant_b-{closure#0}.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/slice_filter.variant_b-{closure#0}.PreCodegen.after.mir index f93f7264dec20..bc7a31d52199b 100644 --- a/tests/mir-opt/pre-codegen/slice_filter.variant_b-{closure#0}.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/slice_filter.variant_b-{closure#0}.PreCodegen.after.mir @@ -4,46 +4,40 @@ fn variant_b::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:11:25: 11:41}, let mut _0: bool; let mut _3: &(usize, usize, usize, usize); let _4: usize; - let mut _5: &(usize, usize, usize, usize); + let _5: usize; let _6: usize; - let mut _7: &(usize, usize, usize, usize); - let _8: usize; - let mut _9: &(usize, usize, usize, usize); - let _10: usize; - let mut _11: bool; - let mut _12: bool; - let mut _13: bool; + let _7: usize; + let mut _8: bool; + let mut _9: bool; + let mut _10: bool; scope 1 { debug a => _4; - debug b => _6; - debug c => _8; - debug d => _10; + debug b => _5; + debug c => _6; + debug d => _7; } bb0: { _3 = copy (*_2); _4 = copy ((*_3).0: usize); - _5 = copy (*_2); - _6 = copy ((*_5).1: usize); - _7 = copy (*_2); - _8 = copy ((*_7).2: usize); - _9 = copy (*_2); - _10 = copy ((*_9).3: usize); - StorageLive(_11); - _11 = Le(copy _4, copy _8); - switchInt(move _11) -> [0: bb2, otherwise: bb1]; + _5 = copy ((*_3).1: usize); + _6 = copy ((*_3).2: usize); + _7 = copy ((*_3).3: usize); + StorageLive(_8); + _8 = Le(copy _4, copy _6); + switchInt(move _8) -> [0: bb2, otherwise: bb1]; } bb1: { - StorageLive(_12); - _12 = Le(copy _10, copy _6); - switchInt(move _12) -> [0: bb2, otherwise: bb6]; + StorageLive(_9); + _9 = Le(copy _7, copy _5); + switchInt(move _9) -> [0: bb2, otherwise: bb6]; } bb2: { - StorageLive(_13); - _13 = Le(copy _8, copy _4); - switchInt(move _13) -> [0: bb3, otherwise: bb4]; + StorageLive(_10); + _10 = Le(copy _6, copy _4); + switchInt(move _10) -> [0: bb3, otherwise: bb4]; } bb3: { @@ -52,12 +46,12 @@ fn variant_b::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:11:25: 11:41}, } bb4: { - _0 = Le(copy _6, copy _10); + _0 = Le(copy _5, copy _7); goto -> bb5; } bb5: { - StorageDead(_13); + StorageDead(_10); goto -> bb7; } @@ -67,8 +61,8 @@ fn variant_b::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:11:25: 11:41}, } bb7: { - StorageDead(_12); - StorageDead(_11); + StorageDead(_9); + StorageDead(_8); return; } } From ac7dd7a1b3307ddfd6ad95a1b3f58830e0fdbf65 Mon Sep 17 00:00:00 2001 From: dianqk Date: Mon, 24 Mar 2025 16:55:24 +0800 Subject: [PATCH 7/9] Remove `unsound-mir-opts` for `simplify_aggregate_to_copy` --- compiler/rustc_mir_transform/src/gvn.rs | 4 +- tests/codegen/clone_as_copy.rs | 2 - tests/codegen/try_question_mark_nop.rs | 38 ++++++++----- tests/mir-opt/gvn_clone.rs | 2 - .../mir-opt/gvn_clone.{impl#0}-clone.GVN.diff | 6 +-- tests/mir-opt/gvn_copy_aggregate.rs | 2 - tests/mir-opt/pre-codegen/clone_as_copy.rs | 2 - ..._clone.{impl#0}-clone.PreCodegen.after.mir | 6 +-- .../try_identity.old.PreCodegen.after.mir | 8 +-- ..._aggregate_to_copy_miscompile.foo.GVN.diff | 54 ++++++++----------- .../simplify_aggregate_to_copy_miscompile.rs | 12 +++-- 11 files changed, 65 insertions(+), 71 deletions(-) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index a93fdff5817c4..b6294f4ff8a2c 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -1098,9 +1098,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } } - // unsound: https://github.com/rust-lang/rust/issues/132353 - if tcx.sess.opts.unstable_opts.unsound_mir_opts - && let AggregateTy::Def(_, _) = ty + if let AggregateTy::Def(_, _) = ty && let Some(value) = self.simplify_aggregate_to_copy(rvalue, location, &fields, variant_index) { diff --git a/tests/codegen/clone_as_copy.rs b/tests/codegen/clone_as_copy.rs index c39f120044c09..ef834ef59120f 100644 --- a/tests/codegen/clone_as_copy.rs +++ b/tests/codegen/clone_as_copy.rs @@ -1,6 +1,4 @@ //@ revisions: DEBUGINFO NODEBUGINFO -//@ compile-flags: -Zunsound-mir-opts -// FIXME: see //@ compile-flags: -Copt-level=3 -Cno-prepopulate-passes //@ [DEBUGINFO] compile-flags: -Cdebuginfo=full diff --git a/tests/codegen/try_question_mark_nop.rs b/tests/codegen/try_question_mark_nop.rs index 3a3453b22b44f..9430465a2860b 100644 --- a/tests/codegen/try_question_mark_nop.rs +++ b/tests/codegen/try_question_mark_nop.rs @@ -16,12 +16,17 @@ use std::ptr::NonNull; #[no_mangle] pub fn option_nop_match_32(x: Option) -> Option { // CHECK: start: - // TWENTY-NEXT: %[[IS_SOME:.+]] = trunc nuw i32 %0 to i1 - // TWENTY-NEXT: %[[PAYLOAD:.+]] = select i1 %[[IS_SOME]], i32 %1, i32 undef - // CHECK-NEXT: [[REG1:%.*]] = insertvalue { i32, i32 } poison, i32 %0, 0 - // NINETEEN-NEXT: [[REG2:%.*]] = insertvalue { i32, i32 } [[REG1]], i32 %1, 1 - // TWENTY-NEXT: [[REG2:%.*]] = insertvalue { i32, i32 } [[REG1]], i32 %[[PAYLOAD]], 1 - // CHECK-NEXT: ret { i32, i32 } [[REG2]] + // CHECK-NEXT: [[TRUNC:%.*]] = trunc nuw i32 %0 to i1 + + // NINETEEN-NEXT: [[SELECT:%.*]] = select i1 [[TRUNC]], i32 %0, i32 0 + // NINETEEN-NEXT: [[REG2:%.*]] = insertvalue { i32, i32 } poison, i32 [[SELECT]], 0 + // NINETEEN-NEXT: [[REG3:%.*]] = insertvalue { i32, i32 } [[REG2]], i32 %1, 1 + + // TWENTY-NEXT: [[SELECT:%.*]] = select i1 [[TRUNC]], i32 %1, i32 undef + // TWENTY-NEXT: [[REG2:%.*]] = insertvalue { i32, i32 } poison, i32 %0, 0 + // TWENTY-NEXT: [[REG3:%.*]] = insertvalue { i32, i32 } [[REG2]], i32 [[SELECT]], 1 + + // CHECK-NEXT: ret { i32, i32 } [[REG3]] match x { Some(x) => Some(x), None => None, @@ -90,12 +95,17 @@ pub fn control_flow_nop_traits_32(x: ControlFlow) -> ControlFlow) -> Option { // CHECK: start: - // TWENTY-NEXT: %[[TRUNC:[0-9]+]] = trunc nuw i64 %0 to i1 - // TWENTY-NEXT: %[[SEL:\.[0-9]+]] = select i1 %[[TRUNC]], i64 %1, i64 undef - // CHECK-NEXT: [[REG1:%[0-9a-zA-Z_.]+]] = insertvalue { i64, i64 } poison, i64 %0, 0 - // NINETEEN-NEXT: [[REG2:%[0-9a-zA-Z_.]+]] = insertvalue { i64, i64 } [[REG1]], i64 %1, 1 - // TWENTY-NEXT: [[REG2:%[0-9a-zA-Z_.]+]] = insertvalue { i64, i64 } [[REG1]], i64 %[[SEL]], 1 - // CHECK-NEXT: ret { i64, i64 } [[REG2]] + // CHECK-NEXT: [[TRUNC:%.*]] = trunc nuw i64 %0 to i1 + + // NINETEEN-NEXT: [[SELECT:%.*]] = select i1 [[TRUNC]], i64 %0, i64 0 + // NINETEEN-NEXT: [[REG2:%.*]] = insertvalue { i64, i64 } poison, i64 [[SELECT]], 0 + // NINETEEN-NEXT: [[REG3:%.*]] = insertvalue { i64, i64 } [[REG2]], i64 %1, 1 + + // TWENTY-NEXT: [[SELECT:%.*]] = select i1 [[TRUNC]], i64 %1, i64 undef + // TWENTY-NEXT: [[REG2:%.*]] = insertvalue { i64, i64 } poison, i64 %0, 0 + // TWENTY-NEXT: [[REG3:%.*]] = insertvalue { i64, i64 } [[REG2]], i64 [[SELECT]], 1 + + // CHECK-NEXT: ret { i64, i64 } [[REG3]] match x { Some(x) => Some(x), None => None, @@ -164,8 +174,8 @@ pub fn control_flow_nop_traits_64(x: ControlFlow) -> ControlFlow) -> Result { // CHECK: start: - // CHECK-NEXT: getelementptr inbounds {{(nuw )?}}i8 // CHECK-NEXT: store i128 + // CHECK-NEXT: getelementptr inbounds {{(nuw )?}}i8 // CHECK-NEXT: store i128 // CHECK-NEXT: ret void match x { @@ -189,8 +199,8 @@ pub fn result_nop_traits_128(x: Result) -> Result { #[no_mangle] pub fn control_flow_nop_match_128(x: ControlFlow) -> ControlFlow { // CHECK: start: - // CHECK-NEXT: getelementptr inbounds {{(nuw )?}}i8 // CHECK-NEXT: store i128 + // CHECK-NEXT: getelementptr inbounds {{(nuw )?}}i8 // CHECK-NEXT: store i128 // CHECK-NEXT: ret void match x { diff --git a/tests/mir-opt/gvn_clone.rs b/tests/mir-opt/gvn_clone.rs index c16b665fbd39c..08938c0e1b427 100644 --- a/tests/mir-opt/gvn_clone.rs +++ b/tests/mir-opt/gvn_clone.rs @@ -1,5 +1,3 @@ -//@ compile-flags: -Zunsound-mir-opts -// FIXME: see //@ test-mir-pass: GVN //@ compile-flags: -Zmir-enable-passes=+InstSimplify-before-inline diff --git a/tests/mir-opt/gvn_clone.{impl#0}-clone.GVN.diff b/tests/mir-opt/gvn_clone.{impl#0}-clone.GVN.diff index 2a672e829707f..0f23415ec53bb 100644 --- a/tests/mir-opt/gvn_clone.{impl#0}-clone.GVN.diff +++ b/tests/mir-opt/gvn_clone.{impl#0}-clone.GVN.diff @@ -1,7 +1,7 @@ -- // MIR for `::clone` before GVN -+ // MIR for `::clone` after GVN +- // MIR for `::clone` before GVN ++ // MIR for `::clone` after GVN - fn ::clone(_1: &AllCopy) -> AllCopy { + fn ::clone(_1: &AllCopy) -> AllCopy { debug self => _1; let mut _0: AllCopy; let mut _2: i32; diff --git a/tests/mir-opt/gvn_copy_aggregate.rs b/tests/mir-opt/gvn_copy_aggregate.rs index 7c181d1ad3784..c9473025a15f2 100644 --- a/tests/mir-opt/gvn_copy_aggregate.rs +++ b/tests/mir-opt/gvn_copy_aggregate.rs @@ -1,5 +1,3 @@ -//@ compile-flags: -Zunsound-mir-opts -// FIXME: see //@ compile-flags: -Cdebuginfo=full // Check if we have transformed the nested clone to the copy in the complete pipeline. diff --git a/tests/mir-opt/pre-codegen/no_inlined_clone.{impl#0}-clone.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/no_inlined_clone.{impl#0}-clone.PreCodegen.after.mir index 62a9cd9131f0b..9020cf1ef37f2 100644 --- a/tests/mir-opt/pre-codegen/no_inlined_clone.{impl#0}-clone.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/no_inlined_clone.{impl#0}-clone.PreCodegen.after.mir @@ -3,13 +3,9 @@ fn ::clone(_1: &Foo) -> Foo { debug self => _1; let mut _0: Foo; - let mut _2: i32; bb0: { - StorageLive(_2); - _2 = copy ((*_1).0: i32); - _0 = Foo { a: move _2 }; - StorageDead(_2); + _0 = copy (*_1); return; } } diff --git a/tests/mir-opt/pre-codegen/try_identity.old.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/try_identity.old.PreCodegen.after.mir index ac485f485b1cc..889e80d26e1cc 100644 --- a/tests/mir-opt/pre-codegen/try_identity.old.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/try_identity.old.PreCodegen.after.mir @@ -19,14 +19,14 @@ fn old(_1: Result) -> Result { } bb1: { - _3 = move ((_1 as Ok).0: T); - _0 = Result::::Ok(copy _3); + _3 = copy ((_1 as Ok).0: T); + _0 = copy _1; goto -> bb3; } bb2: { - _4 = move ((_1 as Err).0: E); - _0 = Result::::Err(copy _4); + _4 = copy ((_1 as Err).0: E); + _0 = copy _1; goto -> bb3; } diff --git a/tests/mir-opt/simplify_aggregate_to_copy_miscompile.foo.GVN.diff b/tests/mir-opt/simplify_aggregate_to_copy_miscompile.foo.GVN.diff index 2efc4ef56044a..19a00f977eb10 100644 --- a/tests/mir-opt/simplify_aggregate_to_copy_miscompile.foo.GVN.diff +++ b/tests/mir-opt/simplify_aggregate_to_copy_miscompile.foo.GVN.diff @@ -6,60 +6,52 @@ let mut _0: std::option::Option; let mut _2: &std::option::Option; let mut _3: &std::option::Option; - let _4: &&mut std::option::Option; - let mut _5: isize; - let mut _7: !; - let mut _8: std::option::Option; - let mut _9: i32; - let mut _10: !; - let mut _11: &mut std::option::Option; + let mut _4: isize; + let mut _6: !; + let mut _7: std::option::Option; + let mut _8: i32; + let mut _9: !; scope 1 { - debug col => _6; - let _6: i32; + debug col => _5; + let _5: i32; } bb0: { StorageLive(_2); StorageLive(_3); - StorageLive(_4); - _4 = &_1; -- _11 = deref_copy (*_4); -- _3 = &(*_11); -+ _11 = copy _1; -+ _3 = &(*_1); + _3 = &(*_1); _2 = get(move _3) -> [return: bb1, unwind unreachable]; } bb1: { StorageDead(_3); - _5 = discriminant((*_2)); - switchInt(move _5) -> [1: bb2, otherwise: bb3]; + _4 = discriminant((*_2)); + switchInt(move _4) -> [1: bb2, otherwise: bb3]; } bb2: { -- StorageLive(_6); +- StorageLive(_5); + nop; - _6 = copy (((*_2) as Some).0: i32); - StorageLive(_8); -- _8 = Option::::None; -- (*_1) = move _8; -+ _8 = const Option::::None; + _5 = copy (((*_2) as Some).0: i32); + StorageLive(_7); +- _7 = Option::::None; +- (*_1) = move _7; ++ _7 = const Option::::None; + (*_1) = const Option::::None; + StorageDead(_7); + StorageLive(_8); + _8 = copy _5; +- _0 = Option::::Some(move _8); ++ _0 = Option::::Some(copy _5); StorageDead(_8); - StorageLive(_9); - _9 = copy _6; -- _0 = Option::::Some(move _9); -+ _0 = Option::::Some(copy _6); - StorageDead(_9); -- StorageDead(_6); +- StorageDead(_5); + nop; - StorageDead(_4); StorageDead(_2); return; } bb3: { - StorageLive(_10); + StorageLive(_9); unreachable; } + } diff --git a/tests/mir-opt/simplify_aggregate_to_copy_miscompile.rs b/tests/mir-opt/simplify_aggregate_to_copy_miscompile.rs index 47721b768be79..87b52ae480868 100644 --- a/tests/mir-opt/simplify_aggregate_to_copy_miscompile.rs +++ b/tests/mir-opt/simplify_aggregate_to_copy_miscompile.rs @@ -7,8 +7,6 @@ //! This test demonstrates the behavior, and should be adjusted or removed when fixing and relanding //! the mir-opt. #![crate_type = "lib"] -// skip-filecheck -//@ compile-flags: -O -Zunsound-mir-opts //@ test-mir-pass: GVN #![allow(internal_features)] #![feature(rustc_attrs, core_intrinsics)] @@ -16,7 +14,15 @@ // EMIT_MIR simplify_aggregate_to_copy_miscompile.foo.GVN.diff #[no_mangle] fn foo(v: &mut Option) -> Option { - if let &Some(col) = get(&v) { + // CHECK-LABEL: fn foo( + // CHECK-SAME: [[v:_.*]]: &mut Option + // CHECK: [[v_alias_1:_.*]] = &(*_1) + // CHECK-NEXT: [[v_alias_2:_.*]] = get(move [[v_alias_1]]) + // CHECK: (*[[v]]) = const Option::::None; + // CHECK-NOT: _0 = copy (*[[v_alias_2]]) + // CHECK: _0 = Option::::Some + // CHECK-NOT: _0 = copy (*[[v_alias_2]]) + if let &Some(col) = get(v) { *v = None; return Some(col); } else { From 4e05d858ad602de7d34054016c2277730789dcba Mon Sep 17 00:00:00 2001 From: dianqk Date: Mon, 24 Mar 2025 16:55:24 +0800 Subject: [PATCH 8/9] Only preserving derefs for trivial terminators like SwitchInt and Goto --- compiler/rustc_mir_transform/src/gvn.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index b6294f4ff8a2c..046f36bdeddfd 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -1779,8 +1779,14 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> { let opaque = self.new_opaque(); self.assign(local, opaque); } - // Function calls maybe invalidate nested deref, and non-local assignments maybe invalidate deref. - // Currently, no distinction is made between these two cases. + } + // Function calls and ASM may invalidate (nested) derefs. We must handle them carefully. + // Currently, only preserving derefs for trivial terminators like SwitchInt and Goto. + let safe_to_preserve_derefs = matches!( + terminator.kind, + TerminatorKind::SwitchInt { .. } | TerminatorKind::Goto { .. } + ); + if !safe_to_preserve_derefs { self.invalidate_derefs(); } self.super_terminator(terminator, location); From 7d44887374ee667bd5aeb5e861032b8ce4093b29 Mon Sep 17 00:00:00 2001 From: dianqk Date: Tue, 25 Mar 2025 22:21:18 +0800 Subject: [PATCH 9/9] Invalid dereferences for all non-local mutations --- compiler/rustc_mir_transform/src/gvn.rs | 30 +++++++++-------- ...mute.undef_union_as_integer.GVN.32bit.diff | 3 +- ...mute.undef_union_as_integer.GVN.64bit.diff | 3 +- ...in.DestinationPropagation.panic-abort.diff | 10 ++---- ...n.DestinationPropagation.panic-unwind.diff | 10 ++---- ..._aggregate_to_copy_miscompile.foo.GVN.diff | 2 +- .../simplify_aggregate_to_copy_miscompile.rs | 33 ++++++++++++++++--- ..._copy_miscompile.set_discriminant.GVN.diff | 20 +++++++++++ 8 files changed, 75 insertions(+), 36 deletions(-) create mode 100644 tests/mir-opt/simplify_aggregate_to_copy_miscompile.set_discriminant.GVN.diff diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 046f36bdeddfd..68bc0ffce6b5d 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -1728,12 +1728,18 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> { self.tcx } - fn visit_place(&mut self, place: &mut Place<'tcx>, _: PlaceContext, location: Location) { + 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.projection.is_empty() { + // Non-local mutation maybe invalidate deref. + self.invalidate_derefs(); + } + self.super_place(place, context, location); } fn visit_operand(&mut self, operand: &mut Operand<'tcx>, location: Location) { self.simplify_operand(operand, location); + self.super_operand(operand, location); } fn visit_statement(&mut self, stmt: &mut Statement<'tcx>, location: Location) { @@ -1751,22 +1757,18 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> { self.assign(local, value); Some(value) } else { - // Non-local assignments maybe invalidate deref. - self.invalidate_derefs(); value }; - let Some(value) = value else { return }; - - if let Some(const_) = self.try_as_constant(value) { - *rvalue = Rvalue::Use(Operand::Constant(Box::new(const_))); - } else if let Some(local) = self.try_as_local(value, location) - && *rvalue != Rvalue::Use(Operand::Move(local.into())) - { - *rvalue = Rvalue::Use(Operand::Copy(local.into())); - self.reused_locals.insert(local); + if let Some(value) = value { + if let Some(const_) = self.try_as_constant(value) { + *rvalue = Rvalue::Use(Operand::Constant(Box::new(const_))); + } else if let Some(local) = self.try_as_local(value, location) + && *rvalue != Rvalue::Use(Operand::Move(local.into())) + { + *rvalue = Rvalue::Use(Operand::Copy(local.into())); + self.reused_locals.insert(local); + } } - - return; } self.super_statement(stmt, location); } diff --git a/tests/mir-opt/const_prop/transmute.undef_union_as_integer.GVN.32bit.diff b/tests/mir-opt/const_prop/transmute.undef_union_as_integer.GVN.32bit.diff index febb6bfb0a43f..2ac9769a0e773 100644 --- a/tests/mir-opt/const_prop/transmute.undef_union_as_integer.GVN.32bit.diff +++ b/tests/mir-opt/const_prop/transmute.undef_union_as_integer.GVN.32bit.diff @@ -10,8 +10,9 @@ StorageLive(_1); StorageLive(_2); - _2 = (); +- _1 = Union32 { value: move _2 }; + _2 = const (); - _1 = Union32 { value: move _2 }; ++ _1 = Union32 { value: const () }; StorageDead(_2); _0 = move _1 as u32 (Transmute); StorageDead(_1); diff --git a/tests/mir-opt/const_prop/transmute.undef_union_as_integer.GVN.64bit.diff b/tests/mir-opt/const_prop/transmute.undef_union_as_integer.GVN.64bit.diff index febb6bfb0a43f..2ac9769a0e773 100644 --- a/tests/mir-opt/const_prop/transmute.undef_union_as_integer.GVN.64bit.diff +++ b/tests/mir-opt/const_prop/transmute.undef_union_as_integer.GVN.64bit.diff @@ -10,8 +10,9 @@ StorageLive(_1); StorageLive(_2); - _2 = (); +- _1 = Union32 { value: move _2 }; + _2 = const (); - _1 = Union32 { value: move _2 }; ++ _1 = Union32 { value: const () }; StorageDead(_2); _0 = move _1 as u32 (Transmute); StorageDead(_1); diff --git a/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-abort.diff b/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-abort.diff index 557320f017984..ef418798faaf7 100644 --- a/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-abort.diff +++ b/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-abort.diff @@ -5,11 +5,10 @@ let mut _0: (); let _1: main::Un; let mut _2: u32; - let mut _3: u32; scope 1 { debug un => _1; scope 3 (inlined std::mem::drop::) { - debug _x => _3; + debug _x => _2; } } scope 2 (inlined val) { @@ -17,13 +16,10 @@ bb0: { StorageLive(_1); - StorageLive(_2); - nop; _1 = Un { us: const 1_u32 }; + StorageLive(_2); + _2 = copy (_1.0: u32); StorageDead(_2); - StorageLive(_3); - _3 = copy (_1.0: u32); - StorageDead(_3); StorageDead(_1); return; } diff --git a/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-unwind.diff b/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-unwind.diff index 557320f017984..ef418798faaf7 100644 --- a/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-unwind.diff +++ b/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-unwind.diff @@ -5,11 +5,10 @@ let mut _0: (); let _1: main::Un; let mut _2: u32; - let mut _3: u32; scope 1 { debug un => _1; scope 3 (inlined std::mem::drop::) { - debug _x => _3; + debug _x => _2; } } scope 2 (inlined val) { @@ -17,13 +16,10 @@ bb0: { StorageLive(_1); - StorageLive(_2); - nop; _1 = Un { us: const 1_u32 }; + StorageLive(_2); + _2 = copy (_1.0: u32); StorageDead(_2); - StorageLive(_3); - _3 = copy (_1.0: u32); - StorageDead(_3); StorageDead(_1); return; } diff --git a/tests/mir-opt/simplify_aggregate_to_copy_miscompile.foo.GVN.diff b/tests/mir-opt/simplify_aggregate_to_copy_miscompile.foo.GVN.diff index 19a00f977eb10..54c11679f0c69 100644 --- a/tests/mir-opt/simplify_aggregate_to_copy_miscompile.foo.GVN.diff +++ b/tests/mir-opt/simplify_aggregate_to_copy_miscompile.foo.GVN.diff @@ -20,7 +20,7 @@ StorageLive(_2); StorageLive(_3); _3 = &(*_1); - _2 = get(move _3) -> [return: bb1, unwind unreachable]; + _2 = get::>(move _3) -> [return: bb1, unwind unreachable]; } bb1: { diff --git a/tests/mir-opt/simplify_aggregate_to_copy_miscompile.rs b/tests/mir-opt/simplify_aggregate_to_copy_miscompile.rs index 87b52ae480868..33e31b5697784 100644 --- a/tests/mir-opt/simplify_aggregate_to_copy_miscompile.rs +++ b/tests/mir-opt/simplify_aggregate_to_copy_miscompile.rs @@ -9,15 +9,16 @@ #![crate_type = "lib"] //@ test-mir-pass: GVN #![allow(internal_features)] -#![feature(rustc_attrs, core_intrinsics)] +#![feature(core_intrinsics, custom_mir, rustc_attrs)] + +use std::intrinsics::mir::*; // EMIT_MIR simplify_aggregate_to_copy_miscompile.foo.GVN.diff -#[no_mangle] fn foo(v: &mut Option) -> Option { // CHECK-LABEL: fn foo( // CHECK-SAME: [[v:_.*]]: &mut Option // CHECK: [[v_alias_1:_.*]] = &(*_1) - // CHECK-NEXT: [[v_alias_2:_.*]] = get(move [[v_alias_1]]) + // CHECK-NEXT: [[v_alias_2:_.*]] = get::>(move [[v_alias_1]]) // CHECK: (*[[v]]) = const Option::::None; // CHECK-NOT: _0 = copy (*[[v_alias_2]]) // CHECK: _0 = Option::::Some @@ -30,9 +31,31 @@ fn foo(v: &mut Option) -> Option { } } -#[no_mangle] +pub enum Value { + V0(i32), + V1(i32), +} + +// EMIT_MIR simplify_aggregate_to_copy_miscompile.set_discriminant.GVN.diff +#[custom_mir(dialect = "runtime", phase = "initial")] +fn set_discriminant(v: &mut Value) -> Value { + // CHECK-LABEL: fn set_discriminant( + mir! { + let v_: &Value; + { + Call(v_ = get(v), ReturnTo(ret), UnwindUnreachable()) + } + ret = { + let col: i32 = Field(Variant(*v_, 0), 0); + SetDiscriminant(*v, 1); + RET = Value::V0(col); + Return() + } + } +} + #[inline(never)] #[rustc_nounwind] -fn get(v: &Option) -> &Option { +fn get(v: &T) -> &T { v } diff --git a/tests/mir-opt/simplify_aggregate_to_copy_miscompile.set_discriminant.GVN.diff b/tests/mir-opt/simplify_aggregate_to_copy_miscompile.set_discriminant.GVN.diff new file mode 100644 index 0000000000000..41f9763d0240d --- /dev/null +++ b/tests/mir-opt/simplify_aggregate_to_copy_miscompile.set_discriminant.GVN.diff @@ -0,0 +1,20 @@ +- // MIR for `set_discriminant` before GVN ++ // MIR for `set_discriminant` after GVN + + fn set_discriminant(_1: &mut Value) -> Value { + let mut _0: Value; + let mut _2: &Value; + let mut _3: i32; + + bb0: { + _2 = get::(copy _1) -> [return: bb1, unwind unreachable]; + } + + bb1: { + _3 = copy (((*_2) as variant#0).0: i32); + discriminant((*_1)) = 1; + _0 = Value::V0(copy _3); + return; + } + } +