1
Fork 0

Auto merge of #111440 - cjgillot:refprop-debuginfo, r=oli-obk

Allow MIR debuginfo to point to a variable's address

MIR optimizations currently do not to operate on borrowed locals.

When enabling #106285, many borrows will be left as-is because they are used in debuginfo. This pass allows to replace this pattern directly in MIR debuginfo:
```rust
a => _1
_1 = &raw? mut? _2
```
becomes
```rust
a => &_2
// No statement to borrow _2.
```

This pass is implemented as a drive-by in ReferencePropagation MIR pass.

This transformation allows following following MIR opts to treat _2 as an unborrowed local, and optimize it as such, even in builds with debuginfo.

In codegen, when encountering `a => &..&_2`, we create a list of allocas:
```llvm
store ptr %_2.dbg.spill, ptr %a.ref0.dbg.spill
store ptr %a.ref0.dbg.spill, ptr %a.ref1.dbg.spill
...
call void `@llvm.dbg.declare(metadata` ptr %a.ref{n}.dbg.spill, /* ... */)
```

Caveat: this transformation looses the exact type, we do not differentiate `a` as a immutable, mutable reference or a raw pointer. Everything is declared to `*mut` to codegen. I'm not convinced this is a blocker.
This commit is contained in:
bors 2023-05-14 05:31:10 +00:00
commit bc888958c9
26 changed files with 1537 additions and 653 deletions

View file

@ -1111,6 +1111,10 @@ pub struct VarDebugInfo<'tcx> {
/// originated from (starting from 1). Note, if MIR inlining is enabled, then this is the
/// argument number in the original function before it was inlined.
pub argument_index: Option<u16>,
/// The data represents `name` dereferenced `references` times,
/// and not the direct value.
pub references: u8,
}
///////////////////////////////////////////////////////////////////////////
@ -1550,8 +1554,11 @@ impl<V, T> ProjectionElem<V, T> {
/// Returns `true` if this is accepted inside `VarDebugInfoContents::Place`.
pub fn can_use_in_debuginfo(&self) -> bool {
match self {
Self::Deref | Self::Downcast(_, _) | Self::Field(_, _) => true,
Self::ConstantIndex { .. }
Self::ConstantIndex { from_end: false, .. }
| Self::Deref
| Self::Downcast(_, _)
| Self::Field(_, _) => true,
Self::ConstantIndex { from_end: true, .. }
| Self::Index(_)
| Self::OpaqueCast(_)
| Self::Subslice { .. } => false,
@ -1639,18 +1646,7 @@ impl<'tcx> Place<'tcx> {
return self;
}
let mut v: Vec<PlaceElem<'tcx>>;
let new_projections = if self.projection.is_empty() {
more_projections
} else {
v = Vec::with_capacity(self.projection.len() + more_projections.len());
v.extend(self.projection);
v.extend(more_projections);
&v
};
Place { local: self.local, projection: tcx.mk_place_elems(new_projections) }
self.as_ref().project_deeper(more_projections, tcx)
}
}
@ -1721,6 +1717,27 @@ impl<'tcx> PlaceRef<'tcx> {
(base, *proj)
})
}
/// Generates a new place by appending `more_projections` to the existing ones
/// and interning the result.
pub fn project_deeper(
self,
more_projections: &[PlaceElem<'tcx>],
tcx: TyCtxt<'tcx>,
) -> Place<'tcx> {
let mut v: Vec<PlaceElem<'tcx>>;
let new_projections = if self.projection.is_empty() {
more_projections
} else {
v = Vec::with_capacity(self.projection.len() + more_projections.len());
v.extend(self.projection);
v.extend(more_projections);
&v
};
Place { local: self.local, projection: tcx.mk_place_elems(new_projections) }
}
}
impl Debug for Place<'_> {

View file

@ -551,8 +551,13 @@ fn write_scope_tree(
}
let indented_debug_info = format!(
"{0:1$}debug {2} => {3:?};",
INDENT, indent, var_debug_info.name, var_debug_info.value,
"{0:1$}debug {2} => {3:&<4$}{5:?};",
INDENT,
indent,
var_debug_info.name,
"",
var_debug_info.references as usize,
var_debug_info.value,
);
writeln!(

View file

@ -842,6 +842,7 @@ macro_rules! make_mir_visitor {
source_info,
value,
argument_index: _,
references: _,
} = var_debug_info;
self.visit_source_info(source_info);

View file

@ -204,6 +204,7 @@ CloneLiftImpls! {
(),
bool,
usize,
u8,
u16,
u32,
u64,