From a5cf73bd47dc71b5ea512035790d5188cb6d6d34 Mon Sep 17 00:00:00 2001 From: dianqk Date: Sat, 18 Oct 2025 21:42:08 +0800 Subject: [PATCH 1/4] Add miscompiled test cases for GVN --- .../gvn_copy_aggregate.deref_nonssa.GVN.diff | 50 +++++++++++++++++++ tests/mir-opt/gvn_copy_aggregate.rs | 12 +++++ .../gvn_overlapping.copy_overlapping.GVN.diff | 19 +++++++ tests/mir-opt/gvn_overlapping.rs | 17 +++++++ 4 files changed, 98 insertions(+) create mode 100644 tests/mir-opt/gvn_copy_aggregate.deref_nonssa.GVN.diff create mode 100644 tests/mir-opt/gvn_overlapping.copy_overlapping.GVN.diff diff --git a/tests/mir-opt/gvn_copy_aggregate.deref_nonssa.GVN.diff b/tests/mir-opt/gvn_copy_aggregate.deref_nonssa.GVN.diff new file mode 100644 index 0000000000000..d17213993282a --- /dev/null +++ b/tests/mir-opt/gvn_copy_aggregate.deref_nonssa.GVN.diff @@ -0,0 +1,50 @@ +- // MIR for `deref_nonssa` before GVN ++ // MIR for `deref_nonssa` after GVN + + fn deref_nonssa() -> Single { + let mut _0: Single; + let mut _1: Single; + let mut _4: Single; + let mut _5: u8; + scope 1 { + debug a => _1; + let _2: &Single; + scope 2 { + debug b => _2; + let _3: u8; + scope 3 { + debug c => _3; + } + } + } + + bb0: { + StorageLive(_1); +- _1 = Single(const 0_u8); +- StorageLive(_2); ++ _1 = const Single(0_u8); ++ nop; + _2 = &_1; +- StorageLive(_3); ++ nop; + _3 = copy ((*_2).0: u8); + StorageLive(_4); +- _4 = Single(const 1_u8); +- _1 = move _4; ++ _4 = const Single(1_u8); ++ _1 = const Single(1_u8); + StorageDead(_4); + StorageLive(_5); + _5 = copy _3; +- _0 = Single(move _5); ++ _0 = copy (*_2); + StorageDead(_5); +- StorageDead(_3); +- StorageDead(_2); ++ nop; ++ nop; + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/gvn_copy_aggregate.rs b/tests/mir-opt/gvn_copy_aggregate.rs index c9473025a15f2..39460dc1e6942 100644 --- a/tests/mir-opt/gvn_copy_aggregate.rs +++ b/tests/mir-opt/gvn_copy_aggregate.rs @@ -259,3 +259,15 @@ fn remove_storage_dead_from_index(f: fn() -> usize, v: [SameType; 5]) -> SameTyp } } } + +pub struct Single(u8); + +// EMIT_MIR gvn_copy_aggregate.deref_nonssa.GVN.diff +fn deref_nonssa() -> Single { + let mut a = Single(0); + let b = &a; + let c = (*b).0; + a = Single(1); + // GVN shouldn't replace `Single(c)` with `*b`. + Single(c) +} diff --git a/tests/mir-opt/gvn_overlapping.copy_overlapping.GVN.diff b/tests/mir-opt/gvn_overlapping.copy_overlapping.GVN.diff new file mode 100644 index 0000000000000..f13c92e4fd012 --- /dev/null +++ b/tests/mir-opt/gvn_overlapping.copy_overlapping.GVN.diff @@ -0,0 +1,19 @@ +- // MIR for `copy_overlapping` before GVN ++ // MIR for `copy_overlapping` after GVN + + fn copy_overlapping() -> () { + let mut _0: (); + let mut _1: Adt; + let mut _2: u32; + let mut _3: &Adt; + + bb0: { + ((_1 as variant#1).0: u32) = const 0_u32; + _3 = &_1; + _2 = copy (((*_3) as variant#1).0: u32); +- _1 = Adt::Some(copy _2); ++ _1 = copy (*_3); + return; + } + } + diff --git a/tests/mir-opt/gvn_overlapping.rs b/tests/mir-opt/gvn_overlapping.rs index f148a84356125..a41f8ad5fd607 100644 --- a/tests/mir-opt/gvn_overlapping.rs +++ b/tests/mir-opt/gvn_overlapping.rs @@ -64,6 +64,23 @@ fn fields(_1: (Adt, Adt)) { } } +// EMIT_MIR gvn_overlapping.copy_overlapping.GVN.diff +#[custom_mir(dialect = "runtime")] +fn copy_overlapping() { + mir! { + let _1; + let _2; + let _3; + { + place!(Field(Variant(_1, 1), 0)) = 0u32; + _3 = &_1; + _2 = Field(Variant(*_3, 1), 0); + _1 = Adt::Some(_2); + Return() + } + } +} + fn main() { overlapping(Adt::Some(0)); } From 067ecfd551dc146ce49b6f464c9b9b4b4f386a7c Mon Sep 17 00:00:00 2001 From: dianqk Date: Sat, 18 Oct 2025 21:42:12 +0800 Subject: [PATCH 2/4] GVN: Use the borrows only if they are always live --- compiler/rustc_mir_transform/src/gvn.rs | 128 ++++++++++---- tests/mir-opt/const_prop/ref_deref_project.rs | 2 +- ...ng_operand.test.GVN.32bit.panic-abort.diff | 9 +- ...g_operand.test.GVN.32bit.panic-unwind.diff | 9 +- ...ng_operand.test.GVN.64bit.panic-abort.diff | 9 +- ...g_operand.test.GVN.64bit.panic-unwind.diff | 9 +- .../gvn.dereferences.GVN.panic-abort.diff | 30 ++-- .../gvn.dereferences.GVN.panic-unwind.diff | 30 ++-- .../gvn.fn_pointers.GVN.panic-abort.diff | 18 +- .../gvn.fn_pointers.GVN.panic-unwind.diff | 18 +- tests/mir-opt/gvn.rs | 35 ++-- tests/mir-opt/gvn.slices.GVN.panic-abort.diff | 63 +++---- .../mir-opt/gvn.slices.GVN.panic-unwind.diff | 63 +++---- ...xpression_elimination.GVN.panic-abort.diff | 50 ++++-- ...pression_elimination.GVN.panic-unwind.diff | 50 ++++-- .../mir-opt/gvn_clone.{impl#0}-clone.GVN.diff | 18 +- .../gvn_copy_aggregate.all_copy_2.GVN.diff | 16 +- .../gvn_copy_aggregate.deref_nonssa.GVN.diff | 8 +- tests/mir-opt/gvn_copy_aggregate.rs | 10 +- .../mir-opt/gvn_loop.loop_deref_mut.GVN.diff | 12 +- tests/mir-opt/gvn_loop.rs | 3 +- .../gvn_overlapping.copy_overlapping.GVN.diff | 3 +- tests/mir-opt/gvn_overlapping.rs | 34 +++- ...gvn_overlapping.stable_projection.GVN.diff | 3 +- ....stable_projection_nonoverlapping.GVN.diff | 19 ++ ...ef_nested_borrows.src.GVN.panic-abort.diff | 6 +- ...f_nested_borrows.src.GVN.panic-unwind.diff | 5 +- ...rrows.src.PreCodegen.after.panic-abort.mir | 12 +- ...rows.src.PreCodegen.after.panic-unwind.mir | 8 +- ...variant_a-{closure#0}.PreCodegen.after.mir | 164 ++++++++++-------- ...variant_b-{closure#0}.PreCodegen.after.mir | 54 +++--- 31 files changed, 501 insertions(+), 397 deletions(-) create mode 100644 tests/mir-opt/gvn_overlapping.stable_projection_nonoverlapping.GVN.diff diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 8eae80e235ccd..8eca3baf0ca65 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -131,9 +131,19 @@ impl<'tcx> crate::MirPass<'tcx> for GVN { let dominators = body.basic_blocks.dominators().clone(); let maybe_loop_headers = loops::maybe_loop_headers(body); + let immutable_borrows = ImmutableBorrows::new(tcx, body, typing_env, &ssa); + let arena = DroplessArena::default(); - let mut state = - VnState::new(tcx, body, typing_env, &ssa, dominators, &body.local_decls, &arena); + let mut state = VnState::new( + tcx, + body, + typing_env, + &ssa, + dominators, + &body.local_decls, + &arena, + immutable_borrows, + ); for local in body.args_iter().filter(|&local| ssa.is_ssa(local)) { let opaque = state.new_opaque(body.local_decls[local].ty); @@ -204,7 +214,6 @@ enum AddressBase { enum Value<'a, 'tcx> { // Root values. /// Used to represent values we know nothing about. - /// The `usize` is a counter incremented by `new_opaque`. Opaque(VnOpaque), /// Evaluated or unevaluated constant value. Constant { @@ -380,6 +389,7 @@ struct VnState<'body, 'a, 'tcx> { dominators: Dominators, reused_locals: DenseBitSet, arena: &'a DroplessArena, + immutable_borrows: ImmutableBorrows, } impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> { @@ -391,6 +401,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> { dominators: Dominators, local_decls: &'body LocalDecls<'tcx>, arena: &'a DroplessArena, + immutable_borrows: ImmutableBorrows, ) -> 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 @@ -413,6 +424,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> { dominators, reused_locals: DenseBitSet::new_empty(local_decls.len()), arena, + immutable_borrows, } } @@ -420,6 +432,20 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> { self.ecx.typing_env() } + fn insert_unique( + &mut self, + ty: Ty<'tcx>, + evaluated: bool, + value: impl FnOnce(VnOpaque) -> Value<'a, 'tcx>, + ) -> VnIndex { + let index = self.values.insert_unique(ty, value); + let _index = self.evaluated.push(if evaluated { Some(None) } else { None }); + debug_assert_eq!(index, _index); + let _index = self.rev_locals.push(SmallVec::new()); + debug_assert_eq!(index, _index); + index + } + #[instrument(level = "trace", skip(self), ret)] fn insert(&mut self, ty: Ty<'tcx>, value: Value<'a, 'tcx>) -> VnIndex { let (index, new) = self.values.insert(ty, value); @@ -437,12 +463,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> { /// from all the others. #[instrument(level = "trace", skip(self), ret)] fn new_opaque(&mut self, ty: Ty<'tcx>) -> VnIndex { - let index = self.values.insert_unique(ty, Value::Opaque); - let _index = self.evaluated.push(Some(None)); - debug_assert_eq!(index, _index); - let _index = self.rev_locals.push(SmallVec::new()); - debug_assert_eq!(index, _index); - index + self.insert_unique(ty, true, Value::Opaque) } /// Create a new `Value::Address` distinct from all the others. @@ -470,42 +491,30 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> { projection.map(|proj| proj.try_map(|index| self.locals[index], |ty| ty).ok_or(())); let projection = self.arena.try_alloc_from_iter(projection).ok()?; - let index = self.values.insert_unique(ty, |provenance| Value::Address { + let index = self.insert_unique(ty, false, |provenance| Value::Address { base, projection, kind, provenance, }); - let _index = self.evaluated.push(None); - debug_assert_eq!(index, _index); - let _index = self.rev_locals.push(SmallVec::new()); - debug_assert_eq!(index, _index); Some(index) } #[instrument(level = "trace", skip(self), ret)] fn insert_constant(&mut self, value: Const<'tcx>) -> VnIndex { - let (index, new) = if value.is_deterministic() { + if value.is_deterministic() { // The constant is deterministic, no need to disambiguate. let constant = Value::Constant { value, disambiguator: None }; - self.values.insert(value.ty(), constant) + self.insert(value.ty(), constant) } 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 index = self.values.insert_unique(value.ty(), |disambiguator| Value::Constant { + self.insert_unique(value.ty(), false, |disambiguator| Value::Constant { value, disambiguator: Some(disambiguator), - }); - (index, true) - }; - if new { - let _index = self.evaluated.push(None); - debug_assert_eq!(index, _index); - let _index = self.rev_locals.push(SmallVec::new()); - debug_assert_eq!(index, _index); + }) } - index } #[inline] @@ -544,9 +553,12 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> { self.insert(ty, Value::Aggregate(VariantIdx::ZERO, self.arena.alloc_slice(values))) } - fn insert_deref(&mut self, ty: Ty<'tcx>, value: VnIndex) -> VnIndex { + fn insert_deref(&mut self, ty: Ty<'tcx>, value: VnIndex, always_valid: bool) -> VnIndex { let value = self.insert(ty, Value::Projection(value, ProjectionElem::Deref)); - self.derefs.push(value); + // If the borrow lifetime is the whole body, we don't need to invalidate it. + if !always_valid { + self.derefs.push(value); + } value } @@ -818,7 +830,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, '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`. - return Some((projection_ty, self.insert_deref(projection_ty.ty, value))); + return Some((projection_ty, self.insert_deref(projection_ty.ty, value, true))); } else { return None; } @@ -1849,7 +1861,17 @@ impl<'tcx> VnState<'_, '_, 'tcx> { let other = self.rev_locals.get(index)?; other .iter() - .find(|&&other| self.ssa.assignment_dominates(&self.dominators, other, loc)) + .find(|&&other| { + if !self.ssa.assignment_dominates(&self.dominators, other, loc) { + return false; + } + if self.immutable_borrows.locals.contains(other) + && !self.immutable_borrows.always_live.contains(other) + { + return false; + } + return true; + }) .copied() } } @@ -1960,3 +1982,49 @@ impl<'tcx> MutVisitor<'tcx> for StorageRemover<'tcx> { } } } + +struct ImmutableBorrows { + locals: DenseBitSet, + always_live: DenseBitSet, +} + +impl ImmutableBorrows { + fn new<'tcx>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + typing_env: ty::TypingEnv<'tcx>, + ssa: &SsaLocals, + ) -> ImmutableBorrows { + let mut locals: DenseBitSet = DenseBitSet::new_empty(body.local_decls().len()); + for (local, decl) in body.local_decls.iter_enumerated() { + if let Some(Mutability::Not) = decl.ty.ref_mutability() + && ssa.is_ssa(local) + && decl.ty.builtin_deref(true).unwrap().is_freeze(tcx, typing_env) + { + locals.insert(local); + } + } + let mut always_live: DenseBitSet = DenseBitSet::new_empty(body.local_decls().len()); + for local in body.args_iter() { + if locals.contains(local) { + always_live.insert(local); + } + } + let mut always_live_immutable_borrows = ImmutableBorrows { locals, always_live }; + for (bb, bb_data) in body.basic_blocks.iter_enumerated() { + always_live_immutable_borrows.visit_basic_block_data(bb, bb_data); + } + always_live_immutable_borrows + } +} + +impl<'tcx> Visitor<'tcx> for ImmutableBorrows { + fn visit_assign(&mut self, place: &Place<'tcx>, rvalue: &Rvalue<'tcx>, _: Location) { + if let Some(local) = place.as_local() + && self.locals.contains(local) + && let Rvalue::Use(Operand::Constant(_)) = rvalue + { + self.always_live.insert(local); + }; + } +} diff --git a/tests/mir-opt/const_prop/ref_deref_project.rs b/tests/mir-opt/const_prop/ref_deref_project.rs index 5a48a887f93d7..9363a6408c428 100644 --- a/tests/mir-opt/const_prop/ref_deref_project.rs +++ b/tests/mir-opt/const_prop/ref_deref_project.rs @@ -1,6 +1,6 @@ -// This does not currently propagate (#67862) //@ test-mir-pass: GVN +// Checks that GVN knows a is 5. // EMIT_MIR ref_deref_project.main.GVN.diff fn main() { // CHECK-LABEL: fn main( diff --git a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff index 38beb81e1ead2..bfe8d163c9904 100644 --- a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff @@ -74,8 +74,7 @@ bb0: { StorageLive(_1); -- StorageLive(_2); -+ nop; + StorageLive(_2); StorageLive(_3); StorageLive(_4); - _4 = (); @@ -145,12 +144,10 @@ StorageDead(_4); _2 = &_3; _1 = &(*_2); -- StorageDead(_2); + StorageDead(_2); - StorageLive(_5); -- _10 = copy (*_1); -+ nop; + nop; -+ _10 = copy (*_2); + _10 = copy (*_1); _11 = copy ((_10.0: std::ptr::Unique<()>).0: std::ptr::NonNull<()>) as *const () (Transmute); _5 = &raw const (*_11); - StorageLive(_6); diff --git a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-unwind.diff b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-unwind.diff index 82a14a8b6ec99..9a354fc005ed5 100644 --- a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-unwind.diff @@ -37,8 +37,7 @@ bb0: { StorageLive(_1); -- StorageLive(_2); -+ nop; + StorageLive(_2); StorageLive(_3); StorageLive(_4); - _4 = (); @@ -51,12 +50,10 @@ StorageDead(_4); _2 = &_3; _1 = &(*_2); -- StorageDead(_2); + StorageDead(_2); - StorageLive(_5); -- _10 = copy (*_1); -+ nop; + nop; -+ _10 = copy (*_2); + _10 = copy (*_1); _11 = copy ((_10.0: std::ptr::Unique<()>).0: std::ptr::NonNull<()>) as *const () (Transmute); _5 = &raw const (*_11); - StorageLive(_6); diff --git a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff index 047579cdb5094..3f8884d26b602 100644 --- a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff @@ -74,8 +74,7 @@ bb0: { StorageLive(_1); -- StorageLive(_2); -+ nop; + StorageLive(_2); StorageLive(_3); StorageLive(_4); - _4 = (); @@ -145,12 +144,10 @@ StorageDead(_4); _2 = &_3; _1 = &(*_2); -- StorageDead(_2); + StorageDead(_2); - StorageLive(_5); -- _10 = copy (*_1); -+ nop; + nop; -+ _10 = copy (*_2); + _10 = copy (*_1); _11 = copy ((_10.0: std::ptr::Unique<()>).0: std::ptr::NonNull<()>) as *const () (Transmute); _5 = &raw const (*_11); - StorageLive(_6); diff --git a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-unwind.diff b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-unwind.diff index 82a14a8b6ec99..9a354fc005ed5 100644 --- a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-unwind.diff @@ -37,8 +37,7 @@ bb0: { StorageLive(_1); -- StorageLive(_2); -+ nop; + StorageLive(_2); StorageLive(_3); StorageLive(_4); - _4 = (); @@ -51,12 +50,10 @@ StorageDead(_4); _2 = &_3; _1 = &(*_2); -- StorageDead(_2); + StorageDead(_2); - StorageLive(_5); -- _10 = copy (*_1); -+ nop; + nop; -+ _10 = copy (*_2); + _10 = copy (*_1); _11 = copy ((_10.0: std::ptr::Unique<()>).0: std::ptr::NonNull<()>) as *const () (Transmute); _5 = &raw const (*_11); - StorageLive(_6); diff --git a/tests/mir-opt/gvn.dereferences.GVN.panic-abort.diff b/tests/mir-opt/gvn.dereferences.GVN.panic-abort.diff index ecd7bdc433cd9..a763614dc644b 100644 --- a/tests/mir-opt/gvn.dereferences.GVN.panic-abort.diff +++ b/tests/mir-opt/gvn.dereferences.GVN.panic-abort.diff @@ -107,18 +107,23 @@ StorageLive(_18); _18 = &(*_1); StorageLive(_19); - StorageLive(_20); +- StorageLive(_20); ++ nop; _20 = copy (*_18); - _19 = opaque::(move _20) -> [return: bb7, unwind unreachable]; +- _19 = opaque::(move _20) -> [return: bb7, unwind unreachable]; ++ _19 = opaque::(copy _20) -> [return: bb7, unwind unreachable]; } bb7: { - StorageDead(_20); +- StorageDead(_20); ++ nop; StorageDead(_19); StorageLive(_21); StorageLive(_22); - _22 = copy (*_18); - _21 = opaque::(move _22) -> [return: bb8, unwind unreachable]; +- _22 = copy (*_18); +- _21 = opaque::(move _22) -> [return: bb8, unwind unreachable]; ++ _22 = copy _20; ++ _21 = opaque::(copy _20) -> [return: bb8, unwind unreachable]; } bb8: { @@ -152,18 +157,23 @@ StorageDead(_28); StorageDead(_27); StorageLive(_29); - StorageLive(_30); +- StorageLive(_30); ++ nop; _30 = copy ((*_3).0: u32); - _29 = opaque::(move _30) -> [return: bb12, unwind unreachable]; +- _29 = opaque::(move _30) -> [return: bb12, unwind unreachable]; ++ _29 = opaque::(copy _30) -> [return: bb12, unwind unreachable]; } bb12: { - StorageDead(_30); +- StorageDead(_30); ++ nop; StorageDead(_29); StorageLive(_31); StorageLive(_32); - _32 = copy ((*_3).0: u32); - _31 = opaque::(move _32) -> [return: bb13, unwind unreachable]; +- _32 = copy ((*_3).0: u32); +- _31 = opaque::(move _32) -> [return: bb13, unwind unreachable]; ++ _32 = copy _30; ++ _31 = opaque::(copy _30) -> [return: bb13, unwind unreachable]; } bb13: { diff --git a/tests/mir-opt/gvn.dereferences.GVN.panic-unwind.diff b/tests/mir-opt/gvn.dereferences.GVN.panic-unwind.diff index bbca6bc3c754d..ca6fda483642c 100644 --- a/tests/mir-opt/gvn.dereferences.GVN.panic-unwind.diff +++ b/tests/mir-opt/gvn.dereferences.GVN.panic-unwind.diff @@ -107,18 +107,23 @@ StorageLive(_18); _18 = &(*_1); StorageLive(_19); - StorageLive(_20); +- StorageLive(_20); ++ nop; _20 = copy (*_18); - _19 = opaque::(move _20) -> [return: bb7, unwind continue]; +- _19 = opaque::(move _20) -> [return: bb7, unwind continue]; ++ _19 = opaque::(copy _20) -> [return: bb7, unwind continue]; } bb7: { - StorageDead(_20); +- StorageDead(_20); ++ nop; StorageDead(_19); StorageLive(_21); StorageLive(_22); - _22 = copy (*_18); - _21 = opaque::(move _22) -> [return: bb8, unwind continue]; +- _22 = copy (*_18); +- _21 = opaque::(move _22) -> [return: bb8, unwind continue]; ++ _22 = copy _20; ++ _21 = opaque::(copy _20) -> [return: bb8, unwind continue]; } bb8: { @@ -152,18 +157,23 @@ StorageDead(_28); StorageDead(_27); StorageLive(_29); - StorageLive(_30); +- StorageLive(_30); ++ nop; _30 = copy ((*_3).0: u32); - _29 = opaque::(move _30) -> [return: bb12, unwind continue]; +- _29 = opaque::(move _30) -> [return: bb12, unwind continue]; ++ _29 = opaque::(copy _30) -> [return: bb12, unwind continue]; } bb12: { - StorageDead(_30); +- StorageDead(_30); ++ nop; StorageDead(_29); StorageLive(_31); StorageLive(_32); - _32 = copy ((*_3).0: u32); - _31 = opaque::(move _32) -> [return: bb13, unwind continue]; +- _32 = copy ((*_3).0: u32); +- _31 = opaque::(move _32) -> [return: bb13, unwind continue]; ++ _32 = copy _30; ++ _31 = opaque::(copy _30) -> [return: bb13, unwind continue]; } bb13: { 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..8e4660ab7c163 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:610:19: 610: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:610:19: 610: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:610:19: 610: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:610:19: 610:21}; - StorageLive(_8); + nop; -+ _7 = const ZeroSized: {closure@$DIR/gvn.rs:617:19: 617:21}; ++ _7 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610: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:610:19: 610:21}; ++ _8 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610: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:610:19: 610:21}; ++ _12 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610: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..c80b6ec82d034 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:610:19: 610: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:610:19: 610: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:610:19: 610: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:610:19: 610:21}; - StorageLive(_8); + nop; -+ _7 = const ZeroSized: {closure@$DIR/gvn.rs:617:19: 617:21}; ++ _7 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610: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:610:19: 610:21}; ++ _8 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610: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:610:19: 610:21}; ++ _12 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610: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 3c3241fefe22e..598c0386cb126 100644 --- a/tests/mir-opt/gvn.rs +++ b/tests/mir-opt/gvn.rs @@ -99,14 +99,12 @@ 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 too. // CHECK: [[ref:_.*]] = &_3; // CHECK: [[deref:_.*]] = copy (*[[ref]]); - // 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]]) + // CHECK: [[addref:_.*]] = Add(copy [[deref]], copy _1); + // CHECK: opaque::(copy [[addref]]) + // CHECK: opaque::(copy [[addref]]) let a = &z; opaque(*a + x); opaque(*a + x); @@ -139,15 +137,13 @@ fn subexpression_elimination(x: u64, y: u64, mut z: u64) { opaque(*d + x); } - // We still cannot substitute again, and never with the earlier computations. + // We can substitute again, but not 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: [[addref3:_.*]] = Add(move [[deref3]], copy _1); - // CHECK: opaque::(move [[addref3]]) + // CHECK: [[addref2:_.*]] = Add(copy [[deref2]], copy _1); + // CHECK: opaque::(copy [[addref2]]) + // CHECK: opaque::(copy [[addref2]]) let e = &z; opaque(*e + x); opaque(*e + x); @@ -499,16 +495,15 @@ fn dereferences(t: &mut u32, u: &impl Copy, s: &S) { unsafe { opaque(*z) }; unsafe { opaque(*z) }; - // Do not reuse dereferences of `&Freeze`. + // We can reuse dereferences of `&Freeze`. // CHECK: [[ref:_.*]] = &(*_1); // CHECK: [[st7:_.*]] = copy (*[[ref]]); - // CHECK: opaque::(move [[st7]]) - // CHECK: [[st8:_.*]] = copy (*[[ref]]); - // CHECK: opaque::(move [[st8]]) + // CHECK: opaque::(copy [[st7]]) + // CHECK: opaque::(copy [[st7]]) let z = &*t; opaque(*z); opaque(*z); - // Not in reborrows either. + // But not in reborrows. // CHECK: [[reborrow:_.*]] = &(*[[ref]]); // CHECK: opaque::<&u32>(move [[reborrow]]) opaque(&*z); @@ -521,11 +516,9 @@ fn dereferences(t: &mut u32, u: &impl Copy, s: &S) { opaque(*u); opaque(*u); - // `*s` is not Copy, but `(*s).0` is, but we still cannot reuse. // CHECK: [[st10:_.*]] = copy ((*_3).0: u32); - // CHECK: opaque::(move [[st10]]) - // CHECK: [[st11:_.*]] = copy ((*_3).0: u32); - // CHECK: opaque::(move [[st11]]) + // CHECK: opaque::(copy [[st10]]) + // CHECK: opaque::(copy [[st10]]) opaque(s.0); opaque(s.0); } diff --git a/tests/mir-opt/gvn.slices.GVN.panic-abort.diff b/tests/mir-opt/gvn.slices.GVN.panic-abort.diff index 091c3bd5c7b2a..eb6668ff409c6 100644 --- a/tests/mir-opt/gvn.slices.GVN.panic-abort.diff +++ b/tests/mir-opt/gvn.slices.GVN.panic-abort.diff @@ -112,9 +112,8 @@ StorageDead(_5); StorageLive(_7); StorageLive(_8); -- StorageLive(_9); + StorageLive(_9); - StorageLive(_10); -+ nop; + nop; StorageLive(_11); _11 = &(*_1); @@ -124,9 +123,8 @@ bb3: { StorageDead(_11); _9 = &_10; -- StorageLive(_12); + StorageLive(_12); - StorageLive(_13); -+ nop; + nop; StorageLive(_14); - _14 = &(*_4); @@ -137,18 +135,13 @@ bb4: { StorageDead(_14); _12 = &_13; -- _8 = (move _9, move _12); -- StorageDead(_12); -- StorageDead(_9); -+ _8 = (copy _9, copy _12); -+ nop; -+ nop; + _8 = (move _9, move _12); + StorageDead(_12); + StorageDead(_9); StorageLive(_15); -- _15 = copy (_8.0: &*const u8); -+ _15 = copy _9; + _15 = copy (_8.0: &*const u8); StorageLive(_16); -- _16 = copy (_8.1: &*const u8); -+ _16 = copy _12; + _16 = copy (_8.1: &*const u8); StorageLive(_17); StorageLive(_18); - _18 = copy (*_15); @@ -174,8 +167,7 @@ + nop; StorageDead(_8); StorageDead(_7); -- StorageLive(_29); -+ nop; + StorageLive(_29); StorageLive(_30); _30 = &(*_1); _29 = move _30 as &[u8] (Transmute); @@ -183,8 +175,7 @@ StorageLive(_31); StorageLive(_32); _32 = copy _29; -- _31 = opaque::<&[u8]>(move _32) -> [return: bb7, unwind unreachable]; -+ _31 = opaque::<&[u8]>(copy _29) -> [return: bb7, unwind unreachable]; + _31 = opaque::<&[u8]>(move _32) -> [return: bb7, unwind unreachable]; } bb6: { @@ -200,13 +191,11 @@ + _23 = const core::panicking::AssertKind::Eq; StorageLive(_24); StorageLive(_25); -- _25 = &(*_15); -+ _25 = &(*_9); + _25 = &(*_15); _24 = &(*_25); StorageLive(_26); StorageLive(_27); -- _27 = &(*_16); -+ _27 = &(*_12); + _27 = &(*_16); _26 = &(*_27); StorageLive(_28); _28 = Option::>::None; @@ -219,9 +208,8 @@ StorageDead(_31); StorageLive(_33); StorageLive(_34); -- StorageLive(_35); + StorageLive(_35); - StorageLive(_36); -+ nop; + nop; StorageLive(_37); _37 = &(*_1); @@ -231,9 +219,8 @@ bb8: { StorageDead(_37); _35 = &_36; -- StorageLive(_38); + StorageLive(_38); - StorageLive(_39); -+ nop; + nop; StorageLive(_40); _40 = &(*_29); @@ -243,18 +230,13 @@ bb9: { StorageDead(_40); _38 = &_39; -- _34 = (move _35, move _38); -- StorageDead(_38); -- StorageDead(_35); -+ _34 = (copy _35, copy _38); -+ nop; -+ nop; + _34 = (move _35, move _38); + StorageDead(_38); + StorageDead(_35); StorageLive(_41); -- _41 = copy (_34.0: &*const u8); -+ _41 = copy _35; + _41 = copy (_34.0: &*const u8); StorageLive(_42); -- _42 = copy (_34.1: &*const u8); -+ _42 = copy _38; + _42 = copy (_34.1: &*const u8); StorageLive(_43); StorageLive(_44); - _44 = copy (*_41); @@ -281,8 +263,7 @@ StorageDead(_34); StorageDead(_33); _0 = const (); -- StorageDead(_29); -+ nop; + StorageDead(_29); StorageDead(_4); - StorageDead(_1); + nop; @@ -302,13 +283,11 @@ + _49 = const core::panicking::AssertKind::Eq; StorageLive(_50); StorageLive(_51); -- _51 = &(*_41); -+ _51 = &(*_35); + _51 = &(*_41); _50 = &(*_51); StorageLive(_52); StorageLive(_53); -- _53 = &(*_42); -+ _53 = &(*_38); + _53 = &(*_42); _52 = &(*_53); StorageLive(_54); _54 = Option::>::None; diff --git a/tests/mir-opt/gvn.slices.GVN.panic-unwind.diff b/tests/mir-opt/gvn.slices.GVN.panic-unwind.diff index 9768956c9c870..654cad710bca8 100644 --- a/tests/mir-opt/gvn.slices.GVN.panic-unwind.diff +++ b/tests/mir-opt/gvn.slices.GVN.panic-unwind.diff @@ -112,9 +112,8 @@ StorageDead(_5); StorageLive(_7); StorageLive(_8); -- StorageLive(_9); + StorageLive(_9); - StorageLive(_10); -+ nop; + nop; StorageLive(_11); _11 = &(*_1); @@ -124,9 +123,8 @@ bb3: { StorageDead(_11); _9 = &_10; -- StorageLive(_12); + StorageLive(_12); - StorageLive(_13); -+ nop; + nop; StorageLive(_14); - _14 = &(*_4); @@ -137,18 +135,13 @@ bb4: { StorageDead(_14); _12 = &_13; -- _8 = (move _9, move _12); -- StorageDead(_12); -- StorageDead(_9); -+ _8 = (copy _9, copy _12); -+ nop; -+ nop; + _8 = (move _9, move _12); + StorageDead(_12); + StorageDead(_9); StorageLive(_15); -- _15 = copy (_8.0: &*const u8); -+ _15 = copy _9; + _15 = copy (_8.0: &*const u8); StorageLive(_16); -- _16 = copy (_8.1: &*const u8); -+ _16 = copy _12; + _16 = copy (_8.1: &*const u8); StorageLive(_17); StorageLive(_18); - _18 = copy (*_15); @@ -174,8 +167,7 @@ + nop; StorageDead(_8); StorageDead(_7); -- StorageLive(_29); -+ nop; + StorageLive(_29); StorageLive(_30); _30 = &(*_1); _29 = move _30 as &[u8] (Transmute); @@ -183,8 +175,7 @@ StorageLive(_31); StorageLive(_32); _32 = copy _29; -- _31 = opaque::<&[u8]>(move _32) -> [return: bb7, unwind continue]; -+ _31 = opaque::<&[u8]>(copy _29) -> [return: bb7, unwind continue]; + _31 = opaque::<&[u8]>(move _32) -> [return: bb7, unwind continue]; } bb6: { @@ -200,13 +191,11 @@ + _23 = const core::panicking::AssertKind::Eq; StorageLive(_24); StorageLive(_25); -- _25 = &(*_15); -+ _25 = &(*_9); + _25 = &(*_15); _24 = &(*_25); StorageLive(_26); StorageLive(_27); -- _27 = &(*_16); -+ _27 = &(*_12); + _27 = &(*_16); _26 = &(*_27); StorageLive(_28); _28 = Option::>::None; @@ -219,9 +208,8 @@ StorageDead(_31); StorageLive(_33); StorageLive(_34); -- StorageLive(_35); + StorageLive(_35); - StorageLive(_36); -+ nop; + nop; StorageLive(_37); _37 = &(*_1); @@ -231,9 +219,8 @@ bb8: { StorageDead(_37); _35 = &_36; -- StorageLive(_38); + StorageLive(_38); - StorageLive(_39); -+ nop; + nop; StorageLive(_40); _40 = &(*_29); @@ -243,18 +230,13 @@ bb9: { StorageDead(_40); _38 = &_39; -- _34 = (move _35, move _38); -- StorageDead(_38); -- StorageDead(_35); -+ _34 = (copy _35, copy _38); -+ nop; -+ nop; + _34 = (move _35, move _38); + StorageDead(_38); + StorageDead(_35); StorageLive(_41); -- _41 = copy (_34.0: &*const u8); -+ _41 = copy _35; + _41 = copy (_34.0: &*const u8); StorageLive(_42); -- _42 = copy (_34.1: &*const u8); -+ _42 = copy _38; + _42 = copy (_34.1: &*const u8); StorageLive(_43); StorageLive(_44); - _44 = copy (*_41); @@ -281,8 +263,7 @@ StorageDead(_34); StorageDead(_33); _0 = const (); -- StorageDead(_29); -+ nop; + StorageDead(_29); StorageDead(_4); - StorageDead(_1); + nop; @@ -302,13 +283,11 @@ + _49 = const core::panicking::AssertKind::Eq; StorageLive(_50); StorageLive(_51); -- _51 = &(*_41); -+ _51 = &(*_35); + _51 = &(*_41); _50 = &(*_51); StorageLive(_52); StorageLive(_53); -- _53 = &(*_42); -+ _53 = &(*_38); + _53 = &(*_42); _52 = &(*_53); StorageLive(_54); _54 = Option::>::None; 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..7a479bc55da75 100644 --- a/tests/mir-opt/gvn.subexpression_elimination.GVN.panic-abort.diff +++ b/tests/mir-opt/gvn.subexpression_elimination.GVN.panic-abort.diff @@ -758,32 +758,39 @@ StorageLive(_126); _126 = &_3; StorageLive(_127); - StorageLive(_128); - StorageLive(_129); +- StorageLive(_128); +- StorageLive(_129); ++ nop; ++ nop; _129 = copy (*_126); StorageLive(_130); _130 = copy _1; - _128 = Add(move _129, move _130); -+ _128 = Add(move _129, copy _1); ++ _128 = Add(copy _129, copy _1); StorageDead(_130); - StorageDead(_129); - _127 = opaque::(move _128) -> [return: bb35, unwind unreachable]; +- StorageDead(_129); +- _127 = opaque::(move _128) -> [return: bb35, unwind unreachable]; ++ nop; ++ _127 = opaque::(copy _128) -> [return: bb35, unwind unreachable]; } bb35: { - StorageDead(_128); +- StorageDead(_128); ++ nop; StorageDead(_127); StorageLive(_131); StorageLive(_132); StorageLive(_133); - _133 = copy (*_126); +- _133 = copy (*_126); ++ _133 = copy _129; StorageLive(_134); _134 = copy _1; - _132 = Add(move _133, move _134); -+ _132 = Add(move _133, copy _1); ++ _132 = copy _128; StorageDead(_134); StorageDead(_133); - _131 = opaque::(move _132) -> [return: bb36, unwind unreachable]; +- _131 = opaque::(move _132) -> [return: bb36, unwind unreachable]; ++ _131 = opaque::(copy _128) -> [return: bb36, unwind unreachable]; } bb36: { @@ -899,32 +906,39 @@ StorageLive(_163); _163 = &_3; StorageLive(_164); - StorageLive(_165); - StorageLive(_166); +- StorageLive(_165); +- StorageLive(_166); ++ nop; ++ nop; _166 = copy (*_163); StorageLive(_167); _167 = copy _1; - _165 = Add(move _166, move _167); -+ _165 = Add(move _166, copy _1); ++ _165 = Add(copy _166, copy _1); StorageDead(_167); - StorageDead(_166); - _164 = opaque::(move _165) -> [return: bb43, unwind unreachable]; +- StorageDead(_166); +- _164 = opaque::(move _165) -> [return: bb43, unwind unreachable]; ++ nop; ++ _164 = opaque::(copy _165) -> [return: bb43, unwind unreachable]; } bb43: { - StorageDead(_165); +- StorageDead(_165); ++ nop; StorageDead(_164); StorageLive(_168); StorageLive(_169); StorageLive(_170); - _170 = copy (*_163); +- _170 = copy (*_163); ++ _170 = copy _166; StorageLive(_171); _171 = copy _1; - _169 = Add(move _170, move _171); -+ _169 = Add(move _170, copy _1); ++ _169 = copy _165; StorageDead(_171); StorageDead(_170); - _168 = opaque::(move _169) -> [return: bb44, unwind unreachable]; +- _168 = opaque::(move _169) -> [return: bb44, unwind unreachable]; ++ _168 = opaque::(copy _165) -> [return: bb44, unwind unreachable]; } bb44: { 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..3ca5238663c28 100644 --- a/tests/mir-opt/gvn.subexpression_elimination.GVN.panic-unwind.diff +++ b/tests/mir-opt/gvn.subexpression_elimination.GVN.panic-unwind.diff @@ -758,32 +758,39 @@ StorageLive(_126); _126 = &_3; StorageLive(_127); - StorageLive(_128); - StorageLive(_129); +- StorageLive(_128); +- StorageLive(_129); ++ nop; ++ nop; _129 = copy (*_126); StorageLive(_130); _130 = copy _1; - _128 = Add(move _129, move _130); -+ _128 = Add(move _129, copy _1); ++ _128 = Add(copy _129, copy _1); StorageDead(_130); - StorageDead(_129); - _127 = opaque::(move _128) -> [return: bb35, unwind continue]; +- StorageDead(_129); +- _127 = opaque::(move _128) -> [return: bb35, unwind continue]; ++ nop; ++ _127 = opaque::(copy _128) -> [return: bb35, unwind continue]; } bb35: { - StorageDead(_128); +- StorageDead(_128); ++ nop; StorageDead(_127); StorageLive(_131); StorageLive(_132); StorageLive(_133); - _133 = copy (*_126); +- _133 = copy (*_126); ++ _133 = copy _129; StorageLive(_134); _134 = copy _1; - _132 = Add(move _133, move _134); -+ _132 = Add(move _133, copy _1); ++ _132 = copy _128; StorageDead(_134); StorageDead(_133); - _131 = opaque::(move _132) -> [return: bb36, unwind continue]; +- _131 = opaque::(move _132) -> [return: bb36, unwind continue]; ++ _131 = opaque::(copy _128) -> [return: bb36, unwind continue]; } bb36: { @@ -899,32 +906,39 @@ StorageLive(_163); _163 = &_3; StorageLive(_164); - StorageLive(_165); - StorageLive(_166); +- StorageLive(_165); +- StorageLive(_166); ++ nop; ++ nop; _166 = copy (*_163); StorageLive(_167); _167 = copy _1; - _165 = Add(move _166, move _167); -+ _165 = Add(move _166, copy _1); ++ _165 = Add(copy _166, copy _1); StorageDead(_167); - StorageDead(_166); - _164 = opaque::(move _165) -> [return: bb43, unwind continue]; +- StorageDead(_166); +- _164 = opaque::(move _165) -> [return: bb43, unwind continue]; ++ nop; ++ _164 = opaque::(copy _165) -> [return: bb43, unwind continue]; } bb43: { - StorageDead(_165); +- StorageDead(_165); ++ nop; StorageDead(_164); StorageLive(_168); StorageLive(_169); StorageLive(_170); - _170 = copy (*_163); +- _170 = copy (*_163); ++ _170 = copy _166; StorageLive(_171); _171 = copy _1; - _169 = Add(move _170, move _171); -+ _169 = Add(move _170, copy _1); ++ _169 = copy _165; StorageDead(_171); StorageDead(_170); - _168 = opaque::(move _169) -> [return: bb44, unwind continue]; +- _168 = opaque::(move _169) -> [return: bb44, unwind continue]; ++ _168 = opaque::(copy _165) -> [return: bb44, unwind continue]; } bb44: { 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 0f23415ec53bb..9381c7c0af537 100644 --- a/tests/mir-opt/gvn_clone.{impl#0}-clone.GVN.diff +++ b/tests/mir-opt/gvn_clone.{impl#0}-clone.GVN.diff @@ -17,8 +17,7 @@ bb0: { StorageLive(_2); StorageLive(_3); -- StorageLive(_4); -+ nop; + StorageLive(_4); _4 = &((*_1).0: i32); _3 = copy _4; - _2 = copy (*_3); @@ -30,8 +29,7 @@ StorageDead(_3); StorageLive(_5); StorageLive(_6); -- StorageLive(_7); -+ nop; + StorageLive(_7); _7 = &((*_1).1: u64); _6 = copy _7; - _5 = copy (*_6); @@ -43,8 +41,7 @@ StorageDead(_6); StorageLive(_8); StorageLive(_9); -- StorageLive(_10); -+ nop; + StorageLive(_10); _10 = &((*_1).2: [i8; 3]); _9 = copy _10; - _8 = copy (*_9); @@ -55,15 +52,12 @@ bb3: { StorageDead(_9); - _0 = AllCopy { a: move _2, b: move _5, c: move _8 }; -- StorageDead(_10); + _0 = copy (*_1); -+ nop; + StorageDead(_10); StorageDead(_8); -- StorageDead(_7); -+ nop; + StorageDead(_7); StorageDead(_5); -- StorageDead(_4); -+ nop; + StorageDead(_4); StorageDead(_2); return; } diff --git a/tests/mir-opt/gvn_copy_aggregate.all_copy_2.GVN.diff b/tests/mir-opt/gvn_copy_aggregate.all_copy_2.GVN.diff index eed8cb7d62e70..2eeeff56cc778 100644 --- a/tests/mir-opt/gvn_copy_aggregate.all_copy_2.GVN.diff +++ b/tests/mir-opt/gvn_copy_aggregate.all_copy_2.GVN.diff @@ -29,17 +29,13 @@ _8 = copy (*_1); _2 = copy ((*_8).0: i32); - StorageLive(_3); -- _9 = copy (*_1); -- _3 = copy ((*_9).1: u64); -- StorageLive(_4); -- _10 = copy (*_1); -- _4 = copy ((*_10).2: [i8; 3]); + nop; -+ _9 = copy _8; -+ _3 = copy ((*_8).1: u64); + _9 = copy (*_1); + _3 = copy ((*_9).1: u64); +- StorageLive(_4); + nop; -+ _10 = copy _8; -+ _4 = copy ((*_8).2: [i8; 3]); + _10 = copy (*_1); + _4 = copy ((*_10).2: [i8; 3]); StorageLive(_5); _5 = copy _2; StorageLive(_6); @@ -47,7 +43,7 @@ StorageLive(_7); _7 = copy _4; - _0 = AllCopy { a: move _5, b: move _6, c: move _7 }; -+ _0 = copy (*_8); ++ _0 = AllCopy { a: copy _2, b: copy _3, c: copy _4 }; StorageDead(_7); StorageDead(_6); StorageDead(_5); diff --git a/tests/mir-opt/gvn_copy_aggregate.deref_nonssa.GVN.diff b/tests/mir-opt/gvn_copy_aggregate.deref_nonssa.GVN.diff index d17213993282a..d9707e40c0bda 100644 --- a/tests/mir-opt/gvn_copy_aggregate.deref_nonssa.GVN.diff +++ b/tests/mir-opt/gvn_copy_aggregate.deref_nonssa.GVN.diff @@ -21,9 +21,8 @@ bb0: { StorageLive(_1); - _1 = Single(const 0_u8); -- StorageLive(_2); + _1 = const Single(0_u8); -+ nop; + StorageLive(_2); _2 = &_1; - StorageLive(_3); + nop; @@ -37,12 +36,11 @@ StorageLive(_5); _5 = copy _3; - _0 = Single(move _5); -+ _0 = copy (*_2); ++ _0 = Single(copy _3); StorageDead(_5); - StorageDead(_3); -- StorageDead(_2); -+ nop; + nop; + StorageDead(_2); StorageDead(_1); return; } diff --git a/tests/mir-opt/gvn_copy_aggregate.rs b/tests/mir-opt/gvn_copy_aggregate.rs index 39460dc1e6942..49fb5c7ff2bc6 100644 --- a/tests/mir-opt/gvn_copy_aggregate.rs +++ b/tests/mir-opt/gvn_copy_aggregate.rs @@ -24,13 +24,13 @@ fn all_copy(v: &AllCopy) -> AllCopy { AllCopy { a, b, c } } +// FIXME: This can be a dereference of the dereference of `v`. +// This requires that we know the dereference is in its valid liveness. // EMIT_MIR gvn_copy_aggregate.all_copy_2.GVN.diff fn all_copy_2(v: &&AllCopy) -> AllCopy { // CHECK-LABEL: fn all_copy_2( // CHECK: bb0: { - // CHECK-NOT: = AllCopy { {{.*}} }; - // CHECK: [[V1:_.*]] = copy (*_1); - // CHECK: _0 = copy (*[[V1]]); + // CHECK: _0 = AllCopy { {{.*}} }; let a = v.a; let b = v.b; let c = v.c; @@ -264,6 +264,10 @@ pub struct Single(u8); // EMIT_MIR gvn_copy_aggregate.deref_nonssa.GVN.diff fn deref_nonssa() -> Single { + // CHECK-LABEL: fn deref_nonssa( + // CHECK: debug c => [[C:_.*]]; + // CHECK-NOT: _0 = copy (*_{{.*}}); + // CHECK: _0 = Single(copy [[C]]); let mut a = Single(0); let b = &a; let c = (*b).0; diff --git a/tests/mir-opt/gvn_loop.loop_deref_mut.GVN.diff b/tests/mir-opt/gvn_loop.loop_deref_mut.GVN.diff index 92e5ccabedf9e..5eaa78b893985 100644 --- a/tests/mir-opt/gvn_loop.loop_deref_mut.GVN.diff +++ b/tests/mir-opt/gvn_loop.loop_deref_mut.GVN.diff @@ -34,8 +34,7 @@ bb0: { StorageLive(_2); -- StorageLive(_3); -+ nop; + StorageLive(_3); StorageLive(_4); _4 = &(*_1); _3 = get::(move _4) -> [return: bb1, unwind unreachable]; @@ -44,12 +43,10 @@ bb1: { _2 = &(*_3); StorageDead(_4); -- StorageDead(_3); -+ nop; + StorageDead(_3); StorageLive(_5); _5 = const false; -- _8 = discriminant((*_2)); -+ _8 = discriminant((*_3)); + _8 = discriminant((*_2)); switchInt(move _8) -> [0: bb3, otherwise: bb2]; } @@ -59,9 +56,8 @@ bb3: { - StorageLive(_7); -- _7 = copy (((*_2) as V0).0: i32); + nop; -+ _7 = copy (((*_3) as V0).0: i32); + _7 = copy (((*_2) as V0).0: i32); StorageLive(_9); goto -> bb4; } diff --git a/tests/mir-opt/gvn_loop.rs b/tests/mir-opt/gvn_loop.rs index 6e9df55a968dc..4fa18adfcd42d 100644 --- a/tests/mir-opt/gvn_loop.rs +++ b/tests/mir-opt/gvn_loop.rs @@ -14,7 +14,8 @@ pub enum Value { fn loop_deref_mut(val: &mut Value) -> Value { // CHECK-LABEL: fn loop_deref_mut( // CHECK: [[VAL_REF:_.*]] = get::( - // CHECK: [[V:_.*]] = copy (((*[[VAL_REF]]) as V0).0: i32); + // CHECK: [[VAL_REF_2:_.*]] = &(*[[VAL_REF]]); + // CHECK: [[V:_.*]] = copy (((*[[VAL_REF_2]]) as V0).0: i32); // CEHCK-NOT: copy (*[[VAL_REF]]); // CHECK: [[RET:_*]] = Value::V0(copy [[V]]); // CEHCK-NOT: copy (*[[VAL_REF]]); diff --git a/tests/mir-opt/gvn_overlapping.copy_overlapping.GVN.diff b/tests/mir-opt/gvn_overlapping.copy_overlapping.GVN.diff index f13c92e4fd012..7b7537bc9b40e 100644 --- a/tests/mir-opt/gvn_overlapping.copy_overlapping.GVN.diff +++ b/tests/mir-opt/gvn_overlapping.copy_overlapping.GVN.diff @@ -11,8 +11,7 @@ ((_1 as variant#1).0: u32) = const 0_u32; _3 = &_1; _2 = copy (((*_3) as variant#1).0: u32); -- _1 = Adt::Some(copy _2); -+ _1 = copy (*_3); + _1 = Adt::Some(copy _2); return; } } diff --git a/tests/mir-opt/gvn_overlapping.rs b/tests/mir-opt/gvn_overlapping.rs index a41f8ad5fd607..c6db2e87d81e6 100644 --- a/tests/mir-opt/gvn_overlapping.rs +++ b/tests/mir-opt/gvn_overlapping.rs @@ -5,7 +5,7 @@ use std::intrinsics::mir::*; // EMIT_MIR gvn_overlapping.overlapping.GVN.diff -/// Check that we do not create overlapping assignments. +// Check that we do not create overlapping assignments. #[custom_mir(dialect = "runtime")] fn overlapping(_17: Adt) { // CHECK-LABEL: fn overlapping( @@ -25,14 +25,39 @@ fn overlapping(_17: Adt) { } } +// EMIT_MIR gvn_overlapping.stable_projection_nonoverlapping.GVN.diff +// FIXME: We allow dereferences in the RHS if the LHS is a stable projection. +#[custom_mir(dialect = "runtime")] +fn stable_projection_nonoverlapping(_1: (Adt,)) { + // CHECK-LABEL: fn stable_projection_nonoverlapping( + // CHECK: let mut _2: *mut Adt; + // CHECK: let mut _4: &Adt; + // CHECK: (_5.0: Adt) = Adt::Some(copy {{.*}}); + mir! { + let _2: *mut Adt; + let _3: u32; + let _4: &Adt; + let _5: (Adt, ); + { + _2 = core::ptr::addr_of_mut!(_1.0); + _4 = &(*_2); + _3 = Field(Variant((*_4), 1), 0); + _5.0 = Adt::Some(_3); + Return() + } + } +} + // EMIT_MIR gvn_overlapping.stable_projection.GVN.diff -/// Check that we allow dereferences in the RHS if the LHS is a stable projection. +// This introduces copy overlapping if dereferencing `_2` or `_4`. #[custom_mir(dialect = "runtime")] fn stable_projection(_1: (Adt,)) { // CHECK-LABEL: fn stable_projection( // CHECK: let mut _2: *mut Adt; // CHECK: let mut _4: &Adt; - // CHECK: (_1.0: Adt) = copy (*_4); + // CHECK-NOT: (_1.0: Adt) = copy (*_2); + // CHECK: (_1.0: Adt) = Adt::Some(copy {{.*}}); + // CHECK-NOT: (_1.0: Adt) = copy (*_2); mir! { let _2: *mut Adt; let _3: u32; @@ -67,6 +92,9 @@ fn fields(_1: (Adt, Adt)) { // EMIT_MIR gvn_overlapping.copy_overlapping.GVN.diff #[custom_mir(dialect = "runtime")] fn copy_overlapping() { + // CHECK-LABEL: fn copy_overlapping( + // CHECK-NOT: _1 = copy (*_{{.*}}); + // CHECK: _1 = Adt::Some(copy _2); mir! { let _1; let _2; diff --git a/tests/mir-opt/gvn_overlapping.stable_projection.GVN.diff b/tests/mir-opt/gvn_overlapping.stable_projection.GVN.diff index 0883545659113..9bfb0ba2d584f 100644 --- a/tests/mir-opt/gvn_overlapping.stable_projection.GVN.diff +++ b/tests/mir-opt/gvn_overlapping.stable_projection.GVN.diff @@ -11,8 +11,7 @@ _2 = &raw mut (_1.0: Adt); _4 = &(*_2); _3 = copy (((*_4) as variant#1).0: u32); -- (_1.0: Adt) = Adt::Some(copy _3); -+ (_1.0: Adt) = copy (*_4); + (_1.0: Adt) = Adt::Some(copy _3); return; } } diff --git a/tests/mir-opt/gvn_overlapping.stable_projection_nonoverlapping.GVN.diff b/tests/mir-opt/gvn_overlapping.stable_projection_nonoverlapping.GVN.diff new file mode 100644 index 0000000000000..c3acb57aa29da --- /dev/null +++ b/tests/mir-opt/gvn_overlapping.stable_projection_nonoverlapping.GVN.diff @@ -0,0 +1,19 @@ +- // MIR for `stable_projection_nonoverlapping` before GVN ++ // MIR for `stable_projection_nonoverlapping` after GVN + + fn stable_projection_nonoverlapping(_1: (Adt,)) -> () { + let mut _0: (); + let mut _2: *mut Adt; + let mut _3: u32; + let mut _4: &Adt; + let mut _5: (Adt,); + + bb0: { + _2 = &raw mut (_1.0: Adt); + _4 = &(*_2); + _3 = copy (((*_4) as variant#1).0: u32); + (_5.0: Adt) = Adt::Some(copy _3); + return; + } + } + diff --git a/tests/mir-opt/pre-codegen/deref_nested_borrows.src.GVN.panic-abort.diff b/tests/mir-opt/pre-codegen/deref_nested_borrows.src.GVN.panic-abort.diff index 269af438e37ef..72d77368fca8c 100644 --- a/tests/mir-opt/pre-codegen/deref_nested_borrows.src.GVN.panic-abort.diff +++ b/tests/mir-opt/pre-codegen/deref_nested_borrows.src.GVN.panic-abort.diff @@ -24,8 +24,10 @@ bb1: { StorageLive(_4); - _7 = copy (*_1); - _4 = copy (*_7); +- _7 = copy (*_1); +- _4 = copy (*_7); ++ _7 = copy _6; ++ _4 = copy (*_6); StorageLive(_5); _5 = copy _2; - _0 = Eq(move _4, move _5); diff --git a/tests/mir-opt/pre-codegen/deref_nested_borrows.src.GVN.panic-unwind.diff b/tests/mir-opt/pre-codegen/deref_nested_borrows.src.GVN.panic-unwind.diff index 9ce17342a445c..dcf91435d486d 100644 --- a/tests/mir-opt/pre-codegen/deref_nested_borrows.src.GVN.panic-unwind.diff +++ b/tests/mir-opt/pre-codegen/deref_nested_borrows.src.GVN.panic-unwind.diff @@ -25,11 +25,12 @@ bb1: { StorageLive(_4); _7 = copy (*_1); - _4 = copy (*_7); +- _4 = copy (*_7); ++ _4 = copy _2; StorageLive(_5); _5 = copy _2; - _0 = Eq(move _4, move _5); -+ _0 = Eq(move _4, copy _2); ++ _0 = const true; StorageDead(_5); StorageDead(_4); - StorageDead(_2); diff --git a/tests/mir-opt/pre-codegen/deref_nested_borrows.src.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/deref_nested_borrows.src.PreCodegen.after.panic-abort.mir index 23b1c3f3f43ad..694108dcebde1 100644 --- a/tests/mir-opt/pre-codegen/deref_nested_borrows.src.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/deref_nested_borrows.src.PreCodegen.after.panic-abort.mir @@ -6,8 +6,7 @@ fn src(_1: &&u8) -> bool { let mut _2: &u8; let _3: u8; let _4: (); - let mut _5: &u8; - let mut _6: u8; + let mut _5: u8; scope 1 { debug y => _3; } @@ -19,11 +18,10 @@ fn src(_1: &&u8) -> bool { } bb1: { - StorageLive(_6); - _5 = copy (*_1); - _6 = copy (*_5); - _0 = Eq(move _6, copy _3); - StorageDead(_6); + StorageLive(_5); + _5 = copy (*_2); + _0 = Eq(move _5, copy _3); + StorageDead(_5); return; } } diff --git a/tests/mir-opt/pre-codegen/deref_nested_borrows.src.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/deref_nested_borrows.src.PreCodegen.after.panic-unwind.mir index 4c01e9464bf49..7fab6e5511fd8 100644 --- a/tests/mir-opt/pre-codegen/deref_nested_borrows.src.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/deref_nested_borrows.src.PreCodegen.after.panic-unwind.mir @@ -6,8 +6,6 @@ fn src(_1: &&u8) -> bool { let mut _2: &u8; let _3: u8; let _4: (); - let mut _5: &u8; - let mut _6: u8; scope 1 { debug y => _3; } @@ -19,11 +17,7 @@ fn src(_1: &&u8) -> bool { } bb1: { - StorageLive(_6); - _5 = copy (*_1); - _6 = copy (*_5); - _0 = Eq(move _6, copy _3); - StorageDead(_6); + _0 = const true; 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 2cab88182962f..346f6fafa9573 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 @@ -3,134 +3,148 @@ fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:7:25: 7:39}, _2: &&(usize, usize, usize, usize)) -> bool { let mut _0: bool; let mut _3: &(usize, usize, usize, usize); - let mut _6: bool; + let mut _4: &(usize, usize, usize, usize); + let mut _5: &(usize, usize, usize, usize); + let mut _6: &(usize, usize, usize, usize); let mut _9: bool; - let mut _10: bool; - let _13: &usize; - let _14: &usize; - let _15: &usize; + let mut _12: bool; + let mut _13: bool; let _16: &usize; - let mut _17: &&usize; - let mut _18: &&usize; - let mut _19: &&usize; + let _17: &usize; + let _18: &usize; + let _19: &usize; let mut _20: &&usize; let mut _21: &&usize; let mut _22: &&usize; let mut _23: &&usize; let mut _24: &&usize; + let mut _25: &&usize; + let mut _26: &&usize; + let mut _27: &&usize; scope 1 { - debug a => _13; - debug b => _14; - debug c => _15; - debug d => _16; + debug a => _16; + debug b => _17; + debug c => _18; + debug d => _19; scope 2 (inlined std::cmp::impls::::le) { - debug self => _17; - debug other => _18; + debug self => _20; + debug other => _21; scope 3 (inlined std::cmp::impls::::le) { - debug self => _13; - debug other => _15; - let mut _4: usize; - let mut _5: usize; + debug self => _16; + debug other => _18; + let mut _7: usize; + let mut _8: usize; } } scope 4 (inlined std::cmp::impls::::le) { - debug self => _19; - debug other => _20; + debug self => _22; + debug other => _23; scope 5 (inlined std::cmp::impls::::le) { - debug self => _16; - debug other => _14; - let mut _7: usize; - let mut _8: usize; + debug self => _19; + debug other => _17; + let mut _10: usize; + let mut _11: usize; } } scope 6 (inlined std::cmp::impls::::le) { - debug self => _21; - debug other => _22; + debug self => _24; + debug other => _25; scope 7 (inlined std::cmp::impls::::le) { - debug self => _15; - debug other => _13; + debug self => _18; + debug other => _16; } } scope 8 (inlined std::cmp::impls::::le) { - debug self => _23; - debug other => _24; + debug self => _26; + debug other => _27; scope 9 (inlined std::cmp::impls::::le) { - debug self => _14; - debug other => _16; - let mut _11: usize; - let mut _12: usize; + debug self => _17; + debug other => _19; + let mut _14: usize; + let mut _15: usize; } } } bb0: { _3 = copy (*_2); - // DBG: _13 = &((*_3).0: usize); - // DBG: _14 = &((*_3).1: usize); - // DBG: _15 = &((*_3).2: usize); - // DBG: _16 = &((*_3).3: usize); - StorageLive(_6); - // DBG: _17 = &_13; - // DBG: _18 = &?; - _4 = copy ((*_3).0: usize); - _5 = copy ((*_3).2: usize); - _6 = Le(copy _4, copy _5); - switchInt(move _6) -> [0: bb2, otherwise: bb1]; + // DBG: _16 = &((*_3).0: usize); + _4 = copy (*_2); + // DBG: _17 = &((*_4).1: usize); + _5 = copy (*_2); + // DBG: _18 = &((*_5).2: usize); + _6 = copy (*_2); + // DBG: _19 = &((*_6).3: usize); + StorageLive(_9); + // DBG: _20 = &_16; + // DBG: _21 = &_18; + _7 = copy ((*_3).0: usize); + _8 = copy ((*_5).2: usize); + _9 = Le(copy _7, copy _8); + switchInt(move _9) -> [0: bb1, otherwise: bb2]; } bb1: { - StorageLive(_9); - // DBG: _19 = &_16; - // DBG: _20 = &?; - StorageLive(_7); - _7 = copy ((*_3).3: usize); - StorageLive(_8); - _8 = copy ((*_3).1: usize); - _9 = Le(move _7, move _8); - StorageDead(_8); - StorageDead(_7); - switchInt(move _9) -> [0: bb2, otherwise: bb6]; + goto -> bb4; } bb2: { + StorageLive(_12); + // DBG: _22 = &_19; + // DBG: _23 = &_17; StorageLive(_10); - // DBG: _21 = &_15; - // DBG: _22 = &?; - _10 = Le(copy _5, copy _4); - switchInt(move _10) -> [0: bb3, otherwise: bb4]; + _10 = copy ((*_6).3: usize); + StorageLive(_11); + _11 = copy ((*_4).1: usize); + _12 = Le(move _10, move _11); + StorageDead(_11); + StorageDead(_10); + switchInt(move _12) -> [0: bb3, otherwise: bb8]; } bb3: { - _0 = const false; - goto -> bb5; + goto -> bb4; } bb4: { - // DBG: _23 = &_14; - // DBG: _24 = &?; - StorageLive(_11); - _11 = copy ((*_3).1: usize); - StorageLive(_12); - _12 = copy ((*_3).3: usize); - _0 = Le(move _11, move _12); - StorageDead(_12); - StorageDead(_11); - goto -> bb5; + StorageLive(_13); + // DBG: _24 = &_18; + // DBG: _25 = &_16; + _13 = Le(copy _8, copy _7); + switchInt(move _13) -> [0: bb5, otherwise: bb6]; } bb5: { - StorageDead(_10); + _0 = const false; goto -> bb7; } bb6: { - _0 = const true; + // DBG: _26 = &_17; + // DBG: _27 = &_19; + StorageLive(_14); + _14 = copy ((*_4).1: usize); + StorageLive(_15); + _15 = copy ((*_6).3: usize); + _0 = Le(move _14, move _15); + StorageDead(_15); + StorageDead(_14); goto -> bb7; } bb7: { + StorageDead(_13); + goto -> bb9; + } + + bb8: { + _0 = const true; + goto -> bb9; + } + + bb9: { + StorageDead(_12); StorageDead(_9); - StorageDead(_6); 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 bc7a31d52199b..f93f7264dec20 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,40 +4,46 @@ 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 _5: usize; + let mut _5: &(usize, usize, usize, usize); let _6: usize; - let _7: usize; - let mut _8: bool; - let mut _9: bool; - let mut _10: bool; + 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; scope 1 { debug a => _4; - debug b => _5; - debug c => _6; - debug d => _7; + debug b => _6; + debug c => _8; + debug d => _10; } bb0: { _3 = copy (*_2); _4 = copy ((*_3).0: usize); - _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]; + _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]; } bb1: { - StorageLive(_9); - _9 = Le(copy _7, copy _5); - switchInt(move _9) -> [0: bb2, otherwise: bb6]; + StorageLive(_12); + _12 = Le(copy _10, copy _6); + switchInt(move _12) -> [0: bb2, otherwise: bb6]; } bb2: { - StorageLive(_10); - _10 = Le(copy _6, copy _4); - switchInt(move _10) -> [0: bb3, otherwise: bb4]; + StorageLive(_13); + _13 = Le(copy _8, copy _4); + switchInt(move _13) -> [0: bb3, otherwise: bb4]; } bb3: { @@ -46,12 +52,12 @@ fn variant_b::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:11:25: 11:41}, } bb4: { - _0 = Le(copy _5, copy _7); + _0 = Le(copy _6, copy _10); goto -> bb5; } bb5: { - StorageDead(_10); + StorageDead(_13); goto -> bb7; } @@ -61,8 +67,8 @@ fn variant_b::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:11:25: 11:41}, } bb7: { - StorageDead(_9); - StorageDead(_8); + StorageDead(_12); + StorageDead(_11); return; } } From 6064a9027840eb5fa0851d3691d37d869f33546c Mon Sep 17 00:00:00 2001 From: dianqk Date: Tue, 21 Oct 2025 20:06:44 +0800 Subject: [PATCH 3/4] GVN: Remove unused invalidate_derefs --- compiler/rustc_middle/src/mir/terminator.rs | 22 ---------- compiler/rustc_mir_transform/src/gvn.rs | 45 ++------------------- 2 files changed, 3 insertions(+), 64 deletions(-) diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index db8251c7d9dc8..e5cf37f0abb49 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -696,28 +696,6 @@ impl<'tcx> TerminatorKind<'tcx> { _ => None, } } - - /// Returns true if the terminator can write to memory. - pub fn can_write_to_memory(&self) -> bool { - match self { - TerminatorKind::Goto { .. } - | TerminatorKind::SwitchInt { .. } - | TerminatorKind::UnwindResume - | TerminatorKind::UnwindTerminate(_) - | TerminatorKind::Return - | TerminatorKind::Assert { .. } - | TerminatorKind::CoroutineDrop - | TerminatorKind::FalseEdge { .. } - | TerminatorKind::FalseUnwind { .. } - | TerminatorKind::Unreachable => false, - TerminatorKind::Call { .. } - | TerminatorKind::Drop { .. } - | TerminatorKind::TailCall { .. } - // Yield writes to the resume_arg place. - | TerminatorKind::Yield { .. } - | TerminatorKind::InlineAsm { .. } => true, - } - } } #[derive(Copy, Clone, Debug)] diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 8eca3baf0ca65..dc551d8b966f6 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -129,7 +129,6 @@ impl<'tcx> crate::MirPass<'tcx> for GVN { let ssa = SsaLocals::new(tcx, body, typing_env); // Clone dominators because we need them while mutating the body. let dominators = body.basic_blocks.dominators().clone(); - let maybe_loop_headers = loops::maybe_loop_headers(body); let immutable_borrows = ImmutableBorrows::new(tcx, body, typing_env, &ssa); @@ -152,11 +151,6 @@ impl<'tcx> crate::MirPass<'tcx> for GVN { let reverse_postorder = body.basic_blocks.reverse_postorder().to_vec(); for bb in reverse_postorder { - // N.B. With loops, reverse postorder cannot produce a valid topological order. - // A statement or terminator from inside the loop, that is not processed yet, may have performed an indirect write. - if maybe_loop_headers.contains(bb) { - state.invalidate_derefs(); - } let data = &mut body.basic_blocks.as_mut_preserves_cfg()[bb]; state.visit_basic_block_data(bb, data); } @@ -359,12 +353,6 @@ impl<'a, 'tcx> ValueSet<'a, 'tcx> { fn ty(&self, index: VnIndex) -> Ty<'tcx> { self.types[index] } - - /// Replace the value associated with `index` with an opaque value. - #[inline] - fn forget(&mut self, index: VnIndex) { - self.values[index] = Value::Opaque(VnOpaque); - } } struct VnState<'body, 'a, 'tcx> { @@ -383,8 +371,6 @@ struct VnState<'body, 'a, 'tcx> { /// - `Some(None)` are values for which computation has failed; /// - `Some(Some(op))` are successful computations. evaluated: IndexVec>>>, - /// Cache the deref values. - derefs: Vec, ssa: &'body SsaLocals, dominators: Dominators, reused_locals: DenseBitSet, @@ -419,7 +405,6 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> { rev_locals: IndexVec::with_capacity(num_values), values: ValueSet::new(num_values), evaluated: IndexVec::with_capacity(num_values), - derefs: Vec::new(), ssa, dominators, reused_locals: DenseBitSet::new_empty(local_decls.len()), @@ -553,19 +538,8 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> { self.insert(ty, Value::Aggregate(VariantIdx::ZERO, self.arena.alloc_slice(values))) } - fn insert_deref(&mut self, ty: Ty<'tcx>, value: VnIndex, always_valid: bool) -> VnIndex { - let value = self.insert(ty, Value::Projection(value, ProjectionElem::Deref)); - // If the borrow lifetime is the whole body, we don't need to invalidate it. - if !always_valid { - self.derefs.push(value); - } - value - } - - fn invalidate_derefs(&mut self) { - for deref in std::mem::take(&mut self.derefs) { - self.values.forget(deref); - } + fn insert_deref(&mut self, ty: Ty<'tcx>, value: VnIndex) -> VnIndex { + self.insert(ty, Value::Projection(value, ProjectionElem::Deref)) } #[instrument(level = "trace", skip(self), ret)] @@ -830,7 +804,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, '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`. - return Some((projection_ty, self.insert_deref(projection_ty.ty, value, true))); + return Some((projection_ty, self.insert_deref(projection_ty.ty, value))); } else { return None; } @@ -1883,10 +1857,6 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, '_, 'tcx> { 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(); - } self.super_place(place, context, location); } @@ -1916,11 +1886,6 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, '_, 'tcx> { } } - if lhs.is_indirect() { - // Non-local mutation maybe invalidate deref. - self.invalidate_derefs(); - } - if let Some(local) = lhs.as_local() && self.ssa.is_ssa(local) && let rvalue_ty = rvalue.ty(self.local_decls, self.tcx) @@ -1943,10 +1908,6 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, '_, 'tcx> { self.assign(local, opaque); } } - // Terminators that can write to memory may invalidate (nested) derefs. - if terminator.kind.can_write_to_memory() { - self.invalidate_derefs(); - } self.super_terminator(terminator, location); } } From c8fbb6250cc434c0558999b3553f3d7796489e7c Mon Sep 17 00:00:00 2001 From: dianqk Date: Mon, 27 Oct 2025 21:43:11 +0800 Subject: [PATCH 4/4] GVN: Avoid merging borrows from the dereferenced value --- compiler/rustc_mir_transform/src/gvn.rs | 48 +++++++++++++++---- .../pre-codegen/deref_nested_borrows.rs | 8 ++++ ...ef_nested_borrows.src.GVN.panic-abort.diff | 6 +-- ...f_nested_borrows.src.GVN.panic-unwind.diff | 5 +- ...rrows.src.PreCodegen.after.panic-abort.mir | 12 +++-- ...rows.src.PreCodegen.after.panic-unwind.mir | 8 +++- 6 files changed, 64 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index dc551d8b966f6..b85c0ad49d2b8 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -246,7 +246,13 @@ enum Value<'a, 'tcx> { // Extractions. /// This is the *value* obtained by projecting another value. - Projection(VnIndex, ProjectionElem), + Projection { + base: VnIndex, + elem: ProjectionElem, + /// Some values may be a borrow or pointer. + /// Give them a different provenance, so we don't merge them. + provenance: Option, + }, /// Discriminant of the given value. Discriminant(VnIndex), @@ -295,6 +301,7 @@ impl<'a, 'tcx> ValueSet<'a, 'tcx> { debug_assert!(match value { Value::Opaque(_) | Value::Address { .. } => true, Value::Constant { disambiguator, .. } => disambiguator.is_some(), + Value::Projection { provenance, .. } => provenance.is_some(), _ => false, }); @@ -539,7 +546,18 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> { } fn insert_deref(&mut self, ty: Ty<'tcx>, value: VnIndex) -> VnIndex { - self.insert(ty, Value::Projection(value, ProjectionElem::Deref)) + if ty.is_any_ptr() { + // Give each borrow and pointer a different provenance, so we don't merge them. + return self.insert_unique(ty, true, |provenance| Value::Projection { + base: value, + elem: ProjectionElem::Deref, + provenance: Some(provenance), + }); + } + self.insert( + ty, + Value::Projection { base: value, elem: ProjectionElem::Deref, provenance: None }, + ) } #[instrument(level = "trace", skip(self), ret)] @@ -622,7 +640,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> { ImmTy::from_immediate(ptr_imm, ty).into() } - Projection(base, elem) => { + Projection { base, elem, .. } => { let base = self.eval_to_const(base)?; // `Index` by constants should have been replaced by `ConstantIndex` by // `simplify_place_projection`. @@ -813,8 +831,9 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> { ProjectionElem::Field(f, _) => match self.get(value) { Value::Aggregate(_, fields) => return Some((projection_ty, fields[f.as_usize()])), Value::Union(active, field) if active == f => return Some((projection_ty, field)), - Value::Projection(outer_value, ProjectionElem::Downcast(_, read_variant)) - if let Value::Aggregate(written_variant, fields) = self.get(outer_value) + Value::Projection { + base, elem: ProjectionElem::Downcast(_, read_variant), .. + } if let Value::Aggregate(written_variant, fields) = self.get(base) // 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 // ``` @@ -867,7 +886,10 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> { ProjectionElem::UnwrapUnsafeBinder(_) => ProjectionElem::UnwrapUnsafeBinder(()), }; - let value = self.insert(projection_ty.ty, Value::Projection(value, proj)); + let value = self.insert( + projection_ty.ty, + Value::Projection { base: value, elem: proj, provenance: None }, + ); Some((projection_ty, value)) } @@ -1096,11 +1118,17 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, '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 { base: 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 { + base: pointer, + elem: ProjectionElem::Field(from_index, _), + .. + } = self.get(v) && copy_from_value == pointer && from_index.index() == index { @@ -1112,7 +1140,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, '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 { base: pointer, elem: proj, .. } = self.get(copy_from_value) && let ProjectionElem::Downcast(_, read_variant) = proj { if variant_index == read_variant { @@ -1817,7 +1845,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 { base: pointer, elem: proj, .. } = self.get(index) && (allow_complex_projection || proj.is_stable_offset()) && let Some(proj) = self.try_as_place_elem(self.ty(index), proj, loc) { diff --git a/tests/mir-opt/pre-codegen/deref_nested_borrows.rs b/tests/mir-opt/pre-codegen/deref_nested_borrows.rs index 738cd981ae674..23ad0189a66de 100644 --- a/tests/mir-opt/pre-codegen/deref_nested_borrows.rs +++ b/tests/mir-opt/pre-codegen/deref_nested_borrows.rs @@ -2,6 +2,14 @@ fn src(x: &&u8) -> bool { // CHECK-LABEL: fn src( + // CHECK: debug y => [[Y:_.*]]; + // CHECK: bb0: + // CHECK: [[BORROW_u8:_.*]] = copy (*_1); + // CHECK: [[Y]] = copy (*[[BORROW_u8]]); + // CHECK: bb1: + // BORROW_u8 outside its lifetime in bb1. + // CHECK-NOT: copy (*[[BORROW_u8]]); + // CHECK: copy (*_1); // CHECK-NOT: _0 = const true; // CHECK: _0 = Eq({{.*}}, {{.*}}); // CHECK-NOT: _0 = const true; diff --git a/tests/mir-opt/pre-codegen/deref_nested_borrows.src.GVN.panic-abort.diff b/tests/mir-opt/pre-codegen/deref_nested_borrows.src.GVN.panic-abort.diff index 72d77368fca8c..269af438e37ef 100644 --- a/tests/mir-opt/pre-codegen/deref_nested_borrows.src.GVN.panic-abort.diff +++ b/tests/mir-opt/pre-codegen/deref_nested_borrows.src.GVN.panic-abort.diff @@ -24,10 +24,8 @@ bb1: { StorageLive(_4); -- _7 = copy (*_1); -- _4 = copy (*_7); -+ _7 = copy _6; -+ _4 = copy (*_6); + _7 = copy (*_1); + _4 = copy (*_7); StorageLive(_5); _5 = copy _2; - _0 = Eq(move _4, move _5); diff --git a/tests/mir-opt/pre-codegen/deref_nested_borrows.src.GVN.panic-unwind.diff b/tests/mir-opt/pre-codegen/deref_nested_borrows.src.GVN.panic-unwind.diff index dcf91435d486d..9ce17342a445c 100644 --- a/tests/mir-opt/pre-codegen/deref_nested_borrows.src.GVN.panic-unwind.diff +++ b/tests/mir-opt/pre-codegen/deref_nested_borrows.src.GVN.panic-unwind.diff @@ -25,12 +25,11 @@ bb1: { StorageLive(_4); _7 = copy (*_1); -- _4 = copy (*_7); -+ _4 = copy _2; + _4 = copy (*_7); StorageLive(_5); _5 = copy _2; - _0 = Eq(move _4, move _5); -+ _0 = const true; ++ _0 = Eq(move _4, copy _2); StorageDead(_5); StorageDead(_4); - StorageDead(_2); diff --git a/tests/mir-opt/pre-codegen/deref_nested_borrows.src.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/deref_nested_borrows.src.PreCodegen.after.panic-abort.mir index 694108dcebde1..23b1c3f3f43ad 100644 --- a/tests/mir-opt/pre-codegen/deref_nested_borrows.src.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/deref_nested_borrows.src.PreCodegen.after.panic-abort.mir @@ -6,7 +6,8 @@ fn src(_1: &&u8) -> bool { let mut _2: &u8; let _3: u8; let _4: (); - let mut _5: u8; + let mut _5: &u8; + let mut _6: u8; scope 1 { debug y => _3; } @@ -18,10 +19,11 @@ fn src(_1: &&u8) -> bool { } bb1: { - StorageLive(_5); - _5 = copy (*_2); - _0 = Eq(move _5, copy _3); - StorageDead(_5); + StorageLive(_6); + _5 = copy (*_1); + _6 = copy (*_5); + _0 = Eq(move _6, copy _3); + StorageDead(_6); return; } } diff --git a/tests/mir-opt/pre-codegen/deref_nested_borrows.src.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/deref_nested_borrows.src.PreCodegen.after.panic-unwind.mir index 7fab6e5511fd8..4c01e9464bf49 100644 --- a/tests/mir-opt/pre-codegen/deref_nested_borrows.src.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/deref_nested_borrows.src.PreCodegen.after.panic-unwind.mir @@ -6,6 +6,8 @@ fn src(_1: &&u8) -> bool { let mut _2: &u8; let _3: u8; let _4: (); + let mut _5: &u8; + let mut _6: u8; scope 1 { debug y => _3; } @@ -17,7 +19,11 @@ fn src(_1: &&u8) -> bool { } bb1: { - _0 = const true; + StorageLive(_6); + _5 = copy (*_1); + _6 = copy (*_5); + _0 = Eq(move _6, copy _3); + StorageDead(_6); return; } }