summaryrefslogtreecommitdiff
path: root/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_codegen_ssa/src/mir/debuginfo.rs')
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/debuginfo.rs150
1 files changed, 101 insertions, 49 deletions
diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
index 4e5e2dd5d50..bba2800fb05 100644
--- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
@@ -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) => {
@@ -540,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,
});
}
}