Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit bda8139

Browse files
committed
Auto merge of rust-lang#119471 - cjgillot:mir-composite-deref, r=<try>
[perf only] Reimplement references debuginfo as projection. This PR is not meant to be merged: it completely breaks debuginfo, as LLVM does not support implicit pointers in debuginfo yet.
2 parents fcfe05a + 4679331 commit bda8139

File tree

35 files changed

+2106
-1056
lines changed

35 files changed

+2106
-1056
lines changed

‎compiler/rustc_codegen_ssa/src/mir/debuginfo.rs

Lines changed: 93 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@ use super::operand::{OperandRef, OperandValue};
1717
use super::place::PlaceRef;
1818
use super::{FunctionCx, LocalRef};
1919

20-
use std::ops::Range;
21-
2220
pub struct FunctionDebugContext<'tcx, S, L> {
2321
/// Maps from source code to the corresponding debug info scope.
2422
pub scopes: IndexVec<mir::SourceScope, DebugScope<S, L>>,
@@ -36,17 +34,17 @@ pub enum VariableKind {
3634
#[derive(Clone)]
3735
pub struct PerLocalVarDebugInfo<'tcx, D> {
3836
pub name: Symbol,
37+
pub ty: Ty<'tcx>,
3938
pub source_info: mir::SourceInfo,
4039

4140
/// `DIVariable` returned by `create_dbg_var`.
4241
pub dbg_var: Option<D>,
4342

44-
/// Byte range in the `dbg_var` covered by this fragment,
45-
/// if this is a fragment of a composite `VarDebugInfo`.
46-
pub fragment: Option<Range<Size>>,
47-
4843
/// `.place.projection` from `mir::VarDebugInfo`.
49-
pub projection: &'tcx ty::List<mir::PlaceElem<'tcx>>,
44+
pub projection: &'tcx [mir::PlaceElem<'tcx>],
45+
46+
/// Projection from fragment debuginfo.
47+
pub fragment: &'tcx [mir::PlaceElem<'tcx>],
5048
}
5149

5250
#[derive(Clone, Copy, Debug)]
@@ -149,6 +147,8 @@ struct DebugInfoOffset<T> {
149147
indirect_offsets: Vec<Size>,
150148
/// The final location debuginfo should point to.
151149
result: T,
150+
/// Whether the final location is a fragment of a larger contiguous projection.
151+
fragment: bool,
152152
}
153153

154154
fn calculate_debuginfo_offset<
@@ -165,17 +165,21 @@ fn calculate_debuginfo_offset<
165165
// FIXME(eddyb) use smallvec here.
166166
let mut indirect_offsets = vec![];
167167
let mut place = base;
168+
let mut fragment = false;
168169

169170
for elem in projection {
171+
let layout = place.layout();
170172
match *elem {
171173
mir::ProjectionElem::Deref => {
172174
indirect_offsets.push(Size::ZERO);
173175
place = place.deref(bx);
176+
fragment = false;
174177
}
175178
mir::ProjectionElem::Field(field, _) => {
176179
let offset = indirect_offsets.last_mut().unwrap_or(&mut direct_offset);
177180
*offset += place.layout().fields.offset(field.index());
178181
place = place.project_field(bx, field);
182+
fragment |= place.layout().size != layout.size;
179183
}
180184
mir::ProjectionElem::Downcast(_, variant) => {
181185
place = place.downcast(bx, variant);
@@ -191,16 +195,17 @@ fn calculate_debuginfo_offset<
191195
};
192196
*offset += stride * index;
193197
place = place.project_constant_index(bx, index);
198+
fragment |= place.layout().size != layout.size;
194199
}
195200
_ => {
196201
// Sanity check for `can_use_in_debuginfo`.
197202
debug_assert!(!elem.can_use_in_debuginfo());
198-
bug!("unsupported var debuginfo projection `{:?}`", projection)
203+
bug!("unsupported var debuginfo place `{:?}`", projection)
199204
}
200205
}
201206
}
202207

