Skip to content

Two DWARF variant part improvements #138953

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion llvm/include/llvm/IR/DIBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,9 @@ namespace llvm {
/// \param OffsetInBits Member offset.
/// \param Flags Flags to encode member attribute, e.g. private
/// \param Discriminant The discriminant for this branch; null for
/// the default branch
/// the default branch. This may be a
/// ConstantDataArray if the variant applies
/// for multiple discriminants.
/// \param Ty Parent type.
DIDerivedType *createVariantMemberType(DIScope *Scope, StringRef Name,
DIFile *File, unsigned LineNo,
Expand Down
61 changes: 53 additions & 8 deletions llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ void DwarfUnit::addSInt(DIEValueList &Die, dwarf::Attribute Attribute,
addAttribute(Die, Attribute, *Form, DIEInteger(Integer));
}

void DwarfUnit::addSInt(DIELoc &Die, std::optional<dwarf::Form> Form,
void DwarfUnit::addSInt(DIEValueList &Die, std::optional<dwarf::Form> Form,
int64_t Integer) {
addSInt(Die, (dwarf::Attribute)0, Form, Integer);
}
Expand Down Expand Up @@ -961,6 +961,43 @@ void DwarfUnit::addAnnotation(DIE &Buffer, DINodeArray Annotations) {
}
}

void DwarfUnit::addDiscriminant(DIE &Variant, Constant *Discriminant,
bool IsUnsigned) {
if (const auto *CI = dyn_cast_or_null<ConstantInt>(Discriminant)) {
addInt(Variant, dwarf::DW_AT_discr_value, CI->getValue(), IsUnsigned);
} else if (const auto *CA =
dyn_cast_or_null<ConstantDataArray>(Discriminant)) {
// Must have an even number of operands.
unsigned NElems = CA->getNumElements();
if (NElems % 2 != 0) {
return;
}

DIEBlock *Block = new (DIEValueAllocator) DIEBlock;

auto AddInt = [&](const APInt &Val) {
if (IsUnsigned)
addUInt(*Block, dwarf::DW_FORM_udata, Val.getZExtValue());
else
addSInt(*Block, dwarf::DW_FORM_sdata, Val.getSExtValue());
};

for (unsigned I = 0; I < NElems; I += 2) {
APInt LV = CA->getElementAsAPInt(I);
APInt HV = CA->getElementAsAPInt(I + 1);
if (LV == HV) {
addUInt(*Block, dwarf::DW_FORM_data1, dwarf::DW_DSC_label);
AddInt(LV);
} else {
addUInt(*Block, dwarf::DW_FORM_data1, dwarf::DW_DSC_range);
AddInt(LV);
AddInt(HV);
}
}
addBlock(Variant, dwarf::DW_AT_discr_list, Block);
}
}

void DwarfUnit::constructTypeDIE(DIE &Buffer, const DICompositeType *CTy) {
// Add name if not anonymous or intermediate type.
StringRef Name = CTy->getName();
Expand Down Expand Up @@ -989,8 +1026,17 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DICompositeType *CTy) {
// If the variant part has a discriminant, the discriminant is
// represented by a separate debugging information entry which is
// a child of the variant part entry.
DIE &DiscMember = constructMemberDIE(Buffer, Discriminator);
addDIEEntry(Buffer, dwarf::DW_AT_discr, DiscMember);
// However, for a language like Ada, this yields a weird
// result: a discriminant field would have to be emitted
// multiple times, once per variant part. Instead, this DWARF
// restriction was lifted for DWARF 6 (see
// https://dwarfstd.org/issues/180123.1.html) and so we allow
// this here.
DIE *DiscDIE = getDIE(Discriminator);
if (DiscDIE == nullptr) {
DiscDIE = &constructMemberDIE(Buffer, Discriminator);
}
addDIEEntry(Buffer, dwarf::DW_AT_discr, *DiscDIE);
}
}

Expand All @@ -1016,10 +1062,9 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DICompositeType *CTy) {
// When emitting a variant part, wrap each member in
// DW_TAG_variant.
DIE &Variant = createAndAddDIE(dwarf::DW_TAG_variant, Buffer);
if (const ConstantInt *CI =
dyn_cast_or_null<ConstantInt>(DDTy->getDiscriminantValue())) {
addInt(Variant, dwarf::DW_AT_discr_value, CI->getValue(),
DD->isUnsignedDIType(Discriminator->getBaseType()));
if (Constant *CI = DDTy->getDiscriminantValue()) {
addDiscriminant(Variant, CI,
DD->isUnsignedDIType(Discriminator->getBaseType()));
}
constructMemberDIE(Variant, DDTy);
} else {
Expand Down Expand Up @@ -1755,7 +1800,7 @@ void DwarfUnit::constructContainingTypeDIEs() {
}

DIE &DwarfUnit::constructMemberDIE(DIE &Buffer, const DIDerivedType *DT) {
DIE &MemberDie = createAndAddDIE(DT->getTag(), Buffer);
DIE &MemberDie = createAndAddDIE(DT->getTag(), Buffer, DT);
StringRef Name = DT->getName();
if (!Name.empty())
addString(MemberDie, dwarf::DW_AT_name, Name);
Expand Down
6 changes: 5 additions & 1 deletion llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,8 @@ class DwarfUnit : public DIEUnit {
void addSInt(DIEValueList &Die, dwarf::Attribute Attribute,
std::optional<dwarf::Form> Form, int64_t Integer);

void addSInt(DIELoc &Die, std::optional<dwarf::Form> Form, int64_t Integer);
void addSInt(DIEValueList &Die, std::optional<dwarf::Form> Form,
int64_t Integer);

/// Add an integer attribute data and value; value may be any width.
void addInt(DIE &Die, dwarf::Attribute Attribute, const APInt &Integer,
Expand Down Expand Up @@ -342,6 +343,9 @@ class DwarfUnit : public DIEUnit {
/// form.
void addIntAsBlock(DIE &Die, dwarf::Attribute Attribute, const APInt &Val);

// Add discriminant constants to a DW_TAG_variant DIE.
void addDiscriminant(DIE &Variant, Constant *Discriminant, bool IsUnsigned);

void constructTypeDIE(DIE &Buffer, const DIBasicType *BTy);
void constructTypeDIE(DIE &Buffer, const DIFixedPointType *BTy);
void constructTypeDIE(DIE &Buffer, const DIStringType *BTy);
Expand Down
74 changes: 74 additions & 0 deletions llvm/test/DebugInfo/Generic/discriminant-member.ll
Original file line number Diff line number Diff line change
@@ -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 that has two members, where one uses a list
; of discriminants, and where both refer to a DIE that is not a child
; of the variant.

; CHECK: DW_AT_name [DW_FORM_strp] ({{.*}} = "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_list [DW_FORM_block1] (<0x05> 00 17 01 61 6c )
; CHECK: DW_TAG_member
; CHECK: DW_AT_name [DW_FORM_strp] ({{.*}} = "var0")
; CHECK: DW_AT_type
; CHECK: DW_AT_alignment
; CHECK: DW_AT_data_member_location [DW_FORM_data1] (0x00)
; CHECK: DW_TAG_variant
; CHECK: DW_AT_discr_value [DW_FORM_data1] (0x4b)
; CHECK: DW_TAG_member
; 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] }
%"F::Nope" = type {}

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 !28), !dbg !29
store ptr null, ptr %qq, !dbg !29
ret void, !dbg !30
}

; 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: 8)
!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: !27, 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, !24}
!17 = !DIDerivedType(tag: DW_TAG_member, name: "var0", scope: !15, file: !7, baseType: !18, size: 128, align: 64, extraData: [4 x i32] [i32 23, i32 23, i32 97, i32 108])
!18 = !DICompositeType(tag: DW_TAG_structure_type, name: "Yep", scope: !12, file: !7, size: 128, align: 64, elements: !19, identifier: "7ce1efff6b82281ab9ceb730566e7e20::Yep")
!19 = !{!20, !22}
!20 = !DIDerivedType(tag: DW_TAG_member, name: "var1", scope: !18, file: !7, baseType: !21, size: 8, align: 8, offset: 64)
!21 = !DIBasicType(name: "u8", size: 8, encoding: DW_ATE_unsigned)
!22 = !DIDerivedType(tag: DW_TAG_member, name: "var2", scope: !18, file: !7, baseType: !23, size: 64, align: 64)
!23 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "&u8", baseType: !21, size: 64, align: 64)
!24 = !DIDerivedType(tag: DW_TAG_member, scope: !15, file: !7, baseType: !25, size: 128, align: 64, extraData: i32 75)
!25 = !DICompositeType(tag: DW_TAG_structure_type, name: "Nope", scope: !12, file: !7, size: 128, align: 64, elements: !4, identifier: "7ce1efff6b82281ab9ceb730566e7e20::Nope")
!27 = !DIBasicType(name: "u64", size: 64, encoding: DW_ATE_unsigned)
!28 = !DIExpression()
!29 = !DILocation(line: 3, scope: !11)
!30 = !DILocation(line: 4, scope: !5)
Loading