diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp index 2481a9bd3ce74..bfe6e7d6a802a 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -895,7 +895,10 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DIDerivedType *DTy) { } } -void DwarfUnit::constructSubprogramArguments(DIE &Buffer, DITypeRefArray Args) { +std::optional +DwarfUnit::constructSubprogramArguments(DIE &Buffer, DITypeRefArray Args) { + // Args[0] is the return type. + std::optional ObjectPointerIndex; for (unsigned i = 1, N = Args.size(); i < N; ++i) { const DIType *Ty = Args[i]; if (!Ty) { @@ -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) { @@ -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 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 e1156bccfb1ab..43bf197563867 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h @@ -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 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 0000000000000..40b791fd27e32 --- /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 d9988ac31451e..596727dce0433 100644 --- a/llvm/test/DebugInfo/X86/DW_AT_object_pointer.ll +++ b/llvm/test/DebugInfo/X86/DW_AT_object_pointer.ll @@ -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 } diff --git a/llvm/test/tools/llvm-dwarfdump/X86/statistics.ll b/llvm/test/tools/llvm-dwarfdump/X86/statistics.ll index a454bf14c3353..77de0241daeab 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,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,