Auto merge of #115252 - cjgillot:mir-composite, r=davidtwco
Represent MIR composite debuginfo as projections instead of aggregates Composite debuginfo for MIR is currently represented as ``` debug name => Type { projection1 => place1, projection2 => place2 }; ``` ie. a single `VarDebugInfo` object with that name, and its value a `VarDebugInfoContents::Composite`. This PR proposes to reverse the representation to be ``` debug name.projection1 => place1; debug name.projection2 => place2; ``` ie. multiple `VarDebugInfo` objects with each their projection. This simplifies the handling of composite debuginfo by the compiler by avoiding weird nesting. Based on https://github.com/rust-lang/rust/pull/115139
This commit is contained in:
commit
a5b2ac6906
17 changed files with 298 additions and 305 deletions
|
@ -1028,19 +1028,6 @@ pub enum VarDebugInfoContents<'tcx> {
|
|||
/// This `Place` only contains projection which satisfy `can_use_in_debuginfo`.
|
||||
Place(Place<'tcx>),
|
||||
Const(Constant<'tcx>),
|
||||
/// The user variable's data is split across several fragments,
|
||||
/// each described by a `VarDebugInfoFragment`.
|
||||
/// See DWARF 5's "2.6.1.2 Composite Location Descriptions"
|
||||
/// and LLVM's `DW_OP_LLVM_fragment` for more details on
|
||||
/// the underlying debuginfo feature this relies on.
|
||||
Composite {
|
||||
/// Type of the original user variable.
|
||||
/// This cannot contain a union or an enum.
|
||||
ty: Ty<'tcx>,
|
||||
/// All the parts of the original user variable, which ended
|
||||
/// up in disjoint places, due to optimizations.
|
||||
fragments: Vec<VarDebugInfoFragment<'tcx>>,
|
||||
},
|
||||
}
|
||||
|
||||
impl<'tcx> Debug for VarDebugInfoContents<'tcx> {
|
||||
|
@ -1048,19 +1035,16 @@ impl<'tcx> Debug for VarDebugInfoContents<'tcx> {
|
|||
match self {
|
||||
VarDebugInfoContents::Const(c) => write!(fmt, "{c}"),
|
||||
VarDebugInfoContents::Place(p) => write!(fmt, "{p:?}"),
|
||||
VarDebugInfoContents::Composite { ty, fragments } => {
|
||||
write!(fmt, "{ty:?}{{ ")?;
|
||||
for f in fragments.iter() {
|
||||
write!(fmt, "{f:?}, ")?;
|
||||
}
|
||||
write!(fmt, "}}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
|
||||
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub struct VarDebugInfoFragment<'tcx> {
|
||||
/// Type of the original user variable.
|
||||
/// This cannot contain a union or an enum.
|
||||
pub ty: Ty<'tcx>,
|
||||
|
||||
/// Where in the composite user variable this fragment is,
|
||||
/// represented as a "projection" into the composite variable.
|
||||
/// At lower levels, this corresponds to a byte/bit range.
|
||||
|
@ -1071,29 +1055,10 @@ pub struct VarDebugInfoFragment<'tcx> {
|
|||
// to match on the discriminant, or by using custom type debuginfo
|
||||
// with non-overlapping variants for the composite variable.
|
||||
pub projection: Vec<PlaceElem<'tcx>>,
|
||||
|
||||
/// Where the data for this fragment can be found.
|
||||
/// This `Place` only contains projection which satisfy `can_use_in_debuginfo`.
|
||||
pub contents: Place<'tcx>,
|
||||
}
|
||||
|
||||
impl Debug for VarDebugInfoFragment<'_> {
|
||||
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
||||
for elem in self.projection.iter() {
|
||||
match elem {
|
||||
ProjectionElem::Field(field, _) => {
|
||||
write!(fmt, ".{:?}", field.index())?;
|
||||
}
|
||||
_ => bug!("unsupported fragment projection `{:?}`", elem),
|
||||
}
|
||||
}
|
||||
|
||||
write!(fmt, " => {:?}", self.contents)
|
||||
}
|
||||
}
|
||||
|
||||
/// Debug information pertaining to a user variable.
|
||||
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
|
||||
#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub struct VarDebugInfo<'tcx> {
|
||||
pub name: Symbol,
|
||||
|
||||
|
@ -1102,6 +1067,13 @@ pub struct VarDebugInfo<'tcx> {
|
|||
/// (see `LocalDecl`'s `source_info` field for more details).
|
||||
pub source_info: SourceInfo,
|
||||
|
||||
/// The user variable's data is split across several fragments,
|
||||
/// each described by a `VarDebugInfoFragment`.
|
||||
/// See DWARF 5's "2.6.1.2 Composite Location Descriptions"
|
||||
/// and LLVM's `DW_OP_LLVM_fragment` for more details on
|
||||
/// the underlying debuginfo feature this relies on.
|
||||
pub composite: Option<Box<VarDebugInfoFragment<'tcx>>>,
|
||||
|
||||
/// Where the data for this user variable is to be found.
|
||||
pub value: VarDebugInfoContents<'tcx>,
|
||||
|
||||
|
@ -1111,6 +1083,20 @@ pub struct VarDebugInfo<'tcx> {
|
|||
pub argument_index: Option<u16>,
|
||||
}
|
||||
|
||||
impl Debug for VarDebugInfo<'_> {
|
||||
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
||||
if let Some(box VarDebugInfoFragment { ty, ref projection }) = self.composite {
|
||||
pre_fmt_projection(&projection[..], fmt)?;
|
||||
write!(fmt, "({}: {})", self.name, ty)?;
|
||||
post_fmt_projection(&projection[..], fmt)?;
|
||||
} else {
|
||||
write!(fmt, "{}", self.name)?;
|
||||
}
|
||||
|
||||
write!(fmt, " => {:?}", self.value)
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// BasicBlock
|
||||
|
||||
|
@ -1575,7 +1561,7 @@ impl<V, T> ProjectionElem<V, T> {
|
|||
/// need neither the `V` parameter for `Index` nor the `T` for `Field`.
|
||||
pub type ProjectionKind = ProjectionElem<(), ()>;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct PlaceRef<'tcx> {
|
||||
pub local: Local,
|
||||
pub projection: &'tcx [PlaceElem<'tcx>],
|
||||
|
@ -1753,69 +1739,83 @@ impl<'tcx> PlaceRef<'tcx> {
|
|||
|
||||
impl Debug for Place<'_> {
|
||||
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
||||
for elem in self.projection.iter().rev() {
|
||||
match elem {
|
||||
ProjectionElem::OpaqueCast(_)
|
||||
| ProjectionElem::Downcast(_, _)
|
||||
| ProjectionElem::Field(_, _) => {
|
||||
write!(fmt, "(").unwrap();
|
||||
}
|
||||
ProjectionElem::Deref => {
|
||||
write!(fmt, "(*").unwrap();
|
||||
}
|
||||
ProjectionElem::Index(_)
|
||||
| ProjectionElem::ConstantIndex { .. }
|
||||
| ProjectionElem::Subslice { .. } => {}
|
||||
}
|
||||
}
|
||||
|
||||
write!(fmt, "{:?}", self.local)?;
|
||||
|
||||
for elem in self.projection.iter() {
|
||||
match elem {
|
||||
ProjectionElem::OpaqueCast(ty) => {
|
||||
write!(fmt, " as {ty})")?;
|
||||
}
|
||||
ProjectionElem::Downcast(Some(name), _index) => {
|
||||
write!(fmt, " as {name})")?;
|
||||
}
|
||||
ProjectionElem::Downcast(None, index) => {
|
||||
write!(fmt, " as variant#{index:?})")?;
|
||||
}
|
||||
ProjectionElem::Deref => {
|
||||
write!(fmt, ")")?;
|
||||
}
|
||||
ProjectionElem::Field(field, ty) => {
|
||||
write!(fmt, ".{:?}: {:?})", field.index(), ty)?;
|
||||
}
|
||||
ProjectionElem::Index(ref index) => {
|
||||
write!(fmt, "[{index:?}]")?;
|
||||
}
|
||||
ProjectionElem::ConstantIndex { offset, min_length, from_end: false } => {
|
||||
write!(fmt, "[{offset:?} of {min_length:?}]")?;
|
||||
}
|
||||
ProjectionElem::ConstantIndex { offset, min_length, from_end: true } => {
|
||||
write!(fmt, "[-{offset:?} of {min_length:?}]")?;
|
||||
}
|
||||
ProjectionElem::Subslice { from, to, from_end: true } if to == 0 => {
|
||||
write!(fmt, "[{from:?}:]")?;
|
||||
}
|
||||
ProjectionElem::Subslice { from, to, from_end: true } if from == 0 => {
|
||||
write!(fmt, "[:-{to:?}]")?;
|
||||
}
|
||||
ProjectionElem::Subslice { from, to, from_end: true } => {
|
||||
write!(fmt, "[{from:?}:-{to:?}]")?;
|
||||
}
|
||||
ProjectionElem::Subslice { from, to, from_end: false } => {
|
||||
write!(fmt, "[{from:?}..{to:?}]")?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
self.as_ref().fmt(fmt)
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for PlaceRef<'_> {
|
||||
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
||||
pre_fmt_projection(self.projection, fmt)?;
|
||||
write!(fmt, "{:?}", self.local)?;
|
||||
post_fmt_projection(self.projection, fmt)
|
||||
}
|
||||
}
|
||||
|
||||
fn pre_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) -> fmt::Result {
|
||||
for &elem in projection.iter().rev() {
|
||||
match elem {
|
||||
ProjectionElem::OpaqueCast(_)
|
||||
| ProjectionElem::Downcast(_, _)
|
||||
| ProjectionElem::Field(_, _) => {
|
||||
write!(fmt, "(").unwrap();
|
||||
}
|
||||
ProjectionElem::Deref => {
|
||||
write!(fmt, "(*").unwrap();
|
||||
}
|
||||
ProjectionElem::Index(_)
|
||||
| ProjectionElem::ConstantIndex { .. }
|
||||
| ProjectionElem::Subslice { .. } => {}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn post_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) -> fmt::Result {
|
||||
for &elem in projection.iter() {
|
||||
match elem {
|
||||
ProjectionElem::OpaqueCast(ty) => {
|
||||
write!(fmt, " as {ty})")?;
|
||||
}
|
||||
ProjectionElem::Downcast(Some(name), _index) => {
|
||||
write!(fmt, " as {name})")?;
|
||||
}
|
||||
ProjectionElem::Downcast(None, index) => {
|
||||
write!(fmt, " as variant#{index:?})")?;
|
||||
}
|
||||
ProjectionElem::Deref => {
|
||||
write!(fmt, ")")?;
|
||||
}
|
||||
ProjectionElem::Field(field, ty) => {
|
||||
write!(fmt, ".{:?}: {:?})", field.index(), ty)?;
|
||||
}
|
||||
ProjectionElem::Index(ref index) => {
|
||||
write!(fmt, "[{index:?}]")?;
|
||||
}
|
||||
ProjectionElem::ConstantIndex { offset, min_length, from_end: false } => {
|
||||
write!(fmt, "[{offset:?} of {min_length:?}]")?;
|
||||
}
|
||||
ProjectionElem::ConstantIndex { offset, min_length, from_end: true } => {
|
||||
write!(fmt, "[-{offset:?} of {min_length:?}]")?;
|
||||
}
|
||||
ProjectionElem::Subslice { from, to, from_end: true } if to == 0 => {
|
||||
write!(fmt, "[{from:?}:]")?;
|
||||
}
|
||||
ProjectionElem::Subslice { from, to, from_end: true } if from == 0 => {
|
||||
write!(fmt, "[:-{to:?}]")?;
|
||||
}
|
||||
ProjectionElem::Subslice { from, to, from_end: true } => {
|
||||
write!(fmt, "[{from:?}:-{to:?}]")?;
|
||||
}
|
||||
ProjectionElem::Subslice { from, to, from_end: false } => {
|
||||
write!(fmt, "[{from:?}..{to:?}]")?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Scopes
|
||||
|
||||
|
@ -3056,6 +3056,6 @@ mod size_asserts {
|
|||
static_assert_size!(StatementKind<'_>, 16);
|
||||
static_assert_size!(Terminator<'_>, 104);
|
||||
static_assert_size!(TerminatorKind<'_>, 88);
|
||||
static_assert_size!(VarDebugInfo<'_>, 80);
|
||||
static_assert_size!(VarDebugInfo<'_>, 88);
|
||||
// tidy-alphabetical-end
|
||||
}
|
||||
|
|
|
@ -554,10 +554,7 @@ fn write_scope_tree(
|
|||
continue;
|
||||
}
|
||||
|
||||
let indented_debug_info = format!(
|
||||
"{0:1$}debug {2} => {3:?};",
|
||||
INDENT, indent, var_debug_info.name, var_debug_info.value,
|
||||
);
|
||||
let indented_debug_info = format!("{0:1$}debug {2:?};", INDENT, indent, var_debug_info);
|
||||
|
||||
if tcx.sess.opts.unstable_opts.mir_include_spans {
|
||||
writeln!(
|
||||
|
|
|
@ -838,12 +838,20 @@ macro_rules! make_mir_visitor {
|
|||
let VarDebugInfo {
|
||||
name: _,
|
||||
source_info,
|
||||
composite,
|
||||
value,
|
||||
argument_index: _,
|
||||
} = var_debug_info;
|
||||
|
||||
self.visit_source_info(source_info);
|
||||
let location = Location::START;
|
||||
if let Some(box VarDebugInfoFragment { ref $($mutability)? ty, ref $($mutability)? projection }) = composite {
|
||||
self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
|
||||
for elem in projection {
|
||||
let ProjectionElem::Field(_, ty) = elem else { bug!() };
|
||||
self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
|
||||
}
|
||||
}
|
||||
match value {
|
||||
VarDebugInfoContents::Const(c) => self.visit_constant(c, location),
|
||||
VarDebugInfoContents::Place(place) =>
|
||||
|
@ -852,17 +860,6 @@ macro_rules! make_mir_visitor {
|
|||
PlaceContext::NonUse(NonUseContext::VarDebugInfo),
|
||||
location
|
||||
),
|
||||
VarDebugInfoContents::Composite { ty, fragments } => {
|
||||
// FIXME(eddyb) use a better `TyContext` here.
|
||||
self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
|
||||
for VarDebugInfoFragment { projection: _, contents } in fragments {
|
||||
self.visit_place(
|
||||
contents,
|
||||
PlaceContext::NonUse(NonUseContext::VarDebugInfo),
|
||||
location,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue