diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 7c69baba62e8b..a919cf9227880 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -1162,7 +1162,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_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 5c34ab2e3040d..f907500b4cc66 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 025f5fb54f428..2bac3fa402256 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/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index e819aa2d8f815..06134d0d0947b 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,34 @@ impl<'tcx> BasicBlockData<'tcx> { self.terminator().successors() } } + + pub fn retain_statements(&mut self, mut f: F) + where + F: FnMut(&Statement<'tcx>) -> bool, + { + let mut debuginfos = Vec::new(); + self.statements.retain_mut(|stmt| { + let retain = f(stmt); + if retain { + stmt.debuginfos.splice(0..0, mem::take(&mut debuginfos)); + } else { + debuginfos.extend_from_slice(&stmt.debuginfos); + } + retain + }); + self.after_last_stmt_debuginfos.extend_from_slice(&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(); + } + } } /////////////////////////////////////////////////////////////////////////// @@ -1707,10 +1744,10 @@ 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<'_>, 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/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 683d7b486171f..4a68ed6098024 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -15,17 +15,27 @@ use crate::ty::CoroutineArgsExt; pub struct Statement<'tcx> { pub source_info: SourceInfo, pub kind: StatementKind<'tcx>, + 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) { - 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 { + let Some(debuginfo) = replaced_stmt.as_debuginfo() else { + bug!("debuginfo is not yet supported.") + }; + self.debuginfos.push(debuginfo); + } } pub fn new(source_info: SourceInfo, kind: StatementKind<'tcx>) -> Self { - Statement { source_info, kind } + Statement { source_info, kind, debuginfos: Vec::new() } } } @@ -63,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, + } + } } /////////////////////////////////////////////////////////////////////////// @@ -939,3 +960,8 @@ impl RawPtrKind { } } } + +#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] +pub enum StmtDebugInfo<'tcx> { + AssignRef(Local, Place<'tcx>), +} 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_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 929ebe1aee181..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. @@ -95,6 +97,24 @@ 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 + ) { + if Self::VISIT_DEBUG_INFO { + 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 +321,7 @@ macro_rules! make_mir_visitor { { let BasicBlockData { statements, + after_last_stmt_debuginfos, terminator, is_cleanup: _ } = data; @@ -312,8 +333,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,14 +398,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 ) { - 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..e461f7b0155eb 100644 --- a/compiler/rustc_mir_dataflow/src/debuginfo.rs +++ b/compiler/rustc_mir_dataflow/src/debuginfo.rs @@ -5,16 +5,18 @@ 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); + 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 6ec1b03a34e68..2b2a8cbba458f 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,48 @@ 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() + // 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() && stmt_kind.as_debuginfo().is_some()))) + .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 +279,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..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 } @@ -138,7 +140,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 +152,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..63832c04058ca 100644 --- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs +++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs @@ -22,21 +22,21 @@ 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 // 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,47 +75,28 @@ 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))); } } } } 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 } 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 { @@ -125,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 { @@ -145,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/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 6b11706d2b55f..2d56c257b5eb7 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -1749,6 +1749,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 } @@ -1846,7 +1848,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/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 1c0fc7748675c..d5af8a9bcc2d0 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()); @@ -1226,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/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/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/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..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 } @@ -409,7 +413,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..64e0da42ad575 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -34,10 +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, 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}; @@ -141,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; @@ -156,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(); @@ -174,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); @@ -212,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(); @@ -231,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); @@ -308,7 +344,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.strip_nops(); } } } @@ -481,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 @@ -499,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. @@ -544,9 +591,10 @@ 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(..) => {} StatementKind::Assign(box (ref place, ref rvalue)) => { if rvalue.is_safe_to_remove() { @@ -565,7 +613,10 @@ impl<'tcx> Visitor<'tcx> for UsedLocals { } } - fn visit_local(&mut self, local: Local, _ctx: PlaceContext, _location: 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 { @@ -588,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.statements.retain(|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(); } } } @@ -620,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 } @@ -628,3 +679,44 @@ 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 { + const VISIT_DEBUG_INFO: bool = true; + + fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) { + if matches!(context, PlaceContext::NonUse(_)) { + return; + } + self.locals.insert(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/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index cbb9bbfd12f9f..fbb595dd36baa 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -280,6 +280,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( @@ -627,6 +628,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 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)); +} 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 new file mode 100644 index 0000000000000..2babbc5f16577 --- /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-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 new file mode 100644 index 0000000000000..02519c72b9b13 --- /dev/null +++ b/tests/mir-opt/dead-store-elimination/ref.tuple.DeadStoreElimination-initial.diff @@ -0,0 +1,25 @@ +- // 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) + _4 = deref_copy (_1.1: &Foo); + _0 = copy ((*_4).0: i32); +- 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 new file mode 100644 index 0000000000000..dcd4e5853f196 --- /dev/null +++ b/tests/mir-opt/debuginfo/simplifycfg.drop_debuginfo.SimplifyCfg-final.diff @@ -0,0 +1,26 @@ +- // 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) +- goto -> bb2; +- } +- +- bb2: { + // DBG: _4 = &((*_1).1: i64) + _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..6a98a9d90673f --- /dev/null +++ b/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_1.SimplifyCfg-final.diff @@ -0,0 +1,30 @@ +- // 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) +- goto -> bb2; +- } +- +- bb2: { + // DBG: _4 = &((*_1).1: i64) + _0 = copy ((*_1).2: i32); + // DBG: _5 = &((*_1).2: i32) + 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..33ca4b8988fc7 --- /dev/null +++ b/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_2.SimplifyCfg-final.diff @@ -0,0 +1,29 @@ +- // 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) +- goto -> bb2; +- } +- +- bb2: { + // DBG: _3 = &((*_1).1: i64) + _0 = copy ((*_1).2: i32); + // DBG: _4 = &((*_1).2: i32) + 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() + } + } +} 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..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 @@ -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: { @@ -61,17 +63,17 @@ + StorageLive(_10); + 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); -+ StorageDead(_11); ++ 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); + _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 +85,33 @@ 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); ++ _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(_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 1e9a6dd4f5c8f..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 @@ -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 { + } + } @@ -131,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); @@ -170,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); @@ -228,29 +221,18 @@ + _22 = &mut (*_23); + StorageDead(_24); + StorageLive(_45); -+ StorageLive(_46); -+ StorageLive(_51); ++ StorageLive(_50); + StorageLive(_42); + StorageLive(_43); -+ StorageLive(_44); -+ _46 = &mut _19; -+ StorageLive(_47); -+ StorageLive(_48); -+ _48 = &mut (_19.0: &mut std::future::Ready<()>); + _45 = copy (_19.0: &mut std::future::Ready<()>); ++ StorageLive(_48); ++ _48 = Option::<()>::None; ++ _43 = copy ((*_45).0: std::option::Option<()>); ++ ((*_45).0: std::option::Option<()>) = copy _48; + 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; -+ _43 = copy ((*_45).0: std::option::Option<()>); -+ ((*_45).0: std::option::Option<()>) = copy _49; -+ StorageDead(_49); -+ StorageDead(_44); -+ StorageLive(_50); -+ _50 = discriminant(_43); -+ switchInt(move _50) -> [0: bb11, 1: bb12, otherwise: bb5]; ++ _49 = discriminant(_43); ++ switchInt(move _49) -> [0: bb11, 1: bb12, otherwise: bb5]; + } + + bb5: { @@ -313,17 +295,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(_46); ++ StorageDead(_50); + 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 94b89a310baa8..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 @@ -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 { + } + } @@ -133,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); @@ -184,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); @@ -245,29 +238,18 @@ + _22 = &mut (*_23); + StorageDead(_24); + StorageLive(_47); -+ StorageLive(_48); -+ StorageLive(_53); ++ StorageLive(_52); + StorageLive(_44); + StorageLive(_45); -+ StorageLive(_46); -+ _48 = &mut _19; -+ StorageLive(_49); -+ StorageLive(_50); -+ _50 = &mut (_19.0: &mut std::future::Ready<()>); + _47 = copy (_19.0: &mut std::future::Ready<()>); ++ StorageLive(_50); ++ _50 = Option::<()>::None; ++ _45 = copy ((*_47).0: std::option::Option<()>); ++ ((*_47).0: std::option::Option<()>) = copy _50; + 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; -+ _45 = copy ((*_47).0: std::option::Option<()>); -+ ((*_47).0: std::option::Option<()>) = copy _51; -+ StorageDead(_51); -+ StorageDead(_46); -+ StorageLive(_52); -+ _52 = discriminant(_45); -+ switchInt(move _52) -> [0: bb16, 1: bb17, otherwise: bb7]; ++ _51 = discriminant(_45); ++ switchInt(move _51) -> [0: bb16, 1: bb17, otherwise: bb7]; } - bb6 (cleanup): { @@ -354,17 +336,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(_48); ++ StorageDead(_52); + 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 c02bab3524bca..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); - _7 = &(*_2)[0 of 3]; - StorageLive(_8); - _8 = &(*_2)[1 of 3]; - StorageLive(_9); - _9 = &(*_2)[2 of 3]; - StorageDead(_9); - StorageDead(_8); - StorageDead(_7); + // DBG: _7 = &(*_2)[0 of 3] + // DBG: _8 = &(*_2)[1 of 3] + // DBG: _9 = &(*_2)[2 of 3] 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 49be042588cb3..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); - _7 = &(*_2)[0 of 3]; - StorageLive(_8); - _8 = &(*_2)[1 of 3]; - StorageLive(_9); - _9 = &(*_2)[2 of 3]; - StorageDead(_9); - StorageDead(_8); - StorageDead(_7); + // DBG: _7 = &(*_2)[0 of 3] + // DBG: _8 = &(*_2)[1 of 3] + // DBG: _9 = &(*_2)[2 of 3] StorageDead(_4); return; } 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..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); - _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..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: { - _3 = &(((*_1) as A).0: AllCopy); _0 = copy (*_1); - goto -> bb3; - } - - bb2: { - _4 = &(((*_1) as B).0: NestCopy); - StorageLive(_5); - _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.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..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 @@ -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,42 @@ 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]; + // DBG: _14 = &(_4.0: usize) + // 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(_7); - StorageDead(_6); StorageDead(_10); - StorageDead(_13); StorageDead(_4); return; } bb3: { + _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..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 @@ -3,183 +3,142 @@ 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); + // DBG: _17 = &_13 + // 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); goto -> bb4; } bb2: { - StorageDead(_9); - StorageDead(_10); + StorageLive(_9); + // DBG: _19 = &_16 + // 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); - 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]; + StorageDead(_7); + switchInt(move _9) -> [0: bb3, otherwise: bb8]; } bb3: { - StorageDead(_15); - StorageDead(_16); - StorageDead(_14); goto -> bb4; } bb4: { - StorageLive(_23); - StorageLive(_20); - _20 = &_6; - StorageLive(_22); - StorageLive(_21); - _21 = copy _4; - _22 = &_21; - _23 = Le(copy _12, copy _11); - switchInt(move _23) -> [0: bb5, otherwise: bb6]; + StorageLive(_10); + // DBG: _21 = &_15 + // DBG: _22 = &_13 + _10 = Le(copy _5, copy _4); + switchInt(move _10) -> [0: bb5, otherwise: bb6]; } bb5: { - StorageDead(_21); - StorageDead(_22); - StorageDead(_20); _0 = const false; goto -> bb7; } bb6: { - StorageDead(_21); - StorageDead(_22); - StorageDead(_20); - StorageLive(_24); - _24 = &_5; - StorageLive(_26); - StorageLive(_25); - _25 = copy _7; - _26 = &_25; - StorageLive(_27); - _27 = copy ((*_3).1: usize); - StorageLive(_28); - _28 = copy ((*_3).3: usize); - _0 = Le(move _27, move _28); - StorageDead(_28); - StorageDead(_27); - StorageDead(_25); - StorageDead(_26); - StorageDead(_24); + // DBG: _23 = &_14 + // 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); goto -> bb7; } bb7: { - StorageDead(_23); + StorageDead(_10); goto -> bb9; } bb8: { - StorageDead(_15); - StorageDead(_16); - StorageDead(_14); _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..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 @@ -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,6 +57,8 @@ 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 2eee8a97db0d4..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 @@ -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,6 +57,8 @@ 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/ui/extern/extern-types-field-offset.rs b/tests/ui/extern/extern-types-field-offset.rs index 75f3eab3e275f..fab853c09cc04 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); }