Skip to content

Commit 386f2ca

Browse files
authored
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.
1 parent f687ed9 commit 386f2ca

File tree

6 files changed

+125
-1
lines changed

6 files changed

+125
-1
lines changed

llvm/docs/LangRef.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6363,6 +6363,8 @@ The following ``tag:`` values are valid:
63636363
DW_TAG_enumeration_type = 4
63646364
DW_TAG_structure_type = 19
63656365
DW_TAG_union_type = 23
6366+
DW_TAG_variant = 25
6367+
DW_TAG_variant_part = 51
63666368

63676369
For ``DW_TAG_array_type``, the ``elements:`` should be :ref:`subrange
63686370
descriptors <DISubrange>` or :ref:`subrange descriptors
@@ -6398,6 +6400,16 @@ For ``DW_TAG_structure_type``, ``DW_TAG_class_type``, and
63986400
``tag: DW_TAG_friend``; or :ref:`subprograms <DISubprogram>` with
63996401
``isDefinition: false``.
64006402

6403+
``DW_TAG_variant_part`` introduces a variant part of a structure type.
6404+
This should have a discriminant, a member that is used to decide which
6405+
elements are active. The elements of the variant part should each be
6406+
a ``DW_TAG_member``; if a member has a non-null ``ExtraData``, then it
6407+
is a ``ConstantInt`` or ``ConstantDataArray`` indicating the values of
6408+
the discriminant member that cause the activation of this branch. A
6409+
member itself may be of composite type with tag ``DW_TAG_variant``; in
6410+
this case the members of that composite type are inlined into the
6411+
current one.
6412+
64016413
.. _DISubrange:
64026414

64036415
DISubrange

llvm/include/llvm/IR/DIBuilder.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,19 @@ namespace llvm {
406406
Constant *Discriminant,
407407
DINode::DIFlags Flags, DIType *Ty);
408408

409+
/// Create debugging information entry for a variant. A variant
410+
/// created this way "inlines" multiple members into the enclosing
411+
/// variant part.
412+
/// \param Scope Scope in which this variant is defined.
413+
/// \param Elements Variant elements.
414+
/// \param Discriminant The discriminant for this branch; null for
415+
/// the default branch. This may be a
416+
/// ConstantDataArray if the variant applies
417+
/// for multiple discriminants.
418+
/// \param Ty Parent type.
419+
DIDerivedType *createVariantMemberType(DIScope *Scope, DINodeArray Elements,
420+
Constant *Discriminant, DIType *Ty);
421+
409422
/// Create debugging information entry for a bit field member.
410423
/// \param Scope Member scope.
411424
/// \param Name Member name.

llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1013,6 +1013,7 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DICompositeType *CTy) {
10131013
constructEnumTypeDIE(Buffer, CTy);
10141014
break;
10151015
case dwarf::DW_TAG_variant_part:
1016+
case dwarf::DW_TAG_variant:
10161017
case dwarf::DW_TAG_structure_type:
10171018
case dwarf::DW_TAG_union_type:
10181019
case dwarf::DW_TAG_class_type:
@@ -1066,7 +1067,17 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DICompositeType *CTy) {
10661067
addDiscriminant(Variant, CI,
10671068
DD->isUnsignedDIType(Discriminator->getBaseType()));
10681069
}
1069-
constructMemberDIE(Variant, DDTy);
1070+
// If the variant holds a composite type with tag
1071+
// DW_TAG_variant, inline those members into the variant
1072+
// DIE.
1073+
if (auto *Composite =
1074+
dyn_cast_or_null<DICompositeType>(DDTy->getBaseType());
1075+
Composite != nullptr &&
1076+
Composite->getTag() == dwarf::DW_TAG_variant) {
1077+
constructTypeDIE(Variant, Composite);
1078+
} else {
1079+
constructMemberDIE(Variant, DDTy);
1080+
}
10701081
} else {
10711082
constructMemberDIE(Buffer, DDTy);
10721083
}

llvm/lib/IR/DIBuilder.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,19 @@ DIDerivedType *DIBuilder::createVariantMemberType(
444444
std::nullopt, std::nullopt, Flags, getConstantOrNull(Discriminant));
445445
}
446446

447+
DIDerivedType *DIBuilder::createVariantMemberType(DIScope *Scope,
448+
DINodeArray Elements,
449+
Constant *Discriminant,
450+
DIType *Ty) {
451+
auto *V = DICompositeType::get(VMContext, dwarf::DW_TAG_variant, {}, nullptr,
452+
0, getNonCompileUnitScope(Scope), {}, 0, 0, 0,
453+
DINode::FlagZero, Elements, 0, {}, nullptr);
454+
455+
trackIfUnresolved(V);
456+
return createVariantMemberType(Scope, {}, nullptr, 0, 0, 0, 0, Discriminant,
457+
DINode::FlagZero, V);
458+
}
459+
447460
DIDerivedType *DIBuilder::createBitFieldMemberType(
448461
DIScope *Scope, StringRef Name, DIFile *File, unsigned LineNumber,
449462
uint64_t SizeInBits, uint64_t OffsetInBits, uint64_t StorageOffsetInBits,

llvm/lib/IR/Verifier.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1343,6 +1343,7 @@ void Verifier::visitDICompositeType(const DICompositeType &N) {
13431343
N.getTag() == dwarf::DW_TAG_enumeration_type ||
13441344
N.getTag() == dwarf::DW_TAG_class_type ||
13451345
N.getTag() == dwarf::DW_TAG_variant_part ||
1346+
N.getTag() == dwarf::DW_TAG_variant ||
13461347
N.getTag() == dwarf::DW_TAG_namelist,
13471348
"invalid tag", &N);
13481349

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
; RUN: %llc_dwarf -O0 -filetype=obj < %s > %t
2+
; RUN: llvm-dwarfdump -v -debug-info %t | FileCheck %s
3+
4+
; Check for a variant part where a variant has multiple members.
5+
6+
; CHECK: DW_AT_name [DW_FORM_str{{[a-z]+}}] ({{.*}} = "Discr")
7+
; CHECK: DW_TAG_variant_part
8+
; CHECK-NOT: TAG
9+
; CHECK: DW_AT_discr [DW_FORM_ref4] (cu + {{0x[0-9a-fA-F]+}} => {[[OFFSET:0x[0-9a-fA-F]+]]})
10+
; CHECK: DW_TAG_variant
11+
; CHECK: DW_AT_discr_value [DW_FORM_data1] (0x4a)
12+
; CHECK: DW_TAG_member
13+
; CHECK: DW_AT_name [DW_FORM_str{{[a-z]+}}] ({{.*}} = "field0")
14+
; CHECK: DW_AT_type
15+
; CHECK: DW_AT_alignment
16+
; CHECK: DW_AT_data_member_location [DW_FORM_data1] (0x00)
17+
; CHECK: DW_TAG_member
18+
; CHECK: DW_AT_name [DW_FORM_str{{[a-z]+}}] ({{.*}} = "field1")
19+
; CHECK: DW_AT_type
20+
; CHECK: DW_AT_alignment
21+
; CHECK: DW_AT_data_member_location [DW_FORM_data1] (0x08)
22+
; CHECK: DW_TAG_variant
23+
; CHECK: DW_AT_discr_value [DW_FORM_data1] (0x4b)
24+
; CHECK: DW_TAG_member
25+
; CHECK: DW_AT_name [DW_FORM_str{{[a-z]+}}] ({{.*}} = "field2")
26+
; CHECK: DW_AT_type
27+
; CHECK: DW_AT_alignment
28+
; CHECK: DW_AT_data_member_location [DW_FORM_data1] (0x00)
29+
30+
%F = type { [0 x i8], ptr, [8 x i8] }
31+
32+
define internal void @_ZN2e34main17h934ff72f9a38d4bbE() unnamed_addr #0 !dbg !5 {
33+
start:
34+
%qq = alloca %F, align 8
35+
call void @llvm.dbg.declare(metadata ptr %qq, metadata !10, metadata !24), !dbg !25
36+
store ptr null, ptr %qq, !dbg !25
37+
ret void, !dbg !26
38+
}
39+
40+
; Function Attrs: nounwind readnone
41+
declare void @llvm.dbg.declare(metadata, metadata, metadata) #0
42+
43+
attributes #0 = { nounwind uwtable }
44+
45+
!llvm.module.flags = !{!0, !1}
46+
!llvm.dbg.cu = !{!2}
47+
48+
!0 = !{i32 1, !"PIE Level", i32 2}
49+
!1 = !{i32 2, !"Debug Info Version", i32 3}
50+
!2 = distinct !DICompileUnit(language: DW_LANG_Ada95, file: !3, producer: "gnat-llvm", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4)
51+
!3 = !DIFile(filename: "e3.rs", directory: "/home/tromey/Ada")
52+
!4 = !{}
53+
!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)
54+
!6 = !DINamespace(name: "e3", scope: null)
55+
!7 = !DIFile(filename: "<unknown>", directory: "")
56+
!8 = !DISubroutineType(types: !9)
57+
!9 = !{null}
58+
!10 = !DILocalVariable(name: "qq", scope: !11, file: !3, line: 3, type: !12, align: 64)
59+
!11 = distinct !DILexicalBlock(scope: !5, file: !3, line: 3, column: 4)
60+
!12 = !DICompositeType(tag: DW_TAG_structure_type, name: "F", scope: !6, file: !7, size: 128, align: 64, elements: !13, identifier: "7ce1efff6b82281ab9ceb730566e7e20")
61+
!13 = !{!14, !15}
62+
!14 = !DIDerivedType(tag: DW_TAG_member, name: "Discr", scope: !12, file: !7, baseType: !23, size: 64, align: 64)
63+
!15 = !DICompositeType(tag: DW_TAG_variant_part, scope: !12, file: !7, size: 128, align: 64, elements: !16, identifier: "7ce1efff6b82281ab9ceb730566e7e20", discriminator: !14)
64+
!16 = !{!17, !22}
65+
!17 = !DIDerivedType(tag: DW_TAG_member, scope: !15, file: !7, baseType: !18, size: 128, align: 64, extraData: i32 74)
66+
!18 = !DICompositeType(tag: DW_TAG_variant, scope: !15, file: !7, size: 128, align: 64, elements: !19)
67+
!19 = !{!20, !21}
68+
!20 = !DIDerivedType(tag: DW_TAG_member, name: "field0", scope: !18, file: !7, baseType: !23, size: 64, align: 64, offset: 0)
69+
!21 = !DIDerivedType(tag: DW_TAG_member, name: "field1", scope: !18, file: !7, baseType: !23, size: 64, align: 64, offset: 64)
70+
!22 = !DIDerivedType(tag: DW_TAG_member, name: "field2", scope: !15, file: !7, baseType: !23, size: 64, align: 64, offset: 0, extraData: i32 75)
71+
!23 = !DIBasicType(name: "u64", size: 64, encoding: DW_ATE_unsigned)
72+
!24 = !DIExpression()
73+
!25 = !DILocation(line: 3, scope: !11)
74+
!26 = !DILocation(line: 4, scope: !5)

0 commit comments

Comments
 (0)