diff options
Diffstat (limited to 'compiler/rustc_codegen_ssa/src/mir/debuginfo.rs')
-rw-r--r-- | compiler/rustc_codegen_ssa/src/mir/debuginfo.rs | 153 |
1 files changed, 103 insertions, 50 deletions
diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index d049bafb8..bba2800fb 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -1,5 +1,5 @@ use crate::traits::*; -use rustc_index::vec::IndexVec; +use rustc_index::IndexVec; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir; use rustc_middle::ty; @@ -8,7 +8,7 @@ use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; use rustc_session::config::DebugInfo; use rustc_span::symbol::{kw, Symbol}; use rustc_span::{BytePos, Span}; -use rustc_target::abi::{Abi, FieldIdx, Size, VariantIdx}; +use rustc_target::abi::{Abi, FieldIdx, FieldsShape, Size, VariantIdx}; use super::operand::{OperandRef, OperandValue}; use super::place::PlaceRef; @@ -41,6 +41,9 @@ pub struct PerLocalVarDebugInfo<'tcx, D> { /// `.place.projection` from `mir::VarDebugInfo`. pub projection: &'tcx ty::List<mir::PlaceElem<'tcx>>, + + /// `references` from `mir::VarDebugInfo`. + pub references: u8, } #[derive(Clone, Copy, Debug)] @@ -80,6 +83,7 @@ trait DebugInfoOffsetLocation<'tcx, Bx> { fn deref(&self, bx: &mut Bx) -> Self; fn layout(&self) -> TyAndLayout<'tcx>; fn project_field(&self, bx: &mut Bx, field: FieldIdx) -> Self; + fn project_constant_index(&self, bx: &mut Bx, offset: u64) -> Self; fn downcast(&self, bx: &mut Bx, variant: VariantIdx) -> Self; } @@ -98,6 +102,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> DebugInfoOffsetLocation<'tcx, Bx> PlaceRef::project_field(*self, bx, field.index()) } + fn project_constant_index(&self, bx: &mut Bx, offset: u64) -> Self { + let lloffset = bx.cx().const_usize(offset); + self.project_index(bx, lloffset) + } + fn downcast(&self, bx: &mut Bx, variant: VariantIdx) -> Self { self.project_downcast(bx, variant) } @@ -120,6 +129,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> DebugInfoOffsetLocation<'tcx, Bx> self.field(bx.cx(), field.index()) } + fn project_constant_index(&self, bx: &mut Bx, index: u64) -> Self { + self.field(bx.cx(), index as usize) + } + fn downcast(&self, bx: &mut Bx, variant: VariantIdx) -> Self { self.for_variant(bx.cx(), variant) } @@ -165,6 +178,18 @@ fn calculate_debuginfo_offset< mir::ProjectionElem::Downcast(_, variant) => { place = place.downcast(bx, variant); } + mir::ProjectionElem::ConstantIndex { + offset: index, + min_length: _, + from_end: false, + } => { + let offset = indirect_offsets.last_mut().unwrap_or(&mut direct_offset); + let FieldsShape::Array { stride, count: _ } = place.layout().fields else { + span_bug!(var.source_info.span, "ConstantIndex on non-array type {:?}", place.layout()) + }; + *offset += stride * index; + place = place.project_constant_index(bx, index); + } _ => { // Sanity check for `can_use_in_debuginfo`. debug_assert!(!elem.can_use_in_debuginfo()); @@ -293,6 +318,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { dbg_var, fragment: None, projection: ty::List::empty(), + references: 0, }) } } else { @@ -358,55 +384,74 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let vars = vars.iter().cloned().chain(fallback_var); for var in vars { - let Some(dbg_var) = var.dbg_var else { continue }; - let Some(dbg_loc) = self.dbg_loc(var.source_info) else { continue }; - - let DebugInfoOffset { direct_offset, indirect_offsets, result: _ } = - calculate_debuginfo_offset(bx, local, &var, base.layout); - - // When targeting MSVC, create extra allocas for arguments instead of pointing multiple - // dbg_var_addr() calls into the same alloca with offsets. MSVC uses CodeView records - // not DWARF and LLVM doesn't support translating the resulting - // [DW_OP_deref, DW_OP_plus_uconst, offset, DW_OP_deref] debug info to CodeView. - // Creating extra allocas on the stack makes the resulting debug info simple enough - // that LLVM can generate correct CodeView records and thus the values appear in the - // debugger. (#83709) - let should_create_individual_allocas = bx.cx().sess().target.is_like_msvc - && self.mir.local_kind(local) == mir::LocalKind::Arg - // LLVM can handle simple things but anything more complex than just a direct - // offset or one indirect offset of 0 is too complex for it to generate CV records - // correctly. - && (direct_offset != Size::ZERO - || !matches!(&indirect_offsets[..], [Size::ZERO] | [])); - - if should_create_individual_allocas { - let DebugInfoOffset { direct_offset: _, indirect_offsets: _, result: place } = - calculate_debuginfo_offset(bx, local, &var, base); - - // Create a variable which will be a pointer to the actual value - let ptr_ty = bx - .tcx() - .mk_ptr(ty::TypeAndMut { mutbl: mir::Mutability::Mut, ty: place.layout.ty }); - let ptr_layout = bx.layout_of(ptr_ty); - let alloca = PlaceRef::alloca(bx, ptr_layout); - bx.set_var_name(alloca.llval, &(var.name.to_string() + ".dbg.spill")); - - // Write the pointer to the variable - bx.store(place.llval, alloca.llval, alloca.align); - - // Point the debug info to `*alloca` for the current variable - bx.dbg_var_addr(dbg_var, dbg_loc, alloca.llval, Size::ZERO, &[Size::ZERO], None); - } else { - bx.dbg_var_addr( - dbg_var, - dbg_loc, - base.llval, - direct_offset, - &indirect_offsets, - None, - ); + self.debug_introduce_local_as_var(bx, local, base, var); + } + } + + fn debug_introduce_local_as_var( + &self, + bx: &mut Bx, + local: mir::Local, + mut base: PlaceRef<'tcx, Bx::Value>, + 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 { mut direct_offset, indirect_offsets, result: _ } = + calculate_debuginfo_offset(bx, local, &var, base.layout); + let mut indirect_offsets = &indirect_offsets[..]; + + // When targeting MSVC, create extra allocas for arguments instead of pointing multiple + // dbg_var_addr() calls into the same alloca with offsets. MSVC uses CodeView records + // not DWARF and LLVM doesn't support translating the resulting + // [DW_OP_deref, DW_OP_plus_uconst, offset, DW_OP_deref] debug info to CodeView. + // Creating extra allocas on the stack makes the resulting debug info simple enough + // that LLVM can generate correct CodeView records and thus the values appear in the + // debugger. (#83709) + let should_create_individual_allocas = bx.cx().sess().target.is_like_msvc + && self.mir.local_kind(local) == mir::LocalKind::Arg + // LLVM can handle simple things but anything more complex than just a direct + // offset or one indirect offset of 0 is too complex for it to generate CV records + // correctly. + && (direct_offset != Size::ZERO || !matches!(indirect_offsets, [Size::ZERO] | [])); + + let create_alloca = |bx: &mut Bx, place: PlaceRef<'tcx, Bx::Value>, refcount| { + // Create a variable which will be a pointer to the actual value + let ptr_ty = bx + .tcx() + .mk_ptr(ty::TypeAndMut { mutbl: mir::Mutability::Mut, ty: place.layout.ty }); + let ptr_layout = bx.layout_of(ptr_ty); + let alloca = PlaceRef::alloca(bx, ptr_layout); + bx.set_var_name(alloca.llval, &format!("{}.ref{}.dbg.spill", var.name, refcount)); + + // Write the pointer to the variable + bx.store(place.llval, alloca.llval, alloca.align); + + // Point the debug info to `*alloca` for the current variable + alloca + }; + + if var.references > 0 { + base = calculate_debuginfo_offset(bx, local, &var, base).result; + + // Point the debug info to `&...&base == alloca` for the current variable + for refcount in 0..var.references { + base = create_alloca(bx, base, refcount); } + + direct_offset = Size::ZERO; + indirect_offsets = &[]; + } else if should_create_individual_allocas { + let place = calculate_debuginfo_offset(bx, local, &var, base).result; + + // Point the debug info to `*alloca` for the current variable + base = create_alloca(bx, place, 0); + direct_offset = Size::ZERO; + indirect_offsets = &[Size::ZERO]; } + + bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, direct_offset, indirect_offsets, None); } pub fn debug_introduce_locals(&self, bx: &mut Bx) { @@ -439,7 +484,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }; let dbg_var = dbg_scope_and_span.map(|(dbg_scope, _, span)| { - let (var_ty, var_kind) = match var.value { + let (mut var_ty, var_kind) = match var.value { mir::VarDebugInfoContents::Place(place) => { let var_ty = self.monomorphized_place_ty(place.as_ref()); let var_kind = if let Some(arg_index) = var.argument_index @@ -476,6 +521,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } }; + for _ in 0..var.references { + var_ty = + bx.tcx().mk_ptr(ty::TypeAndMut { mutbl: mir::Mutability::Mut, ty: var_ty }); + } + self.cx.create_dbg_var(var.name, var_ty, dbg_scope, var_kind, span) }); @@ -487,6 +537,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { dbg_var, fragment: None, projection: place.projection, + references: var.references, }); } mir::VarDebugInfoContents::Const(c) => { @@ -494,6 +545,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let Some(dbg_loc) = self.dbg_loc(var.source_info) else { continue }; if let Ok(operand) = self.eval_mir_constant_to_operand(bx, &c) { + self.set_debug_loc(bx, var.source_info); let base = Self::spill_operand_to_stack( &operand, Some(var.name.to_string()), @@ -539,6 +591,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { Some(fragment_start..fragment_start + fragment_layout.size) }, projection: place.projection, + references: var.references, }); } } |