From 27da40721d336ac87ee084664c9f6c4e9f7c436d Mon Sep 17 00:00:00 2001 From: dianqk Date: Sun, 8 Jun 2025 15:30:09 +0800 Subject: [PATCH 1/8] mir: Introduce an empty `StmtDebugInfo` --- .../rustc_borrowck/src/diagnostics/mutability_errors.rs | 1 - compiler/rustc_middle/src/mir/mod.rs | 2 +- compiler/rustc_middle/src/mir/statement.rs | 7 ++++++- compiler/rustc_middle/src/mir/visit.rs | 3 ++- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index a06540f832507..4d7f0c79496ff 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -1146,7 +1146,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let opt_assignment_rhs_span = self.find_assignments(local).first().map(|&location| { if let Some(mir::Statement { - source_info: _, kind: mir::StatementKind::Assign(box ( _, diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index e819aa2d8f815..fbd70f8ecb910 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1710,7 +1710,7 @@ mod size_asserts { static_assert_size!(BasicBlockData<'_>, 128); static_assert_size!(LocalDecl<'_>, 40); static_assert_size!(SourceScopeData<'_>, 64); - static_assert_size!(Statement<'_>, 32); + static_assert_size!(Statement<'_>, 56); static_assert_size!(Terminator<'_>, 96); static_assert_size!(VarDebugInfo<'_>, 88); // tidy-alphabetical-end diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index 683d7b486171f..f05b70f51482c 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -15,17 +15,19 @@ use crate::ty::CoroutineArgsExt; pub struct Statement<'tcx> { pub source_info: SourceInfo, pub kind: StatementKind<'tcx>, + pub debug_info: Vec, } impl<'tcx> Statement<'tcx> { /// Changes a statement to a nop. This is both faster than deleting instructions and avoids /// invalidating statement indices in `Location`s. pub fn make_nop(&mut self) { + // TODO: convert the stmt to debuginfo. self.kind = StatementKind::Nop } pub fn new(source_info: SourceInfo, kind: StatementKind<'tcx>) -> Self { - Statement { source_info, kind } + Statement { source_info, kind, debug_info: Vec::new() } } } @@ -939,3 +941,6 @@ impl RawPtrKind { } } } + +#[derive(Debug, Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] +pub struct StmtDebugInfo {} diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 929ebe1aee181..128491f652404 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -381,7 +381,8 @@ macro_rules! make_mir_visitor { statement: & $($mutability)? Statement<'tcx>, location: Location ) { - let Statement { source_info, kind } = statement; + // TODO: visit debuginfo + let Statement { source_info, kind, .. } = statement; self.visit_source_info(source_info); match kind { From d33935bb6cf184d582ce936d07bf8b5aaf132dde Mon Sep 17 00:00:00 2001 From: dianqk Date: Wed, 11 Jun 2025 21:38:52 +0800 Subject: [PATCH 2/8] mir-opt: Eliminate dead ref statements --- compiler/rustc_middle/src/mir/mod.rs | 46 +++- compiler/rustc_middle/src/mir/pretty.rs | 16 ++ compiler/rustc_middle/src/mir/statement.rs | 30 ++- compiler/rustc_middle/src/mir/visit.rs | 55 ++++- compiler/rustc_mir_dataflow/src/debuginfo.rs | 10 +- .../rustc_mir_dataflow/src/impls/liveness.rs | 78 +++--- .../src/cleanup_post_borrowck.rs | 4 +- compiler/rustc_mir_transform/src/copy_prop.rs | 4 +- compiler/rustc_mir_transform/src/coroutine.rs | 2 +- .../src/dead_store_elimination.rs | 47 +--- compiler/rustc_mir_transform/src/dest_prop.rs | 4 +- compiler/rustc_mir_transform/src/gvn.rs | 2 +- .../rustc_mir_transform/src/large_enums.rs | 2 +- compiler/rustc_mir_transform/src/nrvo.rs | 2 +- .../rustc_mir_transform/src/promote_consts.rs | 2 +- compiler/rustc_mir_transform/src/ref_prop.rs | 2 +- .../src/remove_place_mention.rs | 2 +- .../src/remove_storage_markers.rs | 2 +- .../rustc_mir_transform/src/remove_zsts.rs | 2 +- compiler/rustc_mir_transform/src/simplify.rs | 23 +- .../src/simplify_branches.rs | 2 +- .../src/simplify_comparison_integral.rs | 4 +- compiler/rustc_mir_transform/src/sroa.rs | 10 +- tests/mir-opt/dead-store-elimination/ref.rs | 19 ++ ...ef.tuple.DeadStoreElimination-initial.diff | 26 ++ .../inline_shims.drop.Inline.panic-abort.diff | 56 +++-- ...y.run2-{closure#0}.Inline.panic-abort.diff | 40 ++- ....run2-{closure#0}.Inline.panic-unwind.diff | 40 ++- ...implifyComparisonIntegral.panic-abort.diff | 6 +- ...mplifyComparisonIntegral.panic-unwind.diff | 6 +- ...git.PreCodegen.after.32bit.panic-abort.mir | 4 + ...it.PreCodegen.after.32bit.panic-unwind.mir | 4 + ...git.PreCodegen.after.64bit.panic-abort.mir | 4 + ...it.PreCodegen.after.64bit.panic-unwind.mir | 4 + ...p_forward.PreCodegen.after.panic-abort.mir | 40 ++- ..._forward.PreCodegen.after.panic-unwind.mir | 40 ++- ...as_copy.clone_as_copy.PreCodegen.after.mir | 2 +- ...py.enum_clone_as_copy.PreCodegen.after.mir | 6 +- .../loops.filter_mapped.PreCodegen.after.mir | 44 ++-- .../loops.int_range.PreCodegen.after.mir | 90 +++---- .../loops.mapped.PreCodegen.after.mir | 84 +++---- ...variant_a-{closure#0}.PreCodegen.after.mir | 199 +++++++-------- ...erse_loop.PreCodegen.after.panic-abort.mir | 223 +++++++++++++++-- ...rse_loop.PreCodegen.after.panic-unwind.mir | 231 +++++++++++++++--- ...next_back.PreCodegen.after.panic-abort.mir | 189 +++++++++++++- ...ext_back.PreCodegen.after.panic-unwind.mir | 189 +++++++++++++- ...ans.outer.PreCodegen.after.panic-abort.mir | 2 +- ...ns.outer.PreCodegen.after.panic-unwind.mir | 2 +- ..._to_slice.PreCodegen.after.panic-abort.mir | 8 + ...to_slice.PreCodegen.after.panic-unwind.mir | 8 + 50 files changed, 1437 insertions(+), 480 deletions(-) create mode 100644 tests/mir-opt/dead-store-elimination/ref.rs create mode 100644 tests/mir-opt/dead-store-elimination/ref.tuple.DeadStoreElimination-initial.diff diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index fbd70f8ecb910..10fe6f49021f3 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -4,8 +4,8 @@ use std::borrow::Cow; use std::fmt::{self, Debug, Formatter}; -use std::iter; use std::ops::{Index, IndexMut}; +use std::{iter, mem}; pub use basic_blocks::{BasicBlocks, SwitchTargetValue}; use either::Either; @@ -1341,6 +1341,10 @@ pub struct BasicBlockData<'tcx> { /// List of statements in this block. pub statements: Vec>, + /// All debuginfos happen before the statement. + /// Put debuginfos here when the last statement is eliminated. + pub after_last_stmt_debuginfos: Vec>, + /// Terminator for this block. /// /// N.B., this should generally ONLY be `None` during construction. @@ -1368,7 +1372,12 @@ impl<'tcx> BasicBlockData<'tcx> { terminator: Option>, is_cleanup: bool, ) -> BasicBlockData<'tcx> { - BasicBlockData { statements, terminator, is_cleanup } + BasicBlockData { + statements, + after_last_stmt_debuginfos: Vec::new(), + terminator, + is_cleanup, + } } /// Accessor for terminator. @@ -1403,6 +1412,37 @@ impl<'tcx> BasicBlockData<'tcx> { self.terminator().successors() } } + + pub fn retain_statements(&mut self, mut f: F) + where + F: FnMut(&Statement<'tcx>) -> bool, + { + // Fast path without debugging information + if self.statements.iter().all(|stmt| stmt.debuginfos.is_empty()) { + self.statements.retain_mut(|stmt| f(stmt)); + return; + } + let mut debuginfos = Vec::new(); + self.statements.retain_mut(|stmt| { + let retain = f(stmt); + if retain { + if !debuginfos.is_empty() { + if !stmt.debuginfos.is_empty() { + debuginfos.append(&mut stmt.debuginfos); + } + mem::swap(&mut debuginfos, &mut stmt.debuginfos); + } + } else { + if !stmt.debuginfos.is_empty() { + debuginfos.append(&mut stmt.debuginfos); + } + } + retain + }); + if !debuginfos.is_empty() { + self.after_last_stmt_debuginfos.append(&mut debuginfos); + } + } } /////////////////////////////////////////////////////////////////////////// @@ -1707,7 +1747,7 @@ mod size_asserts { use super::*; // tidy-alphabetical-start - static_assert_size!(BasicBlockData<'_>, 128); + static_assert_size!(BasicBlockData<'_>, 152); static_assert_size!(LocalDecl<'_>, 40); static_assert_size!(SourceScopeData<'_>, 64); static_assert_size!(Statement<'_>, 56); diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 8e403dfddaed8..df8f4c0e7bc9e 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -778,6 +778,9 @@ where let mut current_location = Location { block, statement_index: 0 }; for statement in &data.statements { extra_data(PassWhere::BeforeLocation(current_location), w)?; + for debuginfo in statement.debuginfos.iter() { + writeln!(w, "{INDENT}{INDENT}// DBG: {debuginfo:?}")?; + } let indented_body = format!("{INDENT}{INDENT}{statement:?};"); if options.include_extra_comments { writeln!( @@ -812,6 +815,9 @@ where // Terminator at the bottom. extra_data(PassWhere::BeforeLocation(current_location), w)?; + for debuginfo in data.after_last_stmt_debuginfos.iter() { + writeln!(w, "{INDENT}{INDENT}// DBG: {debuginfo:?}")?; + } if data.terminator.is_some() { let indented_terminator = format!("{0}{0}{1:?};", INDENT, data.terminator().kind); if options.include_extra_comments { @@ -891,6 +897,16 @@ impl Debug for Statement<'_> { } } +impl Debug for StmtDebugInfo<'_> { + fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { + match self { + StmtDebugInfo::AssignRef(local, place) => { + write!(fmt, "{local:?} = &{place:?}") + } + } + } +} + impl Display for NonDivergingIntrinsic<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index f05b70f51482c..1c35797da37ef 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -15,19 +15,33 @@ use crate::ty::CoroutineArgsExt; pub struct Statement<'tcx> { pub source_info: SourceInfo, pub kind: StatementKind<'tcx>, - pub debug_info: Vec, + pub debuginfos: Vec>, } impl<'tcx> Statement<'tcx> { /// Changes a statement to a nop. This is both faster than deleting instructions and avoids /// invalidating statement indices in `Location`s. - pub fn make_nop(&mut self) { - // TODO: convert the stmt to debuginfo. - self.kind = StatementKind::Nop + pub fn make_nop(&mut self, drop_debuginfo: bool) { + if matches!(self.kind, StatementKind::Nop) { + return; + } + let replaced_stmt = std::mem::replace(&mut self.kind, StatementKind::Nop); + if !drop_debuginfo { + match replaced_stmt { + StatementKind::Assign(box (place, Rvalue::Ref(_, _, ref_place))) + if let Some(local) = place.as_local() => + { + self.debuginfos.push(StmtDebugInfo::AssignRef(local, ref_place)); + } + _ => { + bug!("debuginfo is not yet supported.") + } + } + } } pub fn new(source_info: SourceInfo, kind: StatementKind<'tcx>) -> Self { - Statement { source_info, kind, debug_info: Vec::new() } + Statement { source_info, kind, debuginfos: Vec::new() } } } @@ -942,5 +956,7 @@ impl RawPtrKind { } } -#[derive(Debug, Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] -pub struct StmtDebugInfo {} +#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] +pub enum StmtDebugInfo<'tcx> { + AssignRef(Local, Place<'tcx>), +} diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 128491f652404..3e9c7a50311d9 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -95,6 +95,22 @@ macro_rules! make_mir_visitor { self.super_source_scope_data(scope_data); } + fn visit_statement_debuginfos( + &mut self, + stmt_debuginfo: & $($mutability)? [StmtDebugInfo<'tcx>], + location: Location + ) { + self.super_statement_debuginfos(stmt_debuginfo, location); + } + + fn visit_statement_debuginfo( + &mut self, + stmt_debuginfo: & $($mutability)? StmtDebugInfo<'tcx>, + location: Location + ) { + self.super_statement_debuginfo(stmt_debuginfo, location); + } + fn visit_statement( &mut self, statement: & $($mutability)? Statement<'tcx>, @@ -301,6 +317,7 @@ macro_rules! make_mir_visitor { { let BasicBlockData { statements, + after_last_stmt_debuginfos, terminator, is_cleanup: _ } = data; @@ -312,8 +329,9 @@ macro_rules! make_mir_visitor { index += 1; } + let location = Location { block, statement_index: index }; + self.visit_statement_debuginfos(after_last_stmt_debuginfos, location); if let Some(terminator) = terminator { - let location = Location { block, statement_index: index }; self.visit_terminator(terminator, location); } } @@ -376,15 +394,46 @@ macro_rules! make_mir_visitor { } } + fn super_statement_debuginfos( + &mut self, + stmt_debuginfo: & $($mutability)? [StmtDebugInfo<'tcx>], + location: Location + ) { + for debuginfo in stmt_debuginfo { + self.visit_statement_debuginfo(debuginfo, location); + } + } + + fn super_statement_debuginfo( + &mut self, + stmt_debuginfo: & $($mutability)? StmtDebugInfo<'tcx>, + location: Location + ) { + match stmt_debuginfo { + StmtDebugInfo::AssignRef(local, place) => { + self.visit_local( + $(& $mutability)? *local, + PlaceContext::NonUse(NonUseContext::VarDebugInfo), + location + ); + self.visit_place( + place, + PlaceContext::NonUse(NonUseContext::VarDebugInfo), + location + ); + }, + } + } + fn super_statement( &mut self, statement: & $($mutability)? Statement<'tcx>, location: Location ) { - // TODO: visit debuginfo - let Statement { source_info, kind, .. } = statement; + let Statement { source_info, kind, debuginfos } = statement; self.visit_source_info(source_info); + self.visit_statement_debuginfos(debuginfos, location); match kind { StatementKind::Assign(box (place, rvalue)) => { self.visit_assign(place, rvalue, location); diff --git a/compiler/rustc_mir_dataflow/src/debuginfo.rs b/compiler/rustc_mir_dataflow/src/debuginfo.rs index 0d25ce91c9a9e..274c5943946c2 100644 --- a/compiler/rustc_mir_dataflow/src/debuginfo.rs +++ b/compiler/rustc_mir_dataflow/src/debuginfo.rs @@ -5,16 +5,16 @@ use rustc_middle::mir::*; /// Return the set of locals that appear in debuginfo. pub fn debuginfo_locals(body: &Body<'_>) -> DenseBitSet { let mut visitor = DebuginfoLocals(DenseBitSet::new_empty(body.local_decls.len())); - for debuginfo in body.var_debug_info.iter() { - visitor.visit_var_debug_info(debuginfo); - } + visitor.visit_body(body); visitor.0 } struct DebuginfoLocals(DenseBitSet); impl Visitor<'_> for DebuginfoLocals { - fn visit_local(&mut self, local: Local, _: PlaceContext, _: Location) { - self.0.insert(local); + fn visit_local(&mut self, local: Local, place_context: PlaceContext, _: Location) { + if place_context == PlaceContext::NonUse(NonUseContext::VarDebugInfo) { + self.0.insert(local); + } } } diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs index 6ec1b03a34e68..abeb6186aa0a5 100644 --- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs @@ -205,6 +205,7 @@ impl DefUse { /// All of the caveats of `MaybeLiveLocals` apply. pub struct MaybeTransitiveLiveLocals<'a> { always_live: &'a DenseBitSet, + debuginfo_locals: &'a DenseBitSet, } impl<'a> MaybeTransitiveLiveLocals<'a> { @@ -212,8 +213,46 @@ impl<'a> MaybeTransitiveLiveLocals<'a> { /// considered live. /// /// This should include at least all locals that are ever borrowed. - pub fn new(always_live: &'a DenseBitSet) -> Self { - MaybeTransitiveLiveLocals { always_live } + pub fn new( + always_live: &'a DenseBitSet, + debuginfo_locals: &'a DenseBitSet, + ) -> Self { + MaybeTransitiveLiveLocals { always_live, debuginfo_locals } + } + + pub fn can_be_removed_if_dead<'tcx>( + stmt_kind: &StatementKind<'tcx>, + always_live: &DenseBitSet, + debuginfo_locals: &'a DenseBitSet, + ) -> Option> { + // Compute the place that we are storing to, if any + let destination = match stmt_kind { + StatementKind::Assign(box (place, rvalue)) => (rvalue.is_safe_to_remove() + && (!debuginfo_locals.contains(place.local) + || (place.as_local().is_some() && matches!(rvalue, mir::Rvalue::Ref(..))))) + .then_some(*place), + StatementKind::SetDiscriminant { place, .. } | StatementKind::Deinit(place) => { + (!debuginfo_locals.contains(place.local)).then_some(**place) + } + StatementKind::FakeRead(_) + | StatementKind::StorageLive(_) + | StatementKind::StorageDead(_) + | StatementKind::Retag(..) + | StatementKind::AscribeUserType(..) + | StatementKind::PlaceMention(..) + | StatementKind::Coverage(..) + | StatementKind::Intrinsic(..) + | StatementKind::ConstEvalCounter + | StatementKind::BackwardIncompatibleDropHint { .. } + | StatementKind::Nop => None, + }; + if let Some(destination) = destination + && !destination.is_indirect() + && !always_live.contains(destination.local) + { + return Some(destination); + } + None } } @@ -238,32 +277,15 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> { statement: &mir::Statement<'tcx>, location: Location, ) { - // Compute the place that we are storing to, if any - let destination = match &statement.kind { - StatementKind::Assign(assign) => assign.1.is_safe_to_remove().then_some(assign.0), - StatementKind::SetDiscriminant { place, .. } | StatementKind::Deinit(place) => { - Some(**place) - } - StatementKind::FakeRead(_) - | StatementKind::StorageLive(_) - | StatementKind::StorageDead(_) - | StatementKind::Retag(..) - | StatementKind::AscribeUserType(..) - | StatementKind::PlaceMention(..) - | StatementKind::Coverage(..) - | StatementKind::Intrinsic(..) - | StatementKind::ConstEvalCounter - | StatementKind::BackwardIncompatibleDropHint { .. } - | StatementKind::Nop => None, - }; - if let Some(destination) = destination { - if !destination.is_indirect() - && !state.contains(destination.local) - && !self.always_live.contains(destination.local) - { - // This store is dead - return; - } + if let Some(destination) = + Self::can_be_removed_if_dead(&statement.kind, &self.always_live, &self.debuginfo_locals) + && !state.contains(destination.local) + // FIXME: We can eliminate the statement, but we'll need the statements it depends on + // for debuginfos. We need a way to handle this. + && !self.debuginfo_locals.contains(destination.local) + { + // This store is dead + return; } TransferFunction(state).visit_statement(statement, location); } diff --git a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs index 4be67b873f737..b0bf7f484bedf 100644 --- a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs +++ b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs @@ -36,7 +36,9 @@ impl<'tcx> crate::MirPass<'tcx> for CleanupPostBorrowck { CoverageKind::BlockMarker { .. } | CoverageKind::SpanMarker { .. }, ) | StatementKind::FakeRead(..) - | StatementKind::BackwardIncompatibleDropHint { .. } => statement.make_nop(), + | StatementKind::BackwardIncompatibleDropHint { .. } => { + statement.make_nop(true) + } StatementKind::Assign(box ( _, Rvalue::Cast( diff --git a/compiler/rustc_mir_transform/src/copy_prop.rs b/compiler/rustc_mir_transform/src/copy_prop.rs index cddeefca68174..f0bc286a94022 100644 --- a/compiler/rustc_mir_transform/src/copy_prop.rs +++ b/compiler/rustc_mir_transform/src/copy_prop.rs @@ -138,7 +138,7 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> { if let StatementKind::StorageLive(l) | StatementKind::StorageDead(l) = stmt.kind && self.storage_to_remove.contains(l) { - stmt.make_nop(); + stmt.make_nop(true); return; } @@ -150,7 +150,7 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> { *rhs && lhs == rhs { - stmt.make_nop(); + stmt.make_nop(true); } } } diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 761d5461a996f..879008fd213b3 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -412,7 +412,7 @@ impl<'tcx> MutVisitor<'tcx> for TransformVisitor<'tcx> { if let StatementKind::StorageLive(l) | StatementKind::StorageDead(l) = s.kind && self.remap.contains(l) { - s.make_nop(); + s.make_nop(true); } } diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs index eea2b0990d730..c04655cb634eb 100644 --- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs +++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs @@ -33,10 +33,9 @@ fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // If the user requests complete debuginfo, mark the locals that appear in it as live, so // we don't remove assignments to them. - let mut always_live = debuginfo_locals(body); - always_live.union(&borrowed_locals); + let debuginfo_locals = debuginfo_locals(body); - let mut live = MaybeTransitiveLiveLocals::new(&always_live) + let mut live = MaybeTransitiveLiveLocals::new(&borrowed_locals, &debuginfo_locals) .iterate_to_fixpoint(tcx, body, None) .into_results_cursor(body); @@ -75,35 +74,15 @@ fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { } for (statement_index, statement) in bb_data.statements.iter().enumerate().rev() { - let loc = Location { block: bb, statement_index }; - if let StatementKind::Assign(assign) = &statement.kind { - if !assign.1.is_safe_to_remove() { - continue; - } - } - match &statement.kind { - StatementKind::Assign(box (place, _)) - | StatementKind::SetDiscriminant { place: box place, .. } - | StatementKind::Deinit(box place) => { - if !place.is_indirect() && !always_live.contains(place.local) { - live.seek_before_primary_effect(loc); - if !live.get().contains(place.local) { - patch.push(loc); - } - } - } - StatementKind::Retag(_, _) - | StatementKind::StorageLive(_) - | StatementKind::StorageDead(_) - | StatementKind::Coverage(_) - | StatementKind::Intrinsic(_) - | StatementKind::ConstEvalCounter - | StatementKind::PlaceMention(_) - | StatementKind::BackwardIncompatibleDropHint { .. } - | StatementKind::Nop => {} - - StatementKind::FakeRead(_) | StatementKind::AscribeUserType(_, _) => { - bug!("{:?} not found in this MIR phase!", statement.kind) + if let Some(destination) = MaybeTransitiveLiveLocals::can_be_removed_if_dead( + &statement.kind, + &borrowed_locals, + &debuginfo_locals, + ) { + let loc = Location { block: bb, statement_index }; + live.seek_before_primary_effect(loc); + if !live.get().contains(destination.local) { + patch.push((loc, !debuginfo_locals.contains(destination.local))); } } } @@ -114,8 +93,8 @@ fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { } let bbs = body.basic_blocks.as_mut_preserves_cfg(); - for Location { block, statement_index } in patch { - bbs[block].statements[statement_index].make_nop(); + for (Location { block, statement_index }, drop_debuginfo) in patch { + bbs[block].statements[statement_index].make_nop(drop_debuginfo); } for (block, argument_index) in call_operands_to_move { let TerminatorKind::Call { ref mut args, .. } = bbs[block].terminator_mut().kind else { diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index 4c94a6c524e00..5e8f8de86bb12 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -308,7 +308,7 @@ impl<'tcx> MutVisitor<'tcx> for Merger<'tcx> { StatementKind::StorageDead(local) | StatementKind::StorageLive(local) if self.merged_locals.contains(*local) => { - statement.make_nop(); + statement.make_nop(true); return; } _ => (), @@ -323,7 +323,7 @@ impl<'tcx> MutVisitor<'tcx> for Merger<'tcx> { // (this includes the original statement we wanted to eliminate). if dest == place { debug!("{:?} turned into self-assignment, deleting", location); - statement.make_nop(); + statement.make_nop(true); } } _ => {} diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 6657f89ceb595..9d72117218874 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -1803,7 +1803,7 @@ impl<'tcx> MutVisitor<'tcx> for StorageRemover<'tcx> { StatementKind::StorageLive(l) | StatementKind::StorageDead(l) if self.reused_locals.contains(l) => { - stmt.make_nop() + stmt.make_nop(true) } _ => self.super_statement(stmt, loc), } diff --git a/compiler/rustc_mir_transform/src/large_enums.rs b/compiler/rustc_mir_transform/src/large_enums.rs index 1a91d6bd7da98..1b90e9158f6b8 100644 --- a/compiler/rustc_mir_transform/src/large_enums.rs +++ b/compiler/rustc_mir_transform/src/large_enums.rs @@ -156,7 +156,7 @@ impl<'tcx> crate::MirPass<'tcx> for EnumSizeOpt { patch.add_statement(location, stmt); } - st.make_nop(); + st.make_nop(true); } } diff --git a/compiler/rustc_mir_transform/src/nrvo.rs b/compiler/rustc_mir_transform/src/nrvo.rs index 965002aae04c7..23f7cdbdd67f4 100644 --- a/compiler/rustc_mir_transform/src/nrvo.rs +++ b/compiler/rustc_mir_transform/src/nrvo.rs @@ -54,7 +54,7 @@ impl<'tcx> crate::MirPass<'tcx> for RenameReturnPlace { // Clean up the `NOP`s we inserted for statements made useless by our renaming. for block_data in body.basic_blocks.as_mut_preserves_cfg() { - block_data.statements.retain(|stmt| stmt.kind != mir::StatementKind::Nop); + block_data.retain_statements(|stmt| stmt.kind != mir::StatementKind::Nop); } // Overwrite the debuginfo of `_0` with that of the renamed local. diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index 4e8f30e077b0a..ce4f1eaeb9afc 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -1052,7 +1052,7 @@ fn promote_candidates<'tcx>( // Eliminate assignments to, and drops of promoted temps. let promoted = |index: Local| temps[index] == TempState::PromotedOut; for block in body.basic_blocks_mut() { - block.statements.retain(|statement| match &statement.kind { + block.retain_statements(|statement| match &statement.kind { StatementKind::Assign(box (place, _)) => { if let Some(index) = place.as_local() { !promoted(index) diff --git a/compiler/rustc_mir_transform/src/ref_prop.rs b/compiler/rustc_mir_transform/src/ref_prop.rs index d1c2d6b508f2f..6d557df2722c2 100644 --- a/compiler/rustc_mir_transform/src/ref_prop.rs +++ b/compiler/rustc_mir_transform/src/ref_prop.rs @@ -409,7 +409,7 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'tcx> { StatementKind::StorageLive(l) | StatementKind::StorageDead(l) if self.storage_to_remove.contains(l) => { - stmt.make_nop(); + stmt.make_nop(true); } // Do not remove assignments as they may still be useful for debuginfo. _ => self.super_statement(stmt, loc), diff --git a/compiler/rustc_mir_transform/src/remove_place_mention.rs b/compiler/rustc_mir_transform/src/remove_place_mention.rs index cb598ceb4dfea..d56b51bb496e4 100644 --- a/compiler/rustc_mir_transform/src/remove_place_mention.rs +++ b/compiler/rustc_mir_transform/src/remove_place_mention.rs @@ -14,7 +14,7 @@ impl<'tcx> crate::MirPass<'tcx> for RemovePlaceMention { fn run_pass(&self, _: TyCtxt<'tcx>, body: &mut Body<'tcx>) { trace!("Running RemovePlaceMention on {:?}", body.source); for data in body.basic_blocks.as_mut_preserves_cfg() { - data.statements.retain(|statement| match statement.kind { + data.retain_statements(|statement| match statement.kind { StatementKind::PlaceMention(..) | StatementKind::Nop => false, _ => true, }) diff --git a/compiler/rustc_mir_transform/src/remove_storage_markers.rs b/compiler/rustc_mir_transform/src/remove_storage_markers.rs index 1ae33c0096875..cb97d2c865ac9 100644 --- a/compiler/rustc_mir_transform/src/remove_storage_markers.rs +++ b/compiler/rustc_mir_transform/src/remove_storage_markers.rs @@ -14,7 +14,7 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveStorageMarkers { fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { trace!("Running RemoveStorageMarkers on {:?}", body.source); for data in body.basic_blocks.as_mut_preserves_cfg() { - data.statements.retain(|statement| match statement.kind { + data.retain_statements(|statement| match statement.kind { StatementKind::StorageLive(..) | StatementKind::StorageDead(..) | StatementKind::Nop => false, diff --git a/compiler/rustc_mir_transform/src/remove_zsts.rs b/compiler/rustc_mir_transform/src/remove_zsts.rs index c4dc8638b26ab..90c1b3520b96e 100644 --- a/compiler/rustc_mir_transform/src/remove_zsts.rs +++ b/compiler/rustc_mir_transform/src/remove_zsts.rs @@ -141,7 +141,7 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> { && let ty = place_for_ty.ty(self.local_decls, self.tcx).ty && self.known_to_be_zst(ty) { - statement.make_nop(); + statement.make_nop(true); } else { self.super_statement(statement, loc); } diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index db933da641371..4598dcee0cd94 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -35,7 +35,9 @@ //! pre-"runtime" MIR! use rustc_index::{Idx, IndexSlice, IndexVec}; -use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor}; +use rustc_middle::mir::visit::{ + MutVisitor, MutatingUseContext, NonUseContext, PlaceContext, Visitor, +}; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; use rustc_span::DUMMY_SP; @@ -308,7 +310,7 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { fn strip_nops(&mut self) { for blk in self.basic_blocks.iter_mut() { - blk.statements.retain(|stmt| !matches!(stmt.kind, StatementKind::Nop)) + blk.retain_statements(|stmt| !matches!(stmt.kind, StatementKind::Nop)) } } } @@ -544,12 +546,16 @@ impl<'tcx> Visitor<'tcx> for UsedLocals { self.super_statement(statement, location); } - StatementKind::ConstEvalCounter | StatementKind::Nop => {} - - StatementKind::StorageLive(_local) | StatementKind::StorageDead(_local) => {} + StatementKind::ConstEvalCounter + | StatementKind::Nop + | StatementKind::StorageLive(..) + | StatementKind::StorageDead(..) => { + self.visit_statement_debuginfos(&statement.debuginfos, location); + } StatementKind::Assign(box (ref place, ref rvalue)) => { if rvalue.is_safe_to_remove() { + self.visit_statement_debuginfos(&statement.debuginfos, location); self.visit_lhs(place, location); self.visit_rvalue(rvalue, location); } else { @@ -560,15 +566,16 @@ impl<'tcx> Visitor<'tcx> for UsedLocals { StatementKind::SetDiscriminant { ref place, variant_index: _ } | StatementKind::Deinit(ref place) | StatementKind::BackwardIncompatibleDropHint { ref place, reason: _ } => { + self.visit_statement_debuginfos(&statement.debuginfos, location); self.visit_lhs(place, location); } } } - fn visit_local(&mut self, local: Local, _ctx: PlaceContext, _location: Location) { + fn visit_local(&mut self, local: Local, ctx: PlaceContext, _location: Location) { if self.increment { self.use_count[local] += 1; - } else { + } else if ctx != PlaceContext::NonUse(NonUseContext::VarDebugInfo) { assert_ne!(self.use_count[local], 0); self.use_count[local] -= 1; } @@ -588,7 +595,7 @@ fn remove_unused_definitions_helper(used_locals: &mut UsedLocals, body: &mut Bod for data in body.basic_blocks.as_mut_preserves_cfg() { // Remove unnecessary StorageLive and StorageDead annotations. - data.statements.retain(|statement| { + data.retain_statements(|statement| { let keep = match &statement.kind { StatementKind::StorageLive(local) | StatementKind::StorageDead(local) => { used_locals.is_used(*local) diff --git a/compiler/rustc_mir_transform/src/simplify_branches.rs b/compiler/rustc_mir_transform/src/simplify_branches.rs index 886f4d6e50900..fecbb09b2b67b 100644 --- a/compiler/rustc_mir_transform/src/simplify_branches.rs +++ b/compiler/rustc_mir_transform/src/simplify_branches.rs @@ -28,7 +28,7 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyConstCondition { && let Some(constant) = c.const_.try_eval_bool(tcx, typing_env) { if constant { - stmt.make_nop(); + stmt.make_nop(true); } else { block.statements.clear(); block.terminator_mut().kind = TerminatorKind::Unreachable; diff --git a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs index c60eb566521c5..4597439e269ff 100644 --- a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs +++ b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs @@ -76,7 +76,7 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyComparisonIntegral { // delete comparison statement if it the value being switched on was moved, which means // it can not be user later on if opt.can_remove_bin_op_stmt { - bb.statements[opt.bin_op_stmt_idx].make_nop(); + bb.statements[opt.bin_op_stmt_idx].make_nop(true); } else { // if the integer being compared to a const integral is being moved into the // comparison, e.g `_2 = Eq(move _3, const 'x');` @@ -136,7 +136,7 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyComparisonIntegral { } for (idx, bb_idx) in storage_deads_to_remove { - body.basic_blocks_mut()[bb_idx].statements[idx].make_nop(); + body.basic_blocks_mut()[bb_idx].statements[idx].make_nop(true); } for (idx, stmt) in storage_deads_to_insert { diff --git a/compiler/rustc_mir_transform/src/sroa.rs b/compiler/rustc_mir_transform/src/sroa.rs index 7c6ccc89c4f30..69be045dbd983 100644 --- a/compiler/rustc_mir_transform/src/sroa.rs +++ b/compiler/rustc_mir_transform/src/sroa.rs @@ -334,7 +334,7 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> { for (_, _, fl) in final_locals { self.patch.add_statement(location, StatementKind::StorageLive(fl)); } - statement.make_nop(); + statement.make_nop(true); } return; } @@ -343,7 +343,7 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> { for (_, _, fl) in final_locals { self.patch.add_statement(location, StatementKind::StorageDead(fl)); } - statement.make_nop(); + statement.make_nop(true); } return; } @@ -353,7 +353,7 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> { self.patch .add_statement(location, StatementKind::Deinit(Box::new(fl.into()))); } - statement.make_nop(); + statement.make_nop(true); return; } } @@ -383,7 +383,7 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> { ); } } - statement.make_nop(); + statement.make_nop(true); return; } } @@ -445,7 +445,7 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> { StatementKind::Assign(Box::new((new_local.into(), rvalue))), ); } - statement.make_nop(); + statement.make_nop(true); return; } } diff --git a/tests/mir-opt/dead-store-elimination/ref.rs b/tests/mir-opt/dead-store-elimination/ref.rs new file mode 100644 index 0000000000000..368c589914fa4 --- /dev/null +++ b/tests/mir-opt/dead-store-elimination/ref.rs @@ -0,0 +1,19 @@ +//@ test-mir-pass: DeadStoreElimination-initial + +pub struct Foo { + a: i32, + b: i64, + c: i32, +} + +// EMIT_MIR ref.tuple.DeadStoreElimination-initial.diff +pub fn tuple(v: (i32, &Foo)) -> i32 { + // CHECK-LABEL: fn tuple + // CHECK: debug _dead => [[dead:_[0-9]+]]; + // CHECK: bb0: + // FIXME: Preserve `tmp` for debuginfo, but we can merge it into the debuginfo. + // CHECK: [[tmp:_[0-9]+]] = deref_copy (_1.1: &Foo); + // CHECK-NEXT: DBG: [[dead]] = &((*[[tmp]]).2: i32) + let _dead = &v.1.c; + v.1.a +} diff --git a/tests/mir-opt/dead-store-elimination/ref.tuple.DeadStoreElimination-initial.diff b/tests/mir-opt/dead-store-elimination/ref.tuple.DeadStoreElimination-initial.diff new file mode 100644 index 0000000000000..3428fc90ed5f1 --- /dev/null +++ b/tests/mir-opt/dead-store-elimination/ref.tuple.DeadStoreElimination-initial.diff @@ -0,0 +1,26 @@ +- // MIR for `tuple` before DeadStoreElimination-initial ++ // MIR for `tuple` after DeadStoreElimination-initial + + fn tuple(_1: (i32, &Foo)) -> i32 { + debug v => _1; + let mut _0: i32; + let _2: &i32; + let mut _3: &Foo; + let mut _4: &Foo; + scope 1 { + debug _dead => _2; + } + + bb0: { + StorageLive(_2); + _3 = deref_copy (_1.1: &Foo); +- _2 = &((*_3).2: i32); ++ // DBG: _2 = &((*_3).2: i32) ++ nop; + _4 = deref_copy (_1.1: &Foo); + _0 = copy ((*_4).0: i32); + StorageDead(_2); + return; + } + } + diff --git a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff index f6c111a2228a9..43bf4e069475c 100644 --- a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff @@ -16,10 +16,12 @@ + let mut _9: *mut A; + let mut _10: usize; + scope 3 (inlined Vec::::as_mut_ptr) { ++ let mut _11: &alloc::raw_vec::RawVec; + scope 4 (inlined alloc::raw_vec::RawVec::::ptr) { ++ let mut _12: &alloc::raw_vec::RawVecInner; + scope 5 (inlined alloc::raw_vec::RawVecInner::ptr::) { + scope 6 (inlined alloc::raw_vec::RawVecInner::non_null::) { -+ let mut _11: std::ptr::NonNull; ++ let mut _13: std::ptr::NonNull; + scope 7 (inlined Unique::::cast::) { + scope 8 (inlined NonNull::::cast::) { + scope 9 (inlined NonNull::::as_ptr) { @@ -39,15 +41,15 @@ + } + } + scope 14 (inlined drop_in_place::<[A]> - shim(Some([A]))) { -+ let mut _12: usize; -+ let mut _13: *mut A; -+ let mut _14: bool; ++ let mut _14: usize; ++ let mut _15: *mut A; ++ let mut _16: bool; + } + } + } + scope 15 (inlined drop_in_place::> - shim(Some(Option))) { -+ let mut _15: isize; -+ let mut _16: isize; ++ let mut _17: isize; ++ let mut _18: isize; + } bb0: { @@ -62,16 +64,22 @@ + StorageLive(_8); + StorageLive(_9); + StorageLive(_11); -+ _11 = copy (((((*_6).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); -+ _9 = copy _11 as *mut A (Transmute); ++ // DBG: _11 = &((*_6).0: alloc::raw_vec::RawVec) ++ StorageLive(_12); ++ // DBG: _12 = &(((*_6).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner) ++ StorageLive(_13); ++ _13 = copy (((((*_6).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); ++ _9 = copy _13 as *mut A (Transmute); ++ StorageDead(_13); ++ StorageDead(_12); + StorageDead(_11); + _10 = copy ((*_6).1: usize); + _8 = *mut [A] from (copy _9, copy _10); + StorageDead(_9); -+ StorageLive(_12); -+ StorageLive(_13); + StorageLive(_14); -+ _12 = const 0_usize; ++ StorageLive(_15); ++ StorageLive(_16); ++ _14 = const 0_usize; + goto -> bb4; } @@ -83,35 +91,35 @@ StorageLive(_5); _5 = copy _2; - _0 = drop_in_place::>(move _5) -> [return: bb2, unwind unreachable]; -+ StorageLive(_15); -+ StorageLive(_16); -+ _15 = discriminant((*_5)); -+ switchInt(move _15) -> [0: bb5, otherwise: bb6]; ++ StorageLive(_17); ++ StorageLive(_18); ++ _17 = discriminant((*_5)); ++ switchInt(move _17) -> [0: bb5, otherwise: bb6]; } bb2: { ++ StorageDead(_16); ++ StorageDead(_15); + StorageDead(_14); -+ StorageDead(_13); -+ StorageDead(_12); + StorageDead(_8); + StorageDead(_10); + drop(((*_4).0: alloc::raw_vec::RawVec)) -> [return: bb1, unwind unreachable]; + } + + bb3: { -+ _13 = &raw mut (*_8)[_12]; -+ _12 = Add(move _12, const 1_usize); -+ drop((*_13)) -> [return: bb4, unwind unreachable]; ++ _15 = &raw mut (*_8)[_14]; ++ _14 = Add(move _14, const 1_usize); ++ drop((*_15)) -> [return: bb4, unwind unreachable]; + } + + bb4: { -+ _14 = Eq(copy _12, copy _10); -+ switchInt(move _14) -> [0: bb3, otherwise: bb2]; ++ _16 = Eq(copy _14, copy _10); ++ switchInt(move _16) -> [0: bb3, otherwise: bb2]; + } + + bb5: { -+ StorageDead(_16); -+ StorageDead(_15); ++ StorageDead(_18); ++ StorageDead(_17); StorageDead(_5); return; + } diff --git a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff index 1e9a6dd4f5c8f..3c3e8b8cd3b4d 100644 --- a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff +++ b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff @@ -64,9 +64,8 @@ + let mut _45: &mut std::future::Ready<()>; + let mut _46: &mut std::pin::Pin<&mut std::future::Ready<()>>; + scope 14 (inlined > as DerefMut>::deref_mut) { -+ let mut _47: std::pin::Pin<&mut std::future::Ready<()>>; + scope 15 (inlined Pin::<&mut std::future::Ready<()>>::as_mut) { -+ let mut _48: &mut &mut std::future::Ready<()>; ++ let mut _47: &mut &mut std::future::Ready<()>; + scope 16 (inlined Pin::<&mut std::future::Ready<()>>::new_unchecked) { + } + scope 18 (inlined <&mut std::future::Ready<()> as DerefMut>::deref_mut) { @@ -76,15 +75,15 @@ + } + } + scope 19 (inlined Option::<()>::take) { -+ let mut _49: std::option::Option<()>; ++ let mut _48: std::option::Option<()>; + scope 20 (inlined std::mem::replace::>) { + scope 21 { + } + } + } + scope 22 (inlined #[track_caller] Option::<()>::expect) { -+ let mut _50: isize; -+ let mut _51: !; ++ let mut _49: isize; ++ let mut _50: !; + scope 23 { + } + } @@ -229,28 +228,25 @@ + StorageDead(_24); + StorageLive(_45); + StorageLive(_46); -+ StorageLive(_51); ++ StorageLive(_50); + StorageLive(_42); + StorageLive(_43); + StorageLive(_44); -+ _46 = &mut _19; ++ // DBG: _46 = &_19 + StorageLive(_47); -+ StorageLive(_48); -+ _48 = &mut (_19.0: &mut std::future::Ready<()>); ++ // DBG: _47 = &(_19.0: &mut std::future::Ready<()>) + _45 = copy (_19.0: &mut std::future::Ready<()>); -+ StorageDead(_48); -+ _47 = Pin::<&mut std::future::Ready<()>> { pointer: copy _45 }; + StorageDead(_47); -+ _44 = &mut ((*_45).0: std::option::Option<()>); -+ StorageLive(_49); -+ _49 = Option::<()>::None; ++ // DBG: _44 = &((*_45).0: std::option::Option<()>) ++ StorageLive(_48); ++ _48 = Option::<()>::None; + _43 = copy ((*_45).0: std::option::Option<()>); -+ ((*_45).0: std::option::Option<()>) = copy _49; -+ StorageDead(_49); ++ ((*_45).0: std::option::Option<()>) = copy _48; ++ StorageDead(_48); + StorageDead(_44); -+ StorageLive(_50); -+ _50 = discriminant(_43); -+ switchInt(move _50) -> [0: bb11, 1: bb12, otherwise: bb5]; ++ StorageLive(_49); ++ _49 = discriminant(_43); ++ switchInt(move _49) -> [0: bb11, 1: bb12, otherwise: bb5]; + } + + bb5: { @@ -313,16 +309,16 @@ + } + + bb11: { -+ _51 = option::expect_failed(const "`Ready` polled after completion") -> unwind unreachable; ++ _50 = option::expect_failed(const "`Ready` polled after completion") -> unwind unreachable; + } + + bb12: { + _42 = move ((_43 as Some).0: ()); -+ StorageDead(_50); ++ StorageDead(_49); + StorageDead(_43); + _18 = Poll::<()>::Ready(move _42); + StorageDead(_42); -+ StorageDead(_51); ++ StorageDead(_50); + StorageDead(_46); + StorageDead(_45); + StorageDead(_22); diff --git a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff index 94b89a310baa8..f2ec21508cb14 100644 --- a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff @@ -66,9 +66,8 @@ + let mut _47: &mut std::future::Ready<()>; + let mut _48: &mut std::pin::Pin<&mut std::future::Ready<()>>; + scope 14 (inlined > as DerefMut>::deref_mut) { -+ let mut _49: std::pin::Pin<&mut std::future::Ready<()>>; + scope 15 (inlined Pin::<&mut std::future::Ready<()>>::as_mut) { -+ let mut _50: &mut &mut std::future::Ready<()>; ++ let mut _49: &mut &mut std::future::Ready<()>; + scope 16 (inlined Pin::<&mut std::future::Ready<()>>::new_unchecked) { + } + scope 18 (inlined <&mut std::future::Ready<()> as DerefMut>::deref_mut) { @@ -78,15 +77,15 @@ + } + } + scope 19 (inlined Option::<()>::take) { -+ let mut _51: std::option::Option<()>; ++ let mut _50: std::option::Option<()>; + scope 20 (inlined std::mem::replace::>) { + scope 21 { + } + } + } + scope 22 (inlined #[track_caller] Option::<()>::expect) { -+ let mut _52: isize; -+ let mut _53: !; ++ let mut _51: isize; ++ let mut _52: !; + scope 23 { + } + } @@ -246,28 +245,25 @@ + StorageDead(_24); + StorageLive(_47); + StorageLive(_48); -+ StorageLive(_53); ++ StorageLive(_52); + StorageLive(_44); + StorageLive(_45); + StorageLive(_46); -+ _48 = &mut _19; ++ // DBG: _48 = &_19 + StorageLive(_49); -+ StorageLive(_50); -+ _50 = &mut (_19.0: &mut std::future::Ready<()>); ++ // DBG: _49 = &(_19.0: &mut std::future::Ready<()>) + _47 = copy (_19.0: &mut std::future::Ready<()>); -+ StorageDead(_50); -+ _49 = Pin::<&mut std::future::Ready<()>> { pointer: copy _47 }; + StorageDead(_49); -+ _46 = &mut ((*_47).0: std::option::Option<()>); -+ StorageLive(_51); -+ _51 = Option::<()>::None; ++ // DBG: _46 = &((*_47).0: std::option::Option<()>) ++ StorageLive(_50); ++ _50 = Option::<()>::None; + _45 = copy ((*_47).0: std::option::Option<()>); -+ ((*_47).0: std::option::Option<()>) = copy _51; -+ StorageDead(_51); ++ ((*_47).0: std::option::Option<()>) = copy _50; ++ StorageDead(_50); + StorageDead(_46); -+ StorageLive(_52); -+ _52 = discriminant(_45); -+ switchInt(move _52) -> [0: bb16, 1: bb17, otherwise: bb7]; ++ StorageLive(_51); ++ _51 = discriminant(_45); ++ switchInt(move _51) -> [0: bb16, 1: bb17, otherwise: bb7]; } - bb6 (cleanup): { @@ -354,16 +350,16 @@ + } + + bb16: { -+ _53 = option::expect_failed(const "`Ready` polled after completion") -> bb11; ++ _52 = option::expect_failed(const "`Ready` polled after completion") -> bb11; + } + + bb17: { + _44 = move ((_45 as Some).0: ()); -+ StorageDead(_52); ++ StorageDead(_51); + StorageDead(_45); + _18 = Poll::<()>::Ready(move _44); + StorageDead(_44); -+ StorageDead(_53); ++ StorageDead(_52); + StorageDead(_48); + StorageDead(_47); + StorageDead(_22); diff --git a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff index c02bab3524bca..47b081bec4538 100644 --- a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff +++ b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff @@ -38,11 +38,11 @@ bb2: { StorageLive(_7); - _7 = &(*_2)[0 of 3]; + // DBG: _7 = &(*_2)[0 of 3] StorageLive(_8); - _8 = &(*_2)[1 of 3]; + // DBG: _8 = &(*_2)[1 of 3] StorageLive(_9); - _9 = &(*_2)[2 of 3]; + // DBG: _9 = &(*_2)[2 of 3] StorageDead(_9); StorageDead(_8); StorageDead(_7); diff --git a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff index 49be042588cb3..98766874cbf74 100644 --- a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff +++ b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff @@ -38,11 +38,11 @@ bb2: { StorageLive(_7); - _7 = &(*_2)[0 of 3]; + // DBG: _7 = &(*_2)[0 of 3] StorageLive(_8); - _8 = &(*_2)[1 of 3]; + // DBG: _8 = &(*_2)[1 of 3] StorageLive(_9); - _9 = &(*_2)[2 of 3]; + // DBG: _9 = &(*_2)[2 of 3] StorageDead(_9); StorageDead(_8); StorageDead(_7); diff --git a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-abort.mir b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-abort.mir index 5876c55c52b94..63010352500c7 100644 --- a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-abort.mir +++ b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-abort.mir @@ -6,6 +6,7 @@ fn num_to_digit(_1: char) -> u32 { let mut _4: std::option::Option; scope 1 (inlined char::methods::::is_digit) { let _2: std::option::Option; + let mut _7: &std::option::Option; scope 2 (inlined Option::::is_some) { let mut _3: isize; } @@ -18,14 +19,17 @@ fn num_to_digit(_1: char) -> u32 { } bb0: { + StorageLive(_7); StorageLive(_2); _2 = char::methods::::to_digit(copy _1, const 8_u32) -> [return: bb1, unwind unreachable]; } bb1: { + // DBG: _7 = &_2 StorageLive(_3); _3 = discriminant(_2); StorageDead(_2); + StorageDead(_7); switchInt(move _3) -> [1: bb2, otherwise: bb7]; } diff --git a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-unwind.mir b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-unwind.mir index f1185353a43c8..4e7f960467170 100644 --- a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-unwind.mir +++ b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-unwind.mir @@ -6,6 +6,7 @@ fn num_to_digit(_1: char) -> u32 { let mut _4: std::option::Option; scope 1 (inlined char::methods::::is_digit) { let _2: std::option::Option; + let mut _7: &std::option::Option; scope 2 (inlined Option::::is_some) { let mut _3: isize; } @@ -18,14 +19,17 @@ fn num_to_digit(_1: char) -> u32 { } bb0: { + StorageLive(_7); StorageLive(_2); _2 = char::methods::::to_digit(copy _1, const 8_u32) -> [return: bb1, unwind continue]; } bb1: { + // DBG: _7 = &_2 StorageLive(_3); _3 = discriminant(_2); StorageDead(_2); + StorageDead(_7); switchInt(move _3) -> [1: bb2, otherwise: bb7]; } diff --git a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-abort.mir b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-abort.mir index 5876c55c52b94..63010352500c7 100644 --- a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-abort.mir +++ b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-abort.mir @@ -6,6 +6,7 @@ fn num_to_digit(_1: char) -> u32 { let mut _4: std::option::Option; scope 1 (inlined char::methods::::is_digit) { let _2: std::option::Option; + let mut _7: &std::option::Option; scope 2 (inlined Option::::is_some) { let mut _3: isize; } @@ -18,14 +19,17 @@ fn num_to_digit(_1: char) -> u32 { } bb0: { + StorageLive(_7); StorageLive(_2); _2 = char::methods::::to_digit(copy _1, const 8_u32) -> [return: bb1, unwind unreachable]; } bb1: { + // DBG: _7 = &_2 StorageLive(_3); _3 = discriminant(_2); StorageDead(_2); + StorageDead(_7); switchInt(move _3) -> [1: bb2, otherwise: bb7]; } diff --git a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-unwind.mir b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-unwind.mir index f1185353a43c8..4e7f960467170 100644 --- a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-unwind.mir +++ b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-unwind.mir @@ -6,6 +6,7 @@ fn num_to_digit(_1: char) -> u32 { let mut _4: std::option::Option; scope 1 (inlined char::methods::::is_digit) { let _2: std::option::Option; + let mut _7: &std::option::Option; scope 2 (inlined Option::::is_some) { let mut _3: isize; } @@ -18,14 +19,17 @@ fn num_to_digit(_1: char) -> u32 { } bb0: { + StorageLive(_7); StorageLive(_2); _2 = char::methods::::to_digit(copy _1, const 8_u32) -> [return: bb1, unwind continue]; } bb1: { + // DBG: _7 = &_2 StorageLive(_3); _3 = discriminant(_2); StorageDead(_2); + StorageDead(_7); switchInt(move _3) -> [1: bb2, otherwise: bb7]; } diff --git a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-abort.mir index 1a1c8b4b9427e..588fe1c942f7a 100644 --- a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-abort.mir @@ -5,7 +5,9 @@ fn step_forward(_1: u16, _2: usize) -> u16 { debug n => _2; let mut _0: u16; scope 1 (inlined ::forward) { - let mut _8: u16; + let _8: std::option::Option; + let mut _10: u16; + let mut _11: &std::option::Option; scope 2 { } scope 3 (inlined ::forward_checked) { @@ -13,8 +15,9 @@ fn step_forward(_1: u16, _2: usize) -> u16 { scope 6 (inlined core::num::::checked_add) { let mut _5: (u16, bool); let mut _6: bool; + let mut _7: u16; scope 7 (inlined std::intrinsics::unlikely) { - let _7: (); + let _9: (); } } } @@ -33,6 +36,8 @@ fn step_forward(_1: u16, _2: usize) -> u16 { bb0: { StorageLive(_4); + StorageLive(_11); + StorageLive(_8); StorageLive(_3); _3 = Gt(copy _2, const 65535_usize); switchInt(move _3) -> [0: bb1, otherwise: bb5]; @@ -51,34 +56,55 @@ fn step_forward(_1: u16, _2: usize) -> u16 { bb2: { StorageDead(_5); StorageDead(_6); + StorageLive(_7); + _7 = AddUnchecked(copy _1, copy _4); + _8 = Option::::Some(move _7); + StorageDead(_7); + // DBG: _11 = &_8 + StorageDead(_8); + StorageDead(_11); goto -> bb7; } bb3: { - _7 = std::intrinsics::cold_path() -> [return: bb4, unwind unreachable]; + _9 = std::intrinsics::cold_path() -> [return: bb4, unwind unreachable]; } bb4: { StorageDead(_5); StorageDead(_6); + _8 = const Option::::None; + // DBG: _11 = &_8 goto -> bb6; } bb5: { StorageDead(_3); + _8 = const Option::::None; + // DBG: _11 = &_8 goto -> bb6; } bb6: { + StorageDead(_8); + StorageDead(_11); assert(!const true, "attempt to compute `{} + {}`, which would overflow", const core::num::::MAX, const 1_u16) -> [success: bb7, unwind unreachable]; } bb7: { - StorageLive(_8); - _8 = copy _2 as u16 (IntToInt); - _0 = Add(copy _1, copy _8); - StorageDead(_8); + StorageLive(_10); + _10 = copy _2 as u16 (IntToInt); + _0 = Add(copy _1, copy _10); + StorageDead(_10); StorageDead(_4); return; } } + +ALLOC0 (size: 4, align: 2) { + 00 00 __ __ │ ..░░ +} + +ALLOC1 (size: 4, align: 2) { + 00 00 __ __ │ ..░░ +} diff --git a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-unwind.mir index e7e19af048ae3..f20b599377d55 100644 --- a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-unwind.mir @@ -5,7 +5,9 @@ fn step_forward(_1: u16, _2: usize) -> u16 { debug n => _2; let mut _0: u16; scope 1 (inlined ::forward) { - let mut _8: u16; + let _8: std::option::Option; + let mut _10: u16; + let mut _11: &std::option::Option; scope 2 { } scope 3 (inlined ::forward_checked) { @@ -13,8 +15,9 @@ fn step_forward(_1: u16, _2: usize) -> u16 { scope 6 (inlined core::num::::checked_add) { let mut _5: (u16, bool); let mut _6: bool; + let mut _7: u16; scope 7 (inlined std::intrinsics::unlikely) { - let _7: (); + let _9: (); } } } @@ -33,6 +36,8 @@ fn step_forward(_1: u16, _2: usize) -> u16 { bb0: { StorageLive(_4); + StorageLive(_11); + StorageLive(_8); StorageLive(_3); _3 = Gt(copy _2, const 65535_usize); switchInt(move _3) -> [0: bb1, otherwise: bb5]; @@ -51,34 +56,55 @@ fn step_forward(_1: u16, _2: usize) -> u16 { bb2: { StorageDead(_5); StorageDead(_6); + StorageLive(_7); + _7 = AddUnchecked(copy _1, copy _4); + _8 = Option::::Some(move _7); + StorageDead(_7); + // DBG: _11 = &_8 + StorageDead(_8); + StorageDead(_11); goto -> bb7; } bb3: { - _7 = std::intrinsics::cold_path() -> [return: bb4, unwind unreachable]; + _9 = std::intrinsics::cold_path() -> [return: bb4, unwind unreachable]; } bb4: { StorageDead(_5); StorageDead(_6); + _8 = const Option::::None; + // DBG: _11 = &_8 goto -> bb6; } bb5: { StorageDead(_3); + _8 = const Option::::None; + // DBG: _11 = &_8 goto -> bb6; } bb6: { + StorageDead(_8); + StorageDead(_11); assert(!const true, "attempt to compute `{} + {}`, which would overflow", const core::num::::MAX, const 1_u16) -> [success: bb7, unwind continue]; } bb7: { - StorageLive(_8); - _8 = copy _2 as u16 (IntToInt); - _0 = Add(copy _1, copy _8); - StorageDead(_8); + StorageLive(_10); + _10 = copy _2 as u16 (IntToInt); + _0 = Add(copy _1, copy _10); + StorageDead(_10); StorageDead(_4); return; } } + +ALLOC0 (size: 4, align: 2) { + 00 00 __ __ │ ..░░ +} + +ALLOC1 (size: 4, align: 2) { + 00 00 __ __ │ ..░░ +} diff --git a/tests/mir-opt/pre-codegen/clone_as_copy.clone_as_copy.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/clone_as_copy.clone_as_copy.PreCodegen.after.mir index 34747e5a92854..fd459b8885ee7 100644 --- a/tests/mir-opt/pre-codegen/clone_as_copy.clone_as_copy.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/clone_as_copy.clone_as_copy.PreCodegen.after.mir @@ -13,7 +13,7 @@ fn clone_as_copy(_1: &NestCopy) -> NestCopy { bb0: { StorageLive(_2); - _2 = &((*_1).1: AllCopy); + // DBG: _2 = &((*_1).1: AllCopy) _0 = copy (*_1); StorageDead(_2); return; diff --git a/tests/mir-opt/pre-codegen/clone_as_copy.enum_clone_as_copy.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/clone_as_copy.enum_clone_as_copy.PreCodegen.after.mir index 9f88e1961ec88..29aa07a8a05a2 100644 --- a/tests/mir-opt/pre-codegen/clone_as_copy.enum_clone_as_copy.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/clone_as_copy.enum_clone_as_copy.PreCodegen.after.mir @@ -35,15 +35,15 @@ fn enum_clone_as_copy(_1: &Enum1) -> Enum1 { } bb1: { - _3 = &(((*_1) as A).0: AllCopy); + // DBG: _3 = &(((*_1) as A).0: AllCopy) _0 = copy (*_1); goto -> bb3; } bb2: { - _4 = &(((*_1) as B).0: NestCopy); + // DBG: _4 = &(((*_1) as B).0: NestCopy) StorageLive(_5); - _5 = &((((*_1) as B).0: NestCopy).1: AllCopy); + // DBG: _5 = &((((*_1) as B).0: NestCopy).1: AllCopy) StorageDead(_5); _0 = copy (*_1); goto -> bb3; diff --git a/tests/mir-opt/pre-codegen/loops.filter_mapped.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/loops.filter_mapped.PreCodegen.after.mir index 75e8cb1d8618c..9e00e27b2d10e 100644 --- a/tests/mir-opt/pre-codegen/loops.filter_mapped.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/loops.filter_mapped.PreCodegen.after.mir @@ -6,20 +6,20 @@ fn filter_mapped(_1: impl Iterator, _2: impl Fn(T) -> Option) -> () let mut _0: (); let mut _3: std::iter::FilterMap, impl Fn(T) -> Option>; let mut _4: std::iter::FilterMap, impl Fn(T) -> Option>; - let mut _5: &mut std::iter::FilterMap, impl Fn(T) -> Option>; - let mut _8: std::option::Option; - let mut _9: isize; - let _11: (); + let mut _7: std::option::Option; + let mut _8: isize; + let _10: (); + let mut _11: &mut std::iter::FilterMap, impl Fn(T) -> Option>; scope 1 { debug iter => _4; - let _10: U; + let _9: U; scope 2 { - debug x => _10; + debug x => _9; } scope 4 (inlined , impl Fn(T) -> Option> as Iterator>::next) { - debug self => _5; - let mut _6: &mut impl Iterator; - let mut _7: &mut impl Fn(T) -> Option; + debug self => _11; + let mut _5: &mut impl Iterator; + let mut _6: &mut impl Fn(T) -> Option; } } scope 3 (inlined , impl Fn(T) -> Option> as IntoIterator>::into_iter) { @@ -37,24 +37,24 @@ fn filter_mapped(_1: impl Iterator, _2: impl Fn(T) -> Option) -> () } bb2: { - StorageLive(_8); - _5 = &mut _4; - StorageLive(_6); - _6 = &mut (_4.0: impl Iterator); StorageLive(_7); - _7 = &mut (_4.1: impl Fn(T) -> Option); - _8 = as Iterator>::find_map:: Option>(move _6, move _7) -> [return: bb3, unwind: bb9]; + // DBG: _11 = &_4 + StorageLive(_5); + _5 = &mut (_4.0: impl Iterator); + StorageLive(_6); + _6 = &mut (_4.1: impl Fn(T) -> Option); + _7 = as Iterator>::find_map:: Option>(move _5, move _6) -> [return: bb3, unwind: bb9]; } bb3: { - StorageDead(_7); StorageDead(_6); - _9 = discriminant(_8); - switchInt(move _9) -> [0: bb4, 1: bb6, otherwise: bb8]; + StorageDead(_5); + _8 = discriminant(_7); + switchInt(move _8) -> [0: bb4, 1: bb6, otherwise: bb8]; } bb4: { - StorageDead(_8); + StorageDead(_7); drop(_4) -> [return: bb5, unwind continue]; } @@ -64,12 +64,12 @@ fn filter_mapped(_1: impl Iterator, _2: impl Fn(T) -> Option) -> () } bb6: { - _10 = move ((_8 as Some).0: U); - _11 = opaque::(move _10) -> [return: bb7, unwind: bb9]; + _9 = move ((_7 as Some).0: U); + _10 = opaque::(move _9) -> [return: bb7, unwind: bb9]; } bb7: { - StorageDead(_8); + StorageDead(_7); goto -> bb2; } diff --git a/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir index 154cbd3791cbd..03cb60d51c2a9 100644 --- a/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir @@ -6,31 +6,31 @@ fn int_range(_1: usize, _2: usize) -> () { let mut _0: (); let mut _3: std::ops::Range; let mut _4: std::ops::Range; - let mut _5: &mut std::ops::Range; - let mut _13: std::option::Option; - let _15: (); + let mut _10: std::option::Option; + let _12: (); + let mut _13: &mut std::ops::Range; scope 1 { debug iter => _4; - let _14: usize; + let _11: usize; scope 2 { - debug i => _14; + debug i => _11; } scope 4 (inlined iter::range::>::next) { - debug self => _5; + debug self => _13; scope 5 (inlined as iter::range::RangeIteratorImpl>::spec_next) { - debug self => _5; - let mut _6: &usize; - let mut _7: &usize; - let mut _10: bool; - let _11: usize; - let mut _12: usize; + debug self => _13; + let mut _7: bool; + let _8: usize; + let mut _9: usize; + let mut _14: &usize; + let mut _15: &usize; scope 6 { - debug old => _11; + debug old => _8; scope 8 (inlined ::forward_unchecked) { - debug start => _11; + debug start => _8; debug n => const 1_usize; scope 9 (inlined #[track_caller] core::num::::unchecked_add) { - debug self => _11; + debug self => _8; debug rhs => const 1_usize; scope 10 (inlined core::ub_checks::check_language_ub) { scope 11 (inlined core::ub_checks::check_language_ub::runtime) { @@ -40,10 +40,10 @@ fn int_range(_1: usize, _2: usize) -> () { } } scope 7 (inlined std::cmp::impls::::lt) { - debug self => _6; - debug other => _7; - let mut _8: usize; - let mut _9: usize; + debug self => _14; + debug other => _15; + let mut _5: usize; + let mut _6: usize; } } } @@ -60,48 +60,48 @@ fn int_range(_1: usize, _2: usize) -> () { } bb1: { - StorageLive(_13); - _5 = &mut _4; StorageLive(_10); - StorageLive(_6); - _6 = &(_4.0: usize); + // DBG: _13 = &_4 StorageLive(_7); - _7 = &(_4.1: usize); - StorageLive(_8); - _8 = copy (_4.0: usize); - StorageLive(_9); - _9 = copy (_4.1: usize); - _10 = Lt(move _8, move _9); - StorageDead(_9); - StorageDead(_8); - switchInt(move _10) -> [0: bb2, otherwise: bb3]; + StorageLive(_14); + // DBG: _14 = &(_4.0: usize) + StorageLive(_15); + // DBG: _15 = &(_4.1: usize) + StorageLive(_5); + _5 = copy (_4.0: usize); + StorageLive(_6); + _6 = copy (_4.1: usize); + _7 = Lt(move _5, move _6); + StorageDead(_6); + StorageDead(_5); + switchInt(move _7) -> [0: bb2, otherwise: bb3]; } bb2: { + StorageDead(_15); + StorageDead(_14); StorageDead(_7); - StorageDead(_6); StorageDead(_10); - StorageDead(_13); StorageDead(_4); return; } bb3: { + StorageDead(_15); + StorageDead(_14); + _8 = copy (_4.0: usize); + StorageLive(_9); + _9 = AddUnchecked(copy _8, const 1_usize); + (_4.0: usize) = move _9; + StorageDead(_9); + _10 = Option::::Some(copy _8); StorageDead(_7); - StorageDead(_6); - _11 = copy (_4.0: usize); - StorageLive(_12); - _12 = AddUnchecked(copy _11, const 1_usize); - (_4.0: usize) = move _12; - StorageDead(_12); - _13 = Option::::Some(copy _11); - StorageDead(_10); - _14 = copy ((_13 as Some).0: usize); - _15 = opaque::(move _14) -> [return: bb4, unwind continue]; + _11 = copy ((_10 as Some).0: usize); + _12 = opaque::(move _11) -> [return: bb4, unwind continue]; } bb4: { - StorageDead(_13); + StorageDead(_10); goto -> bb1; } } diff --git a/tests/mir-opt/pre-codegen/loops.mapped.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/loops.mapped.PreCodegen.after.mir index d22ea54004c91..ea7b72f3be7d8 100644 --- a/tests/mir-opt/pre-codegen/loops.mapped.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/loops.mapped.PreCodegen.after.mir @@ -6,32 +6,32 @@ fn mapped(_1: impl Iterator, _2: impl Fn(T) -> U) -> () { let mut _0: (); let mut _3: std::iter::Map, impl Fn(T) -> U>; let mut _4: std::iter::Map, impl Fn(T) -> U>; - let mut _5: &mut std::iter::Map, impl Fn(T) -> U>; - let mut _13: std::option::Option; - let _15: (); + let mut _12: std::option::Option; + let _14: (); + let mut _15: &mut std::iter::Map, impl Fn(T) -> U>; scope 1 { debug iter => _4; - let _14: U; + let _13: U; scope 2 { - debug x => _14; + debug x => _13; } scope 4 (inlined , impl Fn(T) -> U> as Iterator>::next) { - debug self => _5; - let mut _6: &mut impl Iterator; - let mut _7: std::option::Option; - let mut _8: &mut impl Fn(T) -> U; + debug self => _15; + let mut _5: &mut impl Iterator; + let mut _6: std::option::Option; + let mut _7: &mut impl Fn(T) -> U; scope 5 (inlined Option::::map:: U>) { - debug self => _7; - debug f => _8; - let mut _9: isize; - let _10: T; - let mut _11: (T,); - let mut _12: U; + debug self => _6; + debug f => _7; + let mut _8: isize; + let _9: T; + let mut _10: (T,); + let mut _11: U; scope 6 { - debug x => _10; + debug x => _9; scope 7 (inlined ops::function::impls:: for &mut impl Fn(T) -> U>::call_once) { - debug self => _8; - debug args => _11; + debug self => _7; + debug args => _10; } } } @@ -52,30 +52,30 @@ fn mapped(_1: impl Iterator, _2: impl Fn(T) -> U) -> () { } bb2: { - StorageLive(_13); - _5 = &mut _4; - StorageLive(_8); + StorageLive(_12); + // DBG: _15 = &_4 StorageLive(_7); StorageLive(_6); - _6 = &mut (_4.0: impl Iterator); - _7 = as Iterator>::next(move _6) -> [return: bb3, unwind: bb10]; + StorageLive(_5); + _5 = &mut (_4.0: impl Iterator); + _6 = as Iterator>::next(move _5) -> [return: bb3, unwind: bb10]; } bb3: { - StorageDead(_6); - _8 = &mut (_4.1: impl Fn(T) -> U); + StorageDead(_5); + _7 = &mut (_4.1: impl Fn(T) -> U); + StorageLive(_8); StorageLive(_9); - StorageLive(_10); - _9 = discriminant(_7); - switchInt(move _9) -> [0: bb4, 1: bb6, otherwise: bb9]; + _8 = discriminant(_6); + switchInt(move _8) -> [0: bb4, 1: bb6, otherwise: bb9]; } bb4: { - StorageDead(_10); StorageDead(_9); - StorageDead(_7); StorageDead(_8); - StorageDead(_13); + StorageDead(_6); + StorageDead(_7); + StorageDead(_12); drop(_4) -> [return: bb5, unwind continue]; } @@ -85,27 +85,27 @@ fn mapped(_1: impl Iterator, _2: impl Fn(T) -> U) -> () { } bb6: { - _10 = move ((_7 as Some).0: T); - StorageLive(_12); + _9 = move ((_6 as Some).0: T); StorageLive(_11); - _11 = (copy _10,); - _12 = U as FnMut<(T,)>>::call_mut(move _8, move _11) -> [return: bb7, unwind: bb10]; + StorageLive(_10); + _10 = (copy _9,); + _11 = U as FnMut<(T,)>>::call_mut(move _7, move _10) -> [return: bb7, unwind: bb10]; } bb7: { - StorageDead(_11); - _13 = Option::::Some(move _12); - StorageDead(_12); StorageDead(_10); + _12 = Option::::Some(move _11); + StorageDead(_11); StorageDead(_9); - StorageDead(_7); StorageDead(_8); - _14 = move ((_13 as Some).0: U); - _15 = opaque::(move _14) -> [return: bb8, unwind: bb10]; + StorageDead(_6); + StorageDead(_7); + _13 = move ((_12 as Some).0: U); + _14 = opaque::(move _13) -> [return: bb8, unwind: bb10]; } bb8: { - StorageDead(_13); + StorageDead(_12); goto -> bb2; } 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 cbdd194afd3ab..ef93d1b114b47 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,183 +3,164 @@ 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 _4: &usize; - let _5: &usize; - let _6: &usize; - let _7: &usize; - let mut _8: &&usize; - let _9: &usize; - let mut _10: &&usize; - let mut _13: bool; - let mut _14: &&usize; + let mut _6: bool; + let mut _9: bool; + let mut _10: bool; + let _13: &usize; + let _14: &usize; let _15: &usize; - let mut _16: &&usize; - let mut _19: bool; + let _16: &usize; + let mut _17: &&usize; + let mut _18: &&usize; + let mut _19: &&usize; let mut _20: &&usize; - let _21: &usize; + let mut _21: &&usize; let mut _22: &&usize; - let mut _23: bool; + let mut _23: &&usize; let mut _24: &&usize; - let _25: &usize; - let mut _26: &&usize; scope 1 { - debug a => _4; - debug b => _5; - debug c => _6; - debug d => _7; + debug a => _13; + debug b => _14; + debug c => _15; + debug d => _16; scope 2 (inlined std::cmp::impls::::le) { - debug self => _8; - debug other => _10; + debug self => _17; + debug other => _18; scope 3 (inlined std::cmp::impls::::le) { - debug self => _4; - debug other => _6; - let mut _11: usize; - let mut _12: usize; + debug self => _13; + debug other => _15; + let mut _4: usize; + let mut _5: usize; } } scope 4 (inlined std::cmp::impls::::le) { - debug self => _14; - debug other => _16; + debug self => _19; + debug other => _20; scope 5 (inlined std::cmp::impls::::le) { - debug self => _7; - debug other => _5; - let mut _17: usize; - let mut _18: usize; + debug self => _16; + debug other => _14; + let mut _7: usize; + let mut _8: usize; } } scope 6 (inlined std::cmp::impls::::le) { - debug self => _20; + debug self => _21; debug other => _22; scope 7 (inlined std::cmp::impls::::le) { - debug self => _6; - debug other => _4; + debug self => _15; + debug other => _13; } } scope 8 (inlined std::cmp::impls::::le) { - debug self => _24; - debug other => _26; + debug self => _23; + debug other => _24; scope 9 (inlined std::cmp::impls::::le) { - debug self => _5; - debug other => _7; - let mut _27: usize; - let mut _28: usize; + debug self => _14; + debug other => _16; + let mut _11: usize; + let mut _12: usize; } } } bb0: { _3 = copy (*_2); - _4 = &((*_3).0: usize); - _5 = &((*_3).1: usize); - _6 = &((*_3).2: usize); - _7 = &((*_3).3: usize); - StorageLive(_13); - 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]; + // DBG: _13 = &((*_3).0: usize) + // DBG: _14 = &((*_3).1: usize) + // DBG: _15 = &((*_3).2: usize) + // DBG: _16 = &((*_3).3: usize) + StorageLive(_6); + StorageLive(_17); + // DBG: _17 = &_13 + StorageLive(_18); + // DBG: _18 = &_15 + _4 = copy ((*_3).0: usize); + _5 = copy ((*_3).2: usize); + _6 = Le(copy _4, copy _5); + switchInt(move _6) -> [0: bb1, otherwise: bb2]; } bb1: { - StorageDead(_9); - StorageDead(_10); - StorageDead(_8); + StorageDead(_18); + StorageDead(_17); goto -> bb4; } bb2: { - 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 ((*_3).1: usize); - _19 = Le(move _17, move _18); StorageDead(_18); StorageDead(_17); - switchInt(move _19) -> [0: bb3, otherwise: bb8]; + StorageLive(_9); + StorageLive(_19); + // DBG: _19 = &_16 + StorageLive(_20); + // DBG: _20 = &_14 + 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: bb3, otherwise: bb8]; } bb3: { - StorageDead(_15); - StorageDead(_16); - StorageDead(_14); + StorageDead(_20); + StorageDead(_19); goto -> bb4; } bb4: { - StorageLive(_23); - StorageLive(_20); - _20 = &_6; - StorageLive(_22); + StorageLive(_10); StorageLive(_21); - _21 = copy _4; - _22 = &_21; - _23 = Le(copy _12, copy _11); - switchInt(move _23) -> [0: bb5, otherwise: bb6]; + // DBG: _21 = &_15 + StorageLive(_22); + // DBG: _22 = &_13 + _10 = Le(copy _5, copy _4); + switchInt(move _10) -> [0: bb5, otherwise: bb6]; } bb5: { - StorageDead(_21); StorageDead(_22); - StorageDead(_20); + StorageDead(_21); _0 = const false; goto -> bb7; } bb6: { - StorageDead(_21); StorageDead(_22); - StorageDead(_20); + StorageDead(_21); + StorageLive(_23); + // DBG: _23 = &_14 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(_26); + // DBG: _24 = &_16 + StorageLive(_11); + _11 = copy ((*_3).1: usize); + StorageLive(_12); + _12 = copy ((*_3).3: usize); + _0 = Le(move _11, move _12); + StorageDead(_12); + StorageDead(_11); StorageDead(_24); + StorageDead(_23); goto -> bb7; } bb7: { - StorageDead(_23); + StorageDead(_10); goto -> bb9; } bb8: { - StorageDead(_15); - StorageDead(_16); - StorageDead(_14); + StorageDead(_20); + StorageDead(_19); _0 = const true; goto -> bb9; } bb9: { - StorageDead(_19); - StorageDead(_13); + StorageDead(_9); + StorageDead(_6); return; } } diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir index b09e36223441a..810297105b5ee 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir @@ -7,19 +7,89 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { let mut _11: std::slice::Iter<'_, T>; let mut _12: std::iter::Rev>; let mut _13: std::iter::Rev>; - let mut _15: std::option::Option<&T>; - let mut _16: isize; - let mut _18: &impl Fn(&T); - let mut _19: (&T,); - let _20: (); + let mut _36: std::option::Option<&T>; + let mut _38: &impl Fn(&T); + let mut _39: (&T,); + let _40: (); scope 1 { debug iter => _13; - let _17: &T; + let _37: &T; scope 2 { - debug x => _17; + debug x => _37; } scope 18 (inlined > as Iterator>::next) { - let mut _14: &mut std::slice::Iter<'_, T>; + scope 19 (inlined as DoubleEndedIterator>::next_back) { + let mut _14: *const T; + let mut _19: bool; + let mut _20: *const T; + let _35: &T; + scope 20 { + let _15: std::ptr::NonNull; + let _21: usize; + scope 21 { + } + scope 22 { + scope 25 (inlined as PartialEq>::eq) { + let mut _16: std::ptr::NonNull; + let mut _17: *mut T; + let mut _18: *mut T; + scope 26 (inlined NonNull::::as_ptr) { + } + scope 27 (inlined NonNull::::as_ptr) { + } + } + } + scope 23 (inlined std::ptr::const_ptr::::addr) { + scope 24 (inlined std::ptr::const_ptr::::cast::<()>) { + } + } + } + scope 28 (inlined std::slice::Iter::<'_, T>::next_back_unchecked) { + let _28: std::ptr::NonNull; + scope 29 (inlined std::slice::Iter::<'_, T>::pre_dec_end) { + let mut _22: *mut *const T; + let mut _23: *mut std::ptr::NonNull; + let mut _24: std::ptr::NonNull; + let mut _27: std::ptr::NonNull; + let mut _29: *mut *const T; + let mut _30: *mut usize; + let mut _31: usize; + let mut _32: usize; + scope 30 { + scope 31 { + } + scope 32 { + scope 35 (inlined NonNull::::sub) { + scope 36 (inlined #[track_caller] core::num::::unchecked_neg) { + scope 37 (inlined core::ub_checks::check_language_ub) { + scope 38 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + } + scope 39 (inlined NonNull::::offset) { + let mut _25: *const T; + let mut _26: *const T; + scope 40 (inlined NonNull::::as_ptr) { + } + } + } + } + scope 33 (inlined std::ptr::mut_ptr::::cast::) { + } + scope 34 (inlined std::ptr::mut_ptr::::cast::>) { + } + } + } + scope 41 (inlined NonNull::::as_ref::<'_>) { + let mut _33: std::ptr::NonNull; + let _34: *const T; + scope 42 (inlined NonNull::::as_ptr) { + } + scope 43 (inlined std::ptr::mut_ptr::::cast_const) { + } + } + } + } } } scope 3 (inlined core::slice::::iter) { @@ -109,45 +179,146 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { } bb4: { + StorageLive(_36); + StorageLive(_21); + StorageLive(_20); StorageLive(_15); - StorageLive(_14); - _14 = &mut (_13.0: std::slice::Iter<'_, T>); - _15 = as DoubleEndedIterator>::next_back(move _14) -> [return: bb5, unwind unreachable]; + StorageLive(_35); + StorageLive(_19); + switchInt(const ::IS_ZST) -> [0: bb5, otherwise: bb6]; } bb5: { + StorageLive(_14); + _14 = copy ((_13.0: std::slice::Iter<'_, T>).1: *const T); + _15 = move _14 as std::ptr::NonNull (Transmute); StorageDead(_14); - _16 = discriminant(_15); - switchInt(move _16) -> [0: bb6, 1: bb8, otherwise: bb10]; + StorageLive(_17); + StorageLive(_16); + _16 = copy ((_13.0: std::slice::Iter<'_, T>).0: std::ptr::NonNull); + _17 = copy _16 as *mut T (Transmute); + StorageDead(_16); + StorageLive(_18); + _18 = copy _15 as *mut T (Transmute); + _19 = Eq(move _17, move _18); + StorageDead(_18); + StorageDead(_17); + goto -> bb7; } bb6: { - StorageDead(_15); - StorageDead(_13); - drop(_2) -> [return: bb7, unwind unreachable]; + _20 = copy ((_13.0: std::slice::Iter<'_, T>).1: *const T); + _21 = copy _20 as usize (Transmute); + _19 = Eq(copy _21, const 0_usize); + goto -> bb7; } bb7: { - return; + switchInt(move _19) -> [0: bb8, otherwise: bb16]; } bb8: { - _17 = copy ((_15 as Some).0: &T); - StorageLive(_18); - _18 = &_2; - StorageLive(_19); - _19 = (copy _17,); - _20 = >::call(move _18, move _19) -> [return: bb9, unwind unreachable]; + StorageLive(_28); + StorageLive(_30); + StorageLive(_23); + switchInt(const ::IS_ZST) -> [0: bb9, otherwise: bb13]; } bb9: { + StorageLive(_22); + _22 = &raw mut ((_13.0: std::slice::Iter<'_, T>).1: *const T); + _23 = copy _22 as *mut std::ptr::NonNull (PtrToPtr); + StorageDead(_22); + StorageLive(_27); + StorageLive(_24); + _24 = copy (*_23); + switchInt(const ::IS_ZST) -> [0: bb10, otherwise: bb11]; + } + + bb10: { + StorageLive(_26); + StorageLive(_25); + _25 = copy _24 as *const T (Transmute); + _26 = Offset(move _25, const -1_isize); + StorageDead(_25); + _27 = NonNull:: { pointer: move _26 }; + StorageDead(_26); + goto -> bb12; + } + + bb11: { + _27 = copy _24; + goto -> bb12; + } + + bb12: { + StorageDead(_24); + (*_23) = move _27; + StorageDead(_27); + _28 = copy (*_23); + goto -> bb14; + } + + bb13: { + StorageLive(_29); + _29 = &raw mut ((_13.0: std::slice::Iter<'_, T>).1: *const T); + _30 = copy _29 as *mut usize (PtrToPtr); + StorageDead(_29); + StorageLive(_32); + StorageLive(_31); + _31 = copy (*_30); + _32 = SubUnchecked(move _31, const 1_usize); + StorageDead(_31); + (*_30) = move _32; + StorageDead(_32); + _28 = copy ((_13.0: std::slice::Iter<'_, T>).0: std::ptr::NonNull); + goto -> bb14; + } + + bb14: { + StorageDead(_23); + StorageDead(_30); + StorageLive(_33); + StorageLive(_34); + _33 = copy _28; + _34 = copy _33 as *const T (Transmute); + _35 = &(*_34); + StorageDead(_34); + StorageDead(_33); + StorageDead(_28); + _36 = Option::<&T>::Some(copy _35); StorageDead(_19); - StorageDead(_18); + StorageDead(_35); StorageDead(_15); + StorageDead(_20); + StorageDead(_21); + _37 = copy ((_36 as Some).0: &T); + StorageLive(_38); + _38 = &_2; + StorageLive(_39); + _39 = (copy _37,); + _40 = >::call(move _38, move _39) -> [return: bb15, unwind unreachable]; + } + + bb15: { + StorageDead(_39); + StorageDead(_38); + StorageDead(_36); goto -> bb4; } - bb10: { - unreachable; + bb16: { + StorageDead(_19); + StorageDead(_35); + StorageDead(_15); + StorageDead(_20); + StorageDead(_21); + StorageDead(_36); + StorageDead(_13); + drop(_2) -> [return: bb17, unwind unreachable]; + } + + bb17: { + return; } } diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir index 12b54b57b8448..aea27f9cf867b 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir @@ -7,19 +7,89 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { let mut _11: std::slice::Iter<'_, T>; let mut _12: std::iter::Rev>; let mut _13: std::iter::Rev>; - let mut _15: std::option::Option<&T>; - let mut _16: isize; - let mut _18: &impl Fn(&T); - let mut _19: (&T,); - let _20: (); + let mut _36: std::option::Option<&T>; + let mut _38: &impl Fn(&T); + let mut _39: (&T,); + let _40: (); scope 1 { debug iter => _13; - let _17: &T; + let _37: &T; scope 2 { - debug x => _17; + debug x => _37; } scope 18 (inlined > as Iterator>::next) { - let mut _14: &mut std::slice::Iter<'_, T>; + scope 19 (inlined as DoubleEndedIterator>::next_back) { + let mut _14: *const T; + let mut _19: bool; + let mut _20: *const T; + let _35: &T; + scope 20 { + let _15: std::ptr::NonNull; + let _21: usize; + scope 21 { + } + scope 22 { + scope 25 (inlined as PartialEq>::eq) { + let mut _16: std::ptr::NonNull; + let mut _17: *mut T; + let mut _18: *mut T; + scope 26 (inlined NonNull::::as_ptr) { + } + scope 27 (inlined NonNull::::as_ptr) { + } + } + } + scope 23 (inlined std::ptr::const_ptr::::addr) { + scope 24 (inlined std::ptr::const_ptr::::cast::<()>) { + } + } + } + scope 28 (inlined std::slice::Iter::<'_, T>::next_back_unchecked) { + let _28: std::ptr::NonNull; + scope 29 (inlined std::slice::Iter::<'_, T>::pre_dec_end) { + let mut _22: *mut *const T; + let mut _23: *mut std::ptr::NonNull; + let mut _24: std::ptr::NonNull; + let mut _27: std::ptr::NonNull; + let mut _29: *mut *const T; + let mut _30: *mut usize; + let mut _31: usize; + let mut _32: usize; + scope 30 { + scope 31 { + } + scope 32 { + scope 35 (inlined NonNull::::sub) { + scope 36 (inlined #[track_caller] core::num::::unchecked_neg) { + scope 37 (inlined core::ub_checks::check_language_ub) { + scope 38 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + } + scope 39 (inlined NonNull::::offset) { + let mut _25: *const T; + let mut _26: *const T; + scope 40 (inlined NonNull::::as_ptr) { + } + } + } + } + scope 33 (inlined std::ptr::mut_ptr::::cast::) { + } + scope 34 (inlined std::ptr::mut_ptr::::cast::>) { + } + } + } + scope 41 (inlined NonNull::::as_ref::<'_>) { + let mut _33: std::ptr::NonNull; + let _34: *const T; + scope 42 (inlined NonNull::::as_ptr) { + } + scope 43 (inlined std::ptr::mut_ptr::::cast_const) { + } + } + } + } } } scope 3 (inlined core::slice::::iter) { @@ -109,53 +179,154 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { } bb4: { + StorageLive(_36); + StorageLive(_21); + StorageLive(_20); StorageLive(_15); - StorageLive(_14); - _14 = &mut (_13.0: std::slice::Iter<'_, T>); - _15 = as DoubleEndedIterator>::next_back(move _14) -> [return: bb5, unwind: bb11]; + StorageLive(_35); + StorageLive(_19); + switchInt(const ::IS_ZST) -> [0: bb5, otherwise: bb6]; } bb5: { + StorageLive(_14); + _14 = copy ((_13.0: std::slice::Iter<'_, T>).1: *const T); + _15 = move _14 as std::ptr::NonNull (Transmute); StorageDead(_14); - _16 = discriminant(_15); - switchInt(move _16) -> [0: bb6, 1: bb8, otherwise: bb10]; + StorageLive(_17); + StorageLive(_16); + _16 = copy ((_13.0: std::slice::Iter<'_, T>).0: std::ptr::NonNull); + _17 = copy _16 as *mut T (Transmute); + StorageDead(_16); + StorageLive(_18); + _18 = copy _15 as *mut T (Transmute); + _19 = Eq(move _17, move _18); + StorageDead(_18); + StorageDead(_17); + goto -> bb7; } bb6: { - StorageDead(_15); - StorageDead(_13); - drop(_2) -> [return: bb7, unwind continue]; + _20 = copy ((_13.0: std::slice::Iter<'_, T>).1: *const T); + _21 = copy _20 as usize (Transmute); + _19 = Eq(copy _21, const 0_usize); + goto -> bb7; } bb7: { - return; + switchInt(move _19) -> [0: bb8, otherwise: bb18]; } bb8: { - _17 = copy ((_15 as Some).0: &T); - StorageLive(_18); - _18 = &_2; - StorageLive(_19); - _19 = (copy _17,); - _20 = >::call(move _18, move _19) -> [return: bb9, unwind: bb11]; + StorageLive(_28); + StorageLive(_30); + StorageLive(_23); + switchInt(const ::IS_ZST) -> [0: bb9, otherwise: bb13]; } bb9: { + StorageLive(_22); + _22 = &raw mut ((_13.0: std::slice::Iter<'_, T>).1: *const T); + _23 = copy _22 as *mut std::ptr::NonNull (PtrToPtr); + StorageDead(_22); + StorageLive(_27); + StorageLive(_24); + _24 = copy (*_23); + switchInt(const ::IS_ZST) -> [0: bb10, otherwise: bb11]; + } + + bb10: { + StorageLive(_26); + StorageLive(_25); + _25 = copy _24 as *const T (Transmute); + _26 = Offset(move _25, const -1_isize); + StorageDead(_25); + _27 = NonNull:: { pointer: move _26 }; + StorageDead(_26); + goto -> bb12; + } + + bb11: { + _27 = copy _24; + goto -> bb12; + } + + bb12: { + StorageDead(_24); + (*_23) = move _27; + StorageDead(_27); + _28 = copy (*_23); + goto -> bb14; + } + + bb13: { + StorageLive(_29); + _29 = &raw mut ((_13.0: std::slice::Iter<'_, T>).1: *const T); + _30 = copy _29 as *mut usize (PtrToPtr); + StorageDead(_29); + StorageLive(_32); + StorageLive(_31); + _31 = copy (*_30); + _32 = SubUnchecked(move _31, const 1_usize); + StorageDead(_31); + (*_30) = move _32; + StorageDead(_32); + _28 = copy ((_13.0: std::slice::Iter<'_, T>).0: std::ptr::NonNull); + goto -> bb14; + } + + bb14: { + StorageDead(_23); + StorageDead(_30); + StorageLive(_33); + StorageLive(_34); + _33 = copy _28; + _34 = copy _33 as *const T (Transmute); + _35 = &(*_34); + StorageDead(_34); + StorageDead(_33); + StorageDead(_28); + _36 = Option::<&T>::Some(copy _35); StorageDead(_19); - StorageDead(_18); + StorageDead(_35); StorageDead(_15); - goto -> bb4; + StorageDead(_20); + StorageDead(_21); + _37 = copy ((_36 as Some).0: &T); + StorageLive(_38); + _38 = &_2; + StorageLive(_39); + _39 = (copy _37,); + _40 = >::call(move _38, move _39) -> [return: bb15, unwind: bb16]; } - bb10: { - unreachable; + bb15: { + StorageDead(_39); + StorageDead(_38); + StorageDead(_36); + goto -> bb4; } - bb11 (cleanup): { - drop(_2) -> [return: bb12, unwind terminate(cleanup)]; + bb16 (cleanup): { + drop(_2) -> [return: bb17, unwind terminate(cleanup)]; } - bb12 (cleanup): { + bb17 (cleanup): { resume; } + + bb18: { + StorageDead(_19); + StorageDead(_35); + StorageDead(_15); + StorageDead(_20); + StorageDead(_21); + StorageDead(_36); + StorageDead(_13); + drop(_2) -> [return: bb19, unwind continue]; + } + + bb19: { + return; + } } diff --git a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_mut_next_back.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_mut_next_back.PreCodegen.after.panic-abort.mir index 78f96bf419559..7fb801a12227b 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_mut_next_back.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_mut_next_back.PreCodegen.after.panic-abort.mir @@ -3,12 +3,199 @@ fn slice_iter_mut_next_back(_1: &mut std::slice::IterMut<'_, T>) -> Option<&mut T> { debug it => _1; let mut _0: std::option::Option<&mut T>; + scope 1 (inlined as DoubleEndedIterator>::next_back) { + let mut _2: *mut T; + let mut _7: bool; + let mut _8: *mut T; + let mut _23: &mut T; + scope 2 { + let _3: std::ptr::NonNull; + let _9: usize; + scope 3 { + } + scope 4 { + scope 7 (inlined as PartialEq>::eq) { + let mut _4: std::ptr::NonNull; + let mut _5: *mut T; + let mut _6: *mut T; + scope 8 (inlined NonNull::::as_ptr) { + } + scope 9 (inlined NonNull::::as_ptr) { + } + } + } + scope 5 (inlined std::ptr::mut_ptr::::addr) { + scope 6 (inlined std::ptr::mut_ptr::::cast::<()>) { + } + } + } + scope 10 (inlined std::slice::IterMut::<'_, T>::next_back_unchecked) { + let mut _16: std::ptr::NonNull; + scope 11 (inlined std::slice::IterMut::<'_, T>::pre_dec_end) { + let mut _10: *mut *mut T; + let mut _11: *mut std::ptr::NonNull; + let mut _12: std::ptr::NonNull; + let mut _15: std::ptr::NonNull; + let mut _17: *mut *mut T; + let mut _18: *mut usize; + let mut _19: usize; + let mut _20: usize; + scope 12 { + scope 13 { + } + scope 14 { + scope 17 (inlined NonNull::::sub) { + scope 18 (inlined #[track_caller] core::num::::unchecked_neg) { + scope 19 (inlined core::ub_checks::check_language_ub) { + scope 20 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + } + scope 21 (inlined NonNull::::offset) { + let mut _13: *const T; + let mut _14: *const T; + scope 22 (inlined NonNull::::as_ptr) { + } + } + } + } + scope 15 (inlined std::ptr::mut_ptr::::cast::) { + } + scope 16 (inlined std::ptr::mut_ptr::::cast::>) { + } + } + } + scope 23 (inlined NonNull::::as_mut::<'_>) { + let mut _21: std::ptr::NonNull; + let mut _22: *mut T; + scope 24 (inlined NonNull::::as_ptr) { + } + } + } + } bb0: { - _0 = as DoubleEndedIterator>::next_back(move _1) -> [return: bb1, unwind unreachable]; + StorageLive(_9); + StorageLive(_8); + StorageLive(_3); + StorageLive(_2); + StorageLive(_23); + StorageLive(_7); + switchInt(const ::IS_ZST) -> [0: bb1, otherwise: bb2]; } bb1: { + _2 = copy ((*_1).1: *mut T); + _3 = copy _2 as std::ptr::NonNull (Transmute); + StorageLive(_5); + StorageLive(_4); + _4 = copy ((*_1).0: std::ptr::NonNull); + _5 = copy _4 as *mut T (Transmute); + StorageDead(_4); + StorageLive(_6); + _6 = copy _3 as *mut T (Transmute); + _7 = Eq(move _5, move _6); + StorageDead(_6); + StorageDead(_5); + goto -> bb3; + } + + bb2: { + _8 = copy ((*_1).1: *mut T); + _9 = copy _8 as usize (Transmute); + _7 = Eq(copy _9, const 0_usize); + goto -> bb3; + } + + bb3: { + switchInt(move _7) -> [0: bb4, otherwise: bb11]; + } + + bb4: { + StorageLive(_16); + StorageLive(_18); + StorageLive(_11); + switchInt(const ::IS_ZST) -> [0: bb5, otherwise: bb9]; + } + + bb5: { + StorageLive(_10); + _10 = &raw mut ((*_1).1: *mut T); + _11 = copy _10 as *mut std::ptr::NonNull (PtrToPtr); + StorageDead(_10); + StorageLive(_15); + StorageLive(_12); + _12 = copy (*_11); + switchInt(const ::IS_ZST) -> [0: bb6, otherwise: bb7]; + } + + bb6: { + StorageLive(_14); + StorageLive(_13); + _13 = copy _12 as *const T (Transmute); + _14 = Offset(move _13, const -1_isize); + StorageDead(_13); + _15 = NonNull:: { pointer: move _14 }; + StorageDead(_14); + goto -> bb8; + } + + bb7: { + _15 = copy _12; + goto -> bb8; + } + + bb8: { + StorageDead(_12); + (*_11) = move _15; + StorageDead(_15); + _16 = copy (*_11); + goto -> bb10; + } + + bb9: { + StorageLive(_17); + _17 = &raw mut ((*_1).1: *mut T); + _18 = copy _17 as *mut usize (PtrToPtr); + StorageDead(_17); + StorageLive(_20); + StorageLive(_19); + _19 = copy (*_18); + _20 = SubUnchecked(move _19, const 1_usize); + StorageDead(_19); + (*_18) = move _20; + StorageDead(_20); + _16 = copy ((*_1).0: std::ptr::NonNull); + goto -> bb10; + } + + bb10: { + StorageDead(_11); + StorageDead(_18); + StorageLive(_22); + StorageLive(_21); + _21 = copy _16; + _22 = copy _21 as *mut T (Transmute); + StorageDead(_21); + _23 = &mut (*_22); + StorageDead(_22); + StorageDead(_16); + _0 = Option::<&mut T>::Some(copy _23); + goto -> bb12; + } + + bb11: { + _0 = const {transmute(0x0000000000000000): Option<&mut T>}; + goto -> bb12; + } + + bb12: { + StorageDead(_7); + StorageDead(_23); + StorageDead(_2); + StorageDead(_3); + StorageDead(_8); + StorageDead(_9); return; } } diff --git a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_mut_next_back.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_mut_next_back.PreCodegen.after.panic-unwind.mir index dfe5e206fadaf..7fb801a12227b 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_mut_next_back.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_mut_next_back.PreCodegen.after.panic-unwind.mir @@ -3,12 +3,199 @@ fn slice_iter_mut_next_back(_1: &mut std::slice::IterMut<'_, T>) -> Option<&mut T> { debug it => _1; let mut _0: std::option::Option<&mut T>; + scope 1 (inlined as DoubleEndedIterator>::next_back) { + let mut _2: *mut T; + let mut _7: bool; + let mut _8: *mut T; + let mut _23: &mut T; + scope 2 { + let _3: std::ptr::NonNull; + let _9: usize; + scope 3 { + } + scope 4 { + scope 7 (inlined as PartialEq>::eq) { + let mut _4: std::ptr::NonNull; + let mut _5: *mut T; + let mut _6: *mut T; + scope 8 (inlined NonNull::::as_ptr) { + } + scope 9 (inlined NonNull::::as_ptr) { + } + } + } + scope 5 (inlined std::ptr::mut_ptr::::addr) { + scope 6 (inlined std::ptr::mut_ptr::::cast::<()>) { + } + } + } + scope 10 (inlined std::slice::IterMut::<'_, T>::next_back_unchecked) { + let mut _16: std::ptr::NonNull; + scope 11 (inlined std::slice::IterMut::<'_, T>::pre_dec_end) { + let mut _10: *mut *mut T; + let mut _11: *mut std::ptr::NonNull; + let mut _12: std::ptr::NonNull; + let mut _15: std::ptr::NonNull; + let mut _17: *mut *mut T; + let mut _18: *mut usize; + let mut _19: usize; + let mut _20: usize; + scope 12 { + scope 13 { + } + scope 14 { + scope 17 (inlined NonNull::::sub) { + scope 18 (inlined #[track_caller] core::num::::unchecked_neg) { + scope 19 (inlined core::ub_checks::check_language_ub) { + scope 20 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + } + scope 21 (inlined NonNull::::offset) { + let mut _13: *const T; + let mut _14: *const T; + scope 22 (inlined NonNull::::as_ptr) { + } + } + } + } + scope 15 (inlined std::ptr::mut_ptr::::cast::) { + } + scope 16 (inlined std::ptr::mut_ptr::::cast::>) { + } + } + } + scope 23 (inlined NonNull::::as_mut::<'_>) { + let mut _21: std::ptr::NonNull; + let mut _22: *mut T; + scope 24 (inlined NonNull::::as_ptr) { + } + } + } + } bb0: { - _0 = as DoubleEndedIterator>::next_back(move _1) -> [return: bb1, unwind continue]; + StorageLive(_9); + StorageLive(_8); + StorageLive(_3); + StorageLive(_2); + StorageLive(_23); + StorageLive(_7); + switchInt(const ::IS_ZST) -> [0: bb1, otherwise: bb2]; } bb1: { + _2 = copy ((*_1).1: *mut T); + _3 = copy _2 as std::ptr::NonNull (Transmute); + StorageLive(_5); + StorageLive(_4); + _4 = copy ((*_1).0: std::ptr::NonNull); + _5 = copy _4 as *mut T (Transmute); + StorageDead(_4); + StorageLive(_6); + _6 = copy _3 as *mut T (Transmute); + _7 = Eq(move _5, move _6); + StorageDead(_6); + StorageDead(_5); + goto -> bb3; + } + + bb2: { + _8 = copy ((*_1).1: *mut T); + _9 = copy _8 as usize (Transmute); + _7 = Eq(copy _9, const 0_usize); + goto -> bb3; + } + + bb3: { + switchInt(move _7) -> [0: bb4, otherwise: bb11]; + } + + bb4: { + StorageLive(_16); + StorageLive(_18); + StorageLive(_11); + switchInt(const ::IS_ZST) -> [0: bb5, otherwise: bb9]; + } + + bb5: { + StorageLive(_10); + _10 = &raw mut ((*_1).1: *mut T); + _11 = copy _10 as *mut std::ptr::NonNull (PtrToPtr); + StorageDead(_10); + StorageLive(_15); + StorageLive(_12); + _12 = copy (*_11); + switchInt(const ::IS_ZST) -> [0: bb6, otherwise: bb7]; + } + + bb6: { + StorageLive(_14); + StorageLive(_13); + _13 = copy _12 as *const T (Transmute); + _14 = Offset(move _13, const -1_isize); + StorageDead(_13); + _15 = NonNull:: { pointer: move _14 }; + StorageDead(_14); + goto -> bb8; + } + + bb7: { + _15 = copy _12; + goto -> bb8; + } + + bb8: { + StorageDead(_12); + (*_11) = move _15; + StorageDead(_15); + _16 = copy (*_11); + goto -> bb10; + } + + bb9: { + StorageLive(_17); + _17 = &raw mut ((*_1).1: *mut T); + _18 = copy _17 as *mut usize (PtrToPtr); + StorageDead(_17); + StorageLive(_20); + StorageLive(_19); + _19 = copy (*_18); + _20 = SubUnchecked(move _19, const 1_usize); + StorageDead(_19); + (*_18) = move _20; + StorageDead(_20); + _16 = copy ((*_1).0: std::ptr::NonNull); + goto -> bb10; + } + + bb10: { + StorageDead(_11); + StorageDead(_18); + StorageLive(_22); + StorageLive(_21); + _21 = copy _16; + _22 = copy _21 as *mut T (Transmute); + StorageDead(_21); + _23 = &mut (*_22); + StorageDead(_22); + StorageDead(_16); + _0 = Option::<&mut T>::Some(copy _23); + goto -> bb12; + } + + bb11: { + _0 = const {transmute(0x0000000000000000): Option<&mut T>}; + goto -> bb12; + } + + bb12: { + StorageDead(_7); + StorageDead(_23); + StorageDead(_2); + StorageDead(_3); + StorageDead(_8); + StorageDead(_9); return; } } diff --git a/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-abort.mir index fe4e2deab8706..7da8c7971eb03 100644 --- a/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-abort.mir @@ -9,7 +9,7 @@ fn outer(_1: u8) -> u8 { } bb0: { - _2 = &_1; // scope 0 at $DIR/spans.rs:11:11: 11:13 + // DBG: _2 = &_1 _0 = copy _1; // scope 1 at $DIR/spans.rs:15:5: 15:7 return; // scope 0 at $DIR/spans.rs:12:2: 12:2 } diff --git a/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-unwind.mir index fe4e2deab8706..7da8c7971eb03 100644 --- a/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-unwind.mir @@ -9,7 +9,7 @@ fn outer(_1: u8) -> u8 { } bb0: { - _2 = &_1; // scope 0 at $DIR/spans.rs:11:11: 11:13 + // DBG: _2 = &_1 _0 = copy _1; // scope 1 at $DIR/spans.rs:15:5: 15:7 return; // scope 0 at $DIR/spans.rs:12:2: 12:2 } diff --git a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir index 2eee8a97db0d4..7593afa4a82d0 100644 --- a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir @@ -11,7 +11,9 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { let mut _4: usize; scope 3 (inlined Vec::::as_ptr) { debug self => _1; + let mut _6: &alloc::raw_vec::RawVec; scope 4 (inlined alloc::raw_vec::RawVec::::ptr) { + let mut _7: &alloc::raw_vec::RawVecInner; scope 5 (inlined alloc::raw_vec::RawVecInner::ptr::) { scope 6 (inlined alloc::raw_vec::RawVecInner::non_null::) { let mut _2: std::ptr::NonNull; @@ -55,8 +57,14 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { bb0: { StorageLive(_2); StorageLive(_3); + StorageLive(_6); + // DBG: _6 = &((*_1).0: alloc::raw_vec::RawVec) + StorageLive(_7); + // DBG: _7 = &(((*_1).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner) _2 = copy (((((*_1).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); + StorageDead(_7); _3 = copy _2 as *const u8 (Transmute); + StorageDead(_6); StorageLive(_4); _4 = copy ((*_1).1: usize); StorageLive(_5); diff --git a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir index 2eee8a97db0d4..7593afa4a82d0 100644 --- a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir @@ -11,7 +11,9 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { let mut _4: usize; scope 3 (inlined Vec::::as_ptr) { debug self => _1; + let mut _6: &alloc::raw_vec::RawVec; scope 4 (inlined alloc::raw_vec::RawVec::::ptr) { + let mut _7: &alloc::raw_vec::RawVecInner; scope 5 (inlined alloc::raw_vec::RawVecInner::ptr::) { scope 6 (inlined alloc::raw_vec::RawVecInner::non_null::) { let mut _2: std::ptr::NonNull; @@ -55,8 +57,14 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { bb0: { StorageLive(_2); StorageLive(_3); + StorageLive(_6); + // DBG: _6 = &((*_1).0: alloc::raw_vec::RawVec) + StorageLive(_7); + // DBG: _7 = &(((*_1).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner) _2 = copy (((((*_1).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); + StorageDead(_7); _3 = copy _2 as *const u8 (Transmute); + StorageDead(_6); StorageLive(_4); _4 = copy ((*_1).1: usize); StorageLive(_5); From ff4ac03b21d1a85be308a095efa18dcd45f49dfb Mon Sep 17 00:00:00 2001 From: dianqk Date: Wed, 18 Jun 2025 22:04:48 +0800 Subject: [PATCH 3/8] codegen: Generate `dbg_value` for the ref statement --- compiler/rustc_codegen_gcc/src/debuginfo.rs | 7 +- .../src/debuginfo/dwarf_const.rs | 3 + .../rustc_codegen_llvm/src/debuginfo/mod.rs | 43 +++++++--- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 10 +++ compiler/rustc_codegen_ssa/src/mir/block.rs | 1 + .../rustc_codegen_ssa/src/mir/debuginfo.rs | 50 +++++++++++- .../rustc_codegen_ssa/src/mir/statement.rs | 70 +++++++++++++++- .../rustc_codegen_ssa/src/traits/debuginfo.rs | 3 +- .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 13 +++ tests/codegen/debug-fndef-size.rs | 4 +- tests/codegen/debuginfo-dse.rs | 79 +++++++++++++++++++ tests/debuginfo/opt/dead_refs.rs | 49 ++++++++++++ 12 files changed, 311 insertions(+), 21 deletions(-) create mode 100644 tests/codegen/debuginfo-dse.rs create mode 100644 tests/debuginfo/opt/dead_refs.rs diff --git a/compiler/rustc_codegen_gcc/src/debuginfo.rs b/compiler/rustc_codegen_gcc/src/debuginfo.rs index 4c8585192a1b1..be71e2258633a 100644 --- a/compiler/rustc_codegen_gcc/src/debuginfo.rs +++ b/compiler/rustc_codegen_gcc/src/debuginfo.rs @@ -26,14 +26,17 @@ impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods for Builder<'a, 'gcc, 'tcx> { &mut self, _dbg_var: Self::DIVariable, _dbg_loc: Self::DILocation, - _variable_alloca: Self::Value, + is_declared: bool, + val: Self::Value, _direct_offset: Size, _indirect_offsets: &[Size], _fragment: Option>, ) { // FIXME(tempdragon): Not sure if this is correct, probably wrong but still keep it here. #[cfg(feature = "master")] - _variable_alloca.set_location(_dbg_loc); + if is_declared { + val.set_location(_dbg_loc); + } } fn insert_reference_to_gdb_debug_scripts_section_global(&mut self) { diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/dwarf_const.rs b/compiler/rustc_codegen_llvm/src/debuginfo/dwarf_const.rs index 408429152223d..52d04625749b9 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/dwarf_const.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/dwarf_const.rs @@ -35,3 +35,6 @@ declare_constant!(DW_OP_plus_uconst: u64); /// Double-checked by a static assertion in `RustWrapper.cpp`. #[allow(non_upper_case_globals)] pub(crate) const DW_OP_LLVM_fragment: u64 = 0x1000; +// It describes the actual value of a source variable which might not exist in registers or in memory. +#[allow(non_upper_case_globals)] +pub(crate) const DW_OP_stack_value: u64 = 0x9f; diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 5ca2505cec43b..280f3227a9956 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -160,12 +160,13 @@ impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> { &mut self, dbg_var: &'ll DIVariable, dbg_loc: &'ll DILocation, - variable_alloca: Self::Value, + is_declared: bool, + val: Self::Value, direct_offset: Size, indirect_offsets: &[Size], fragment: Option>, ) { - use dwarf_const::{DW_OP_LLVM_fragment, DW_OP_deref, DW_OP_plus_uconst}; + use dwarf_const::{DW_OP_LLVM_fragment, DW_OP_deref, DW_OP_plus_uconst, DW_OP_stack_value}; // Convert the direct and indirect offsets and fragment byte range to address ops. let mut addr_ops = SmallVec::<[u64; 8]>::new(); @@ -173,6 +174,9 @@ impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> { if direct_offset.bytes() > 0 { addr_ops.push(DW_OP_plus_uconst); addr_ops.push(direct_offset.bytes() as u64); + if !is_declared { + addr_ops.push(DW_OP_stack_value); + } } for &offset in indirect_offsets { addr_ops.push(DW_OP_deref); @@ -189,17 +193,30 @@ impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> { addr_ops.push((fragment.end - fragment.start).bits() as u64); } - unsafe { - // FIXME(eddyb) replace `llvm.dbg.declare` with `llvm.dbg.addr`. - llvm::LLVMRustDIBuilderInsertDeclareAtEnd( - DIB(self.cx()), - variable_alloca, - dbg_var, - addr_ops.as_ptr(), - addr_ops.len() as c_uint, - dbg_loc, - self.llbb(), - ); + if is_declared { + unsafe { + llvm::LLVMRustDIBuilderInsertDeclareAtEnd( + DIB(self.cx()), + val, + dbg_var, + addr_ops.as_ptr(), + addr_ops.len() as c_uint, + dbg_loc, + self.llbb(), + ); + } + } else { + unsafe { + llvm::LLVMRustDIBuilderInsertDbgValueAtEnd( + DIB(self.cx()), + val, + dbg_var, + addr_ops.as_ptr(), + addr_ops.len() as c_uint, + dbg_loc, + self.llbb(), + ); + } } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 80a0e5c5accc2..b561a9f2030a0 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2308,6 +2308,16 @@ unsafe extern "C" { InsertAtEnd: &'a BasicBlock, ); + pub(crate) fn LLVMRustDIBuilderInsertDbgValueAtEnd<'a>( + Builder: &DIBuilder<'a>, + Val: &'a Value, + VarInfo: &'a DIVariable, + AddrOps: *const u64, + AddrOpsCount: c_uint, + DL: &'a DILocation, + InsertAtEnd: &'a BasicBlock, + ); + pub(crate) fn LLVMRustDIBuilderCreateEnumerator<'a>( Builder: &DIBuilder<'a>, Name: *const c_char, diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index bde63fd501aa2..1ee6ece17c5fe 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1252,6 +1252,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { for statement in &data.statements { self.codegen_statement(bx, statement); } + self.codegen_stmt_debuginfos(bx, &data.after_last_stmt_debuginfos); let merging_succ = self.codegen_terminator(bx, bb, data.terminator()); if let MergingSucc::False = merging_succ { diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index b8f635ab78161..0833a56611220 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -253,6 +253,52 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { spill_slot } + pub(crate) fn debug_new_value_to_local( + &self, + bx: &mut Bx, + local: mir::Local, + base: PlaceValue, + layout: TyAndLayout<'tcx>, + projection: &[mir::PlaceElem<'tcx>], + ) { + let full_debug_info = bx.sess().opts.debuginfo == DebugInfo::Full; + if !full_debug_info { + return; + } + + let vars = match &self.per_local_var_debug_info { + Some(per_local) => &per_local[local], + None => return, + }; + + for var in vars.iter().cloned() { + self.debug_new_value_to_local_as_var(bx, base, layout, projection, var); + } + } + + fn debug_new_value_to_local_as_var( + &self, + bx: &mut Bx, + base: PlaceValue, + layout: TyAndLayout<'tcx>, + projection: &[mir::PlaceElem<'tcx>], + var: PerLocalVarDebugInfo<'tcx, Bx::DIVariable>, + ) { + let Some(dbg_var) = var.dbg_var else { return }; + let Some(dbg_loc) = self.dbg_loc(var.source_info) else { return }; + let DebugInfoOffset { direct_offset, indirect_offsets, result: _ } = + calculate_debuginfo_offset(bx, projection, layout); + bx.dbg_var_addr( + dbg_var, + dbg_loc, + false, + base.llval, + direct_offset, + &indirect_offsets, + var.fragment, + ); + } + /// Apply debuginfo and/or name, after creating the `alloca` for a local, /// or initializing the local with an operand (whichever applies). pub(crate) fn debug_introduce_local(&self, bx: &mut Bx, local: mir::Local) { @@ -421,6 +467,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx.dbg_var_addr( dbg_var, dbg_loc, + true, alloca.val.llval, Size::ZERO, &[Size::ZERO], @@ -430,6 +477,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx.dbg_var_addr( dbg_var, dbg_loc, + true, base.val.llval, direct_offset, &indirect_offsets, @@ -455,7 +503,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let base = FunctionCx::spill_operand_to_stack(operand, Some(name), bx); bx.clear_dbg_loc(); - bx.dbg_var_addr(dbg_var, dbg_loc, base.val.llval, Size::ZERO, &[], fragment); + bx.dbg_var_addr(dbg_var, dbg_loc, true, base.val.llval, Size::ZERO, &[], fragment); } } } diff --git a/compiler/rustc_codegen_ssa/src/mir/statement.rs b/compiler/rustc_codegen_ssa/src/mir/statement.rs index f164e0f912373..cbf524ec6732e 100644 --- a/compiler/rustc_codegen_ssa/src/mir/statement.rs +++ b/compiler/rustc_codegen_ssa/src/mir/statement.rs @@ -1,13 +1,17 @@ -use rustc_middle::mir::{self, NonDivergingIntrinsic}; -use rustc_middle::span_bug; +use rustc_middle::mir::{self, NonDivergingIntrinsic, StmtDebugInfo}; +use rustc_middle::{bug, span_bug}; use tracing::instrument; use super::{FunctionCx, LocalRef}; +use crate::common::TypeKind; +use crate::mir::operand::OperandValue; +use crate::mir::place::PlaceRef; use crate::traits::*; impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { #[instrument(level = "debug", skip(self, bx))] pub(crate) fn codegen_statement(&mut self, bx: &mut Bx, statement: &mir::Statement<'tcx>) { + self.codegen_stmt_debuginfos(bx, &statement.debuginfos); self.set_debug_loc(bx, statement.source_info); match statement.kind { mir::StatementKind::Assign(box (ref place, ref rvalue)) => { @@ -101,4 +105,66 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { | mir::StatementKind::Nop => {} } } + + pub(crate) fn codegen_stmt_debuginfo(&mut self, bx: &mut Bx, debuginfo: &StmtDebugInfo<'tcx>) { + match debuginfo { + StmtDebugInfo::AssignRef(dest, place) => { + let place_ref = match self.locals[place.local] { + LocalRef::Place(place_ref) | LocalRef::UnsizedPlace(place_ref) => { + Some(place_ref) + } + LocalRef::Operand(operand_ref) => match operand_ref.val { + OperandValue::Immediate(v) => { + Some(PlaceRef::new_sized(v, operand_ref.layout)) + } + OperandValue::Ref(_) + | OperandValue::Pair(_, _) + | OperandValue::ZeroSized => None, + }, + LocalRef::PendingOperand => None, + } + .filter(|place_ref| { + // Drop unsupported projections. + // FIXME: Add a test case. + place.projection.iter().all(|p| p.can_use_in_debuginfo()) && + // Only pointers can calculate addresses. + bx.type_kind(bx.val_ty(place_ref.val.llval)) == TypeKind::Pointer + }); + let (val, layout, projection) = + match (place_ref, place.is_indirect_first_projection()) { + (Some(place_ref), false) => { + (place_ref.val, place_ref.layout, place.projection.as_slice()) + } + (Some(place_ref), true) => { + let projected_ty = + place_ref.layout.ty.builtin_deref(true).unwrap_or_else(|| { + bug!("deref of non-pointer {:?}", place_ref) + }); + let layout = bx.cx().layout_of(projected_ty); + (place_ref.val, layout, &place.projection[1..]) + } + _ => { + // If the address cannot be computed, use poison to indicate that the value has been optimized out. + let ty = self.monomorphize(self.mir.local_decls[*dest].ty); + let layout = bx.cx().layout_of(ty); + let to_backend_ty = bx.cx().immediate_backend_type(layout); + let place_ref = + PlaceRef::new_sized(bx.cx().const_poison(to_backend_ty), layout); + (place_ref.val, layout, [].as_slice()) + } + }; + self.debug_new_value_to_local(bx, *dest, val, layout, projection); + } + } + } + + pub(crate) fn codegen_stmt_debuginfos( + &mut self, + bx: &mut Bx, + debuginfos: &[StmtDebugInfo<'tcx>], + ) { + for debuginfo in debuginfos { + self.codegen_stmt_debuginfo(bx, debuginfo); + } + } } diff --git a/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs index b9d4950e0ad36..7cc3535d19779 100644 --- a/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs @@ -71,7 +71,8 @@ pub trait DebugInfoBuilderMethods: BackendTypes { &mut self, dbg_var: Self::DIVariable, dbg_loc: Self::DILocation, - variable_alloca: Self::Value, + is_declared: bool, + val: Self::Value, direct_offset: Size, // NB: each offset implies a deref (i.e. they're steps in a pointer chain). indirect_offsets: &[Size], diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 90aa9188c8300..cb25ab33481eb 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -58,6 +58,7 @@ using namespace llvm::object; // This opcode is an LLVM detail that could hypothetically change (?), so // verify that the hard-coded value in `dwarf_const.rs` still agrees with LLVM. static_assert(dwarf::DW_OP_LLVM_fragment == 0x1000); +static_assert(dwarf::DW_OP_stack_value == 0x9f); // LLVMAtomicOrdering is already an enum - don't create another // one. @@ -1241,6 +1242,18 @@ LLVMRustDIBuilderInsertDeclareAtEnd(LLVMDIBuilderRef Builder, LLVMValueRef V, DebugLoc(cast(unwrap(DL))), unwrap(InsertAtEnd)); } +extern "C" void +LLVMRustDIBuilderInsertDbgValueAtEnd(LLVMDIBuilderRef Builder, LLVMValueRef V, + LLVMMetadataRef VarInfo, uint64_t *AddrOps, + unsigned AddrOpsCount, LLVMMetadataRef DL, + LLVMBasicBlockRef InsertAtEnd) { + unwrap(Builder)->insertDbgValueIntrinsic( + unwrap(V), unwrap(VarInfo), + unwrap(Builder)->createExpression( + llvm::ArrayRef(AddrOps, AddrOpsCount)), + DebugLoc(cast(unwrap(DL))), unwrap(InsertAtEnd)); +} + extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateEnumerator(LLVMDIBuilderRef Builder, const char *Name, size_t NameLen, const uint64_t Value[2], diff --git a/tests/codegen/debug-fndef-size.rs b/tests/codegen/debug-fndef-size.rs index 8f716c34e7b74..02629bd748c45 100644 --- a/tests/codegen/debug-fndef-size.rs +++ b/tests/codegen/debug-fndef-size.rs @@ -16,5 +16,5 @@ pub fn main() { // CHECK: %compare.dbg.spill = alloca [0 x i8], align 1 // CHECK: dbg{{.}}declare({{(metadata )?}}ptr %compare.dbg.spill, {{(metadata )?}}![[VAR:.*]], {{(metadata )?}}!DIExpression() -// CHECK: ![[TYPE:.*]] = !DIDerivedType(tag: DW_TAG_pointer_type, name: "fn(&i32, &i32) -> core::cmp::Ordering", baseType: !{{.*}}, align: 8, dwarfAddressSpace: {{.*}}) -// CHECK: ![[VAR]] = !DILocalVariable(name: "compare", scope: !{{.*}}, file: !{{.*}}, line: {{.*}}, type: ![[TYPE]], align: 8) +// CHECK-DAG: ![[TYPE:.*]] = !DIDerivedType(tag: DW_TAG_pointer_type, name: "fn(&i32, &i32) -> core::cmp::Ordering", baseType: !{{.*}}, align: 8, dwarfAddressSpace: {{.*}}) +// CHECK-DAG: ![[VAR]] = !DILocalVariable(name: "compare", scope: !{{.*}}, file: !{{.*}}, line: {{.*}}, type: ![[TYPE]], align: 8) diff --git a/tests/codegen/debuginfo-dse.rs b/tests/codegen/debuginfo-dse.rs new file mode 100644 index 0000000000000..42cc0678ec082 --- /dev/null +++ b/tests/codegen/debuginfo-dse.rs @@ -0,0 +1,79 @@ +//@ compile-flags: -Copt-level=3 -g -Zverify-llvm-ir +//@ revisions: CODEGEN OPTIMIZED +//@[CODEGEN] compile-flags: -Cno-prepopulate-passes + +#![crate_type = "lib"] + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct Foo(i32, i64, i32); + +#[no_mangle] +fn r#ref(ref_foo: &Foo) -> i32 { + // CHECK-LABEL: define {{.*}} i32 @ref + // CHECK-SAME: (ptr {{.*}} [[ARG_ref_foo:%.*]]) + // OPTIMIZED: #dbg_value(ptr [[ARG_ref_foo]], [[VAR_ref_foo:![0-9]+]], !DIExpression() + // CHECK: #dbg_value(ptr [[ARG_ref_foo]], [[VAR_ref_v0:![0-9]+]], !DIExpression() + // CHECK: #dbg_value(ptr [[ARG_ref_foo]], [[VAR_ref_v1:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 8, DW_OP_stack_value) + // CHECK: #dbg_value(ptr [[ARG_ref_foo]], [[VAR_ref_v2:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 16, DW_OP_stack_value) + let ref_v0 = &ref_foo.0; + let ref_v1 = &ref_foo.1; + let ref_v2 = &ref_foo.2; + ref_foo.0 +} + +#[no_mangle] +fn ptr(ptr_foo: Foo) -> i32 { + // CHECK-LABEL: define {{.*}} i32 @ptr + // CHECK-SAME: (ptr {{.*}} [[ARG_ptr_foo:%.*]]) + // CHECK: #dbg_value(ptr [[ARG_ptr_foo]], [[VAR_ptr_v0:![0-9]+]], !DIExpression() + // CHECK: #dbg_value(ptr [[ARG_ptr_foo]], [[VAR_ptr_v1:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 8, DW_OP_stack_value) + // CHECK: #dbg_value(ptr [[ARG_ptr_foo]], [[VAR_ptr_v2:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 16, DW_OP_stack_value) + let ptr_v0 = &ptr_foo.0; + let ptr_v1 = &ptr_foo.1; + let ptr_v2 = &ptr_foo.2; + ptr_foo.2 +} + +#[no_mangle] +fn no_ptr(val: i32) -> i32 { + // CHECK-LABEL: define {{.*}} i32 @no_ptr + // CODEGEN: #dbg_value(ptr poison, [[VAR_val_ref:![0-9]+]], !DIExpression() + let val_ref = &val; + val +} + +#[no_mangle] +pub fn fragment(fragment_v1: Foo, mut fragment_v2: Foo) -> Foo { + // CHECK-LABEL: define void @fragment + // CHECK-SAME: (ptr {{.*}}, ptr {{.*}} [[ARG_fragment_v1:%.*]], ptr {{.*}} [[ARG_fragment_v2:%.*]]) + // CHECK: #dbg_declare(ptr [[ARG_fragment_v1]] + // CHECK-NEXT: #dbg_declare(ptr [[ARG_fragment_v2]] + // CHECK-NEXT: #dbg_value(ptr [[ARG_fragment_v2]], [[VAR_fragment_f:![0-9]+]], !DIExpression(DW_OP_LLVM_fragment, 0, 64) + // CHECK-NEXT: #dbg_value(ptr [[ARG_fragment_v1]], [[VAR_fragment_f:![0-9]+]], !DIExpression(DW_OP_LLVM_fragment, 64, 64) + let fragment_f = || { + fragment_v2 = fragment_v1; + }; + fragment_v2 = fragment_v1; + fragment_v2 +} + +#[no_mangle] +pub fn tuple(foo: (i32, &Foo)) -> i32 { + // CHECK-LABEL: define {{.*}} i32 @tuple + // CHECK-SAME: (i32 {{.*}}, ptr {{.*}} [[ARG_tuple_foo_1:%.*]]) + // CHECK: #dbg_value(ptr [[ARG_tuple_foo_1]], [[VAR_tuple_dead:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 16, DW_OP_stack_value) + let tuple_dead = &foo.1.2; + foo.1.0 +} + +// OPTIMIZED-DAG: [[VAR_ref_foo]] = !DILocalVariable(name: "ref_foo" +// CHECK-DAG: [[VAR_ref_v0]] = !DILocalVariable(name: "ref_v0" +// CHECK-DAG: [[VAR_ref_v1]] = !DILocalVariable(name: "ref_v1" +// CHECK-DAG: [[VAR_ref_v2]] = !DILocalVariable(name: "ref_v2" +// CHECK-DAG: [[VAR_ptr_v0]] = !DILocalVariable(name: "ptr_v0" +// CHECK-DAG: [[VAR_ptr_v1]] = !DILocalVariable(name: "ptr_v1" +// CHECK-DAG: [[VAR_ptr_v2]] = !DILocalVariable(name: "ptr_v2" +// CODEGEN-DAG: [[VAR_val_ref]] = !DILocalVariable(name: "val_ref" +// CHECK-DAG: [[VAR_fragment_f]] = !DILocalVariable(name: "fragment_f" +// CHECK-DAG: [[VAR_tuple_dead]] = !DILocalVariable(name: "tuple_dead" diff --git a/tests/debuginfo/opt/dead_refs.rs b/tests/debuginfo/opt/dead_refs.rs new file mode 100644 index 0000000000000..68cc5cf0e4e78 --- /dev/null +++ b/tests/debuginfo/opt/dead_refs.rs @@ -0,0 +1,49 @@ +//@ compile-flags: -g -Copt-level=3 + +// Checks that we still can access dead variables from debuginfos. + +// === GDB TESTS =================================================================================== + +// gdb-command:run +// gdb-command:print *ref_v0 +// gdb-check:$1 = 0 + +// gdb-command:print *ref_v1 +// gdb-check:$2 = 1 + +// gdb-command:print *ref_v2 +// gdb-check:$3 = 2 + +// === LLDB TESTS ================================================================================== + +// lldb-command:run +// lldb-command:v *ref_v0 +// lldb-check:[...] 0 + +// lldb-command:v *ref_v1 +// lldb-check:[...] 1 + +// lldb-command:v *ref_v2 +// lldb-check:[...] 2 + +#![allow(unused_variables)] +#![feature(omit_gdb_pretty_printer_section)] +#![omit_gdb_pretty_printer_section] + +use std::hint::black_box; + +pub struct Foo(i32, i64, i32); + +#[inline(never)] +#[no_mangle] +fn test_ref(ref_foo: &Foo) -> i32 { + let ref_v0 = &ref_foo.0; + let ref_v1 = &ref_foo.1; + let ref_v2 = &ref_foo.2; + ref_foo.0 // #break +} + +fn main() { + let foo = black_box(Foo(0, 1, 2)); + black_box(test_ref(&foo)); +} From 5817e35ab8c22a3acae7e1236cdf721d86b74bf0 Mon Sep 17 00:00:00 2001 From: dianqk Date: Thu, 10 Jul 2025 21:20:54 +0800 Subject: [PATCH 4/8] simplifycfg: Preserve debuginfos when merging bbs --- compiler/rustc_middle/src/mir/terminator.rs | 15 +++ compiler/rustc_mir_transform/src/simplify.rs | 42 +++++- ...ycfg.drop_debuginfo.SimplifyCfg-final.diff | 28 ++++ ...reserve_debuginfo_1.SimplifyCfg-final.diff | 33 +++++ ...reserve_debuginfo_2.SimplifyCfg-final.diff | 32 +++++ tests/mir-opt/debuginfo/simplifycfg.rs | 126 ++++++++++++++++++ 6 files changed, 272 insertions(+), 4 deletions(-) create mode 100644 tests/mir-opt/debuginfo/simplifycfg.drop_debuginfo.SimplifyCfg-final.diff create mode 100644 tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_1.SimplifyCfg-final.diff create mode 100644 tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_2.SimplifyCfg-final.diff create mode 100644 tests/mir-opt/debuginfo/simplifycfg.rs diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index 4034a3a06e943..aeea367af49da 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -444,6 +444,21 @@ impl<'tcx> Terminator<'tcx> { self.kind.successors() } + /// Return `Some` if all successors are identical. + #[inline] + pub fn identical_successor(&self) -> Option { + let mut successors = self.successors(); + let Some(first_succ) = successors.next() else { + return None; + }; + while let Some(succ) = successors.next() { + if first_succ != succ { + return None; + } + } + Some(first_succ) + } + #[inline] pub fn successors_mut<'a>(&'a mut self, f: impl FnMut(&'a mut BasicBlock)) { self.kind.successors_mut(f) diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index 4598dcee0cd94..f4ae4ae48a398 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -143,7 +143,7 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { // statements itself to avoid moving the (relatively) large statements twice. // We do not push the statements directly into the target block (`bb`) as that is slower // due to additional reallocations - let mut merged_blocks = Vec::new(); + let mut merged_blocks: Vec = Vec::new(); let mut outer_changed = false; loop { let mut changed = false; @@ -158,8 +158,21 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { let mut terminator = self.basic_blocks[bb].terminator.take().expect("invalid terminator state"); - terminator - .successors_mut(|successor| self.collapse_goto_chain(successor, &mut changed)); + let mut debuginfos = Vec::new(); + if let Some(mut unique_succ) = terminator.identical_successor() { + self.collapse_goto_chain(&mut unique_succ, &mut changed, &mut debuginfos); + terminator.successors_mut(|successor| { + *successor = unique_succ; + }); + // Add debugging information from the goto chain only when all successors are identical, + // otherwise, we may provide misleading debugging information within a branch. + self.basic_blocks[bb].after_last_stmt_debuginfos.append(&mut debuginfos); + } else { + terminator.successors_mut(|successor| { + debuginfos.clear(); + self.collapse_goto_chain(successor, &mut changed, &mut debuginfos) + }); + } let mut inner_changed = true; merged_blocks.clear(); @@ -176,10 +189,19 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { if statements_to_merge > 0 { let mut statements = std::mem::take(&mut self.basic_blocks[bb].statements); statements.reserve(statements_to_merge); + let mut parent_bb_last_debuginfos = + std::mem::take(&mut self.basic_blocks[bb].after_last_stmt_debuginfos); for &from in &merged_blocks { + if let Some(stmt) = self.basic_blocks[from].statements.first_mut() { + parent_bb_last_debuginfos.append(&mut stmt.debuginfos); + std::mem::swap(&mut parent_bb_last_debuginfos, &mut stmt.debuginfos); + } statements.append(&mut self.basic_blocks[from].statements); + parent_bb_last_debuginfos + .append(&mut self.basic_blocks[from].after_last_stmt_debuginfos); } self.basic_blocks[bb].statements = statements; + self.basic_blocks[bb].after_last_stmt_debuginfos = parent_bb_last_debuginfos; } self.basic_blocks[bb].terminator = Some(terminator); @@ -214,7 +236,12 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { } /// Collapse a goto chain starting from `start` - fn collapse_goto_chain(&mut self, start: &mut BasicBlock, changed: &mut bool) { + fn collapse_goto_chain( + &mut self, + start: &mut BasicBlock, + changed: &mut bool, + pred_debuginfos: &mut Vec>, + ) { // Using `SmallVec` here, because in some logs on libcore oli-obk saw many single-element // goto chains. We should probably benchmark different sizes. let mut terminators: SmallVec<[_; 1]> = Default::default(); @@ -233,6 +260,13 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { else { unreachable!(); }; + if *target != last { + self.basic_blocks[current] + .after_last_stmt_debuginfos + .extend_from_slice(pred_debuginfos); + } + pred_debuginfos + .extend_from_slice(&self.basic_blocks[current].after_last_stmt_debuginfos); *changed |= *target != last; *target = last; debug!("collapsing goto chain from {:?} to {:?}", current, target); diff --git a/tests/mir-opt/debuginfo/simplifycfg.drop_debuginfo.SimplifyCfg-final.diff b/tests/mir-opt/debuginfo/simplifycfg.drop_debuginfo.SimplifyCfg-final.diff new file mode 100644 index 0000000000000..4d7f38c85365c --- /dev/null +++ b/tests/mir-opt/debuginfo/simplifycfg.drop_debuginfo.SimplifyCfg-final.diff @@ -0,0 +1,28 @@ +- // MIR for `drop_debuginfo` before SimplifyCfg-final ++ // MIR for `drop_debuginfo` after SimplifyCfg-final + + fn drop_debuginfo(_1: &Foo, _2: bool) -> i32 { + debug foo_a => _3; + debug foo_b => _4; + let mut _0: i32; + let mut _3: &i32; + let mut _4: &i64; + + bb0: { +- switchInt(copy _2) -> [1: bb1, otherwise: bb2]; +- } +- +- bb1: { +- // DBG: _3 = &((*_1).0: i32) +- nop; +- goto -> bb2; +- } +- +- bb2: { + // DBG: _4 = &((*_1).1: i64) +- nop; + _0 = copy ((*_1).2: i32); + return; + } + } + diff --git a/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_1.SimplifyCfg-final.diff b/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_1.SimplifyCfg-final.diff new file mode 100644 index 0000000000000..c9a95d5dc0f58 --- /dev/null +++ b/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_1.SimplifyCfg-final.diff @@ -0,0 +1,33 @@ +- // MIR for `preserve_debuginfo_1` before SimplifyCfg-final ++ // MIR for `preserve_debuginfo_1` after SimplifyCfg-final + + fn preserve_debuginfo_1(_1: &Foo, _2: &mut bool) -> i32 { + debug foo_a => _3; + debug foo_b => _4; + debug foo_c => _5; + let mut _0: i32; + let mut _3: &i32; + let mut _4: &i64; + let mut _5: &i32; + + bb0: { +- goto -> bb1; +- } +- +- bb1: { + (*_2) = const true; + // DBG: _3 = &((*_1).0: i32) +- nop; +- goto -> bb2; +- } +- +- bb2: { + // DBG: _4 = &((*_1).1: i64) +- nop; + _0 = copy ((*_1).2: i32); + // DBG: _5 = &((*_1).2: i32) +- nop; + return; + } + } + diff --git a/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_2.SimplifyCfg-final.diff b/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_2.SimplifyCfg-final.diff new file mode 100644 index 0000000000000..d206a23d95783 --- /dev/null +++ b/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_2.SimplifyCfg-final.diff @@ -0,0 +1,32 @@ +- // MIR for `preserve_debuginfo_2` before SimplifyCfg-final ++ // MIR for `preserve_debuginfo_2` after SimplifyCfg-final + + fn preserve_debuginfo_2(_1: &Foo) -> i32 { + debug foo_a => _2; + debug foo_b => _3; + debug foo_c => _4; + let mut _0: i32; + let mut _2: &i32; + let mut _3: &i64; + let mut _4: &i32; + + bb0: { +- goto -> bb1; +- } +- +- bb1: { + // DBG: _2 = &((*_1).0: i32) +- nop; +- goto -> bb2; +- } +- +- bb2: { + // DBG: _3 = &((*_1).1: i64) +- nop; + _0 = copy ((*_1).2: i32); + // DBG: _4 = &((*_1).2: i32) +- nop; + return; + } + } + diff --git a/tests/mir-opt/debuginfo/simplifycfg.rs b/tests/mir-opt/debuginfo/simplifycfg.rs new file mode 100644 index 0000000000000..cd7ad79b41e3f --- /dev/null +++ b/tests/mir-opt/debuginfo/simplifycfg.rs @@ -0,0 +1,126 @@ +//@ test-mir-pass: SimplifyCfg-final +//@ compile-flags: -Zmir-enable-passes=+DeadStoreElimination-initial,+SimplifyConstCondition-final + +#![feature(core_intrinsics, custom_mir)] +#![crate_type = "lib"] + +use std::intrinsics::mir::*; + +pub struct Foo { + a: i32, + b: i64, + c: i32, +} + +// EMIT_MIR simplifycfg.drop_debuginfo.SimplifyCfg-final.diff +#[custom_mir(dialect = "runtime")] +pub fn drop_debuginfo(foo: &Foo, c: bool) -> i32 { + // CHECK-LABEL: fn drop_debuginfo + // CHECK: debug foo_b => [[foo_b:_[0-9]+]]; + // CHECK: bb0: { + // CHECK-NEXT: DBG: [[foo_b]] = &((*_1).1: i64) + // CHECK-NEXT: _0 = copy ((*_1).2: i32); + // CHECK-NEXT: return; + mir! { + let _foo_a: &i32; + let _foo_b: &i64; + debug foo_a => _foo_a; + debug foo_b => _foo_b; + { + match c { + true => tmp, + _ => ret, + } + } + tmp = { + // Because we don't know if `c` is always true, we must drop this debuginfo. + _foo_a = &(*foo).a; + Goto(ret) + } + ret = { + _foo_b = &(*foo).b; + RET = (*foo).c; + Return() + } + } +} + +// EMIT_MIR simplifycfg.preserve_debuginfo_1.SimplifyCfg-final.diff +#[custom_mir(dialect = "runtime")] +pub fn preserve_debuginfo_1(foo: &Foo, v: &mut bool) -> i32 { + // CHECK-LABEL: fn preserve_debuginfo_1 + // CHECK: debug foo_a => [[foo_a:_[0-9]+]]; + // CHECK: debug foo_b => [[foo_b:_[0-9]+]]; + // CHECK: debug foo_c => [[foo_c:_[0-9]+]]; + // CHECK: bb0: { + // CHECK-NEXT: (*_2) = const true; + // CHECK-NEXT: DBG: [[foo_a]] = &((*_1).0: i32) + // CHECK-NEXT: DBG: [[foo_b]] = &((*_1).1: i64) + // CHECK-NEXT: _0 = copy ((*_1).2: i32); + // CHECK-NEXT: DBG: [[foo_c]] = &((*_1).2: i32) + // CHECK-NEXT: return; + mir! { + let _foo_a: &i32; + let _foo_b: &i64; + let _foo_c: &i32; + debug foo_a => _foo_a; + debug foo_b => _foo_b; + debug foo_c => _foo_c; + { + match true { + true => tmp, + _ => ret, + } + } + tmp = { + *v = true; + _foo_a = &(*foo).a; + Goto(ret) + } + ret = { + _foo_b = &(*foo).b; + RET = (*foo).c; + _foo_c = &(*foo).c; + Return() + } + } +} + +// EMIT_MIR simplifycfg.preserve_debuginfo_2.SimplifyCfg-final.diff +#[custom_mir(dialect = "runtime")] +pub fn preserve_debuginfo_2(foo: &Foo) -> i32 { + // CHECK-LABEL: fn preserve_debuginfo_2 + // CHECK: debug foo_a => [[foo_a:_[0-9]+]]; + // CHECK: debug foo_b => [[foo_b:_[0-9]+]]; + // CHECK: debug foo_c => [[foo_c:_[0-9]+]]; + // CHECK: bb0: { + // CHECK-NEXT: DBG: [[foo_a]] = &((*_1).0: i32) + // CHECK-NEXT: DBG: [[foo_b]] = &((*_1).1: i64) + // CHECK-NEXT: _0 = copy ((*_1).2: i32); + // CHECK-NEXT: DBG: [[foo_c]] = &((*_1).2: i32) + // CHECK-NEXT: return; + mir! { + let _foo_a: &i32; + let _foo_b: &i64; + let _foo_c: &i32; + debug foo_a => _foo_a; + debug foo_b => _foo_b; + debug foo_c => _foo_c; + { + match true { + true => tmp, + _ => ret, + } + } + tmp = { + _foo_a = &(*foo).a; + Goto(ret) + } + ret = { + _foo_b = &(*foo).b; + RET = (*foo).c; + _foo_c = &(*foo).c; + Return() + } + } +} From 68916e03674b076b457e50fd8bcd4a2f10ecdbaf Mon Sep 17 00:00:00 2001 From: dianqk Date: Tue, 15 Jul 2025 22:54:54 +0800 Subject: [PATCH 5/8] mir-opt: Eliminate trivial unnecessary storage annotations --- compiler/rustc_middle/src/mir/mod.rs | 11 ++ compiler/rustc_middle/src/mir/statement.rs | 25 ++-- .../rustc_mir_dataflow/src/impls/liveness.rs | 4 +- .../src/dead_store_elimination.rs | 15 ++- compiler/rustc_mir_transform/src/inline.rs | 8 +- compiler/rustc_mir_transform/src/simplify.rs | 111 +++++++++++++----- ...le.cycle.DeadStoreElimination-initial.diff | 4 - tests/mir-opt/dead-store-elimination/ref.rs | 2 +- ...ef.tuple.DeadStoreElimination-initial.diff | 5 +- ...ycfg.drop_debuginfo.SimplifyCfg-final.diff | 2 - ...reserve_debuginfo_1.SimplifyCfg-final.diff | 3 - ...reserve_debuginfo_2.SimplifyCfg-final.diff | 3 - .../inline_shims.drop.Inline.panic-abort.diff | 8 -- ...inline_shims.drop.Inline.panic-unwind.diff | 2 - ...y.run2-{closure#0}.Inline.panic-abort.diff | 15 --- ....run2-{closure#0}.Inline.panic-unwind.diff | 15 --- .../issue_101973.inner.GVN.panic-abort.diff | 1 - .../issue_101973.inner.GVN.panic-unwind.diff | 1 - ...implifyComparisonIntegral.panic-abort.diff | 6 - ...mplifyComparisonIntegral.panic-unwind.diff | 6 - ...git.PreCodegen.after.32bit.panic-abort.mir | 4 - ...it.PreCodegen.after.32bit.panic-unwind.mir | 4 - ...git.PreCodegen.after.64bit.panic-abort.mir | 4 - ...it.PreCodegen.after.64bit.panic-unwind.mir | 4 - ...p_forward.PreCodegen.after.panic-abort.mir | 40 ++----- ..._forward.PreCodegen.after.panic-unwind.mir | 40 ++----- ...as_copy.clone_as_copy.PreCodegen.after.mir | 2 - ...py.enum_clone_as_copy.PreCodegen.after.mir | 46 ++------ tests/mir-opt/pre-codegen/clone_as_copy.rs | 16 +-- .../loops.int_range.PreCodegen.after.mir | 6 - ...variant_a-{closure#0}.PreCodegen.after.mir | 22 ---- ..._to_slice.PreCodegen.after.panic-abort.mir | 4 - ...to_slice.PreCodegen.after.panic-unwind.mir | 4 - tests/ui/extern/extern-types-field-offset.rs | 5 + 34 files changed, 164 insertions(+), 284 deletions(-) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 10fe6f49021f3..42ad28d16c458 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1443,6 +1443,17 @@ impl<'tcx> BasicBlockData<'tcx> { self.after_last_stmt_debuginfos.append(&mut debuginfos); } } + + pub fn strip_nops(&mut self) { + self.retain_statements(|stmt| !matches!(stmt.kind, StatementKind::Nop)) + } + + pub fn drop_debuginfo(&mut self) { + self.after_last_stmt_debuginfos = Vec::new(); + for stmt in self.statements.iter_mut() { + stmt.debuginfos = Vec::new(); + } + } } /////////////////////////////////////////////////////////////////////////// diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index 1c35797da37ef..4a68ed6098024 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -27,16 +27,10 @@ impl<'tcx> Statement<'tcx> { } let replaced_stmt = std::mem::replace(&mut self.kind, StatementKind::Nop); if !drop_debuginfo { - match replaced_stmt { - StatementKind::Assign(box (place, Rvalue::Ref(_, _, ref_place))) - if let Some(local) = place.as_local() => - { - self.debuginfos.push(StmtDebugInfo::AssignRef(local, ref_place)); - } - _ => { - bug!("debuginfo is not yet supported.") - } - } + let Some(debuginfo) = replaced_stmt.as_debuginfo() else { + bug!("debuginfo is not yet supported.") + }; + self.debuginfos.push(debuginfo); } } @@ -79,6 +73,17 @@ impl<'tcx> StatementKind<'tcx> { _ => None, } } + + pub fn as_debuginfo(&self) -> Option> { + match self { + StatementKind::Assign(box (place, Rvalue::Ref(_, _, ref_place))) + if let Some(local) = place.as_local() => + { + Some(StmtDebugInfo::AssignRef(local, *ref_place)) + } + _ => None, + } + } } /////////////////////////////////////////////////////////////////////////// diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs index abeb6186aa0a5..2b2a8cbba458f 100644 --- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs @@ -228,8 +228,10 @@ impl<'a> MaybeTransitiveLiveLocals<'a> { // Compute the place that we are storing to, if any let destination = match stmt_kind { StatementKind::Assign(box (place, rvalue)) => (rvalue.is_safe_to_remove() + // FIXME: We are not sure how we should represent this debugging information for some statements, + // keep it for now. && (!debuginfo_locals.contains(place.local) - || (place.as_local().is_some() && matches!(rvalue, mir::Rvalue::Ref(..))))) + || (place.as_local().is_some() && stmt_kind.as_debuginfo().is_some()))) .then_some(*place), StatementKind::SetDiscriminant { place, .. } | StatementKind::Deinit(place) => { (!debuginfo_locals.contains(place.local)).then_some(**place) diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs index c04655cb634eb..63832c04058ca 100644 --- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs +++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs @@ -22,13 +22,14 @@ use rustc_mir_dataflow::impls::{ LivenessTransferFunction, MaybeTransitiveLiveLocals, borrowed_locals, }; +use crate::simplify::UsedInStmtLocals; use crate::util::is_within_packed; /// Performs the optimization on the body /// /// The `borrowed` set must be a `DenseBitSet` of all the locals that are ever borrowed in this /// body. It can be generated via the [`borrowed_locals`] function. -fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { +fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool { let borrowed_locals = borrowed_locals(body); // If the user requests complete debuginfo, mark the locals that appear in it as live, so @@ -89,8 +90,9 @@ fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { } if patch.is_empty() && call_operands_to_move.is_empty() { - return; + return false; } + let eliminated = !patch.is_empty(); let bbs = body.basic_blocks.as_mut_preserves_cfg(); for (Location { block, statement_index }, drop_debuginfo) in patch { @@ -104,6 +106,8 @@ fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let Operand::Copy(place) = *arg else { bug!() }; *arg = Operand::Move(place); } + + eliminated } pub(super) enum DeadStoreElimination { @@ -124,7 +128,12 @@ impl<'tcx> crate::MirPass<'tcx> for DeadStoreElimination { } fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - eliminate(tcx, body); + if eliminate(tcx, body) { + UsedInStmtLocals::new(body).remove_unused_storage_annotations(body); + for data in body.basic_blocks.as_mut_preserves_cfg() { + data.strip_nops(); + } + } } fn is_required(&self) -> bool { diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 1c0fc7748675c..5e7ed2cd5944b 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -21,7 +21,7 @@ use tracing::{debug, instrument, trace, trace_span}; use crate::cost_checker::{CostChecker, is_call_like}; use crate::deref_separator::deref_finder; -use crate::simplify::simplify_cfg; +use crate::simplify::{UsedInStmtLocals, simplify_cfg}; use crate::validate::validate_types; use crate::{check_inline, util}; @@ -935,7 +935,7 @@ fn inline_call<'tcx, I: Inliner<'tcx>>( in_cleanup_block: false, return_block, tcx, - always_live_locals: DenseBitSet::new_filled(callee_body.local_decls.len()), + always_live_locals: UsedInStmtLocals::new(&callee_body).locals, }; // Map all `Local`s, `SourceScope`s and `BasicBlock`s to new ones @@ -995,6 +995,10 @@ fn inline_call<'tcx, I: Inliner<'tcx>>( // people working on rust can build with or without debuginfo while // still getting consistent results from the mir-opt tests. caller_body.var_debug_info.append(&mut callee_body.var_debug_info); + } else { + for bb in callee_body.basic_blocks_mut() { + bb.drop_debuginfo(); + } } caller_body.basic_blocks_mut().append(callee_body.basic_blocks_mut()); diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index f4ae4ae48a398..08e8162f94536 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -34,12 +34,12 @@ //! The normal logic that a program with UB can be changed to do anything does not apply to //! pre-"runtime" MIR! +use rustc_index::bit_set::DenseBitSet; use rustc_index::{Idx, IndexSlice, IndexVec}; -use rustc_middle::mir::visit::{ - MutVisitor, MutatingUseContext, NonUseContext, PlaceContext, Visitor, -}; +use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; +use rustc_mir_dataflow::debuginfo::debuginfo_locals; use rustc_span::DUMMY_SP; use smallvec::SmallVec; use tracing::{debug, trace}; @@ -344,7 +344,7 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { fn strip_nops(&mut self) { for blk in self.basic_blocks.iter_mut() { - blk.retain_statements(|stmt| !matches!(stmt.kind, StatementKind::Nop)) + blk.strip_nops(); } } } @@ -517,17 +517,22 @@ fn make_local_map( /// Keeps track of used & unused locals. struct UsedLocals { increment: bool, - arg_count: u32, use_count: IndexVec, + always_used: DenseBitSet, } impl UsedLocals { /// Determines which locals are used & unused in the given body. fn new(body: &Body<'_>) -> Self { + let mut always_used = debuginfo_locals(body); + always_used.insert(RETURN_PLACE); + for arg in body.args_iter() { + always_used.insert(arg); + } let mut this = Self { increment: true, - arg_count: body.arg_count.try_into().unwrap(), use_count: IndexVec::from_elem(0, &body.local_decls), + always_used, }; this.visit_body(body); this @@ -535,10 +540,16 @@ impl UsedLocals { /// Checks if local is used. /// - /// Return place and arguments are always considered used. + /// Return place, arguments, var debuginfo are always considered used. fn is_used(&self, local: Local) -> bool { - trace!("is_used({:?}): use_count: {:?}", local, self.use_count[local]); - local.as_u32() <= self.arg_count || self.use_count[local] != 0 + trace!( + "is_used({:?}): use_count: {:?}, always_used: {}", + local, + self.use_count[local], + self.always_used.contains(local) + ); + // To keep things simple, we don't handle debugging information here, these are in DSE. + self.always_used.contains(local) || self.use_count[local] != 0 } /// Updates the use counts to reflect the removal of given statement. @@ -583,13 +594,10 @@ impl<'tcx> Visitor<'tcx> for UsedLocals { StatementKind::ConstEvalCounter | StatementKind::Nop | StatementKind::StorageLive(..) - | StatementKind::StorageDead(..) => { - self.visit_statement_debuginfos(&statement.debuginfos, location); - } + | StatementKind::StorageDead(..) => {} StatementKind::Assign(box (ref place, ref rvalue)) => { if rvalue.is_safe_to_remove() { - self.visit_statement_debuginfos(&statement.debuginfos, location); self.visit_lhs(place, location); self.visit_rvalue(rvalue, location); } else { @@ -600,16 +608,18 @@ impl<'tcx> Visitor<'tcx> for UsedLocals { StatementKind::SetDiscriminant { ref place, variant_index: _ } | StatementKind::Deinit(ref place) | StatementKind::BackwardIncompatibleDropHint { ref place, reason: _ } => { - self.visit_statement_debuginfos(&statement.debuginfos, location); self.visit_lhs(place, location); } } } fn visit_local(&mut self, local: Local, ctx: PlaceContext, _location: Location) { + if matches!(ctx, PlaceContext::NonUse(_)) { + return; + } if self.increment { self.use_count[local] += 1; - } else if ctx != PlaceContext::NonUse(NonUseContext::VarDebugInfo) { + } else { assert_ne!(self.use_count[local], 0); self.use_count[local] -= 1; } @@ -629,28 +639,26 @@ fn remove_unused_definitions_helper(used_locals: &mut UsedLocals, body: &mut Bod for data in body.basic_blocks.as_mut_preserves_cfg() { // Remove unnecessary StorageLive and StorageDead annotations. - data.retain_statements(|statement| { - let keep = match &statement.kind { + for statement in data.statements.iter_mut() { + let keep_statement = match &statement.kind { StatementKind::StorageLive(local) | StatementKind::StorageDead(local) => { used_locals.is_used(*local) } - StatementKind::Assign(box (place, _)) => used_locals.is_used(place.local), - - StatementKind::SetDiscriminant { place, .. } - | StatementKind::BackwardIncompatibleDropHint { place, reason: _ } - | StatementKind::Deinit(place) => used_locals.is_used(place.local), - StatementKind::Nop => false, - _ => true, + StatementKind::Assign(box (place, _)) + | StatementKind::SetDiscriminant { box place, .. } + | StatementKind::BackwardIncompatibleDropHint { box place, .. } + | StatementKind::Deinit(box place) => used_locals.is_used(place.local), + _ => continue, }; - - if !keep { - trace!("removing statement {:?}", statement); - modified = true; - used_locals.statement_removed(statement); + if keep_statement { + continue; } - - keep - }); + trace!("removing statement {:?}", statement); + modified = true; + used_locals.statement_removed(statement); + statement.make_nop(true); + } + data.strip_nops(); } } } @@ -669,3 +677,42 @@ impl<'tcx> MutVisitor<'tcx> for LocalUpdater<'tcx> { *l = self.map[*l].unwrap(); } } + +pub(crate) struct UsedInStmtLocals { + pub(crate) locals: DenseBitSet, +} + +impl UsedInStmtLocals { + pub(crate) fn new(body: &Body<'_>) -> Self { + let mut this = Self { locals: DenseBitSet::new_empty(body.local_decls.len()) }; + this.visit_body(body); + this + } + + pub(crate) fn remove_unused_storage_annotations<'tcx>(&self, body: &mut Body<'tcx>) { + for data in body.basic_blocks.as_mut_preserves_cfg() { + // Remove unnecessary StorageLive and StorageDead annotations. + for statement in data.statements.iter_mut() { + let keep_statement = match &statement.kind { + StatementKind::StorageLive(local) | StatementKind::StorageDead(local) => { + self.locals.contains(*local) + } + _ => continue, + }; + if keep_statement { + continue; + } + statement.make_nop(true); + } + } + } +} + +impl<'tcx> Visitor<'tcx> for UsedInStmtLocals { + fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) { + if matches!(context, PlaceContext::NonUse(_)) { + return; + } + self.locals.insert(local); + } +} diff --git a/tests/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination-initial.diff b/tests/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination-initial.diff index ff18df1efcfc9..d584de6861c0c 100644 --- a/tests/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination-initial.diff +++ b/tests/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination-initial.diff @@ -19,10 +19,6 @@ - _3 = copy _2; - _2 = copy _1; - _1 = copy _5; -+ nop; -+ nop; -+ nop; -+ nop; _4 = cond() -> [return: bb1, unwind continue]; } diff --git a/tests/mir-opt/dead-store-elimination/ref.rs b/tests/mir-opt/dead-store-elimination/ref.rs index 368c589914fa4..2babbc5f16577 100644 --- a/tests/mir-opt/dead-store-elimination/ref.rs +++ b/tests/mir-opt/dead-store-elimination/ref.rs @@ -12,7 +12,7 @@ pub fn tuple(v: (i32, &Foo)) -> i32 { // CHECK: debug _dead => [[dead:_[0-9]+]]; // CHECK: bb0: // FIXME: Preserve `tmp` for debuginfo, but we can merge it into the debuginfo. - // CHECK: [[tmp:_[0-9]+]] = deref_copy (_1.1: &Foo); + // CHECK-NEXT: [[tmp:_[0-9]+]] = deref_copy (_1.1: &Foo); // CHECK-NEXT: DBG: [[dead]] = &((*[[tmp]]).2: i32) let _dead = &v.1.c; v.1.a diff --git a/tests/mir-opt/dead-store-elimination/ref.tuple.DeadStoreElimination-initial.diff b/tests/mir-opt/dead-store-elimination/ref.tuple.DeadStoreElimination-initial.diff index 3428fc90ed5f1..02519c72b9b13 100644 --- a/tests/mir-opt/dead-store-elimination/ref.tuple.DeadStoreElimination-initial.diff +++ b/tests/mir-opt/dead-store-elimination/ref.tuple.DeadStoreElimination-initial.diff @@ -12,14 +12,13 @@ } bb0: { - StorageLive(_2); +- StorageLive(_2); _3 = deref_copy (_1.1: &Foo); - _2 = &((*_3).2: i32); + // DBG: _2 = &((*_3).2: i32) -+ nop; _4 = deref_copy (_1.1: &Foo); _0 = copy ((*_4).0: i32); - StorageDead(_2); +- StorageDead(_2); return; } } diff --git a/tests/mir-opt/debuginfo/simplifycfg.drop_debuginfo.SimplifyCfg-final.diff b/tests/mir-opt/debuginfo/simplifycfg.drop_debuginfo.SimplifyCfg-final.diff index 4d7f38c85365c..dcd4e5853f196 100644 --- a/tests/mir-opt/debuginfo/simplifycfg.drop_debuginfo.SimplifyCfg-final.diff +++ b/tests/mir-opt/debuginfo/simplifycfg.drop_debuginfo.SimplifyCfg-final.diff @@ -14,13 +14,11 @@ - - bb1: { - // DBG: _3 = &((*_1).0: i32) -- nop; - goto -> bb2; - } - - bb2: { // DBG: _4 = &((*_1).1: i64) -- nop; _0 = copy ((*_1).2: i32); return; } diff --git a/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_1.SimplifyCfg-final.diff b/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_1.SimplifyCfg-final.diff index c9a95d5dc0f58..6a98a9d90673f 100644 --- a/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_1.SimplifyCfg-final.diff +++ b/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_1.SimplifyCfg-final.diff @@ -17,16 +17,13 @@ - bb1: { (*_2) = const true; // DBG: _3 = &((*_1).0: i32) -- nop; - goto -> bb2; - } - - bb2: { // DBG: _4 = &((*_1).1: i64) -- nop; _0 = copy ((*_1).2: i32); // DBG: _5 = &((*_1).2: i32) -- nop; return; } } diff --git a/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_2.SimplifyCfg-final.diff b/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_2.SimplifyCfg-final.diff index d206a23d95783..33ca4b8988fc7 100644 --- a/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_2.SimplifyCfg-final.diff +++ b/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_2.SimplifyCfg-final.diff @@ -16,16 +16,13 @@ - - bb1: { // DBG: _2 = &((*_1).0: i32) -- nop; - goto -> bb2; - } - - bb2: { // DBG: _3 = &((*_1).1: i64) -- nop; _0 = copy ((*_1).2: i32); // DBG: _4 = &((*_1).2: i32) -- nop; return; } } diff --git a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff index 43bf4e069475c..63abba3d5d72f 100644 --- a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff @@ -63,16 +63,10 @@ + StorageLive(_10); + StorageLive(_8); + StorageLive(_9); -+ StorageLive(_11); -+ // DBG: _11 = &((*_6).0: alloc::raw_vec::RawVec) -+ StorageLive(_12); -+ // DBG: _12 = &(((*_6).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner) + StorageLive(_13); + _13 = copy (((((*_6).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); + _9 = copy _13 as *mut A (Transmute); + StorageDead(_13); -+ StorageDead(_12); -+ StorageDead(_11); + _10 = copy ((*_6).1: usize); + _8 = *mut [A] from (copy _9, copy _10); + StorageDead(_9); @@ -92,7 +86,6 @@ _5 = copy _2; - _0 = drop_in_place::>(move _5) -> [return: bb2, unwind unreachable]; + StorageLive(_17); -+ StorageLive(_18); + _17 = discriminant((*_5)); + switchInt(move _17) -> [0: bb5, otherwise: bb6]; } @@ -118,7 +111,6 @@ + } + + bb5: { -+ StorageDead(_18); + StorageDead(_17); StorageDead(_5); return; diff --git a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-unwind.diff index 1832427642528..34f89da19f51f 100644 --- a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-unwind.diff @@ -27,13 +27,11 @@ _5 = copy _2; - _0 = drop_in_place::>(move _5) -> [return: bb2, unwind continue]; + StorageLive(_6); -+ StorageLive(_7); + _6 = discriminant((*_5)); + switchInt(move _6) -> [0: bb2, otherwise: bb3]; } bb2: { -+ StorageDead(_7); + StorageDead(_6); StorageDead(_5); return; diff --git a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff index 3c3e8b8cd3b4d..3bb08962876f8 100644 --- a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff +++ b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff @@ -130,11 +130,8 @@ _10 = deref_copy (_1.1: &mut std::task::Context<'_>); _9 = &mut (*_10); - _7 = <{async fn body of ActionPermit<'_, T>::perform()} as Future>::poll(move _8, move _9) -> [return: bb3, unwind unreachable]; -+ StorageLive(_11); -+ StorageLive(_15); + StorageLive(_16); + StorageLive(_25); -+ StorageLive(_27); + StorageLive(_30); + StorageLive(_31); + StorageLive(_32); @@ -169,11 +166,8 @@ + StorageDead(_32); + StorageDead(_31); + StorageDead(_30); -+ StorageDead(_27); + StorageDead(_25); + StorageDead(_16); -+ StorageDead(_15); -+ StorageDead(_11); StorageDead(_9); StorageDead(_8); StorageDead(_7); @@ -227,23 +221,15 @@ + _22 = &mut (*_23); + StorageDead(_24); + StorageLive(_45); -+ StorageLive(_46); + StorageLive(_50); + StorageLive(_42); + StorageLive(_43); -+ StorageLive(_44); -+ // DBG: _46 = &_19 -+ StorageLive(_47); -+ // DBG: _47 = &(_19.0: &mut std::future::Ready<()>) + _45 = copy (_19.0: &mut std::future::Ready<()>); -+ StorageDead(_47); -+ // DBG: _44 = &((*_45).0: std::option::Option<()>) + StorageLive(_48); + _48 = Option::<()>::None; + _43 = copy ((*_45).0: std::option::Option<()>); + ((*_45).0: std::option::Option<()>) = copy _48; + StorageDead(_48); -+ StorageDead(_44); + StorageLive(_49); + _49 = discriminant(_43); + switchInt(move _49) -> [0: bb11, 1: bb12, otherwise: bb5]; @@ -319,7 +305,6 @@ + _18 = Poll::<()>::Ready(move _42); + StorageDead(_42); + StorageDead(_50); -+ StorageDead(_46); + StorageDead(_45); + StorageDead(_22); + StorageDead(_19); diff --git a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff index f2ec21508cb14..3aba5ba111030 100644 --- a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff @@ -132,11 +132,8 @@ _10 = deref_copy (_1.1: &mut std::task::Context<'_>); _9 = &mut (*_10); - _7 = <{async fn body of ActionPermit<'_, T>::perform()} as Future>::poll(move _8, move _9) -> [return: bb3, unwind: bb5]; -+ StorageLive(_11); -+ StorageLive(_15); + StorageLive(_16); + StorageLive(_25); -+ StorageLive(_27); + StorageLive(_30); + StorageLive(_31); + StorageLive(_32); @@ -183,11 +180,8 @@ + StorageDead(_32); + StorageDead(_31); + StorageDead(_30); -+ StorageDead(_27); + StorageDead(_25); + StorageDead(_16); -+ StorageDead(_15); -+ StorageDead(_11); StorageDead(_9); StorageDead(_8); StorageDead(_7); @@ -244,23 +238,15 @@ + _22 = &mut (*_23); + StorageDead(_24); + StorageLive(_47); -+ StorageLive(_48); + StorageLive(_52); + StorageLive(_44); + StorageLive(_45); -+ StorageLive(_46); -+ // DBG: _48 = &_19 -+ StorageLive(_49); -+ // DBG: _49 = &(_19.0: &mut std::future::Ready<()>) + _47 = copy (_19.0: &mut std::future::Ready<()>); -+ StorageDead(_49); -+ // DBG: _46 = &((*_47).0: std::option::Option<()>) + StorageLive(_50); + _50 = Option::<()>::None; + _45 = copy ((*_47).0: std::option::Option<()>); + ((*_47).0: std::option::Option<()>) = copy _50; + StorageDead(_50); -+ StorageDead(_46); + StorageLive(_51); + _51 = discriminant(_45); + switchInt(move _51) -> [0: bb16, 1: bb17, otherwise: bb7]; @@ -360,7 +346,6 @@ + _18 = Poll::<()>::Ready(move _44); + StorageDead(_44); + StorageDead(_52); -+ StorageDead(_48); + StorageDead(_47); + StorageDead(_22); + StorageDead(_19); diff --git a/tests/mir-opt/issue_101973.inner.GVN.panic-abort.diff b/tests/mir-opt/issue_101973.inner.GVN.panic-abort.diff index ac88fe67bb86f..3ea7387a48d3c 100644 --- a/tests/mir-opt/issue_101973.inner.GVN.panic-abort.diff +++ b/tests/mir-opt/issue_101973.inner.GVN.panic-abort.diff @@ -30,7 +30,6 @@ StorageLive(_4); StorageLive(_5); _5 = copy _1; - nop; - StorageLive(_14); - _14 = BitAnd(copy _5, const 255_u32); - _4 = BitOr(const 0_u32, move _14); diff --git a/tests/mir-opt/issue_101973.inner.GVN.panic-unwind.diff b/tests/mir-opt/issue_101973.inner.GVN.panic-unwind.diff index 96c3cae2d334a..832db856b2cf9 100644 --- a/tests/mir-opt/issue_101973.inner.GVN.panic-unwind.diff +++ b/tests/mir-opt/issue_101973.inner.GVN.panic-unwind.diff @@ -30,7 +30,6 @@ StorageLive(_4); StorageLive(_5); _5 = copy _1; - nop; - StorageLive(_14); - _14 = BitAnd(copy _5, const 255_u32); - _4 = BitOr(const 0_u32, move _14); diff --git a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff index 47b081bec4538..84d23a590cd25 100644 --- a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff +++ b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff @@ -37,15 +37,9 @@ } bb2: { - StorageLive(_7); // DBG: _7 = &(*_2)[0 of 3] - StorageLive(_8); // DBG: _8 = &(*_2)[1 of 3] - StorageLive(_9); // DBG: _9 = &(*_2)[2 of 3] - StorageDead(_9); - StorageDead(_8); - StorageDead(_7); StorageDead(_4); return; } diff --git a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff index 98766874cbf74..a4b9a8d79fdaf 100644 --- a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff +++ b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff @@ -37,15 +37,9 @@ } bb2: { - StorageLive(_7); // DBG: _7 = &(*_2)[0 of 3] - StorageLive(_8); // DBG: _8 = &(*_2)[1 of 3] - StorageLive(_9); // DBG: _9 = &(*_2)[2 of 3] - StorageDead(_9); - StorageDead(_8); - StorageDead(_7); StorageDead(_4); return; } diff --git a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-abort.mir b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-abort.mir index 63010352500c7..5876c55c52b94 100644 --- a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-abort.mir +++ b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-abort.mir @@ -6,7 +6,6 @@ fn num_to_digit(_1: char) -> u32 { let mut _4: std::option::Option; scope 1 (inlined char::methods::::is_digit) { let _2: std::option::Option; - let mut _7: &std::option::Option; scope 2 (inlined Option::::is_some) { let mut _3: isize; } @@ -19,17 +18,14 @@ fn num_to_digit(_1: char) -> u32 { } bb0: { - StorageLive(_7); StorageLive(_2); _2 = char::methods::::to_digit(copy _1, const 8_u32) -> [return: bb1, unwind unreachable]; } bb1: { - // DBG: _7 = &_2 StorageLive(_3); _3 = discriminant(_2); StorageDead(_2); - StorageDead(_7); switchInt(move _3) -> [1: bb2, otherwise: bb7]; } diff --git a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-unwind.mir b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-unwind.mir index 4e7f960467170..f1185353a43c8 100644 --- a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-unwind.mir +++ b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-unwind.mir @@ -6,7 +6,6 @@ fn num_to_digit(_1: char) -> u32 { let mut _4: std::option::Option; scope 1 (inlined char::methods::::is_digit) { let _2: std::option::Option; - let mut _7: &std::option::Option; scope 2 (inlined Option::::is_some) { let mut _3: isize; } @@ -19,17 +18,14 @@ fn num_to_digit(_1: char) -> u32 { } bb0: { - StorageLive(_7); StorageLive(_2); _2 = char::methods::::to_digit(copy _1, const 8_u32) -> [return: bb1, unwind continue]; } bb1: { - // DBG: _7 = &_2 StorageLive(_3); _3 = discriminant(_2); StorageDead(_2); - StorageDead(_7); switchInt(move _3) -> [1: bb2, otherwise: bb7]; } diff --git a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-abort.mir b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-abort.mir index 63010352500c7..5876c55c52b94 100644 --- a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-abort.mir +++ b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-abort.mir @@ -6,7 +6,6 @@ fn num_to_digit(_1: char) -> u32 { let mut _4: std::option::Option; scope 1 (inlined char::methods::::is_digit) { let _2: std::option::Option; - let mut _7: &std::option::Option; scope 2 (inlined Option::::is_some) { let mut _3: isize; } @@ -19,17 +18,14 @@ fn num_to_digit(_1: char) -> u32 { } bb0: { - StorageLive(_7); StorageLive(_2); _2 = char::methods::::to_digit(copy _1, const 8_u32) -> [return: bb1, unwind unreachable]; } bb1: { - // DBG: _7 = &_2 StorageLive(_3); _3 = discriminant(_2); StorageDead(_2); - StorageDead(_7); switchInt(move _3) -> [1: bb2, otherwise: bb7]; } diff --git a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-unwind.mir b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-unwind.mir index 4e7f960467170..f1185353a43c8 100644 --- a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-unwind.mir +++ b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-unwind.mir @@ -6,7 +6,6 @@ fn num_to_digit(_1: char) -> u32 { let mut _4: std::option::Option; scope 1 (inlined char::methods::::is_digit) { let _2: std::option::Option; - let mut _7: &std::option::Option; scope 2 (inlined Option::::is_some) { let mut _3: isize; } @@ -19,17 +18,14 @@ fn num_to_digit(_1: char) -> u32 { } bb0: { - StorageLive(_7); StorageLive(_2); _2 = char::methods::::to_digit(copy _1, const 8_u32) -> [return: bb1, unwind continue]; } bb1: { - // DBG: _7 = &_2 StorageLive(_3); _3 = discriminant(_2); StorageDead(_2); - StorageDead(_7); switchInt(move _3) -> [1: bb2, otherwise: bb7]; } diff --git a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-abort.mir index 588fe1c942f7a..1a1c8b4b9427e 100644 --- a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-abort.mir @@ -5,9 +5,7 @@ fn step_forward(_1: u16, _2: usize) -> u16 { debug n => _2; let mut _0: u16; scope 1 (inlined ::forward) { - let _8: std::option::Option; - let mut _10: u16; - let mut _11: &std::option::Option; + let mut _8: u16; scope 2 { } scope 3 (inlined ::forward_checked) { @@ -15,9 +13,8 @@ fn step_forward(_1: u16, _2: usize) -> u16 { scope 6 (inlined core::num::::checked_add) { let mut _5: (u16, bool); let mut _6: bool; - let mut _7: u16; scope 7 (inlined std::intrinsics::unlikely) { - let _9: (); + let _7: (); } } } @@ -36,8 +33,6 @@ fn step_forward(_1: u16, _2: usize) -> u16 { bb0: { StorageLive(_4); - StorageLive(_11); - StorageLive(_8); StorageLive(_3); _3 = Gt(copy _2, const 65535_usize); switchInt(move _3) -> [0: bb1, otherwise: bb5]; @@ -56,55 +51,34 @@ fn step_forward(_1: u16, _2: usize) -> u16 { bb2: { StorageDead(_5); StorageDead(_6); - StorageLive(_7); - _7 = AddUnchecked(copy _1, copy _4); - _8 = Option::::Some(move _7); - StorageDead(_7); - // DBG: _11 = &_8 - StorageDead(_8); - StorageDead(_11); goto -> bb7; } bb3: { - _9 = std::intrinsics::cold_path() -> [return: bb4, unwind unreachable]; + _7 = std::intrinsics::cold_path() -> [return: bb4, unwind unreachable]; } bb4: { StorageDead(_5); StorageDead(_6); - _8 = const Option::::None; - // DBG: _11 = &_8 goto -> bb6; } bb5: { StorageDead(_3); - _8 = const Option::::None; - // DBG: _11 = &_8 goto -> bb6; } bb6: { - StorageDead(_8); - StorageDead(_11); assert(!const true, "attempt to compute `{} + {}`, which would overflow", const core::num::::MAX, const 1_u16) -> [success: bb7, unwind unreachable]; } bb7: { - StorageLive(_10); - _10 = copy _2 as u16 (IntToInt); - _0 = Add(copy _1, copy _10); - StorageDead(_10); + StorageLive(_8); + _8 = copy _2 as u16 (IntToInt); + _0 = Add(copy _1, copy _8); + StorageDead(_8); StorageDead(_4); return; } } - -ALLOC0 (size: 4, align: 2) { - 00 00 __ __ │ ..░░ -} - -ALLOC1 (size: 4, align: 2) { - 00 00 __ __ │ ..░░ -} diff --git a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-unwind.mir index f20b599377d55..e7e19af048ae3 100644 --- a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-unwind.mir @@ -5,9 +5,7 @@ fn step_forward(_1: u16, _2: usize) -> u16 { debug n => _2; let mut _0: u16; scope 1 (inlined ::forward) { - let _8: std::option::Option; - let mut _10: u16; - let mut _11: &std::option::Option; + let mut _8: u16; scope 2 { } scope 3 (inlined ::forward_checked) { @@ -15,9 +13,8 @@ fn step_forward(_1: u16, _2: usize) -> u16 { scope 6 (inlined core::num::::checked_add) { let mut _5: (u16, bool); let mut _6: bool; - let mut _7: u16; scope 7 (inlined std::intrinsics::unlikely) { - let _9: (); + let _7: (); } } } @@ -36,8 +33,6 @@ fn step_forward(_1: u16, _2: usize) -> u16 { bb0: { StorageLive(_4); - StorageLive(_11); - StorageLive(_8); StorageLive(_3); _3 = Gt(copy _2, const 65535_usize); switchInt(move _3) -> [0: bb1, otherwise: bb5]; @@ -56,55 +51,34 @@ fn step_forward(_1: u16, _2: usize) -> u16 { bb2: { StorageDead(_5); StorageDead(_6); - StorageLive(_7); - _7 = AddUnchecked(copy _1, copy _4); - _8 = Option::::Some(move _7); - StorageDead(_7); - // DBG: _11 = &_8 - StorageDead(_8); - StorageDead(_11); goto -> bb7; } bb3: { - _9 = std::intrinsics::cold_path() -> [return: bb4, unwind unreachable]; + _7 = std::intrinsics::cold_path() -> [return: bb4, unwind unreachable]; } bb4: { StorageDead(_5); StorageDead(_6); - _8 = const Option::::None; - // DBG: _11 = &_8 goto -> bb6; } bb5: { StorageDead(_3); - _8 = const Option::::None; - // DBG: _11 = &_8 goto -> bb6; } bb6: { - StorageDead(_8); - StorageDead(_11); assert(!const true, "attempt to compute `{} + {}`, which would overflow", const core::num::::MAX, const 1_u16) -> [success: bb7, unwind continue]; } bb7: { - StorageLive(_10); - _10 = copy _2 as u16 (IntToInt); - _0 = Add(copy _1, copy _10); - StorageDead(_10); + StorageLive(_8); + _8 = copy _2 as u16 (IntToInt); + _0 = Add(copy _1, copy _8); + StorageDead(_8); StorageDead(_4); return; } } - -ALLOC0 (size: 4, align: 2) { - 00 00 __ __ │ ..░░ -} - -ALLOC1 (size: 4, align: 2) { - 00 00 __ __ │ ..░░ -} diff --git a/tests/mir-opt/pre-codegen/clone_as_copy.clone_as_copy.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/clone_as_copy.clone_as_copy.PreCodegen.after.mir index fd459b8885ee7..dcdc99312d9aa 100644 --- a/tests/mir-opt/pre-codegen/clone_as_copy.clone_as_copy.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/clone_as_copy.clone_as_copy.PreCodegen.after.mir @@ -12,10 +12,8 @@ fn clone_as_copy(_1: &NestCopy) -> NestCopy { } bb0: { - StorageLive(_2); // DBG: _2 = &((*_1).1: AllCopy) _0 = copy (*_1); - StorageDead(_2); return; } } diff --git a/tests/mir-opt/pre-codegen/clone_as_copy.enum_clone_as_copy.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/clone_as_copy.enum_clone_as_copy.PreCodegen.after.mir index 29aa07a8a05a2..8ad0ad95d5758 100644 --- a/tests/mir-opt/pre-codegen/clone_as_copy.enum_clone_as_copy.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/clone_as_copy.enum_clone_as_copy.PreCodegen.after.mir @@ -5,58 +5,28 @@ fn enum_clone_as_copy(_1: &Enum1) -> Enum1 { let mut _0: Enum1; scope 1 (inlined ::clone) { debug self => _1; - let mut _2: isize; - let mut _3: &AllCopy; - let mut _4: &NestCopy; + let mut _2: &AllCopy; + let mut _3: &NestCopy; scope 2 { - debug __self_0 => _3; + debug __self_0 => _2; scope 6 (inlined ::clone) { - debug self => _3; + debug self => _2; } } scope 3 { - debug __self_0 => _4; + debug __self_0 => _3; scope 4 (inlined ::clone) { - debug self => _4; - let _5: &AllCopy; + debug self => _3; + let _4: &AllCopy; scope 5 (inlined ::clone) { - debug self => _5; + debug self => _4; } } } } bb0: { - StorageLive(_2); - StorageLive(_3); - StorageLive(_4); - _2 = discriminant((*_1)); - switchInt(move _2) -> [0: bb1, 1: bb2, otherwise: bb4]; - } - - bb1: { - // DBG: _3 = &(((*_1) as A).0: AllCopy) _0 = copy (*_1); - goto -> bb3; - } - - bb2: { - // DBG: _4 = &(((*_1) as B).0: NestCopy) - StorageLive(_5); - // DBG: _5 = &((((*_1) as B).0: NestCopy).1: AllCopy) - StorageDead(_5); - _0 = copy (*_1); - goto -> bb3; - } - - bb3: { - StorageDead(_4); - StorageDead(_3); - StorageDead(_2); return; } - - bb4: { - unreachable; - } } diff --git a/tests/mir-opt/pre-codegen/clone_as_copy.rs b/tests/mir-opt/pre-codegen/clone_as_copy.rs index f5ff1854d387d..00f24754d5913 100644 --- a/tests/mir-opt/pre-codegen/clone_as_copy.rs +++ b/tests/mir-opt/pre-codegen/clone_as_copy.rs @@ -25,19 +25,19 @@ enum Enum1 { // EMIT_MIR clone_as_copy.clone_as_copy.PreCodegen.after.mir fn clone_as_copy(v: &NestCopy) -> NestCopy { // CHECK-LABEL: fn clone_as_copy( - // CHECK-NOT: = AllCopy { {{.*}} }; - // CHECK-NOT: = NestCopy { {{.*}} }; - // CHECK: _0 = copy (*_1); - // CHECK: return; + // CHECK: let [[DEAD_VAR:_.*]]: &AllCopy; + // CHECK: bb0: { + // CHECK-NEXT: DBG: [[DEAD_VAR]] = &((*_1).1: AllCopy) + // CHECK-NEXT: _0 = copy (*_1); + // CHECK-NEXT: return; v.clone() } -// FIXME: We can merge into exactly one assignment statement. // EMIT_MIR clone_as_copy.enum_clone_as_copy.PreCodegen.after.mir fn enum_clone_as_copy(v: &Enum1) -> Enum1 { // CHECK-LABEL: fn enum_clone_as_copy( - // CHECK-NOT: = Enum1:: - // CHECK: _0 = copy (*_1); - // CHECK: _0 = copy (*_1); + // CHECK: bb0: { + // CHECK-NEXT: _0 = copy (*_1); + // CHECK-NEXT: return; v.clone() } diff --git a/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir index 03cb60d51c2a9..9c08c8c34a1b5 100644 --- a/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir @@ -63,9 +63,7 @@ fn int_range(_1: usize, _2: usize) -> () { StorageLive(_10); // DBG: _13 = &_4 StorageLive(_7); - StorageLive(_14); // DBG: _14 = &(_4.0: usize) - StorageLive(_15); // DBG: _15 = &(_4.1: usize) StorageLive(_5); _5 = copy (_4.0: usize); @@ -78,8 +76,6 @@ fn int_range(_1: usize, _2: usize) -> () { } bb2: { - StorageDead(_15); - StorageDead(_14); StorageDead(_7); StorageDead(_10); StorageDead(_4); @@ -87,8 +83,6 @@ fn int_range(_1: usize, _2: usize) -> () { } bb3: { - StorageDead(_15); - StorageDead(_14); _8 = copy (_4.0: usize); StorageLive(_9); _9 = AddUnchecked(copy _8, const 1_usize); 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 ef93d1b114b47..96e2a2fc19251 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 @@ -70,9 +70,7 @@ fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:7:25: 7:39}, _2 // DBG: _15 = &((*_3).2: usize) // DBG: _16 = &((*_3).3: usize) StorageLive(_6); - StorageLive(_17); // DBG: _17 = &_13 - StorageLive(_18); // DBG: _18 = &_15 _4 = copy ((*_3).0: usize); _5 = copy ((*_3).2: usize); @@ -81,18 +79,12 @@ fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:7:25: 7:39}, _2 } bb1: { - StorageDead(_18); - StorageDead(_17); goto -> bb4; } bb2: { - StorageDead(_18); - StorageDead(_17); StorageLive(_9); - StorageLive(_19); // DBG: _19 = &_16 - StorageLive(_20); // DBG: _20 = &_14 StorageLive(_7); _7 = copy ((*_3).3: usize); @@ -105,34 +97,24 @@ fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:7:25: 7:39}, _2 } bb3: { - StorageDead(_20); - StorageDead(_19); goto -> bb4; } bb4: { StorageLive(_10); - StorageLive(_21); // DBG: _21 = &_15 - StorageLive(_22); // DBG: _22 = &_13 _10 = Le(copy _5, copy _4); switchInt(move _10) -> [0: bb5, otherwise: bb6]; } bb5: { - StorageDead(_22); - StorageDead(_21); _0 = const false; goto -> bb7; } bb6: { - StorageDead(_22); - StorageDead(_21); - StorageLive(_23); // DBG: _23 = &_14 - StorageLive(_24); // DBG: _24 = &_16 StorageLive(_11); _11 = copy ((*_3).1: usize); @@ -141,8 +123,6 @@ fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:7:25: 7:39}, _2 _0 = Le(move _11, move _12); StorageDead(_12); StorageDead(_11); - StorageDead(_24); - StorageDead(_23); goto -> bb7; } @@ -152,8 +132,6 @@ fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:7:25: 7:39}, _2 } bb8: { - StorageDead(_20); - StorageDead(_19); _0 = const true; goto -> bb9; } diff --git a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir index 7593afa4a82d0..d3b346173a896 100644 --- a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir @@ -57,14 +57,10 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { bb0: { StorageLive(_2); StorageLive(_3); - StorageLive(_6); // DBG: _6 = &((*_1).0: alloc::raw_vec::RawVec) - StorageLive(_7); // DBG: _7 = &(((*_1).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner) _2 = copy (((((*_1).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); - StorageDead(_7); _3 = copy _2 as *const u8 (Transmute); - StorageDead(_6); StorageLive(_4); _4 = copy ((*_1).1: usize); StorageLive(_5); diff --git a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir index 7593afa4a82d0..d3b346173a896 100644 --- a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir @@ -57,14 +57,10 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { bb0: { StorageLive(_2); StorageLive(_3); - StorageLive(_6); // DBG: _6 = &((*_1).0: alloc::raw_vec::RawVec) - StorageLive(_7); // DBG: _7 = &(((*_1).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner) _2 = copy (((((*_1).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); - StorageDead(_7); _3 = copy _2 as *const u8 (Transmute); - StorageDead(_6); StorageLive(_4); _4 = copy ((*_1).1: usize); StorageLive(_5); diff --git a/tests/ui/extern/extern-types-field-offset.rs b/tests/ui/extern/extern-types-field-offset.rs index 035f063cd502c..3db8bed18aba6 100644 --- a/tests/ui/extern/extern-types-field-offset.rs +++ b/tests/ui/extern/extern-types-field-offset.rs @@ -22,12 +22,17 @@ fn main() { let x: &Newtype = unsafe { &*(&buf as *const _ as *const Newtype) }; // Projecting to the newtype works, because it is always at offset 0. let field = &x.0; + // Avoid being eliminated by DSE. + std::hint::black_box(field); let x: &S = unsafe { &*(&buf as *const _ as *const S) }; // Accessing sized fields is perfectly fine, even at non-zero offsets. let field = &x.i; + std::hint::black_box(field); let field = &x.j; + std::hint::black_box(field); // This needs to compute the field offset, but we don't know the type's alignment, // so this panics. let field = &x.a; + std::hint::black_box(field); } From de1588353d9a2b4bfe8c19e4b2839f4154f7b9a7 Mon Sep 17 00:00:00 2001 From: dianqk Date: Wed, 16 Jul 2025 21:33:54 +0800 Subject: [PATCH 6/8] test: Visit debuginfos when needed --- compiler/rustc_middle/src/mir/visit.rs | 6 +++++- compiler/rustc_mir_dataflow/src/debuginfo.rs | 2 ++ compiler/rustc_mir_transform/src/copy_prop.rs | 2 ++ compiler/rustc_mir_transform/src/dest_prop.rs | 1 + compiler/rustc_mir_transform/src/gvn.rs | 2 ++ compiler/rustc_mir_transform/src/inline.rs | 2 ++ compiler/rustc_mir_transform/src/prettify.rs | 2 ++ compiler/rustc_mir_transform/src/ref_prop.rs | 4 ++++ compiler/rustc_mir_transform/src/simplify.rs | 4 ++++ compiler/rustc_mir_transform/src/validate.rs | 2 ++ 10 files changed, 26 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 3e9c7a50311d9..2823e1ce17454 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -68,6 +68,8 @@ use crate::ty::CanonicalUserTypeAnnotation; macro_rules! make_mir_visitor { ($visitor_trait_name:ident, $($mutability:ident)?) => { pub trait $visitor_trait_name<'tcx> { + const VISIT_DEBUG_INFO: bool = false; + // Override these, and call `self.super_xxx` to revert back to the // default behavior. @@ -100,7 +102,9 @@ macro_rules! make_mir_visitor { stmt_debuginfo: & $($mutability)? [StmtDebugInfo<'tcx>], location: Location ) { - self.super_statement_debuginfos(stmt_debuginfo, location); + if Self::VISIT_DEBUG_INFO { + self.super_statement_debuginfos(stmt_debuginfo, location); + } } fn visit_statement_debuginfo( diff --git a/compiler/rustc_mir_dataflow/src/debuginfo.rs b/compiler/rustc_mir_dataflow/src/debuginfo.rs index 274c5943946c2..e461f7b0155eb 100644 --- a/compiler/rustc_mir_dataflow/src/debuginfo.rs +++ b/compiler/rustc_mir_dataflow/src/debuginfo.rs @@ -12,6 +12,8 @@ pub fn debuginfo_locals(body: &Body<'_>) -> DenseBitSet { struct DebuginfoLocals(DenseBitSet); impl Visitor<'_> for DebuginfoLocals { + const VISIT_DEBUG_INFO: bool = true; + fn visit_local(&mut self, local: Local, place_context: PlaceContext, _: Location) { if place_context == PlaceContext::NonUse(NonUseContext::VarDebugInfo) { self.0.insert(local); diff --git a/compiler/rustc_mir_transform/src/copy_prop.rs b/compiler/rustc_mir_transform/src/copy_prop.rs index f0bc286a94022..9e7d879bc1ae3 100644 --- a/compiler/rustc_mir_transform/src/copy_prop.rs +++ b/compiler/rustc_mir_transform/src/copy_prop.rs @@ -104,6 +104,8 @@ struct Replacer<'a, 'tcx> { } impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> { + const VISIT_DEBUG_INFO: bool = true; + fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index 5e8f8de86bb12..9ca4cf42ed4b2 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -292,6 +292,7 @@ struct Merger<'tcx> { } impl<'tcx> MutVisitor<'tcx> for Merger<'tcx> { + const VISIT_DEBUG_INFO: bool = true; fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 9d72117218874..8640609d13c22 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -1699,6 +1699,8 @@ impl<'tcx> VnState<'_, 'tcx> { } impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> { + const VISIT_DEBUG_INFO: bool = true; + fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 5e7ed2cd5944b..d5af8a9bcc2d0 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -1230,6 +1230,8 @@ impl Integrator<'_, '_> { } impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> { + const VISIT_DEBUG_INFO: bool = true; + fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } diff --git a/compiler/rustc_mir_transform/src/prettify.rs b/compiler/rustc_mir_transform/src/prettify.rs index 8217feff24eca..307d03d765246 100644 --- a/compiler/rustc_mir_transform/src/prettify.rs +++ b/compiler/rustc_mir_transform/src/prettify.rs @@ -148,6 +148,8 @@ struct LocalUpdater<'tcx> { } impl<'tcx> MutVisitor<'tcx> for LocalUpdater<'tcx> { + const VISIT_DEBUG_INFO: bool = true; + fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } diff --git a/compiler/rustc_mir_transform/src/ref_prop.rs b/compiler/rustc_mir_transform/src/ref_prop.rs index 6d557df2722c2..fa9a059f5e749 100644 --- a/compiler/rustc_mir_transform/src/ref_prop.rs +++ b/compiler/rustc_mir_transform/src/ref_prop.rs @@ -284,6 +284,8 @@ fn compute_replacement<'tcx>( where F: FnMut(Place<'tcx>, Location) -> bool, { + const VISIT_DEBUG_INFO: bool = true; + fn visit_place(&mut self, place: &Place<'tcx>, ctxt: PlaceContext, loc: Location) { if matches!(ctxt, PlaceContext::NonUse(_)) { // There is no need to check liveness for non-uses. @@ -354,6 +356,8 @@ struct Replacer<'tcx> { } impl<'tcx> MutVisitor<'tcx> for Replacer<'tcx> { + const VISIT_DEBUG_INFO: bool = true; + fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index 08e8162f94536..64e0da42ad575 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -669,6 +669,8 @@ struct LocalUpdater<'tcx> { } impl<'tcx> MutVisitor<'tcx> for LocalUpdater<'tcx> { + const VISIT_DEBUG_INFO: bool = true; + fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } @@ -709,6 +711,8 @@ impl UsedInStmtLocals { } impl<'tcx> Visitor<'tcx> for UsedInStmtLocals { + const VISIT_DEBUG_INFO: bool = true; + fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) { if matches!(context, PlaceContext::NonUse(_)) { return; diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index 5860072d541f2..d029cec1e661f 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -282,6 +282,7 @@ impl<'a, 'tcx> CfgChecker<'a, 'tcx> { } impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { + const VISIT_DEBUG_INFO: bool = true; fn visit_local(&mut self, local: Local, _context: PlaceContext, location: Location) { if self.body.local_decls.get(local).is_none() { self.fail( @@ -629,6 +630,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { + const VISIT_DEBUG_INFO: bool = true; fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) { // This check is somewhat expensive, so only run it when -Zvalidate-mir is passed. if self.tcx.sess.opts.unstable_opts.validate_mir From 1b79b87715c02e0a0868b7c7d131f05ef61ff6f6 Mon Sep 17 00:00:00 2001 From: dianqk Date: Sat, 19 Jul 2025 18:49:47 +0800 Subject: [PATCH 7/8] mir-opt: Eliminate dead statements even if they are used by debuginfos --- .../rustc_codegen_ssa/src/mir/statement.rs | 70 ++++++++++--------- compiler/rustc_middle/src/mir/pretty.rs | 3 +- compiler/rustc_middle/src/mir/statement.rs | 4 +- compiler/rustc_middle/src/mir/visit.rs | 12 ++-- compiler/rustc_mir_dataflow/src/debuginfo.rs | 2 - .../rustc_mir_dataflow/src/impls/liveness.rs | 3 - compiler/rustc_mir_transform/src/simplify.rs | 36 ++++++++++ .../src/strip_debuginfo.rs | 13 ++++ tests/codegen/debuginfo-dse.rs | 23 +++++- tests/mir-opt/dead-store-elimination/ref.rs | 4 +- ...ef.tuple.DeadStoreElimination-initial.diff | 2 +- .../inline_shims.drop.Inline.panic-abort.diff | 50 +++++++------ ...variant_a-{closure#0}.PreCodegen.after.mir | 42 +++++------ ..._to_slice.PreCodegen.after.panic-abort.mir | 4 -- ...to_slice.PreCodegen.after.panic-unwind.mir | 4 -- 15 files changed, 160 insertions(+), 112 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/statement.rs b/compiler/rustc_codegen_ssa/src/mir/statement.rs index cbf524ec6732e..7897caa774723 100644 --- a/compiler/rustc_codegen_ssa/src/mir/statement.rs +++ b/compiler/rustc_codegen_ssa/src/mir/statement.rs @@ -109,31 +109,31 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { pub(crate) fn codegen_stmt_debuginfo(&mut self, bx: &mut Bx, debuginfo: &StmtDebugInfo<'tcx>) { match debuginfo { StmtDebugInfo::AssignRef(dest, place) => { - let place_ref = match self.locals[place.local] { - LocalRef::Place(place_ref) | LocalRef::UnsizedPlace(place_ref) => { - Some(place_ref) - } - LocalRef::Operand(operand_ref) => match operand_ref.val { - OperandValue::Immediate(v) => { - Some(PlaceRef::new_sized(v, operand_ref.layout)) + let assign_ref = if let Some(place) = place { + let place_ref = match self.locals[place.local] { + LocalRef::Place(place_ref) | LocalRef::UnsizedPlace(place_ref) => { + Some(place_ref) } - OperandValue::Ref(_) - | OperandValue::Pair(_, _) - | OperandValue::ZeroSized => None, - }, - LocalRef::PendingOperand => None, - } - .filter(|place_ref| { - // Drop unsupported projections. - // FIXME: Add a test case. - place.projection.iter().all(|p| p.can_use_in_debuginfo()) && - // Only pointers can calculate addresses. - bx.type_kind(bx.val_ty(place_ref.val.llval)) == TypeKind::Pointer - }); - let (val, layout, projection) = + LocalRef::Operand(operand_ref) => match operand_ref.val { + OperandValue::Immediate(v) => { + Some(PlaceRef::new_sized(v, operand_ref.layout)) + } + OperandValue::Ref(_) + | OperandValue::Pair(_, _) + | OperandValue::ZeroSized => None, + }, + LocalRef::PendingOperand => None, + } + .filter(|place_ref| { + // Drop unsupported projections. + // FIXME: Add a test case. + place.projection.iter().all(|p| p.can_use_in_debuginfo()) && + // Only pointers can calculate addresses. + bx.type_kind(bx.val_ty(place_ref.val.llval)) == TypeKind::Pointer + }); match (place_ref, place.is_indirect_first_projection()) { (Some(place_ref), false) => { - (place_ref.val, place_ref.layout, place.projection.as_slice()) + Some((place_ref.val, place_ref.layout, place.projection.as_slice())) } (Some(place_ref), true) => { let projected_ty = @@ -141,18 +141,22 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bug!("deref of non-pointer {:?}", place_ref) }); let layout = bx.cx().layout_of(projected_ty); - (place_ref.val, layout, &place.projection[1..]) + Some((place_ref.val, layout, &place.projection[1..])) } - _ => { - // If the address cannot be computed, use poison to indicate that the value has been optimized out. - let ty = self.monomorphize(self.mir.local_decls[*dest].ty); - let layout = bx.cx().layout_of(ty); - let to_backend_ty = bx.cx().immediate_backend_type(layout); - let place_ref = - PlaceRef::new_sized(bx.cx().const_poison(to_backend_ty), layout); - (place_ref.val, layout, [].as_slice()) - } - }; + _ => None, + } + } else { + None + }; + let (val, layout, projection) = assign_ref.unwrap_or_else(|| { + // If the address cannot be computed, use poison to indicate that the value has been optimized out. + let ty = self.monomorphize(self.mir.local_decls[*dest].ty); + let layout = bx.cx().layout_of(ty); + let to_backend_ty = bx.cx().immediate_backend_type(layout); + let place_ref = + PlaceRef::new_sized(bx.cx().const_poison(to_backend_ty), layout); + (place_ref.val, layout, [].as_slice()) + }); self.debug_new_value_to_local(bx, *dest, val, layout, projection); } } diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index df8f4c0e7bc9e..2537a930cbf3d 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -901,7 +901,8 @@ impl Debug for StmtDebugInfo<'_> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { match self { StmtDebugInfo::AssignRef(local, place) => { - write!(fmt, "{local:?} = &{place:?}") + write!(fmt, "{local:?} = &")?; + if let Some(place) = place { write!(fmt, "{place:?}") } else { write!(fmt, "?") } } } } diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index 4a68ed6098024..4fc1d08a1f94f 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -79,7 +79,7 @@ impl<'tcx> StatementKind<'tcx> { StatementKind::Assign(box (place, Rvalue::Ref(_, _, ref_place))) if let Some(local) = place.as_local() => { - Some(StmtDebugInfo::AssignRef(local, *ref_place)) + Some(StmtDebugInfo::AssignRef(local, Some(*ref_place))) } _ => None, } @@ -963,5 +963,5 @@ impl RawPtrKind { #[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] pub enum StmtDebugInfo<'tcx> { - AssignRef(Local, Place<'tcx>), + AssignRef(Local, Option>), } diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 2823e1ce17454..8077c2faa2238 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -420,11 +420,13 @@ macro_rules! make_mir_visitor { PlaceContext::NonUse(NonUseContext::VarDebugInfo), location ); - self.visit_place( - place, - PlaceContext::NonUse(NonUseContext::VarDebugInfo), - location - ); + if let Some(place) = place { + self.visit_place( + place, + PlaceContext::NonUse(NonUseContext::VarDebugInfo), + location + ); + } }, } } diff --git a/compiler/rustc_mir_dataflow/src/debuginfo.rs b/compiler/rustc_mir_dataflow/src/debuginfo.rs index e461f7b0155eb..274c5943946c2 100644 --- a/compiler/rustc_mir_dataflow/src/debuginfo.rs +++ b/compiler/rustc_mir_dataflow/src/debuginfo.rs @@ -12,8 +12,6 @@ pub fn debuginfo_locals(body: &Body<'_>) -> DenseBitSet { struct DebuginfoLocals(DenseBitSet); impl Visitor<'_> for DebuginfoLocals { - const VISIT_DEBUG_INFO: bool = true; - fn visit_local(&mut self, local: Local, place_context: PlaceContext, _: Location) { if place_context == PlaceContext::NonUse(NonUseContext::VarDebugInfo) { self.0.insert(local); diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs index 2b2a8cbba458f..567873f5cbbc1 100644 --- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs @@ -282,9 +282,6 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> { if let Some(destination) = Self::can_be_removed_if_dead(&statement.kind, &self.always_live, &self.debuginfo_locals) && !state.contains(destination.local) - // FIXME: We can eliminate the statement, but we'll need the statements it depends on - // for debuginfos. We need a way to handle this. - && !self.debuginfo_locals.contains(destination.local) { // This store is dead return; diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index 64e0da42ad575..716c7418a2f8c 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -663,6 +663,19 @@ fn remove_unused_definitions_helper(used_locals: &mut UsedLocals, body: &mut Bod } } +struct InvalidPlace<'a> { + map: &'a IndexVec>, + is_invalid: bool, +} + +impl<'tcx, 'a> Visitor<'tcx> for InvalidPlace<'a> { + fn visit_local(&mut self, local: Local, _: PlaceContext, _: Location) { + if self.map[local].is_none() { + self.is_invalid = true; + } + } +} + struct LocalUpdater<'tcx> { map: IndexVec>, tcx: TyCtxt<'tcx>, @@ -675,6 +688,29 @@ impl<'tcx> MutVisitor<'tcx> for LocalUpdater<'tcx> { self.tcx } + fn visit_statement_debuginfo( + &mut self, + stmt_debuginfo: &mut StmtDebugInfo<'tcx>, + location: Location, + ) { + match stmt_debuginfo { + StmtDebugInfo::AssignRef(_, place) => { + if place.is_some_and(|ref place| { + let mut invalid_place = InvalidPlace { map: &self.map, is_invalid: false }; + invalid_place.visit_place( + place, + PlaceContext::NonUse(visit::NonUseContext::VarDebugInfo), + location, + ); + invalid_place.is_invalid + }) { + *place = None; + } + } + } + self.super_statement_debuginfo(stmt_debuginfo, location); + } + fn visit_local(&mut self, l: &mut Local, _: PlaceContext, _: Location) { *l = self.map[*l].unwrap(); } diff --git a/compiler/rustc_mir_transform/src/strip_debuginfo.rs b/compiler/rustc_mir_transform/src/strip_debuginfo.rs index 9ede8aa79c44a..94428e971c2a5 100644 --- a/compiler/rustc_mir_transform/src/strip_debuginfo.rs +++ b/compiler/rustc_mir_transform/src/strip_debuginfo.rs @@ -1,5 +1,6 @@ use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; +use rustc_mir_dataflow::debuginfo::debuginfo_locals; use rustc_session::config::MirStripDebugInfo; /// Conditionally remove some of the VarDebugInfo in MIR. @@ -30,6 +31,18 @@ impl<'tcx> crate::MirPass<'tcx> for StripDebugInfo { if place.local.as_usize() <= body.arg_count && place.local != RETURN_PLACE, ) }); + + let debuginfo_locals = debuginfo_locals(body); + for data in body.basic_blocks.as_mut_preserves_cfg() { + for stmt in data.statements.iter_mut() { + stmt.debuginfos.retain(|debuginfo| match debuginfo { + StmtDebugInfo::AssignRef(local, _) => debuginfo_locals.contains(*local), + }); + } + data.after_last_stmt_debuginfos.retain(|debuginfo| match debuginfo { + StmtDebugInfo::AssignRef(local, _) => debuginfo_locals.contains(*local), + }); + } } fn is_required(&self) -> bool { diff --git a/tests/codegen/debuginfo-dse.rs b/tests/codegen/debuginfo-dse.rs index 42cc0678ec082..bdca3ee02548b 100644 --- a/tests/codegen/debuginfo-dse.rs +++ b/tests/codegen/debuginfo-dse.rs @@ -1,4 +1,4 @@ -//@ compile-flags: -Copt-level=3 -g -Zverify-llvm-ir +//@ compile-flags: -Copt-level=3 -g -Zverify-llvm-ir -Zmerge-functions=disabled //@ revisions: CODEGEN OPTIMIZED //@[CODEGEN] compile-flags: -Cno-prepopulate-passes @@ -8,6 +8,13 @@ #[derive(Clone, Copy)] pub struct Foo(i32, i64, i32); +#[repr(C)] +pub struct Bar<'a> { + a: i32, + b: i64, + foo: &'a Foo, +} + #[no_mangle] fn r#ref(ref_foo: &Foo) -> i32 { // CHECK-LABEL: define {{.*}} i32 @ref @@ -58,11 +65,20 @@ pub fn fragment(fragment_v1: Foo, mut fragment_v2: Foo) -> Foo { fragment_v2 } +#[no_mangle] +pub fn deref(bar: Bar) -> i32 { + // CHECK-LABEL: define {{.*}} i32 @deref + // We are unable to represent dereference within this expression. + // CHECK: #dbg_value(ptr poison, [[VAR_deref_dead:![0-9]+]], !DIExpression() + let deref_dead = &bar.foo.2; + bar.a +} + #[no_mangle] pub fn tuple(foo: (i32, &Foo)) -> i32 { // CHECK-LABEL: define {{.*}} i32 @tuple - // CHECK-SAME: (i32 {{.*}}, ptr {{.*}} [[ARG_tuple_foo_1:%.*]]) - // CHECK: #dbg_value(ptr [[ARG_tuple_foo_1]], [[VAR_tuple_dead:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 16, DW_OP_stack_value) + // Although there is no dereference here, there is a dereference in the MIR. + // CHECK: #dbg_value(ptr poison, [[VAR_tuple_dead:![0-9]+]], !DIExpression() let tuple_dead = &foo.1.2; foo.1.0 } @@ -77,3 +93,4 @@ pub fn tuple(foo: (i32, &Foo)) -> i32 { // CODEGEN-DAG: [[VAR_val_ref]] = !DILocalVariable(name: "val_ref" // CHECK-DAG: [[VAR_fragment_f]] = !DILocalVariable(name: "fragment_f" // CHECK-DAG: [[VAR_tuple_dead]] = !DILocalVariable(name: "tuple_dead" +// CHECK-DAG: [[VAR_deref_dead]] = !DILocalVariable(name: "deref_dead" diff --git a/tests/mir-opt/dead-store-elimination/ref.rs b/tests/mir-opt/dead-store-elimination/ref.rs index 2babbc5f16577..841f121e16c8a 100644 --- a/tests/mir-opt/dead-store-elimination/ref.rs +++ b/tests/mir-opt/dead-store-elimination/ref.rs @@ -11,9 +11,7 @@ pub fn tuple(v: (i32, &Foo)) -> i32 { // CHECK-LABEL: fn tuple // CHECK: debug _dead => [[dead:_[0-9]+]]; // CHECK: bb0: - // FIXME: Preserve `tmp` for debuginfo, but we can merge it into the debuginfo. - // CHECK-NEXT: [[tmp:_[0-9]+]] = deref_copy (_1.1: &Foo); - // CHECK-NEXT: DBG: [[dead]] = &((*[[tmp]]).2: i32) + // CHECK-NEXT: DBG: [[dead]] = &((*_3).2: i32) let _dead = &v.1.c; v.1.a } diff --git a/tests/mir-opt/dead-store-elimination/ref.tuple.DeadStoreElimination-initial.diff b/tests/mir-opt/dead-store-elimination/ref.tuple.DeadStoreElimination-initial.diff index 02519c72b9b13..0b2472b98730e 100644 --- a/tests/mir-opt/dead-store-elimination/ref.tuple.DeadStoreElimination-initial.diff +++ b/tests/mir-opt/dead-store-elimination/ref.tuple.DeadStoreElimination-initial.diff @@ -13,7 +13,7 @@ bb0: { - StorageLive(_2); - _3 = deref_copy (_1.1: &Foo); +- _3 = deref_copy (_1.1: &Foo); - _2 = &((*_3).2: i32); + // DBG: _2 = &((*_3).2: i32) _4 = deref_copy (_1.1: &Foo); diff --git a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff index 63abba3d5d72f..9509739413b76 100644 --- a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff @@ -16,12 +16,10 @@ + let mut _9: *mut A; + let mut _10: usize; + scope 3 (inlined Vec::::as_mut_ptr) { -+ let mut _11: &alloc::raw_vec::RawVec; + scope 4 (inlined alloc::raw_vec::RawVec::::ptr) { -+ let mut _12: &alloc::raw_vec::RawVecInner; + scope 5 (inlined alloc::raw_vec::RawVecInner::ptr::) { + scope 6 (inlined alloc::raw_vec::RawVecInner::non_null::) { -+ let mut _13: std::ptr::NonNull; ++ let mut _11: std::ptr::NonNull; + scope 7 (inlined Unique::::cast::) { + scope 8 (inlined NonNull::::cast::) { + scope 9 (inlined NonNull::::as_ptr) { @@ -41,15 +39,15 @@ + } + } + scope 14 (inlined drop_in_place::<[A]> - shim(Some([A]))) { -+ let mut _14: usize; -+ let mut _15: *mut A; -+ let mut _16: bool; ++ let mut _12: usize; ++ let mut _13: *mut A; ++ let mut _14: bool; + } + } + } + scope 15 (inlined drop_in_place::> - shim(Some(Option))) { -+ let mut _17: isize; -+ let mut _18: isize; ++ let mut _15: isize; ++ let mut _16: isize; + } bb0: { @@ -63,17 +61,17 @@ + StorageLive(_10); + StorageLive(_8); + StorageLive(_9); -+ StorageLive(_13); -+ _13 = copy (((((*_6).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); -+ _9 = copy _13 as *mut A (Transmute); -+ StorageDead(_13); ++ StorageLive(_11); ++ _11 = copy (((((*_6).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); ++ _9 = copy _11 as *mut A (Transmute); ++ StorageDead(_11); + _10 = copy ((*_6).1: usize); + _8 = *mut [A] from (copy _9, copy _10); + StorageDead(_9); ++ StorageLive(_12); ++ StorageLive(_13); + StorageLive(_14); -+ StorageLive(_15); -+ StorageLive(_16); -+ _14 = const 0_usize; ++ _12 = const 0_usize; + goto -> bb4; } @@ -85,33 +83,33 @@ StorageLive(_5); _5 = copy _2; - _0 = drop_in_place::>(move _5) -> [return: bb2, unwind unreachable]; -+ StorageLive(_17); -+ _17 = discriminant((*_5)); -+ switchInt(move _17) -> [0: bb5, otherwise: bb6]; ++ StorageLive(_15); ++ _15 = discriminant((*_5)); ++ switchInt(move _15) -> [0: bb5, otherwise: bb6]; } bb2: { -+ StorageDead(_16); -+ StorageDead(_15); + StorageDead(_14); ++ StorageDead(_13); ++ StorageDead(_12); + StorageDead(_8); + StorageDead(_10); + drop(((*_4).0: alloc::raw_vec::RawVec)) -> [return: bb1, unwind unreachable]; + } + + bb3: { -+ _15 = &raw mut (*_8)[_14]; -+ _14 = Add(move _14, const 1_usize); -+ drop((*_15)) -> [return: bb4, unwind unreachable]; ++ _13 = &raw mut (*_8)[_12]; ++ _12 = Add(move _12, const 1_usize); ++ drop((*_13)) -> [return: bb4, unwind unreachable]; + } + + bb4: { -+ _16 = Eq(copy _14, copy _10); -+ switchInt(move _16) -> [0: bb3, otherwise: bb2]; ++ _14 = Eq(copy _12, copy _10); ++ switchInt(move _14) -> [0: bb3, otherwise: bb2]; + } + + bb5: { -+ StorageDead(_17); ++ StorageDead(_15); StorageDead(_5); 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 96e2a2fc19251..46ab65f8bab43 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 @@ -71,21 +71,17 @@ fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:7:25: 7:39}, _2 // DBG: _16 = &((*_3).3: usize) StorageLive(_6); // DBG: _17 = &_13 - // DBG: _18 = &_15 + // DBG: _18 = &? _4 = copy ((*_3).0: usize); _5 = copy ((*_3).2: usize); _6 = Le(copy _4, copy _5); - switchInt(move _6) -> [0: bb1, otherwise: bb2]; + switchInt(move _6) -> [0: bb2, otherwise: bb1]; } bb1: { - goto -> bb4; - } - - bb2: { StorageLive(_9); // DBG: _19 = &_16 - // DBG: _20 = &_14 + // DBG: _20 = &? StorageLive(_7); _7 = copy ((*_3).3: usize); StorageLive(_8); @@ -93,29 +89,25 @@ fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:7:25: 7:39}, _2 _9 = Le(move _7, move _8); StorageDead(_8); StorageDead(_7); - switchInt(move _9) -> [0: bb3, otherwise: bb8]; - } - - bb3: { - goto -> bb4; + switchInt(move _9) -> [0: bb2, otherwise: bb6]; } - bb4: { + bb2: { StorageLive(_10); // DBG: _21 = &_15 - // DBG: _22 = &_13 + // DBG: _22 = &? _10 = Le(copy _5, copy _4); - switchInt(move _10) -> [0: bb5, otherwise: bb6]; + switchInt(move _10) -> [0: bb3, otherwise: bb4]; } - bb5: { + bb3: { _0 = const false; - goto -> bb7; + goto -> bb5; } - bb6: { + bb4: { // DBG: _23 = &_14 - // DBG: _24 = &_16 + // DBG: _24 = &? StorageLive(_11); _11 = copy ((*_3).1: usize); StorageLive(_12); @@ -123,20 +115,20 @@ fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:7:25: 7:39}, _2 _0 = Le(move _11, move _12); StorageDead(_12); StorageDead(_11); - goto -> bb7; + goto -> bb5; } - bb7: { + bb5: { StorageDead(_10); - goto -> bb9; + goto -> bb7; } - bb8: { + bb6: { _0 = const true; - goto -> bb9; + goto -> bb7; } - bb9: { + bb7: { StorageDead(_9); StorageDead(_6); return; diff --git a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir index d3b346173a896..2eee8a97db0d4 100644 --- a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir @@ -11,9 +11,7 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { let mut _4: usize; scope 3 (inlined Vec::::as_ptr) { debug self => _1; - let mut _6: &alloc::raw_vec::RawVec; scope 4 (inlined alloc::raw_vec::RawVec::::ptr) { - let mut _7: &alloc::raw_vec::RawVecInner; scope 5 (inlined alloc::raw_vec::RawVecInner::ptr::) { scope 6 (inlined alloc::raw_vec::RawVecInner::non_null::) { let mut _2: std::ptr::NonNull; @@ -57,8 +55,6 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { bb0: { StorageLive(_2); StorageLive(_3); - // DBG: _6 = &((*_1).0: alloc::raw_vec::RawVec) - // DBG: _7 = &(((*_1).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner) _2 = copy (((((*_1).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); _3 = copy _2 as *const u8 (Transmute); StorageLive(_4); diff --git a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir index d3b346173a896..2eee8a97db0d4 100644 --- a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir @@ -11,9 +11,7 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { let mut _4: usize; scope 3 (inlined Vec::::as_ptr) { debug self => _1; - let mut _6: &alloc::raw_vec::RawVec; scope 4 (inlined alloc::raw_vec::RawVec::::ptr) { - let mut _7: &alloc::raw_vec::RawVecInner; scope 5 (inlined alloc::raw_vec::RawVecInner::ptr::) { scope 6 (inlined alloc::raw_vec::RawVecInner::non_null::) { let mut _2: std::ptr::NonNull; @@ -57,8 +55,6 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { bb0: { StorageLive(_2); StorageLive(_3); - // DBG: _6 = &((*_1).0: alloc::raw_vec::RawVec) - // DBG: _7 = &(((*_1).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner) _2 = copy (((((*_1).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); _3 = copy _2 as *const u8 (Transmute); StorageLive(_4); From dabec6602ad5269f3c17f6c797e31bcb6615430a Mon Sep 17 00:00:00 2001 From: dianqk Date: Sun, 20 Jul 2025 11:11:49 +0800 Subject: [PATCH 8/8] mir-opt: Postpone the `MatchBranchSimplification` to after the final DSE This may not be the best phase, but we do need a CFG simplification. A potential improvement would be to implement a trivial simplification. --- compiler/rustc_mir_transform/src/lib.rs | 2 +- ...git.PreCodegen.after.32bit.panic-abort.mir | 2 +- ...it.PreCodegen.after.32bit.panic-unwind.mir | 2 +- ...git.PreCodegen.after.64bit.panic-abort.mir | 2 +- ...it.PreCodegen.after.64bit.panic-unwind.mir | 2 +- ...e_75439.foo.MatchBranchSimplification.diff | 22 ++++++----- ...as_copy.clone_as_copy.PreCodegen.after.mir | 19 ---------- ...py.enum_clone_as_copy.PreCodegen.after.mir | 32 ---------------- tests/mir-opt/pre-codegen/clone_as_copy.rs | 37 ++++++++++--------- ...s_copy.{impl#0}-clone.PreCodegen.after.mir | 11 ++++++ ...s_copy.{impl#1}-clone.PreCodegen.after.mir | 16 ++++++++ ...s_copy.{impl#2}-clone.PreCodegen.after.mir | 29 +++++++++++++++ ....foo.SimplifyLocals-final.panic-abort.diff | 6 +++ ...foo.SimplifyLocals-final.panic-unwind.diff | 6 +++ ...o_self.test.MatchBranchSimplification.diff | 13 ++++++- 15 files changed, 116 insertions(+), 85 deletions(-) delete mode 100644 tests/mir-opt/pre-codegen/clone_as_copy.clone_as_copy.PreCodegen.after.mir delete mode 100644 tests/mir-opt/pre-codegen/clone_as_copy.enum_clone_as_copy.PreCodegen.after.mir create mode 100644 tests/mir-opt/pre-codegen/clone_as_copy.{impl#0}-clone.PreCodegen.after.mir create mode 100644 tests/mir-opt/pre-codegen/clone_as_copy.{impl#1}-clone.PreCodegen.after.mir create mode 100644 tests/mir-opt/pre-codegen/clone_as_copy.{impl#2}-clone.PreCodegen.after.mir diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 08f25276cecc1..bbee8dcd736e5 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -703,7 +703,6 @@ pub(crate) fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<' &dead_store_elimination::DeadStoreElimination::Initial, &gvn::GVN, &simplify::SimplifyLocals::AfterGVN, - &match_branches::MatchBranchSimplification, &dataflow_const_prop::DataflowConstProp, &single_use_consts::SingleUseConsts, &o1(simplify_branches::SimplifyConstCondition::AfterConstProp), @@ -718,6 +717,7 @@ pub(crate) fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<' &strip_debuginfo::StripDebugInfo, ©_prop::CopyProp, &dead_store_elimination::DeadStoreElimination::Final, + &match_branches::MatchBranchSimplification, &nrvo::RenameReturnPlace, &simplify::SimplifyLocals::Final, &multiple_return_terminators::MultipleReturnTerminators, diff --git a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-abort.mir b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-abort.mir index 5876c55c52b94..ee92157e830a0 100644 --- a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-abort.mir +++ b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-abort.mir @@ -18,12 +18,12 @@ fn num_to_digit(_1: char) -> u32 { } bb0: { + StorageLive(_3); StorageLive(_2); _2 = char::methods::::to_digit(copy _1, const 8_u32) -> [return: bb1, unwind unreachable]; } bb1: { - StorageLive(_3); _3 = discriminant(_2); StorageDead(_2); switchInt(move _3) -> [1: bb2, otherwise: bb7]; diff --git a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-unwind.mir b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-unwind.mir index f1185353a43c8..1990deebb0769 100644 --- a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-unwind.mir +++ b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-unwind.mir @@ -18,12 +18,12 @@ fn num_to_digit(_1: char) -> u32 { } bb0: { + StorageLive(_3); StorageLive(_2); _2 = char::methods::::to_digit(copy _1, const 8_u32) -> [return: bb1, unwind continue]; } bb1: { - StorageLive(_3); _3 = discriminant(_2); StorageDead(_2); switchInt(move _3) -> [1: bb2, otherwise: bb7]; diff --git a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-abort.mir b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-abort.mir index 5876c55c52b94..ee92157e830a0 100644 --- a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-abort.mir +++ b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-abort.mir @@ -18,12 +18,12 @@ fn num_to_digit(_1: char) -> u32 { } bb0: { + StorageLive(_3); StorageLive(_2); _2 = char::methods::::to_digit(copy _1, const 8_u32) -> [return: bb1, unwind unreachable]; } bb1: { - StorageLive(_3); _3 = discriminant(_2); StorageDead(_2); switchInt(move _3) -> [1: bb2, otherwise: bb7]; diff --git a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-unwind.mir b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-unwind.mir index f1185353a43c8..1990deebb0769 100644 --- a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-unwind.mir +++ b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-unwind.mir @@ -18,12 +18,12 @@ fn num_to_digit(_1: char) -> u32 { } bb0: { + StorageLive(_3); StorageLive(_2); _2 = char::methods::::to_digit(copy _1, const 8_u32) -> [return: bb1, unwind continue]; } bb1: { - StorageLive(_3); _3 = discriminant(_2); StorageDead(_2); switchInt(move _3) -> [1: bb2, otherwise: bb7]; diff --git a/tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff b/tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff index d8eace98d556e..66e54612c819a 100644 --- a/tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff +++ b/tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff @@ -6,6 +6,7 @@ let mut _0: std::option::Option<[u8; 4]>; let _2: [u32; 4]; let mut _4: [u8; 4]; + let mut _5: bool; scope 1 { debug dwords => _2; scope 2 { @@ -17,34 +18,35 @@ bb0: { StorageLive(_2); _2 = copy _1 as [u32; 4] (Transmute); - switchInt(copy _2[0 of 4]) -> [0: bb1, otherwise: bb4]; + _5 = Ne(copy _2[0 of 4], copy _2[1 of 4]); + switchInt(move _5) -> [0: bb5, otherwise: bb3]; } bb1: { - switchInt(copy _2[1 of 4]) -> [0: bb2, otherwise: bb4]; + switchInt(copy _2[2 of 4]) -> [0: bb2, 4294901760: bb2, otherwise: bb3]; } bb2: { - switchInt(copy _2[2 of 4]) -> [0: bb3, 4294901760: bb3, otherwise: bb4]; - } - - bb3: { _3 = copy _2[3 of 4]; StorageLive(_4); _4 = copy _3 as [u8; 4] (Transmute); _0 = Option::<[u8; 4]>::Some(move _4); StorageDead(_4); - goto -> bb5; + goto -> bb4; } - bb4: { + bb3: { _0 = Option::<[u8; 4]>::None; - goto -> bb5; + goto -> bb4; } - bb5: { + bb4: { StorageDead(_2); return; } + + bb5: { + switchInt(copy _2[0 of 4]) -> [0: bb1, otherwise: bb3]; + } } diff --git a/tests/mir-opt/pre-codegen/clone_as_copy.clone_as_copy.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/clone_as_copy.clone_as_copy.PreCodegen.after.mir deleted file mode 100644 index dcdc99312d9aa..0000000000000 --- a/tests/mir-opt/pre-codegen/clone_as_copy.clone_as_copy.PreCodegen.after.mir +++ /dev/null @@ -1,19 +0,0 @@ -// MIR for `clone_as_copy` after PreCodegen - -fn clone_as_copy(_1: &NestCopy) -> NestCopy { - debug v => _1; - let mut _0: NestCopy; - scope 1 (inlined ::clone) { - debug self => _1; - let _2: &AllCopy; - scope 2 (inlined ::clone) { - debug self => _2; - } - } - - bb0: { - // DBG: _2 = &((*_1).1: AllCopy) - _0 = copy (*_1); - return; - } -} diff --git a/tests/mir-opt/pre-codegen/clone_as_copy.enum_clone_as_copy.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/clone_as_copy.enum_clone_as_copy.PreCodegen.after.mir deleted file mode 100644 index 8ad0ad95d5758..0000000000000 --- a/tests/mir-opt/pre-codegen/clone_as_copy.enum_clone_as_copy.PreCodegen.after.mir +++ /dev/null @@ -1,32 +0,0 @@ -// MIR for `enum_clone_as_copy` after PreCodegen - -fn enum_clone_as_copy(_1: &Enum1) -> Enum1 { - debug v => _1; - let mut _0: Enum1; - scope 1 (inlined ::clone) { - debug self => _1; - let mut _2: &AllCopy; - let mut _3: &NestCopy; - scope 2 { - debug __self_0 => _2; - scope 6 (inlined ::clone) { - debug self => _2; - } - } - scope 3 { - debug __self_0 => _3; - scope 4 (inlined ::clone) { - debug self => _3; - let _4: &AllCopy; - scope 5 (inlined ::clone) { - debug self => _4; - } - } - } - } - - bb0: { - _0 = copy (*_1); - return; - } -} diff --git a/tests/mir-opt/pre-codegen/clone_as_copy.rs b/tests/mir-opt/pre-codegen/clone_as_copy.rs index 00f24754d5913..67799a2cbcc08 100644 --- a/tests/mir-opt/pre-codegen/clone_as_copy.rs +++ b/tests/mir-opt/pre-codegen/clone_as_copy.rs @@ -22,22 +22,23 @@ enum Enum1 { B(NestCopy), } -// EMIT_MIR clone_as_copy.clone_as_copy.PreCodegen.after.mir -fn clone_as_copy(v: &NestCopy) -> NestCopy { - // CHECK-LABEL: fn clone_as_copy( - // CHECK: let [[DEAD_VAR:_.*]]: &AllCopy; - // CHECK: bb0: { - // CHECK-NEXT: DBG: [[DEAD_VAR]] = &((*_1).1: AllCopy) - // CHECK-NEXT: _0 = copy (*_1); - // CHECK-NEXT: return; - v.clone() -} +// EMIT_MIR clone_as_copy.{impl#0}-clone.PreCodegen.after.mir +// CHECK-LABEL: fn ::clone(_1: &AllCopy) -> AllCopy { +// CHECK: bb0: { +// CHECK-NEXT: _0 = copy (*_1); +// CHECK-NEXT: return; -// EMIT_MIR clone_as_copy.enum_clone_as_copy.PreCodegen.after.mir -fn enum_clone_as_copy(v: &Enum1) -> Enum1 { - // CHECK-LABEL: fn enum_clone_as_copy( - // CHECK: bb0: { - // CHECK-NEXT: _0 = copy (*_1); - // CHECK-NEXT: return; - v.clone() -} +// EMIT_MIR clone_as_copy.{impl#1}-clone.PreCodegen.after.mir +// CHECK-LABEL: fn ::clone(_1: &NestCopy) -> NestCopy { +// CHECK: scope 1 (inlined ::clone) { +// CHECK-NEXT: debug self => [[inlined_AllCopy_self:_[0-9]+]]; +// CHECK: bb0: { +// CHECK-NEXT: DBG: [[inlined_AllCopy_self]] = &((*_1).1: AllCopy) +// CHECK-NEXT: _0 = copy (*_1); +// CHECK-NEXT: return; + +// EMIT_MIR clone_as_copy.{impl#2}-clone.PreCodegen.after.mir +// CHECK-LABEL: fn ::clone(_1: &Enum1) -> Enum1 { +// CHECK: bb0: { +// CHECK-NEXT: _0 = copy (*_1); +// CHECK-NEXT: return; diff --git a/tests/mir-opt/pre-codegen/clone_as_copy.{impl#0}-clone.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/clone_as_copy.{impl#0}-clone.PreCodegen.after.mir new file mode 100644 index 0000000000000..37e6042125f13 --- /dev/null +++ b/tests/mir-opt/pre-codegen/clone_as_copy.{impl#0}-clone.PreCodegen.after.mir @@ -0,0 +1,11 @@ +// MIR for `::clone` after PreCodegen + +fn ::clone(_1: &AllCopy) -> AllCopy { + debug self => _1; + let mut _0: AllCopy; + + bb0: { + _0 = copy (*_1); + return; + } +} diff --git a/tests/mir-opt/pre-codegen/clone_as_copy.{impl#1}-clone.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/clone_as_copy.{impl#1}-clone.PreCodegen.after.mir new file mode 100644 index 0000000000000..ff88c8388fb15 --- /dev/null +++ b/tests/mir-opt/pre-codegen/clone_as_copy.{impl#1}-clone.PreCodegen.after.mir @@ -0,0 +1,16 @@ +// MIR for `::clone` after PreCodegen + +fn ::clone(_1: &NestCopy) -> NestCopy { + debug self => _1; + let mut _0: NestCopy; + let _2: &AllCopy; + scope 1 (inlined ::clone) { + debug self => _2; + } + + bb0: { + // DBG: _2 = &((*_1).1: AllCopy) + _0 = copy (*_1); + return; + } +} diff --git a/tests/mir-opt/pre-codegen/clone_as_copy.{impl#2}-clone.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/clone_as_copy.{impl#2}-clone.PreCodegen.after.mir new file mode 100644 index 0000000000000..453084fa4eb8a --- /dev/null +++ b/tests/mir-opt/pre-codegen/clone_as_copy.{impl#2}-clone.PreCodegen.after.mir @@ -0,0 +1,29 @@ +// MIR for `::clone` after PreCodegen + +fn ::clone(_1: &Enum1) -> Enum1 { + debug self => _1; + let mut _0: Enum1; + let mut _2: &AllCopy; + let mut _3: &NestCopy; + scope 1 { + debug __self_0 => _2; + scope 5 (inlined ::clone) { + debug self => _2; + } + } + scope 2 { + debug __self_0 => _3; + scope 3 (inlined ::clone) { + debug self => _3; + let _4: &AllCopy; + scope 4 (inlined ::clone) { + debug self => _4; + } + } + } + + bb0: { + _0 = copy (*_1); + return; + } +} diff --git a/tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.panic-abort.diff b/tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.panic-abort.diff index ff1bc58524bc2..f79991792af26 100644 --- a/tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.panic-abort.diff +++ b/tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.panic-abort.diff @@ -36,6 +36,12 @@ bb2: { _6 = copy (((_1.0: std::option::Option) as Some).0: u8); +- StorageLive(_7); +- _7 = Gt(copy _6, const 42_u8); +- StorageLive(_9); +- _9 = move _7; +- StorageDead(_9); +- StorageDead(_7); goto -> bb3; } diff --git a/tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.panic-unwind.diff b/tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.panic-unwind.diff index 2c289c664754a..03fdf8a4209e8 100644 --- a/tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.panic-unwind.diff +++ b/tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.panic-unwind.diff @@ -36,6 +36,12 @@ bb2: { _6 = copy (((_1.0: std::option::Option) as Some).0: u8); +- StorageLive(_7); +- _7 = Gt(copy _6, const 42_u8); +- StorageLive(_9); +- _9 = move _7; +- StorageDead(_9); +- StorageDead(_7); goto -> bb3; } diff --git a/tests/mir-opt/switch_to_self.test.MatchBranchSimplification.diff b/tests/mir-opt/switch_to_self.test.MatchBranchSimplification.diff index fef708d9962e5..a07259b6bfe3c 100644 --- a/tests/mir-opt/switch_to_self.test.MatchBranchSimplification.diff +++ b/tests/mir-opt/switch_to_self.test.MatchBranchSimplification.diff @@ -3,16 +3,27 @@ fn test(_1: bool) -> () { let mut _0: (); + let mut _2: bool; ++ let mut _3: bool; bb0: { goto -> bb1; } bb1: { + _2 = Ne(copy _1, copy _1); +- switchInt(move _2) -> [0: bb3, otherwise: bb2]; +- } +- +- bb2: { ++ StorageLive(_3); ++ _3 = move _2; ++ StorageDead(_3); switchInt(copy _1) -> [0: bb1, otherwise: bb2]; } - bb2: { +- bb3: { ++ bb2: { switchInt(copy _1) -> [0: bb1, otherwise: bb2]; } }