203-
DebugInfoOffset { direct_offset, indirect_offsets, result: place }
208+
DebugInfoOffset { direct_offset, indirect_offsets, result: place, fragment }
204209
}
205210

206211
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
@@ -295,14 +300,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
295300
} else {
296301
let name = kw::Empty;
297302
let decl = &self.mir.local_decls[local];
303+
let arg_ty = self.monomorphize(decl.ty);
304+
298305
let dbg_var = if full_debug_info {
299306
self.adjusted_span_and_dbg_scope(decl.source_info).map(
300307
|(dbg_scope, _, span)| {
301308
// FIXME(eddyb) is this `+ 1` needed at all?
302309
let kind = VariableKind::ArgumentVariable(arg_index + 1);
303310

304-
let arg_ty = self.monomorphize(decl.ty);
305-
306311
self.cx.create_dbg_var(name, arg_ty, dbg_scope, kind, span)
307312
},
308313
)
@@ -312,10 +317,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
312317

313318
Some(PerLocalVarDebugInfo {
314319
name,
320+
ty: arg_ty,
315321
source_info: decl.source_info,
316322
dbg_var,
317-
fragment: None,
318-
projection: ty::List::empty(),
323+
fragment: &[],
324+
projection: &[],
319325
})
320326
}
321327
} else {
@@ -397,8 +403,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
397403
let Some(dbg_var) = var.dbg_var else { return };
398404
let Some(dbg_loc) = self.dbg_loc(var.source_info) else { return };
399405

400-
let DebugInfoOffset { direct_offset, indirect_offsets, result: _ } =
406+
let DebugInfoOffset { mutdirect_offset, indirect_offsets, result: _,fragment: _ } =
401407
calculate_debuginfo_offset(bx, var.projection, base.layout);
408+
let mut indirect_offsets = &indirect_offsets[..];
402409

403410
// When targeting MSVC, create extra allocas for arguments instead of pointing multiple
404411
// dbg_var_addr() calls into the same alloca with offsets. MSVC uses CodeView records
@@ -415,8 +422,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
415422
&& (direct_offset != Size::ZERO || !matches!(&indirect_offsets[..], [Size::ZERO] | []));
416423

417424
if should_create_individual_allocas {
418-
let DebugInfoOffset { direct_offset: _, indirect_offsets: _, result: place } =
419-
calculate_debuginfo_offset(bx, var.projection, base);
425+
let DebugInfoOffset {
426+
direct_offset: _,
427+
indirect_offsets: _,
428+
fragment: _,
429+
result: place,
430+
} = calculate_debuginfo_offset(bx, var.projection, base);
420431

421432
// Create a variable which will be a pointer to the actual value
422433
let ptr_ty = Ty::new_ptr(
@@ -431,24 +442,61 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
431442
bx.store(place.llval, alloca.llval, alloca.align);
432443

433444
// Point the debug info to `*alloca` for the current variable
434-
bx.dbg_var_addr(
435-
dbg_var,
436-
dbg_loc,
437-
alloca.llval,
438-
Size::ZERO,
439-
&[Size::ZERO],
440-
var.fragment,
441-
);
445+
direct_offset = Size::ZERO;
446+
indirect_offsets = &[Size::ZERO];
447+
}
448+
449+
self.debug_introduce_place(
450+
bx,
451+
dbg_var,
452+
dbg_loc,
453+
base.llval,
454+
direct_offset,
455+
indirect_offsets,
456+
var.ty,
457+
var.fragment,
458+
);
459+
}
460+
461+
fn debug_introduce_place(
462+
&self,
463+
bx: &mut Bx,
464+
dbg_var: Bx::DIVariable,
465+
dbg_loc: Bx::DILocation,
466+
base: Bx::Value,
467+
direct_offset: Size,
468+
mut indirect_offsets: &[Size],
469+
ty: Ty<'tcx>,
470+
fragment: &[mir::PlaceElem<'tcx>],
471+
) {
472+
let DebugInfoOffset {
473+
direct_offset: fragment_offset,
474+
indirect_offsets: mut fragment_indirect,
475+
result: fragment_layout,
476+
fragment,
477+
} = calculate_debuginfo_offset(bx, fragment, bx.layout_of(ty));
478+
479+
let fragment = if fragment_layout.size == Size::ZERO {
480+
return;
481+
} else if fragment {
482+
Some(fragment_offset..fragment_offset + fragment_layout.size)
442483
} else {
443-
bx.dbg_var_addr(
444-
dbg_var,
445-
dbg_loc,
446-
base.llval,
447-
direct_offset,
448-
&indirect_offsets,
449-
var.fragment,
450-
);
484+
None
485+
};
486+
487+
while let Some(last_inv) = fragment_indirect.pop() {
488+
if let Some((&last_off, rest)) = indirect_offsets.split_last()
489+
&& last_inv == last_off
490+
{
491+
indirect_offsets = rest;
492+
continue;
493+
} else {
494+
return;
495+
}
451496
}
497+
assert!(fragment_indirect.is_empty());
498+
499+
bx.dbg_var_addr(dbg_var, dbg_loc, base, direct_offset, indirect_offsets, fragment);
452500
}
453501

454502
pub fn debug_introduce_locals(&self, bx: &mut Bx) {
@@ -520,32 +568,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
520568
self.cx.create_dbg_var(var.name, var_ty, dbg_scope, var_kind, span)
521569
});
522570

523-
let fragment = if let Some(ref fragment) = var.composite {
524-
let var_layout = self.cx.layout_of(var_ty);
525-
526-
let DebugInfoOffset { direct_offset, indirect_offsets, result: fragment_layout } =
527-
calculate_debuginfo_offset(bx, &fragment.projection, var_layout);
528-
debug_assert!(indirect_offsets.is_empty());
529-
530-
if fragment_layout.size == Size::ZERO {
531-
// Fragment is a ZST, so does not represent anything. Avoid generating anything
532-
// as this may conflict with a fragment that covers the entire variable.
533-
continue;
534-
} else if fragment_layout.size == var_layout.size {
535-
// Fragment covers entire variable, so as far as
536-
// DWARF is concerned, it's not really a fragment.
537-
None
538-
} else {
539-
Some(direct_offset..direct_offset + fragment_layout.size)
540-
}
541-
} else {
542-
None
543-
};
571+
let fragment =
572+
if let Some(ref fragment) = var.composite { &fragment.projection[..] } else { &[] };
544573

545574
match var.value {
546575
mir::VarDebugInfoContents::Place(place) => {
547576
per_local[place.local].push(PerLocalVarDebugInfo {
548577
name: var.name,
578+
ty: var_ty,
549579
source_info: var.source_info,
550580
dbg_var,
551581
fragment,
@@ -561,7 +591,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
561591
let base =
562592
Self::spill_operand_to_stack(operand, Some(var.name.to_string()), bx);
563593

564-
bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, Size::ZERO, &[], fragment);
594+
self.debug_introduce_place(
595+
bx,
596+
dbg_var,
597+
dbg_loc,
598+
base.llval,
599+
Size::ZERO,
600+
&[],
601+
var_ty,
602+
fragment,
603+
);
565604
}
566605
}
567606
}

‎compiler/rustc_const_eval/src/transform/validate.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -777,7 +777,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
777777
format!("invalid empty projection in debuginfo for {:?}", debuginfo.name),
778778
);
779779
}
780-
if projection.iter().any(|p| !matches!(p, PlaceElem::Field(..))) {
780+
if !projection.iter().all(|p| matches!(p, PlaceElem::Field(..) | PlaceElem::Deref)) {
781781
self.fail(
782782
START_BLOCK.start_location(),
783783
format!(

‎compiler/rustc_middle/src/mir/visit.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -846,8 +846,13 @@ macro_rules! make_mir_visitor {
846846
if let Some(box VarDebugInfoFragment { ref $($mutability)? ty, ref $($mutability)? projection }) = composite {
847847
self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
848848
for elem in projection {
849-
let ProjectionElem::Field(_, ty) = elem else { bug!() };
850-
self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
849+
match elem {
850+
ProjectionElem::Deref => {}
851+
ProjectionElem::Field(_, ty) => {
852+
self.visit_ty($(& $mutability)? *ty, TyContext::Location(location))
853+
}
854+
_ => bug!("unexpected projection in debuginfo: {elem:?}"),
855+
}
851856
}
852857
}
853858
match value {

‎compiler/rustc_mir_transform/src/ref_prop.rs

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -89,13 +89,20 @@ fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool {
8989
debug!(?replacer.allowed_replacements);
9090
debug!(?replacer.storage_to_remove);
9191

92-
replacer.visit_body_preserves_cfg(body);
92+
replacer.local_decls = Some(&body.local_decls);
93+
for debuginfo in body.var_debug_info.iter_mut() {
94+
replacer.visit_var_debug_info(debuginfo);
95+
}
96+
for (bb, bbdata) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() {
97+
replacer.visit_basic_block_data(bb, bbdata);
98+
}
9399

94100
if replacer.any_replacement {
95101
crate::simplify::remove_unused_definitions(body);
102+
true
103+
} else {
104+
false
96105
}
97-
98-
replacer.any_replacement
99106
}
100107

101108
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
@@ -113,7 +120,7 @@ fn compute_replacement<'tcx>(
113120
tcx: TyCtxt<'tcx>,
114121
body: &Body<'tcx>,
115122
ssa: &SsaLocals,
116-
) -> Replacer<'tcx> {
123+
) -> Replacer<'tcx,'tcx> {
117124
let always_live_locals = always_storage_live_locals(body);
118125

119126
// Compute which locals have a single `StorageLive` statement ever.
@@ -268,7 +275,9 @@ fn compute_replacement<'tcx>(
268275
targets,
269276
storage_to_remove,
270277
allowed_replacements,
278+
fully_replacable_locals,
271279
any_replacement: false,
280+
local_decls: None,
272281
};
273282

274283
struct ReplacementFinder<'a, 'tcx, F> {
@@ -342,15 +351,17 @@ fn fully_replacable_locals(ssa: &SsaLocals) -> BitSet<Local> {
342351
}
343352

344353
/// Utility to help performing subtitution of `*pattern` by `target`.
345-
struct Replacer<'tcx> {
354+
struct Replacer<'a,'tcx> {
346355
tcx: TyCtxt<'tcx>,
347356
targets: IndexVec<Local, Value<'tcx>>,
348357
storage_to_remove: BitSet<Local>,
349358
allowed_replacements: FxHashSet<(Local, Location)>,
350359
any_replacement: bool,
360+
fully_replacable_locals: BitSet<Local>,
361+
local_decls: Option<&'a LocalDecls<'tcx>>,
351362
}
352363

353-
impl<'tcx> MutVisitor<'tcx> for Replacer<'tcx> {
364+
impl<'tcx> MutVisitor<'tcx> for Replacer<'_,'tcx> {
354365
fn tcx(&self) -> TyCtxt<'tcx> {
355366
self.tcx
356367
}
@@ -367,6 +378,19 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'tcx> {
367378
if let Some((&PlaceElem::Deref, rest)) = target.projection.split_last() {
368379
*place = Place::from(target.local).project_deeper(rest, self.tcx);
369380
self.any_replacement = true;
381+
} else if self.fully_replacable_locals.contains(place.local) {
382+
debuginfo
383+
.composite
384+
.get_or_insert_with(|| {
385+
Box::new(VarDebugInfoFragment {
386+
ty: self.local_decls.unwrap()[place.local].ty,
387+
projection: Vec::new(),
388+
})
389+
})
390+
.projection
391+
.push(PlaceElem::Deref);
392+
*place = target;
393+
self.any_replacement = true;
370394
} else {
371395
break;
372396
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /