[llvm] Supports viewing class member variables in lambda when using the vs debugger (PR #71564)

via llvm-commits llvm-commits at lists.llvm.org
Fri Nov 10 09:25:13 PST 2023


https://github.com/GkvJwa updated https://github.com/llvm/llvm-project/pull/71564

>From 9da52a7c9efc6963bb4939c9ea954e6d588b40fc Mon Sep 17 00:00:00 2001
From: GkvJwa <gkvjwa at gmail.com>
Date: Wed, 8 Nov 2023 01:37:19 +0800
Subject: [PATCH] Supports viewing class member in lambda when using the vs
 debugger

Use "__this" in DataMemberRecord, make vs debugger can be parsed normally
---
 llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp |   4 +
 llvm/test/DebugInfo/COFF/lambda-this-info.ll  | 245 ++++++++++++++++++
 2 files changed, 249 insertions(+)
 create mode 100644 llvm/test/DebugInfo/COFF/lambda-this-info.ll

diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
index 3a9d5fa3b936e0e..7d5a58a09eb8e99 100644
--- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
@@ -2605,6 +2605,10 @@ CodeViewDebug::lowerRecordFieldList(const DICompositeType *Ty) {
       MemberBaseType = TypeTable.writeLeafType(BFR);
     }
     uint64_t MemberOffsetInBytes = MemberOffsetInBits / 8;
+    if (Ty->getName().find("<lambda") != std::string::npos &&
+        MemberName == "this") {
+      MemberName = "__this";
+    }
     DataMemberRecord DMR(Access, MemberBaseType, MemberOffsetInBytes,
                          MemberName);
     ContinuationBuilder.writeMemberType(DMR);
diff --git a/llvm/test/DebugInfo/COFF/lambda-this-info.ll b/llvm/test/DebugInfo/COFF/lambda-this-info.ll
new file mode 100644
index 000000000000000..788bb5b3bf0a1eb
--- /dev/null
+++ b/llvm/test/DebugInfo/COFF/lambda-this-info.ll
@@ -0,0 +1,245 @@
+; RUN: llc -filetype=obj %s -o %t.obj
+; RUN: llvm-pdbutil dump -symbols -types %t.obj | FileCheck %s
+
+; C++ source to regenerate:
+; $ cat t.cpp
+; class Foo {
+; public:
+;   void foo() {
+;     int aa = 4;
+;     int bb = 5;
+;     int cc = 6;
+;     auto f = [=] {
+;       int aaa = a + aa;
+;       int bbb = b + bb;
+;       int ccc = c + cc;
+;     };
+;     f();
+;   }
+; 
+; private:
+;   int a = 1;
+;   int b = 2;
+;   int c = 3;
+; };
+; 
+; int main() {
+;   Foo f;
+;   f.foo();
+; 
+;   return 0;
+; }
+; $ clang t.cpp -S -emit-llvm -g -gcodeview -o t.ll
+
+; CHECK:                       Types (.debug$T)
+; CHECK-NEXT: ============================================================
+; CHECK:0x1003 | LF_CLASS [size = 36] `Foo`
+; CHECK:         unique name: `.?AVFoo@@`
+; CHECK:0x1006 | LF_FIELDLIST [size = 52]
+; CHECK:         - LF_MEMBER [name = `a`, Type = 0x0074 (int), offset = 0, attrs = private]
+; CHECK:         - LF_MEMBER [name = `b`, Type = 0x0074 (int), offset = 4, attrs = private]
+; CHECK:         - LF_MEMBER [name = `c`, Type = 0x0074 (int), offset = 8, attrs = private]
+; CHECK:         - LF_ONEMETHOD [name = `foo`]
+; CHECK:0x100C | LF_POINTER [size = 12]
+; CHECK:         referent = 0x1003, mode = pointer, opts = None, kind = ptr64
+; CHECK:0x100E | LF_CLASS [size = 80] `Foo::foo::<lambda_1>`
+; CHECK:         unique name: `.?AV<lambda_1>@?0??foo at Foo@@QEAAXXZ@`
+; CHECK:0x100F | LF_FIELDLIST [size = 72]
+; CHECK:         - LF_MEMBER [name = `__this`, Type = 0x100C, offset = 0, attrs = private]
+; CHECK:         - LF_MEMBER [name = `aa`, Type = 0x0074 (int), offset = 8, attrs = private]
+; CHECK:         - LF_MEMBER [name = `bb`, Type = 0x0074 (int), offset = 12, attrs = private]
+; CHECK:         - LF_MEMBER [name = `cc`, Type = 0x0074 (int), offset = 16, attrs = private]
+
+source_filename = "t.cpp"
+target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc19.37.32825"
+
+%class.Foo = type { i32, i32, i32 }
+%class.anon = type { ptr, i32, i32, i32 }
+
+$"??0Foo@@QEAA at XZ" = comdat any
+
+$"?foo at Foo@@QEAAXXZ" = comdat any
+
+$"??R<lambda_1>@?0??foo at Foo@@QEAAXXZ at QEBA?A?<auto>@@XZ" = comdat any
+
+; Function Attrs: mustprogress noinline norecurse optnone uwtable
+define dso_local noundef i32 @main() #0 !dbg !20 {
+entry:
+  %retval = alloca i32, align 4
+  %f = alloca %class.Foo, align 4
+  store i32 0, ptr %retval, align 4
+  call void @llvm.dbg.declare(metadata ptr %f, metadata !24, metadata !DIExpression()), !dbg !25
+  %call = call noundef ptr @"??0Foo@@QEAA at XZ"(ptr noundef nonnull align 4 dereferenceable(12) %f) #5, !dbg !25
+  call void @"?foo at Foo@@QEAAXXZ"(ptr noundef nonnull align 4 dereferenceable(12) %f), !dbg !26
+  ret i32 0, !dbg !27
+}
+
+; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
+
+; Function Attrs: noinline nounwind optnone uwtable
+define linkonce_odr dso_local noundef ptr @"??0Foo@@QEAA at XZ"(ptr noundef nonnull returned align 4 dereferenceable(12) %this) unnamed_addr #2 comdat align 2 !dbg !28 {
+entry:
+  %this.addr = alloca ptr, align 8
+  store ptr %this, ptr %this.addr, align 8
+  call void @llvm.dbg.declare(metadata ptr %this.addr, metadata !30, metadata !DIExpression()), !dbg !32
+  %this1 = load ptr, ptr %this.addr, align 8
+  %a = getelementptr inbounds %class.Foo, ptr %this1, i32 0, i32 0, !dbg !33
+  store i32 1, ptr %a, align 4, !dbg !33
+  %b = getelementptr inbounds %class.Foo, ptr %this1, i32 0, i32 1, !dbg !33
+  store i32 2, ptr %b, align 4, !dbg !33
+  %c = getelementptr inbounds %class.Foo, ptr %this1, i32 0, i32 2, !dbg !33
+  store i32 3, ptr %c, align 4, !dbg !33
+  ret ptr %this1, !dbg !33
+}
+
+; Function Attrs: mustprogress noinline optnone uwtable
+define linkonce_odr dso_local void @"?foo at Foo@@QEAAXXZ"(ptr noundef nonnull align 4 dereferenceable(12) %this) #3 comdat align 2 !dbg !34 {
+entry:
+  %this.addr = alloca ptr, align 8
+  %aa = alloca i32, align 4
+  %bb = alloca i32, align 4
+  %cc = alloca i32, align 4
+  %f = alloca %class.anon, align 8
+  store ptr %this, ptr %this.addr, align 8
+  call void @llvm.dbg.declare(metadata ptr %this.addr, metadata !35, metadata !DIExpression()), !dbg !36
+  %this1 = load ptr, ptr %this.addr, align 8
+  call void @llvm.dbg.declare(metadata ptr %aa, metadata !37, metadata !DIExpression()), !dbg !38
+  store i32 4, ptr %aa, align 4, !dbg !38
+  call void @llvm.dbg.declare(metadata ptr %bb, metadata !39, metadata !DIExpression()), !dbg !40
+  store i32 5, ptr %bb, align 4, !dbg !40
+  call void @llvm.dbg.declare(metadata ptr %cc, metadata !41, metadata !DIExpression()), !dbg !42
+  store i32 6, ptr %cc, align 4, !dbg !42
+  call void @llvm.dbg.declare(metadata ptr %f, metadata !43, metadata !DIExpression()), !dbg !50
+  %0 = getelementptr inbounds %class.anon, ptr %f, i32 0, i32 0, !dbg !50
+  store ptr %this1, ptr %0, align 8, !dbg !50
+  %1 = getelementptr inbounds %class.anon, ptr %f, i32 0, i32 1, !dbg !50
+  %2 = load i32, ptr %aa, align 4, !dbg !50
+  store i32 %2, ptr %1, align 8, !dbg !50
+  %3 = getelementptr inbounds %class.anon, ptr %f, i32 0, i32 2, !dbg !50
+  %4 = load i32, ptr %bb, align 4, !dbg !50
+  store i32 %4, ptr %3, align 4, !dbg !50
+  %5 = getelementptr inbounds %class.anon, ptr %f, i32 0, i32 3, !dbg !50
+  %6 = load i32, ptr %cc, align 4, !dbg !50
+  store i32 %6, ptr %5, align 8, !dbg !50
+  call void @"??R<lambda_1>@?0??foo at Foo@@QEAAXXZ at QEBA?A?<auto>@@XZ"(ptr noundef nonnull align 8 dereferenceable(24) %f), !dbg !51
+  ret void, !dbg !52
+}
+
+; Function Attrs: mustprogress noinline nounwind optnone uwtable
+define linkonce_odr dso_local void @"??R<lambda_1>@?0??foo at Foo@@QEAAXXZ at QEBA?A?<auto>@@XZ"(ptr noundef nonnull align 8 dereferenceable(24) %this) #4 comdat align 2 !dbg !53 {
+entry:
+  %this.addr = alloca ptr, align 8
+  %aaa = alloca i32, align 4
+  %bbb = alloca i32, align 4
+  %ccc = alloca i32, align 4
+  store ptr %this, ptr %this.addr, align 8
+  call void @llvm.dbg.declare(metadata ptr %this.addr, metadata !59, metadata !DIExpression()), !dbg !61
+  %this1 = load ptr, ptr %this.addr, align 8
+  %0 = getelementptr inbounds %class.anon, ptr %this1, i32 0, i32 0
+  %1 = load ptr, ptr %0, align 8
+  call void @llvm.dbg.declare(metadata ptr %aaa, metadata !62, metadata !DIExpression()), !dbg !63
+  %a = getelementptr inbounds %class.Foo, ptr %1, i32 0, i32 0, !dbg !63
+  %2 = load i32, ptr %a, align 4, !dbg !63
+  %3 = getelementptr inbounds %class.anon, ptr %this1, i32 0, i32 1, !dbg !63
+  %4 = load i32, ptr %3, align 8, !dbg !63
+  %add = add nsw i32 %2, %4, !dbg !63
+  store i32 %add, ptr %aaa, align 4, !dbg !63
+  call void @llvm.dbg.declare(metadata ptr %bbb, metadata !64, metadata !DIExpression()), !dbg !65
+  %b = getelementptr inbounds %class.Foo, ptr %1, i32 0, i32 1, !dbg !65
+  %5 = load i32, ptr %b, align 4, !dbg !65
+  %6 = getelementptr inbounds %class.anon, ptr %this1, i32 0, i32 2, !dbg !65
+  %7 = load i32, ptr %6, align 4, !dbg !65
+  %add2 = add nsw i32 %5, %7, !dbg !65
+  store i32 %add2, ptr %bbb, align 4, !dbg !65
+  call void @llvm.dbg.declare(metadata ptr %ccc, metadata !66, metadata !DIExpression()), !dbg !67
+  %c = getelementptr inbounds %class.Foo, ptr %1, i32 0, i32 2, !dbg !67
+  %8 = load i32, ptr %c, align 4, !dbg !67
+  %9 = getelementptr inbounds %class.anon, ptr %this1, i32 0, i32 3, !dbg !67
+  %10 = load i32, ptr %9, align 8, !dbg !67
+  %add3 = add nsw i32 %8, %10, !dbg !67
+  store i32 %add3, ptr %ccc, align 4, !dbg !67
+  ret void, !dbg !68
+}
+
+attributes #0 = { mustprogress noinline norecurse optnone uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+attributes #1 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
+attributes #2 = { noinline nounwind optnone uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+attributes #3 = { mustprogress noinline optnone uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+attributes #4 = { mustprogress noinline nounwind optnone uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+attributes #5 = { nounwind }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!13, !14, !15, !16, !17, !18}
+!llvm.ident = !{!19}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 18.0.0 (https://github.com/llvm/llvm-project.git 11c182740a3b57a05a2d8cd2eb398a02165d4a57)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, retainedTypes: !2, splitDebugInlining: false, nameTableKind: None)
+!1 = !DIFile(filename: "t.cpp", directory: "/")
+!2 = !{!3}
+!3 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "Foo", file: !1, line: 1, size: 96, flags: DIFlagTypePassByValue | DIFlagNonTrivial, elements: !4, identifier: ".?AVFoo@@")
+!4 = !{!5, !7, !8, !9}
+!5 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !3, file: !1, line: 16, baseType: !6, size: 32)
+!6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!7 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !3, file: !1, line: 17, baseType: !6, size: 32, offset: 32)
+!8 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !3, file: !1, line: 18, baseType: !6, size: 32, offset: 64)
+!9 = !DISubprogram(name: "foo", linkageName: "?foo at Foo@@QEAAXXZ", scope: !3, file: !1, line: 3, type: !10, scopeLine: 3, flags: DIFlagPublic | DIFlagPrototyped, spFlags: 0)
+!10 = !DISubroutineType(types: !11)
+!11 = !{null, !12}
+!12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !3, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!13 = !{i32 2, !"CodeView", i32 1}
+!14 = !{i32 2, !"Debug Info Version", i32 3}
+!15 = !{i32 1, !"wchar_size", i32 2}
+!16 = !{i32 8, !"PIC Level", i32 2}
+!17 = !{i32 7, !"uwtable", i32 2}
+!18 = !{i32 1, !"MaxTLSAlign", i32 65536}
+!19 = !{!"clang version 18.0.0 (https://github.com/llvm/llvm-project.git 11c182740a3b57a05a2d8cd2eb398a02165d4a57)"}
+!20 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 21, type: !21, scopeLine: 21, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !23)
+!21 = !DISubroutineType(types: !22)
+!22 = !{!6}
+!23 = !{}
+!24 = !DILocalVariable(name: "f", scope: !20, file: !1, line: 22, type: !3)
+!25 = !DILocation(line: 22, scope: !20)
+!26 = !DILocation(line: 23, scope: !20)
+!27 = !DILocation(line: 25, scope: !20)
+!28 = distinct !DISubprogram(name: "Foo", linkageName: "??0Foo@@QEAA at XZ", scope: !3, file: !1, line: 1, type: !10, scopeLine: 1, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !29, retainedNodes: !23)
+!29 = !DISubprogram(name: "Foo", scope: !3, type: !10, flags: DIFlagPublic | DIFlagArtificial | DIFlagPrototyped, spFlags: 0)
+!30 = !DILocalVariable(name: "this", arg: 1, scope: !28, type: !31, flags: DIFlagArtificial | DIFlagObjectPointer)
+!31 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !3, size: 64)
+!32 = !DILocation(line: 0, scope: !28)
+!33 = !DILocation(line: 1, scope: !28)
+!34 = distinct !DISubprogram(name: "foo", linkageName: "?foo at Foo@@QEAAXXZ", scope: !3, file: !1, line: 3, type: !10, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !9, retainedNodes: !23)
+!35 = !DILocalVariable(name: "this", arg: 1, scope: !34, type: !31, flags: DIFlagArtificial | DIFlagObjectPointer)
+!36 = !DILocation(line: 0, scope: !34)
+!37 = !DILocalVariable(name: "aa", scope: !34, file: !1, line: 4, type: !6)
+!38 = !DILocation(line: 4, scope: !34)
+!39 = !DILocalVariable(name: "bb", scope: !34, file: !1, line: 5, type: !6)
+!40 = !DILocation(line: 5, scope: !34)
+!41 = !DILocalVariable(name: "cc", scope: !34, file: !1, line: 6, type: !6)
+!42 = !DILocation(line: 6, scope: !34)
+!43 = !DILocalVariable(name: "f", scope: !34, file: !1, line: 7, type: !44)
+!44 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "<lambda_1>", scope: !34, file: !1, line: 7, size: 192, flags: DIFlagTypePassByValue | DIFlagNonTrivial, elements: !45, identifier: ".?AV<lambda_1>@?0??foo at Foo@@QEAAXXZ@")
+!45 = !{!46, !47, !48, !49}
+!46 = !DIDerivedType(tag: DW_TAG_member, name: "this", scope: !44, file: !1, line: 8, baseType: !31, size: 64)
+!47 = !DIDerivedType(tag: DW_TAG_member, name: "aa", scope: !44, file: !1, line: 8, baseType: !6, size: 32, offset: 64)
+!48 = !DIDerivedType(tag: DW_TAG_member, name: "bb", scope: !44, file: !1, line: 9, baseType: !6, size: 32, offset: 96)
+!49 = !DIDerivedType(tag: DW_TAG_member, name: "cc", scope: !44, file: !1, line: 10, baseType: !6, size: 32, offset: 128)
+!50 = !DILocation(line: 7, scope: !34)
+!51 = !DILocation(line: 12, scope: !34)
+!52 = !DILocation(line: 13, scope: !34)
+!53 = distinct !DISubprogram(name: "operator()", linkageName: "??R<lambda_1>@?0??foo at Foo@@QEAAXXZ at QEBA?A?<auto>@@XZ", scope: !44, file: !1, line: 7, type: !54, scopeLine: 7, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !58, retainedNodes: !23)
+!54 = !DISubroutineType(types: !55)
+!55 = !{null, !56}
+!56 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !57, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!57 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !44)
+!58 = !DISubprogram(name: "operator()", scope: !44, file: !1, line: 7, type: !54, scopeLine: 7, flags: DIFlagPublic | DIFlagPrototyped, spFlags: 0)
+!59 = !DILocalVariable(name: "this", arg: 1, scope: !53, type: !60, flags: DIFlagArtificial | DIFlagObjectPointer)
+!60 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !57, size: 64)
+!61 = !DILocation(line: 0, scope: !53)
+!62 = !DILocalVariable(name: "aaa", scope: !53, file: !1, line: 8, type: !6)
+!63 = !DILocation(line: 8, scope: !53)
+!64 = !DILocalVariable(name: "bbb", scope: !53, file: !1, line: 9, type: !6)
+!65 = !DILocation(line: 9, scope: !53)
+!66 = !DILocalVariable(name: "ccc", scope: !53, file: !1, line: 10, type: !6)
+!67 = !DILocation(line: 10, scope: !53)
+!68 = !DILocation(line: 11, scope: !53)



More information about the llvm-commits mailing list