Allow multi-member variants in DWARF (#139300)
Currently, each variant in the variant part of a structure type can only
contain a single member. This was sufficient for Rust, where each
variant is represented as its own type.
However, this isn't really enough for Ada, where a variant can have
multiple members.
This patch adds support for this scenario. This is done by allowing the
use of DW_TAG_variant by DICompositeType, and then changing the DWARF
generator to recognize when a DIDerivedType representing a variant holds
one of these. In this case, the fields from the DW_TAG_variant are
inlined into the variant, like so:
```
<4><7d>: Abbrev Number: 9 (DW_TAG_variant)
<7e> DW_AT_discr_value : 74
<5><7f>: Abbrev Number: 7 (DW_TAG_member)
<80> DW_AT_name : (indirect string, offset: 0x43): field0
<84> DW_AT_type : <0xa7>
<88> DW_AT_alignment : 8
<89> DW_AT_data_member_location: 0
<5><8a>: Abbrev Number: 7 (DW_TAG_member)
<8b> DW_AT_name : (indirect string, offset: 0x4a): field1
<8f> DW_AT_type : <0xa7>
<93> DW_AT_alignment : 8
<94> DW_AT_data_member_location: 8
```
Note that the intermediate DIDerivedType is still needed in this
situation, because that is where the discriminants are stored.
This commit is contained in:
parent
f687ed9ff7
commit
386f2ca03b
@ -6363,6 +6363,8 @@ The following ``tag:`` values are valid:
|
||||
DW_TAG_enumeration_type = 4
|
||||
DW_TAG_structure_type = 19
|
||||
DW_TAG_union_type = 23
|
||||
DW_TAG_variant = 25
|
||||
DW_TAG_variant_part = 51
|
||||
|
||||
For ``DW_TAG_array_type``, the ``elements:`` should be :ref:`subrange
|
||||
descriptors <DISubrange>` or :ref:`subrange descriptors
|
||||
@ -6398,6 +6400,16 @@ For ``DW_TAG_structure_type``, ``DW_TAG_class_type``, and
|
||||
``tag: DW_TAG_friend``; or :ref:`subprograms <DISubprogram>` with
|
||||
``isDefinition: false``.
|
||||
|
||||
``DW_TAG_variant_part`` introduces a variant part of a structure type.
|
||||
This should have a discriminant, a member that is used to decide which
|
||||
elements are active. The elements of the variant part should each be
|
||||
a ``DW_TAG_member``; if a member has a non-null ``ExtraData``, then it
|
||||
is a ``ConstantInt`` or ``ConstantDataArray`` indicating the values of
|
||||
the discriminant member that cause the activation of this branch. A
|
||||
member itself may be of composite type with tag ``DW_TAG_variant``; in
|
||||
this case the members of that composite type are inlined into the
|
||||
current one.
|
||||
|
||||
.. _DISubrange:
|
||||
|
||||
DISubrange
|
||||
|
||||
@ -406,6 +406,19 @@ namespace llvm {
|
||||
Constant *Discriminant,
|
||||
DINode::DIFlags Flags, DIType *Ty);
|
||||
|
||||
/// Create debugging information entry for a variant. A variant
|
||||
/// created this way "inlines" multiple members into the enclosing
|
||||
/// variant part.
|
||||
/// \param Scope Scope in which this variant is defined.
|
||||
/// \param Elements Variant elements.
|
||||
/// \param Discriminant The discriminant for this branch; null for
|
||||
/// the default branch. This may be a
|
||||
/// ConstantDataArray if the variant applies
|
||||
/// for multiple discriminants.
|
||||
/// \param Ty Parent type.
|
||||
DIDerivedType *createVariantMemberType(DIScope *Scope, DINodeArray Elements,
|
||||
Constant *Discriminant, DIType *Ty);
|
||||
|
||||
/// Create debugging information entry for a bit field member.
|
||||
/// \param Scope Member scope.
|
||||
/// \param Name Member name.
|
||||
|
||||
@ -1013,6 +1013,7 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DICompositeType *CTy) {
|
||||
constructEnumTypeDIE(Buffer, CTy);
|
||||
break;
|
||||
case dwarf::DW_TAG_variant_part:
|
||||
case dwarf::DW_TAG_variant:
|
||||
case dwarf::DW_TAG_structure_type:
|
||||
case dwarf::DW_TAG_union_type:
|
||||
case dwarf::DW_TAG_class_type:
|
||||
@ -1066,7 +1067,17 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DICompositeType *CTy) {
|
||||
addDiscriminant(Variant, CI,
|
||||
DD->isUnsignedDIType(Discriminator->getBaseType()));
|
||||
}
|
||||
constructMemberDIE(Variant, DDTy);
|
||||
// If the variant holds a composite type with tag
|
||||
// DW_TAG_variant, inline those members into the variant
|
||||
// DIE.
|
||||
if (auto *Composite =
|
||||
dyn_cast_or_null<DICompositeType>(DDTy->getBaseType());
|
||||
Composite != nullptr &&
|
||||
Composite->getTag() == dwarf::DW_TAG_variant) {
|
||||
constructTypeDIE(Variant, Composite);
|
||||
} else {
|
||||
constructMemberDIE(Variant, DDTy);
|
||||
}
|
||||
} else {
|
||||
constructMemberDIE(Buffer, DDTy);
|
||||
}
|
||||
|
||||
@ -444,6 +444,19 @@ DIDerivedType *DIBuilder::createVariantMemberType(
|
||||
std::nullopt, std::nullopt, Flags, getConstantOrNull(Discriminant));
|
||||
}
|
||||
|
||||
DIDerivedType *DIBuilder::createVariantMemberType(DIScope *Scope,
|
||||
DINodeArray Elements,
|
||||
Constant *Discriminant,
|
||||
DIType *Ty) {
|
||||
auto *V = DICompositeType::get(VMContext, dwarf::DW_TAG_variant, {}, nullptr,
|
||||
0, getNonCompileUnitScope(Scope), {}, 0, 0, 0,
|
||||
DINode::FlagZero, Elements, 0, {}, nullptr);
|
||||
|
||||
trackIfUnresolved(V);
|
||||
return createVariantMemberType(Scope, {}, nullptr, 0, 0, 0, 0, Discriminant,
|
||||
DINode::FlagZero, V);
|
||||
}
|
||||
|
||||
DIDerivedType *DIBuilder::createBitFieldMemberType(
|
||||
DIScope *Scope, StringRef Name, DIFile *File, unsigned LineNumber,
|
||||
uint64_t SizeInBits, uint64_t OffsetInBits, uint64_t StorageOffsetInBits,
|
||||
|
||||
@ -1343,6 +1343,7 @@ void Verifier::visitDICompositeType(const DICompositeType &N) {
|
||||
N.getTag() == dwarf::DW_TAG_enumeration_type ||
|
||||
N.getTag() == dwarf::DW_TAG_class_type ||
|
||||
N.getTag() == dwarf::DW_TAG_variant_part ||
|
||||
N.getTag() == dwarf::DW_TAG_variant ||
|
||||
N.getTag() == dwarf::DW_TAG_namelist,
|
||||
"invalid tag", &N);
|
||||
|
||||
|
||||
74
llvm/test/DebugInfo/Generic/multi-variant.ll
Normal file
74
llvm/test/DebugInfo/Generic/multi-variant.ll
Normal file
@ -0,0 +1,74 @@
|
||||
; RUN: %llc_dwarf -O0 -filetype=obj < %s > %t
|
||||
; RUN: llvm-dwarfdump -v -debug-info %t | FileCheck %s
|
||||
|
||||
; Check for a variant part where a variant has multiple members.
|
||||
|
||||
; CHECK: DW_AT_name [DW_FORM_str{{[a-z]+}}] ({{.*}} = "Discr")
|
||||
; CHECK: DW_TAG_variant_part
|
||||
; CHECK-NOT: TAG
|
||||
; CHECK: DW_AT_discr [DW_FORM_ref4] (cu + {{0x[0-9a-fA-F]+}} => {[[OFFSET:0x[0-9a-fA-F]+]]})
|
||||
; CHECK: DW_TAG_variant
|
||||
; CHECK: DW_AT_discr_value [DW_FORM_data1] (0x4a)
|
||||
; CHECK: DW_TAG_member
|
||||
; CHECK: DW_AT_name [DW_FORM_str{{[a-z]+}}] ({{.*}} = "field0")
|
||||
; CHECK: DW_AT_type
|
||||
; CHECK: DW_AT_alignment
|
||||
; CHECK: DW_AT_data_member_location [DW_FORM_data1] (0x00)
|
||||
; CHECK: DW_TAG_member
|
||||
; CHECK: DW_AT_name [DW_FORM_str{{[a-z]+}}] ({{.*}} = "field1")
|
||||
; CHECK: DW_AT_type
|
||||
; CHECK: DW_AT_alignment
|
||||
; CHECK: DW_AT_data_member_location [DW_FORM_data1] (0x08)
|
||||
; CHECK: DW_TAG_variant
|
||||
; CHECK: DW_AT_discr_value [DW_FORM_data1] (0x4b)
|
||||
; CHECK: DW_TAG_member
|
||||
; CHECK: DW_AT_name [DW_FORM_str{{[a-z]+}}] ({{.*}} = "field2")
|
||||
; CHECK: DW_AT_type
|
||||
; CHECK: DW_AT_alignment
|
||||
; CHECK: DW_AT_data_member_location [DW_FORM_data1] (0x00)
|
||||
|
||||
%F = type { [0 x i8], ptr, [8 x i8] }
|
||||
|
||||
define internal void @_ZN2e34main17h934ff72f9a38d4bbE() unnamed_addr #0 !dbg !5 {
|
||||
start:
|
||||
%qq = alloca %F, align 8
|
||||
call void @llvm.dbg.declare(metadata ptr %qq, metadata !10, metadata !24), !dbg !25
|
||||
store ptr null, ptr %qq, !dbg !25
|
||||
ret void, !dbg !26
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind readnone
|
||||
declare void @llvm.dbg.declare(metadata, metadata, metadata) #0
|
||||
|
||||
attributes #0 = { nounwind uwtable }
|
||||
|
||||
!llvm.module.flags = !{!0, !1}
|
||||
!llvm.dbg.cu = !{!2}
|
||||
|
||||
!0 = !{i32 1, !"PIE Level", i32 2}
|
||||
!1 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
!2 = distinct !DICompileUnit(language: DW_LANG_Ada95, file: !3, producer: "gnat-llvm", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4)
|
||||
!3 = !DIFile(filename: "e3.rs", directory: "/home/tromey/Ada")
|
||||
!4 = !{}
|
||||
!5 = distinct !DISubprogram(name: "main", linkageName: "_ZN2e34mainE", scope: !6, file: !3, line: 2, type: !8, scopeLine: 2, flags: DIFlagPrototyped, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagMainSubprogram, isOptimized: false, unit: !2, templateParams: !4, retainedNodes: !4)
|
||||
!6 = !DINamespace(name: "e3", scope: null)
|
||||
!7 = !DIFile(filename: "<unknown>", directory: "")
|
||||
!8 = !DISubroutineType(types: !9)
|
||||
!9 = !{null}
|
||||
!10 = !DILocalVariable(name: "qq", scope: !11, file: !3, line: 3, type: !12, align: 64)
|
||||
!11 = distinct !DILexicalBlock(scope: !5, file: !3, line: 3, column: 4)
|
||||
!12 = !DICompositeType(tag: DW_TAG_structure_type, name: "F", scope: !6, file: !7, size: 128, align: 64, elements: !13, identifier: "7ce1efff6b82281ab9ceb730566e7e20")
|
||||
!13 = !{!14, !15}
|
||||
!14 = !DIDerivedType(tag: DW_TAG_member, name: "Discr", scope: !12, file: !7, baseType: !23, size: 64, align: 64)
|
||||
!15 = !DICompositeType(tag: DW_TAG_variant_part, scope: !12, file: !7, size: 128, align: 64, elements: !16, identifier: "7ce1efff6b82281ab9ceb730566e7e20", discriminator: !14)
|
||||
!16 = !{!17, !22}
|
||||
!17 = !DIDerivedType(tag: DW_TAG_member, scope: !15, file: !7, baseType: !18, size: 128, align: 64, extraData: i32 74)
|
||||
!18 = !DICompositeType(tag: DW_TAG_variant, scope: !15, file: !7, size: 128, align: 64, elements: !19)
|
||||
!19 = !{!20, !21}
|
||||
!20 = !DIDerivedType(tag: DW_TAG_member, name: "field0", scope: !18, file: !7, baseType: !23, size: 64, align: 64, offset: 0)
|
||||
!21 = !DIDerivedType(tag: DW_TAG_member, name: "field1", scope: !18, file: !7, baseType: !23, size: 64, align: 64, offset: 64)
|
||||
!22 = !DIDerivedType(tag: DW_TAG_member, name: "field2", scope: !15, file: !7, baseType: !23, size: 64, align: 64, offset: 0, extraData: i32 75)
|
||||
!23 = !DIBasicType(name: "u64", size: 64, encoding: DW_ATE_unsigned)
|
||||
!24 = !DIExpression()
|
||||
!25 = !DILocation(line: 3, scope: !11)
|
||||
!26 = !DILocation(line: 4, scope: !5)
|
||||
Loading…
x
Reference in New Issue
Block a user