[llvm] [llvm][DebugInfo] Encode DW_AT_object_pointer on method declarations with DW_FORM_implicit_const (PR #124790)
Michael Buch via llvm-commits
llvm-commits at lists.llvm.org
Tue Jan 28 09:22:45 PST 2025
https://github.com/Michael137 updated https://github.com/llvm/llvm-project/pull/124790
>From de162644aac2fdcdbc315c179d34ea3a8a2d7629 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Tue, 28 Jan 2025 13:45:16 +0000
Subject: [PATCH] [llvm][DebugInfo] Encode DW_AT_object_pointer on method
declarations with DW_FORM_implicit_const
We started attaching `DW_AT_object_pointer`s on method declarations in https://github.com/llvm/llvm-project/pull/122742. However, that caused the `.debug_info` section size to increase significantly (by around ~10% on some projects). This was mainly due to the large number of new `DW_FORM_ref4` values. This patch tries to address that regression by changing the `DW_FORM_ref4` to a `DW_FORM_implicit_const` for declarations. That way we don't pay for the 4 byte references on every attribute occurrence. In a local build of clang this barely affected the `.debug_info` section size (but did increase `.debug_abbrev` by up to 10%, which doesn't affect the total debug-info size much however).
We guarded this on LLDB tuning (since using `DW_FORM_implicit_const` for this purpose may surprise consumers) and DWARFv5 (since that's where `DW_FORM_implicit_const` was first standardized).
---
llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp | 28 +++++--
llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h | 6 +-
...DW_AT_object_pointer-non-standard-index.ll | 79 +++++++++++++++++++
.../DebugInfo/X86/DW_AT_object_pointer.ll | 22 ++++--
.../tools/llvm-dwarfdump/X86/statistics.ll | 6 +-
5 files changed, 122 insertions(+), 19 deletions(-)
create mode 100644 llvm/test/DebugInfo/X86/DW_AT_object_pointer-non-standard-index.ll
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
index d3450b8b0556fd..05bcaa9405e7dd 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
@@ -849,9 +849,10 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DIDerivedType *DTy) {
}
}
-DIE *DwarfUnit::constructSubprogramArguments(DIE &Buffer, DITypeRefArray Args) {
+std::optional<unsigned>
+DwarfUnit::constructSubprogramArguments(DIE &Buffer, DITypeRefArray Args) {
// Args[0] is the return type.
- DIE *ObjectPointer = nullptr;
+ std::optional<unsigned> ObjectPointerIndex;
for (unsigned i = 1, N = Args.size(); i < N; ++i) {
const DIType *Ty = Args[i];
if (!Ty) {
@@ -863,13 +864,14 @@ DIE *DwarfUnit::constructSubprogramArguments(DIE &Buffer, DITypeRefArray Args) {
if (Ty->isArtificial())
addFlag(Arg, dwarf::DW_AT_artificial);
if (Ty->isObjectPointer()) {
- assert(!ObjectPointer && "Can't have more than one object pointer");
- ObjectPointer = &Arg;
+ assert(!ObjectPointerIndex &&
+ "Can't have more than one object pointer");
+ ObjectPointerIndex = i;
}
}
}
- return ObjectPointer;
+ return ObjectPointerIndex;
}
void DwarfUnit::constructTypeDIE(DIE &Buffer, const DISubroutineType *CTy) {
@@ -1366,8 +1368,20 @@ void DwarfUnit::applySubprogramAttributes(const DISubprogram *SP, DIE &SPDie,
// Add arguments. Do not add arguments for subprogram definition. They will
// be handled while processing variables.
- if (auto *ObjectPointer = constructSubprogramArguments(SPDie, Args))
- addDIEEntry(SPDie, dwarf::DW_AT_object_pointer, *ObjectPointer);
+ //
+ // Encode the object pointer as an index instead of a DIE reference in order
+ // to minimize the affect on the .debug_info size.
+ if (std::optional<unsigned> ObjectPointerIndex =
+ constructSubprogramArguments(SPDie, Args)) {
+ if (getDwarfDebug().tuneForLLDB() &&
+ getDwarfDebug().getDwarfVersion() >= 5) {
+ // 0th index in Args is the return type, hence adjust by 1. In DWARF
+ // we want the first parameter to be at index 0.
+ assert(*ObjectPointerIndex > 0);
+ addSInt(SPDie, dwarf::DW_AT_object_pointer,
+ dwarf::DW_FORM_implicit_const, *ObjectPointerIndex - 1);
+ }
+ }
}
addThrownTypes(SPDie, SP->getThrownTypes());
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h
index 7a5295d826a483..afbe9089942104 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h
@@ -269,8 +269,10 @@ class DwarfUnit : public DIEUnit {
/// Construct function argument DIEs.
///
- /// \returns DIE of the object pointer if one exists. Nullptr otherwise.
- DIE *constructSubprogramArguments(DIE &Buffer, DITypeRefArray Args);
+ /// \returns The index of the object parameter in \c Args if one exists.
+ /// Returns std::nullopt otherwise.
+ std::optional<unsigned> constructSubprogramArguments(DIE &Buffer,
+ DITypeRefArray Args);
/// Create a DIE with the given Tag, add the DIE to its parent, and
/// call insertDIE if MD is not null.
diff --git a/llvm/test/DebugInfo/X86/DW_AT_object_pointer-non-standard-index.ll b/llvm/test/DebugInfo/X86/DW_AT_object_pointer-non-standard-index.ll
new file mode 100644
index 00000000000000..40b791fd27e326
--- /dev/null
+++ b/llvm/test/DebugInfo/X86/DW_AT_object_pointer-non-standard-index.ll
@@ -0,0 +1,79 @@
+; Similar to DW_AT_object_pointer.ll but tests that we correctly
+; encode the object pointer index even if it's not the first argument
+; of the subprogram (which isn't something the major compilers do,
+; but is not mandated by DWARF).
+
+; RUN: llc -mtriple=x86_64-apple-darwin -debugger-tune=lldb -dwarf-version=5 -filetype=obj < %s | \
+; RUN: llvm-dwarfdump -v -debug-info - | FileCheck %s --check-prefixes=CHECK
+
+; CHECK: DW_TAG_class_type
+; CHECK: [[DECL:0x[0-9a-f]+]]: DW_TAG_subprogram
+; CHECK: DW_AT_name {{.*}} "A"
+; CHECK: DW_AT_object_pointer [DW_FORM_implicit_const] (2)
+;
+; CHECK: DW_TAG_subprogram
+; CHECK: DW_AT_object_pointer [DW_FORM_ref4] (cu + 0x{{[0-9a-f]*}} => {[[PARAM:0x[0-9a-f]*]]})
+; CHECK: DW_AT_specification [DW_FORM_ref4] (cu + {{.*}} => {[[DECL]]}
+; CHECK: DW_TAG_formal_parameter
+; CHECK: DW_TAG_formal_parameter
+; CHECK-NOT: "this"
+; CHECK: [[PARAM]]: DW_TAG_formal_parameter
+; CHECK: DW_AT_name
+; CHECK-SAME: = "this")
+; CHECK: DW_TAG_formal_parameter
+
+%class.A = type { i8 }
+
+define linkonce_odr noundef ptr @_ZN1AC1Eii(ptr noundef nonnull returned align 1 dereferenceable(1) %this, i32 noundef %x, i32 noundef %y, i32 noundef %z) !dbg !24 {
+entry:
+ %this.addr = alloca ptr, align 8
+ %x.addr = alloca i32, align 4
+ %y.addr = alloca i32, align 4
+ %z.addr = alloca i32, align 4
+ store ptr %this, ptr %this.addr, align 8
+ #dbg_declare(ptr %this.addr, !26, !DIExpression(), !28)
+ store i32 %x, ptr %x.addr, align 4
+ #dbg_declare(ptr %x.addr, !29, !DIExpression(), !30)
+ store i32 %y, ptr %y.addr, align 4
+ #dbg_declare(ptr %y.addr, !31, !DIExpression(), !32)
+ store i32 %z, ptr %y.addr, align 4
+ #dbg_declare(ptr %z.addr, !36, !DIExpression(), !37)
+ %this1 = load ptr, ptr %this.addr, align 8
+ %0 = load i32, ptr %x.addr, align 4, !dbg !33
+ %1 = load i32, ptr %y.addr, align 4, !dbg !33
+ %2 = load i32, ptr %z.addr, align 4, !dbg !33
+ ret ptr %this1, !dbg !34
+}
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!12, !13}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 3, type: !5, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, producer: "clang version 20.0.0git", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: Apple, sysroot: "/")
+!3 = !DIFile(filename: "object_ptr.cpp", directory: "/tmp")
+!4 = !{!0}
+!5 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "A", file: !3, line: 1, size: 8, flags: DIFlagTypePassByValue | DIFlagNonTrivial, elements: !6, identifier: "_ZTS1A")
+!6 = !{!7}
+!7 = !DISubprogram(name: "A", scope: !5, file: !3, line: 2, type: !8, scopeLine: 2, flags: DIFlagPublic | DIFlagPrototyped, spFlags: 0)
+!8 = !DISubroutineType(types: !9)
+!9 = !{null, !11, !11, !10, !35}
+!10 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!12 = !{i32 7, !"Dwarf Version", i32 5}
+!13 = !{i32 2, !"Debug Info Version", i32 3}
+!18 = !{!"clang version 20.0.0git"}
+!24 = distinct !DISubprogram(name: "A", linkageName: "_ZN1AC1Eii", scope: !5, file: !3, line: 2, type: !8, scopeLine: 2, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, declaration: !7, retainedNodes: !25)
+!25 = !{}
+!26 = !DILocalVariable(name: "this", arg: 3, scope: !24, type: !27, flags: DIFlagArtificial | DIFlagObjectPointer)
+!27 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64)
+!28 = !DILocation(line: 0, scope: !24)
+!29 = !DILocalVariable(name: "x", arg: 2, scope: !24, file: !3, line: 2, type: !11)
+!30 = !DILocation(line: 2, column: 19, scope: !24)
+!31 = !DILocalVariable(name: "y", arg: 1, scope: !24, file: !3, line: 2, type: !11)
+!32 = !DILocation(line: 2, column: 26, scope: !24)
+!33 = !DILocation(line: 2, column: 29, scope: !24)
+!34 = !DILocation(line: 2, column: 30, scope: !24)
+!35 = !DIBasicType(name: "short", size: 16, encoding: DW_ATE_signed)
+!36 = !DILocalVariable(name: "z", arg: 4, scope: !24, file: !3, line: 2, type: !35)
+!37 = !DILocation(line: 2, column: 35, scope: !24)
diff --git a/llvm/test/DebugInfo/X86/DW_AT_object_pointer.ll b/llvm/test/DebugInfo/X86/DW_AT_object_pointer.ll
index 30d4203466766e..596727dce04339 100644
--- a/llvm/test/DebugInfo/X86/DW_AT_object_pointer.ll
+++ b/llvm/test/DebugInfo/X86/DW_AT_object_pointer.ll
@@ -1,5 +1,11 @@
-; RUN: llc -mtriple=x86_64-apple-darwin %s -o %t -filetype=obj
-; RUN: llvm-dwarfdump -v -debug-info %t | FileCheck %s
+; RUN: llc -mtriple=x86_64-apple-darwin -debugger-tune=gdb -dwarf-version=5 -filetype=obj < %s | \
+; RUN: llvm-dwarfdump -v -debug-info - | FileCheck %s --check-prefixes=CHECK,CHECK-GDB
+
+; RUN: llc -mtriple=x86_64-apple-darwin -debugger-tune=lldb -dwarf-version=4 -filetype=obj < %s | \
+; RUN: llvm-dwarfdump -v -debug-info - | FileCheck %s --check-prefixes=CHECK,CHECK-LLDB-DWARF4
+
+; RUN: llc -mtriple=x86_64-apple-darwin -debugger-tune=lldb -dwarf-version=5 -filetype=obj < %s | \
+; RUN: llvm-dwarfdump -v -debug-info - | FileCheck %s --check-prefixes=CHECK,CHECK-LLDB-DWARF5
; CHECK: DW_TAG_formal_parameter [
; CHECK-NOT: ""
@@ -7,16 +13,18 @@
; CHECK: DW_TAG_class_type
; CHECK: [[DECL:0x[0-9a-f]+]]: DW_TAG_subprogram
; CHECK: DW_AT_name {{.*}} "A"
-; CHECK: DW_AT_object_pointer [DW_FORM_ref4]
-; CHECK-SAME: (cu + 0x{{[0-9a-f]*}} => {[[DECL_PARAM:0x[0-9a-f]*]]})
-; CHECK: [[DECL_PARAM]]: DW_TAG_formal_parameter
+; CHECK-LLDB-DWARF5: DW_AT_object_pointer [DW_FORM_implicit_const] (0)
+; CHECK-GDB-NOT: DW_AT_object_pointer
+; CHECK-LLDB-DWARF4-NOT: DW_AT_object_pointer
+; CHECK: DW_TAG_formal_parameter
;
; CHECK: DW_TAG_subprogram
-; CHECK: DW_AT_specification [DW_FORM_ref4] (cu + {{.*}} => {[[DECL]]}
; CHECK: DW_AT_object_pointer [DW_FORM_ref4] (cu + 0x{{[0-9a-f]*}} => {[[PARAM:0x[0-9a-f]*]]})
+; CHECK: DW_AT_specification [DW_FORM_ref4] (cu + {{.*}} => {[[DECL]]}
; CHECK: [[PARAM]]: DW_TAG_formal_parameter
; CHECK-NOT: DW_TAG
-; CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x{{[0-9a-f]*}}] = "this")
+; CHECK: DW_AT_name
+; CHECK-SAME = "this")
%class.A = type { i32 }
diff --git a/llvm/test/tools/llvm-dwarfdump/X86/statistics.ll b/llvm/test/tools/llvm-dwarfdump/X86/statistics.ll
index 9f3a00df2ffe75..77de0241daeabd 100644
--- a/llvm/test/tools/llvm-dwarfdump/X86/statistics.ll
+++ b/llvm/test/tools/llvm-dwarfdump/X86/statistics.ll
@@ -1,4 +1,4 @@
-; RUN: llc -O0 %s -o - -filetype=obj \
+; RUN: llc -O0 %s -o - -filetype=obj -debugger-tune=gdb -accel-tables=Apple \
; RUN: | llvm-dwarfdump -statistics - | FileCheck %s
; CHECK: "version": 9,
@@ -55,8 +55,8 @@
; CHECK: "#bytes within functions": [[FUNCSIZE:[0-9]+]]
; CHECK: "#bytes within inlined functions": [[INLINESIZE:[0-9]+]]
; CHECK: "#bytes in __debug_loc": 35,
-; CHECK-NEXT: "#bytes in __debug_abbrev": 386,
-; CHECK-NEXT: "#bytes in __debug_info": 463,
+; CHECK-NEXT: "#bytes in __debug_abbrev": 375,
+; CHECK-NEXT: "#bytes in __debug_info": 459,
; CHECK-NEXT: "#bytes in __debug_str": 231,
; CHECK-NEXT: "#bytes in __apple_names": 348,
; CHECK-NEXT: "#bytes in __apple_objc": 36,
More information about the llvm-commits
mailing list