Skip to content

[llvm][DebugInfo] Encode DW_AT_object_pointer on method declarations with DW_FORM_implicit_const #124790

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
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
28 changes: 26 additions & 2 deletions llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -895,7 +895,10 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DIDerivedType *DTy) {
}
}

void DwarfUnit::constructSubprogramArguments(DIE &Buffer, DITypeRefArray Args) {
std::optional<unsigned>
DwarfUnit::constructSubprogramArguments(DIE &Buffer, DITypeRefArray Args) {
// Args[0] is the return type.
std::optional<unsigned> ObjectPointerIndex;
for (unsigned i = 1, N = Args.size(); i < N; ++i) {
const DIType *Ty = Args[i];
if (!Ty) {
Expand All @@ -906,8 +909,16 @@ void DwarfUnit::constructSubprogramArguments(DIE &Buffer, DITypeRefArray Args) {
addType(Arg, Ty);
if (Ty->isArtificial())
addFlag(Arg, dwarf::DW_AT_artificial);

if (Ty->isObjectPointer()) {
assert(!ObjectPointerIndex &&
"Can't have more than one object pointer");
ObjectPointerIndex = i;
}
}
}

return ObjectPointerIndex;
}

void DwarfUnit::constructTypeDIE(DIE &Buffer, const DISubroutineType *CTy) {
Expand Down Expand Up @@ -1458,7 +1469,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.
constructSubprogramArguments(SPDie, Args);
//
// 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() &&
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is spec conformant, I don't think we need to hide in LLDB tuning.

Copy link
Member Author

@Michael137 Michael137 Jun 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GDB is currently not equipped with handling this unfortunately. See thread starting with #124790 (comment)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But let me try playing around with GDB again to remind myself whether it's an issue or not

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());
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 @@ -273,7 +273,11 @@ class DwarfUnit : public DIEUnit {
void constructContainingTypeDIEs();

/// Construct function argument DIEs.
void 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.
Expand Down
79 changes: 79 additions & 0 deletions llvm/test/DebugInfo/X86/DW_AT_object_pointer-non-standard-index.ll
Original file line number Diff line number Diff line change
@@ -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)
24 changes: 20 additions & 4 deletions llvm/test/DebugInfo/X86/DW_AT_object_pointer.ll
Original file line number Diff line number Diff line change
@@ -1,14 +1,30 @@
; 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: ""
; CHECK: DW_TAG
; CHECK: DW_TAG_class_type
; CHECK: DW_AT_object_pointer [DW_FORM_ref4] (cu + 0x{{[0-9a-f]*}} => {[[PARAM:0x[0-9a-f]*]]})
; CHECK: [[DECL:0x[0-9a-f]+]]: DW_TAG_subprogram
; CHECK: DW_AT_name {{.*}} "A"
; 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_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 }

Expand Down
4 changes: 2 additions & 2 deletions llvm/test/tools/llvm-dwarfdump/X86/statistics.ll
Original file line number Diff line number Diff line change
@@ -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,

Expand Down Expand Up @@ -55,7 +55,7 @@
; 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": 384,
; 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,
Expand Down