diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -34,6 +34,7 @@ #include "llvm/IR/Constant.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" +#include "llvm/IR/DebugInfo.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Function.h" #include "llvm/IR/GlobalVariable.h" @@ -223,6 +224,7 @@ S->setMetadata(LLVMContext::MD_mem_parallel_loop_access, LoopMemParallelMD); if (AccessGroupMD) S->setMetadata(LLVMContext::MD_access_group, AccessGroupMD); + S->copyMetadata(*MI, LLVMContext::MD_DIAssignID); if (auto *MT = dyn_cast(MI)) { // non-atomics can be volatile @@ -294,9 +296,15 @@ Dest = Builder.CreateBitCast(Dest, NewDstPtrTy); // Extract the fill value and store. - uint64_t Fill = FillC->getZExtValue()*0x0101010101010101ULL; - StoreInst *S = Builder.CreateStore(ConstantInt::get(ITy, Fill), Dest, - MI->isVolatile()); + const uint64_t Fill = FillC->getZExtValue()*0x0101010101010101ULL; + Constant *FillVal = ConstantInt::get(ITy, Fill); + StoreInst *S = Builder.CreateStore(FillVal, Dest, MI->isVolatile()); + S->copyMetadata(*MI, LLVMContext::MD_DIAssignID); + for (auto *DAI : at::getAssignmentMarkers(S)) { + if (any_of(DAI->location_ops(), [&](Value *V) { return V == FillC; })) + DAI->replaceVariableLocationOp(FillC, FillVal); + } + S->setAlignment(Alignment); if (isa(MI)) S->setOrdering(AtomicOrdering::Unordered); diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp @@ -14,6 +14,7 @@ #include "llvm/ADT/SetVector.h" #include "llvm/Analysis/ConstantFolding.h" #include "llvm/IR/DataLayout.h" +#include "llvm/IR/DebugInfo.h" #include "llvm/IR/PatternMatch.h" #include "llvm/Support/KnownBits.h" #include "llvm/Transforms/InstCombine/InstCombiner.h" @@ -163,6 +164,8 @@ New->setAlignment(AI.getAlign()); New->takeName(&AI); New->setUsedWithInAlloca(AI.isUsedWithInAlloca()); + New->setMetadata(LLVMContext::MD_DIAssignID, + AI.getMetadata(LLVMContext::MD_DIAssignID)); // If the allocation has multiple real uses, insert a cast and change all // things that used it to use the new cast. This will also hack on CI, but it diff --git a/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp b/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp @@ -511,6 +511,7 @@ // here. switch (ID) { case LLVMContext::MD_dbg: + case LLVMContext::MD_DIAssignID: case LLVMContext::MD_tbaa: case LLVMContext::MD_prof: case LLVMContext::MD_fpmath: @@ -1554,6 +1555,7 @@ SI.getOrdering(), SI.getSyncScopeID()); InsertNewInstBefore(NewSI, *BBI); NewSI->setDebugLoc(MergedLoc); + NewSI->mergeDIAssignID({&SI, OtherStore}); // If the two stores had AA tags, merge them. AAMDNodes AATags = SI.getAAMetadata(); diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp --- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -4163,6 +4163,11 @@ if (!SunkVariables.insert(DbgUserVariable).second) continue; + // Leave dbg.assign intrinsics in their original positions and there should + // be no need to insert a clone. + if (isa(User)) + continue; + DIIClones.emplace_back(cast(User->clone())); if (isa(User) && isa(I)) DIIClones.back()->replaceVariableLocationOp(I, I->getOperand(0)); diff --git a/llvm/test/DebugInfo/Generic/assignment-tracking/instcombine/alloca-bitcast.ll b/llvm/test/DebugInfo/Generic/assignment-tracking/instcombine/alloca-bitcast.ll new file mode 100644 --- /dev/null +++ b/llvm/test/DebugInfo/Generic/assignment-tracking/instcombine/alloca-bitcast.ll @@ -0,0 +1,74 @@ +; RUN: opt -passes=instcombine -S %s -o - -experimental-assignment-tracking \ +; RUN: | FileCheck %s + +;; NOTE: This test uses typed pointers because it is testing a code path that +;; doesn't get exercised with opaque pointers. If/when PromoteCastOfAllocation +;; is removed from visitBitCast this test should just be deleted. + +;; Check that allocas generated in InstCombine's PromoteCastOfAllocation +;; have DIAssignID copied from the original alloca. +;; +;; $ cat reduce.cpp +;; struct c { +;; c(int); +;; int a, b; +;; }; +;; c d() { +;; c e(1); +;; return e; +;; } +;; $ clang -O2 -c -g reduce.cpp -fno-inline -Xclang -disable-llvm-passes -emit-llvm -S \ +;; | opt -passes=declare-to-assign -S + +; CHECK: entry: +; CHECK-NEXT: %retval = alloca i64, align 8, !DIAssignID ![[ID:[0-9]+]] +; CHECK-NEXT: %tmpcast = bitcast i64* %retval to %struct.c* +; CHECK-NEXT: call void @llvm.dbg.assign(metadata i1 undef, metadata ![[e:[0-9]+]], metadata !DIExpression(), metadata ![[ID]], metadata %struct.c* %tmpcast, metadata !DIExpression()), !dbg +; CHECK: ![[e]] = !DILocalVariable(name: "e", + +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + +%struct.c = type { i32, i32 } + +define dso_local i64 @_Z1dv() !dbg !7 { +entry: + %retval = alloca %struct.c, align 4, !DIAssignID !21 + call void @llvm.dbg.assign(metadata i1 undef, metadata !20, metadata !DIExpression(), metadata !21, metadata %struct.c* %retval, metadata !DIExpression()), !dbg !22 + call void @_ZN1cC1Ei(%struct.c* %retval, i32 1), !dbg !23 + %0 = bitcast %struct.c* %retval to i64*, !dbg !24 + %1 = load i64, i64* %0, align 4, !dbg !24 + ret i64 %1, !dbg !24 +} + +declare dso_local void @_ZN1cC1Ei(%struct.c*, i32) unnamed_addr +declare void @llvm.dbg.assign(metadata, metadata, metadata, metadata, metadata, metadata) + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 12.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "reduce.cpp", directory: "/") +!2 = !{} +!3 = !{i32 7, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 12.0.0"} +!7 = distinct !DISubprogram(name: "d", linkageName: "_Z1dv", scope: !1, file: !1, line: 5, type: !8, scopeLine: 5, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !19) +!8 = !DISubroutineType(types: !9) +!9 = !{!10} +!10 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "c", file: !1, line: 1, size: 64, flags: DIFlagTypePassByValue | DIFlagNonTrivial, elements: !11, identifier: "_ZTS1c") +!11 = !{!12, !14, !15} +!12 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !10, file: !1, line: 3, baseType: !13, size: 32) +!13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!14 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !10, file: !1, line: 3, baseType: !13, size: 32, offset: 32) +!15 = !DISubprogram(name: "c", scope: !10, file: !1, line: 2, type: !16, scopeLine: 2, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized) +!16 = !DISubroutineType(types: !17) +!17 = !{null, !18, !13} +!18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !10, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) +!19 = !{!20} +!20 = !DILocalVariable(name: "e", scope: !7, file: !1, line: 6, type: !10) +!21 = distinct !DIAssignID() +!22 = !DILocation(line: 0, scope: !7) +!23 = !DILocation(line: 6, column: 5, scope: !7) +!24 = !DILocation(line: 7, column: 3, scope: !7) diff --git a/llvm/test/DebugInfo/Generic/assignment-tracking/instcombine/memset.ll b/llvm/test/DebugInfo/Generic/assignment-tracking/instcombine/memset.ll new file mode 100644 --- /dev/null +++ b/llvm/test/DebugInfo/Generic/assignment-tracking/instcombine/memset.ll @@ -0,0 +1,78 @@ +; RUN: opt %s -S -passes=instcombine -o - -experimental-assignment-tracking \ +; RUN: | FileCheck %s + +;; $ cat test.cpp +;; void esc(int*); +;; void fun() { +;; int local[5]; +;; __builtin_memset(local, 8, 4 * 4); +;; __builtin_memset(local, 0, 2 * 4); +;; esc(local); +;; } +;; IR grabbed before instcombine in: +;; clang++ -O2 -g -Xclang -fexperimental-assignment-tracking + +;; Instcombine is going to turn the second memset into a store. Check that it +;; inherits the DIAssignID from the memset and that the dbg.assign's value +;; component is correct. + +; CHECK: store i64 0, ptr %local, align 16{{.*}}, !DIAssignID ![[ID:[0-9]+]] +; CHECK-NEXT: call void @llvm.dbg.assign(metadata i64 0, metadata !{{.*}}, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 64), metadata ![[ID]], metadata ptr %local, metadata !DIExpression()) + +define dso_local void @_Z3funv() local_unnamed_addr #0 !dbg !7 { +entry: + %local = alloca [5 x i32], align 16, !DIAssignID !16 + call void @llvm.dbg.assign(metadata i1 undef, metadata !11, metadata !DIExpression(), metadata !16, metadata ptr %local, metadata !DIExpression()), !dbg !17 + %0 = bitcast ptr %local to ptr, !dbg !18 + call void @llvm.lifetime.start.p0i8(i64 20, ptr %0) #5, !dbg !18 + %arraydecay = getelementptr inbounds [5 x i32], ptr %local, i64 0, i64 0, !dbg !19 + %1 = bitcast ptr %arraydecay to ptr, !dbg !19 + call void @llvm.memset.p0i8.i64(ptr align 16 %1, i8 8, i64 16, i1 false), !dbg !19, !DIAssignID !20 + call void @llvm.dbg.assign(metadata i8 8, metadata !11, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 128), metadata !20, metadata ptr %1, metadata !DIExpression()), !dbg !17 + call void @llvm.memset.p0i8.i64(ptr align 16 %1, i8 0, i64 8, i1 false), !dbg !21, !DIAssignID !22 + call void @llvm.dbg.assign(metadata i8 0, metadata !11, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 64), metadata !22, metadata ptr %1, metadata !DIExpression()), !dbg !17 + call void @_Z3escPi(ptr noundef %arraydecay), !dbg !23 + call void @llvm.lifetime.end.p0i8(i64 20, ptr %0) #5, !dbg !24 + ret void, !dbg !24 +} + +declare void @llvm.lifetime.start.p0i8(i64 immarg, ptr nocapture) +declare void @llvm.memset.p0i8.i64(ptr nocapture writeonly, i8, i64, i1 immarg) +declare !dbg !25 dso_local void @_Z3escPi(ptr noundef) local_unnamed_addr +declare void @llvm.lifetime.end.p0i8(i64 immarg, ptr nocapture) +declare void @llvm.dbg.assign(metadata, metadata, metadata, metadata, metadata, metadata) + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!2, !3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 14.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "test.cpp", directory: "/") +!2 = !{i32 7, !"Dwarf Version", i32 5} +!3 = !{i32 2, !"Debug Info Version", i32 3} +!4 = !{i32 1, !"wchar_size", i32 4} +!5 = !{i32 7, !"uwtable", i32 1} +!6 = !{!"clang version 14.0.0"} +!7 = distinct !DISubprogram(name: "fun", linkageName: "_Z3funv", scope: !1, file: !1, line: 2, type: !8, scopeLine: 2, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !10) +!8 = !DISubroutineType(types: !9) +!9 = !{null} +!10 = !{!11} +!11 = !DILocalVariable(name: "local", scope: !7, file: !1, line: 3, type: !12) +!12 = !DICompositeType(tag: DW_TAG_array_type, baseType: !13, size: 160, elements: !14) +!13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!14 = !{!15} +!15 = !DISubrange(count: 5) +!16 = distinct !DIAssignID() +!17 = !DILocation(line: 0, scope: !7) +!18 = !DILocation(line: 3, column: 3, scope: !7) +!19 = !DILocation(line: 4, column: 3, scope: !7) +!20 = distinct !DIAssignID() +!21 = !DILocation(line: 5, column: 3, scope: !7) +!22 = distinct !DIAssignID() +!23 = !DILocation(line: 6, column: 3, scope: !7) +!24 = !DILocation(line: 7, column: 1, scope: !7) +!25 = !DISubprogram(name: "esc", linkageName: "_Z3escPi", scope: !1, file: !1, line: 1, type: !26, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !29) +!26 = !DISubroutineType(types: !27) +!27 = !{null, !28} +!28 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64) +!29 = !{} diff --git a/llvm/test/DebugInfo/Generic/assignment-tracking/instcombine/sink-store.ll b/llvm/test/DebugInfo/Generic/assignment-tracking/instcombine/sink-store.ll new file mode 100644 --- /dev/null +++ b/llvm/test/DebugInfo/Generic/assignment-tracking/instcombine/sink-store.ll @@ -0,0 +1,108 @@ +; RUN: opt %s -S -passes=instcombine -experimental-assignment-tracking | FileCheck %s + +;; Check that instcombine merges the DIAssignID metadata when merging two +;; stores into a successor. Filecheck directives inline. +;; +;; Generated from the following source: +;; int c; +;; void esc(int*); +;; int get(); +;; void fun() { +;; int local; +;; if (c) { +;; get(); +;; local = 2; +;; } else { +;; local = 2; +;; } +;; esc(&local); +;; } + +; CHECK: if.then: +; CHECK-NEXT: %call = call +; CHECK-NEXT: call void @llvm.dbg.assign(metadata i32 2, metadata ![[LOCAL:[0-9]+]], metadata !DIExpression(), metadata ![[MERGED_ID:[0-9]+]], metadata ptr %local, metadata !DIExpression()), !dbg + +; CHECK: if.else: +; CHECK-NEXT: call void @llvm.dbg.assign(metadata i32 2, metadata ![[LOCAL]], metadata !DIExpression(), metadata ![[MERGED_ID]], metadata ptr %local, metadata !DIExpression()), !dbg + +; CHECK: if.end: +; CHECK-NEXT: store i32 2, ptr %local{{.*}}!DIAssignID ![[MERGED_ID]] + +; CHECK: ![[LOCAL]] = !DILocalVariable(name: "local", + +@c = dso_local local_unnamed_addr global i32 0, align 4, !dbg !0 + +; Function Attrs: uwtable mustprogress +define dso_local void @_Z3funv() local_unnamed_addr !dbg !11 { +entry: + %local = alloca i32, align 4 + %0 = bitcast ptr %local to ptr, !dbg !16 + call void @llvm.lifetime.start.p0i8(i64 4, ptr %0), !dbg !16 + %1 = load i32, ptr @c, align 4, !dbg !17 + %tobool = icmp ne i32 %1, 0, !dbg !17 + br i1 %tobool, label %if.then, label %if.else, !dbg !23 + +if.then: ; preds = %entry + %call = call i32 @_Z3getv(), !dbg !24 + store i32 2, ptr %local, align 4, !dbg !26, !DIAssignID !27 + call void @llvm.dbg.assign(metadata i32 2, metadata !15, metadata !DIExpression(), metadata !27, metadata ptr %local, metadata !DIExpression()), !dbg !26 + br label %if.end, !dbg !28 + +if.else: ; preds = %entry + store i32 2, ptr %local, align 4, !dbg !29, !DIAssignID !31 + call void @llvm.dbg.assign(metadata i32 2, metadata !15, metadata !DIExpression(), metadata !31, metadata ptr %local, metadata !DIExpression()), !dbg !29 + br label %if.end + +if.end: ; preds = %if.else, %if.then + call void @_Z3escPi(ptr %local), !dbg !32 + call void @llvm.lifetime.end.p0i8(i64 4, ptr %0), !dbg !33 + ret void, !dbg !33 +} + +declare !dbg !34 dso_local i32 @_Z3getv() local_unnamed_addr +declare !dbg !37 dso_local void @_Z3escPi(ptr) local_unnamed_addr +declare void @llvm.lifetime.start.p0i8(i64 immarg, ptr nocapture) +declare void @llvm.lifetime.end.p0i8(i64 immarg, ptr nocapture) +declare void @llvm.dbg.assign(metadata, metadata, metadata, metadata, metadata, metadata) + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!7, !8, !9} +!llvm.ident = !{!10} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "c", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, producer: "clang version 12.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, splitDebugInlining: false, nameTableKind: None) +!3 = !DIFile(filename: "test.cpp", directory: "/") +!4 = !{} +!5 = !{!0} +!6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!7 = !{i32 7, !"Dwarf Version", i32 4} +!8 = !{i32 2, !"Debug Info Version", i32 3} +!9 = !{i32 1, !"wchar_size", i32 4} +!10 = !{!"clang version 12.0.0"} +!11 = distinct !DISubprogram(name: "fun", linkageName: "_Z3funv", scope: !3, file: !3, line: 4, type: !12, scopeLine: 4, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !14) +!12 = !DISubroutineType(types: !13) +!13 = !{null} +!14 = !{!15} +!15 = !DILocalVariable(name: "local", scope: !11, file: !3, line: 5, type: !6) +!16 = !DILocation(line: 5, column: 3, scope: !11) +!17 = !DILocation(line: 6, column: 7, scope: !18) +!18 = distinct !DILexicalBlock(scope: !11, file: !3, line: 6, column: 7) +!23 = !DILocation(line: 6, column: 7, scope: !11) +!24 = !DILocation(line: 7, column: 5, scope: !25) +!25 = distinct !DILexicalBlock(scope: !18, file: !3, line: 6, column: 10) +!26 = !DILocation(line: 8, column: 11, scope: !25) +!27 = distinct !DIAssignID() +!28 = !DILocation(line: 9, column: 3, scope: !25) +!29 = !DILocation(line: 10, column: 11, scope: !30) +!30 = distinct !DILexicalBlock(scope: !18, file: !3, line: 9, column: 10) +!31 = distinct !DIAssignID() +!32 = !DILocation(line: 12, column: 3, scope: !11) +!33 = !DILocation(line: 13, column: 1, scope: !11) +!34 = !DISubprogram(name: "get", linkageName: "_Z3getv", scope: !3, file: !3, line: 3, type: !35, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !4) +!35 = !DISubroutineType(types: !36) +!36 = !{!6} +!37 = !DISubprogram(name: "esc", linkageName: "_Z3escPi", scope: !3, file: !3, line: 2, type: !38, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !4) +!38 = !DISubroutineType(types: !39) +!39 = !{null, !40} +!40 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !6, size: 64) diff --git a/llvm/test/DebugInfo/Generic/assignment-tracking/instcombine/sink.ll b/llvm/test/DebugInfo/Generic/assignment-tracking/instcombine/sink.ll new file mode 100644 --- /dev/null +++ b/llvm/test/DebugInfo/Generic/assignment-tracking/instcombine/sink.ll @@ -0,0 +1,142 @@ +; RUN: opt %s -S -passes=instcombine -o - -experimental-assignment-tracking \ +; RUN: | FileCheck %s + +;; Check that when instcombine sinks an instruction used by a dbg.assign, the +;; usual debug intrinsic updating doesn't take place (i.e. do not +;; clone-and-sink a dbg.assign). Assignment tracking should be able to handle +;; this gracefully for variables that still have a stack home. For fully +;; promoted variables we may need to revisit this. + +;; $ cat test.c +;; struct a { +;; char *b; +;; } c() __attribute__((noreturn)); +;; int d; +;; int e(); +;; int f() { +;; if (e()) +;; return d; +;; c(); +;; } +;; void g(); +;; void h() { +;; struct a i; +;; i.b = 0; +;; f(); +;; i.b = 0; +;; g(&i); +;; } +;; $ clang -O2 -g -Xclang -fexperimental-assignment-tracking + +; CHECK: f.exit: +; CHECK-NEXT: store ptr null, ptr %i, align 8,{{.+}}, !DIAssignID ![[ID:[0-9]+]] +; CHECK-NEXT: call void @llvm.dbg.assign({{.+}}, {{.+}}, {{.+}}, metadata ![[ID]], metadata ptr %i, {{.+}}), !dbg + +%struct.a = type { ptr } + +@d = dso_local local_unnamed_addr global i32 0, align 4, !dbg !0 + +; Function Attrs: nounwind uwtable +define dso_local i32 @f() local_unnamed_addr #0 !dbg !11 { +entry: + %call = tail call i32 (...) @e() #5, !dbg !14 + %tobool.not = icmp eq i32 %call, 0, !dbg !14 + br i1 %tobool.not, label %if.end, label %if.then, !dbg !16 + +if.then: ; preds = %entry + %0 = load i32, ptr @d, align 4, !dbg !17 + ret i32 %0, !dbg !22 + +if.end: ; preds = %entry + %call1 = tail call ptr (...) @c() #6, !dbg !23 + unreachable, !dbg !23 +} + +declare !dbg !24 dso_local i32 @e(...) local_unnamed_addr #1 + +; Function Attrs: noreturn +declare !dbg !27 dso_local ptr @c(...) local_unnamed_addr #2 + +; Function Attrs: nounwind uwtable +define dso_local void @h() local_unnamed_addr #0 !dbg !35 { +entry: + %i = alloca %struct.a, align 8, !DIAssignID !40 + call void @llvm.dbg.assign(metadata i1 undef, metadata !39, metadata !DIExpression(), metadata !40, metadata ptr %i, metadata !DIExpression()), !dbg !41 + %0 = bitcast ptr %i to ptr, !dbg !42 + call void @llvm.lifetime.start.p0i8(i64 8, ptr nonnull %0) #5, !dbg !42 + %b = getelementptr inbounds %struct.a, ptr %i, i64 0, i32 0, !dbg !43 + call void @llvm.dbg.assign(metadata ptr null, metadata !39, metadata !DIExpression(), metadata !44, metadata ptr %b, metadata !DIExpression()), !dbg !41 + %call.i = tail call i32 (...) @e() #5, !dbg !45 + %tobool.not.i = icmp eq i32 %call.i, 0, !dbg !45 + br i1 %tobool.not.i, label %if.end.i, label %f.exit, !dbg !47 + +if.end.i: ; preds = %entry + %call1.i = tail call ptr (...) @c() #6, !dbg !48 + unreachable, !dbg !48 + +f.exit: ; preds = %entry + store ptr null, ptr %b, align 8, !dbg !49, !DIAssignID !53 + call void @llvm.dbg.assign(metadata ptr null, metadata !39, metadata !DIExpression(), metadata !53, metadata ptr %b, metadata !DIExpression()), !dbg !41 + call void @g(ptr nonnull %i) #5, !dbg !54 + call void @llvm.lifetime.end.p0i8(i64 8, ptr nonnull %0) #5, !dbg !55 + ret void, !dbg !55 +} + +declare void @llvm.lifetime.start.p0i8(i64 immarg, ptr nocapture) #3 +declare dso_local void @g(...) local_unnamed_addr #1 +declare void @llvm.lifetime.end.p0i8(i64 immarg, ptr nocapture) #3 +declare void @llvm.dbg.assign(metadata, metadata, metadata, metadata, metadata, metadata) #4 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!7, !8, !9} +!llvm.ident = !{!10} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "d", scope: !2, file: !3, line: 4, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 12.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, splitDebugInlining: false, nameTableKind: None) +!3 = !DIFile(filename: "test.c", directory: "/") +!4 = !{} +!5 = !{!0} +!6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!7 = !{i32 7, !"Dwarf Version", i32 4} +!8 = !{i32 2, !"Debug Info Version", i32 3} +!9 = !{i32 1, !"wchar_size", i32 4} +!10 = !{!"clang version 12.0.0"} +!11 = distinct !DISubprogram(name: "f", scope: !3, file: !3, line: 6, type: !12, scopeLine: 6, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !4) +!12 = !DISubroutineType(types: !13) +!13 = !{!6} +!14 = !DILocation(line: 7, column: 7, scope: !15) +!15 = distinct !DILexicalBlock(scope: !11, file: !3, line: 7, column: 7) +!16 = !DILocation(line: 7, column: 7, scope: !11) +!17 = !DILocation(line: 8, column: 12, scope: !15) +!22 = !DILocation(line: 8, column: 5, scope: !15) +!23 = !DILocation(line: 9, column: 3, scope: !11) +!24 = !DISubprogram(name: "e", scope: !3, file: !3, line: 5, type: !25, spFlags: DISPFlagOptimized, retainedNodes: !4) +!25 = !DISubroutineType(types: !26) +!26 = !{!6, null} +!27 = !DISubprogram(name: "c", scope: !3, file: !3, line: 3, type: !28, flags: DIFlagNoReturn, spFlags: DISPFlagOptimized, retainedNodes: !4) +!28 = !DISubroutineType(types: !29) +!29 = !{!30, null} +!30 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "a", file: !3, line: 1, size: 64, elements: !31) +!31 = !{!32} +!32 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !30, file: !3, line: 2, baseType: !33, size: 64) +!33 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !34, size: 64) +!34 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!35 = distinct !DISubprogram(name: "h", scope: !3, file: !3, line: 12, type: !36, scopeLine: 12, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !38) +!36 = !DISubroutineType(types: !37) +!37 = !{null} +!38 = !{!39} +!39 = !DILocalVariable(name: "i", scope: !35, file: !3, line: 13, type: !30) +!40 = distinct !DIAssignID() +!41 = !DILocation(line: 0, scope: !35) +!42 = !DILocation(line: 13, column: 3, scope: !35) +!43 = !DILocation(line: 14, column: 5, scope: !35) +!44 = distinct !DIAssignID() +!45 = !DILocation(line: 7, column: 7, scope: !15, inlinedAt: !46) +!46 = distinct !DILocation(line: 15, column: 3, scope: !35) +!47 = !DILocation(line: 7, column: 7, scope: !11, inlinedAt: !46) +!48 = !DILocation(line: 9, column: 3, scope: !11, inlinedAt: !46) +!49 = !DILocation(line: 16, column: 7, scope: !35) +!53 = distinct !DIAssignID() +!54 = !DILocation(line: 17, column: 3, scope: !35) +!55 = !DILocation(line: 18, column: 1, scope: !35) diff --git a/llvm/test/DebugInfo/Generic/assignment-tracking/instcombine/store-new-type.ll b/llvm/test/DebugInfo/Generic/assignment-tracking/instcombine/store-new-type.ll new file mode 100644 --- /dev/null +++ b/llvm/test/DebugInfo/Generic/assignment-tracking/instcombine/store-new-type.ll @@ -0,0 +1,50 @@ +; RUN: opt %s -passes=instcombine -S | FileCheck %s + +;; Based on test/Transforms/InstCombine/shufflevec-bitcast.ll in which the +;; store of <4 x i4> is replaced with a store of type <2 x i8>. Debug info +;; added by hand. Check the DIAssignID attachment on the store is preserved. + +define <2 x i4> @shuf_bitcast_insert_use2(<2 x i8> %v, i8 %x, ptr %p) { +; CHECK-LABEL: @shuf_bitcast_insert_use2( +; CHECK-NEXT: [[I:%.*]] = insertelement <2 x i8> [[V:%.*]], i8 [[X:%.*]], i64 0 +; CHECK-NEXT: store <2 x i8> [[I]], ptr [[P:%.*]], align 2, !DIAssignID ![[ID:[0-9]+]] +; CHECK-NEXT: dbg.assign(metadata <2 x i8> %i, {{.+}}, {{.+}}, metadata ![[ID]], metadata ptr %p,{{.+}}) +; CHECK-NEXT: [[R:%.*]] = bitcast i8 [[X]] to <2 x i4> +; CHECK-NEXT: ret <2 x i4> [[R]] +; + %i = insertelement <2 x i8> %v, i8 %x, i32 0 + %b = bitcast <2 x i8> %i to <4 x i4> + store <4 x i4> %b, ptr %p, !DIAssignID !37 + call void @llvm.dbg.assign(metadata <4 x i4> %b, metadata !28, metadata !DIExpression(), metadata !37, metadata ptr %p, metadata !DIExpression()), !dbg !26 + %r = shufflevector <4 x i4> %b, <4 x i4> undef, <2 x i32> + ret <2 x i4> %r +} + +declare void @llvm.dbg.assign(metadata, metadata, metadata, metadata, metadata, metadata) + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!12, !13} +!llvm.ident = !{!19} + +!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, producer: "clang version 16.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None) +!3 = !DIFile(filename: "test.cpp", directory: "/") +!4 = !{} +!7 = !DIDerivedType(tag: DW_TAG_typedef, name: "int4", file: !3, line: 1, baseType: !8) +!8 = !DICompositeType(tag: DW_TAG_array_type, baseType: !9, size: 128, flags: DIFlagVector, elements: !10) +!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!10 = !{!11} +!11 = !DISubrange(count: 4) +!12 = !{i32 7, !"Dwarf Version", i32 5} +!13 = !{i32 2, !"Debug Info Version", i32 3} +!19 = !{!"clang version 16.0.0"} +!20 = distinct !DISubprogram(name: "f", linkageName: "_Z1fi", scope: !3, file: !3, line: 3, type: !21, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !23) +!21 = !DISubroutineType(types: !22) +!22 = !{!7, !9} +!23 = !{} +!26 = !DILocation(line: 0, scope: !20) +!28 = !DILocalVariable(name: "a", scope: !20, file: !3, line: 3, type: !29) +!29 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 256, elements: !30) +!30 = !{!31} +!31 = !DISubrange(count: 2) +!37 = distinct !DIAssignID() + diff --git a/llvm/test/DebugInfo/Generic/assignment-tracking/instcombine/storemerge.ll b/llvm/test/DebugInfo/Generic/assignment-tracking/instcombine/storemerge.ll new file mode 100644 --- /dev/null +++ b/llvm/test/DebugInfo/Generic/assignment-tracking/instcombine/storemerge.ll @@ -0,0 +1,252 @@ +; RUN: opt %s -S -passes=instcombine -o - -experimental-assignment-tracking | FileCheck %s + +;; $ cat test.cpp +;; class a { +;; float b; +;; }; +;; class c { +;; public: +;; a d(); +;; }; +;; class e { +;; public: +;; c &f(); +;; }; +;; class g { +;; public: +;; void h(a &); +;; }; +;; class j { +;; g k; +;; e l; +;; e m; +;; bool n; +;; void o(); +;; }; +;; void j::o() { +;; int i; +;; a p; +;; i = 0; +;; for (; i < 3; i++) +;; if (n) +;; p = l.f().d(); +;; else +;; p = m.f().d(); +;; k.h(p); +;; } +;; +;; Generated by grabbing IR before instcombine in: +;; $ clang++ -O2 -g -c test.cpp -Xclang -fexperimental-assignment-tracking + +;; Before instcombine runs we have an unrolled loop (3 iterations). Each +;; unrolled section is an if-diamond with a store in if.then and if.else +;; block. The "same" stores in each unrolled section have the same +;; DIAssignID. Instcombine is going to sink the stores from if.then and if.else +;; into if.end for each unrolled section. This involves merging the DIAssignID +;; of the two stores. Check that each merge updates all linked instructions +;; with the same DIAssignID attachments too. + +; CHECK: if.then: +; CHECK: call void @llvm.dbg.assign(metadata float %call2, metadata ![[var:[0-9]+]], metadata !DIExpression(), metadata ![[id:[0-9]+]], metadata ptr %p, metadata !DIExpression()), !dbg +; CHECK: br label %for.inc + +; CHECK: if.else: +; CHECK: call void @llvm.dbg.assign(metadata float %call5, metadata ![[var]], metadata !DIExpression(), metadata ![[id]], metadata ptr %p, metadata !DIExpression()), !dbg +; CHECK: br label %for.inc + +; CHECK: for.inc: +; CHECK-NEXT: %storemerge = phi float [ %call2, %if.then ], [ %call5, %if.else ] +; CHECK-NEXT: store float %storemerge, ptr %p, align 4{{.+}}!DIAssignID ![[id]] + +; CHECK: if.then.1: +; CHECK: call void @llvm.dbg.assign(metadata float %call2.1, metadata ![[var]], metadata !DIExpression(), metadata ![[id]], metadata ptr %p, metadata !DIExpression()), !dbg +; CHECK: br label %for.inc.1 + +; CHECK: if.else.1: +; CHECK: call void @llvm.dbg.assign(metadata float %call5.1, metadata ![[var]], metadata !DIExpression(), metadata ![[id]], metadata ptr %p, metadata !DIExpression()), !dbg +; CHECK: br label %for.inc.1 + +; CHECK: for.inc.1: +; CHECK-NEXT: %storemerge1 = phi float [ %call2.1, %if.then.1 ], [ %call5.1, %if.else.1 ] +; CHECK-NEXT: store float %storemerge1, ptr %p, align 4{{.+}}!DIAssignID ![[id]] + +; CHECK: if.then.2: +; CHECK: call void @llvm.dbg.assign(metadata float %call2.2, metadata ![[var]], metadata !DIExpression(), metadata ![[id]], metadata ptr %p, metadata !DIExpression()), !dbg +; CHECK: br label %for.inc.2 + +; CHECK: if.else.2: +; CHECK: call void @llvm.dbg.assign(metadata float %call5.2, metadata ![[var]], metadata !DIExpression(), metadata ![[id]], metadata ptr %p, metadata !DIExpression()), !dbg +; CHECK: br label %for.inc.2 + +; CHECK: for.inc.2: +; CHECK-NEXT: %storemerge2 = phi float [ %call2.2, %if.then.2 ], [ %call5.2, %if.else.2 ] +; CHECK-NEXT: store float %storemerge2, ptr %p, align 4{{.+}}!DIAssignID ![[id]] + +%class.j = type { %class.g, %class.e, %class.e, i8 } +%class.g = type { i8 } +%class.e = type { i8 } +%class.a = type { float } +%class.c = type { i8 } + +; Function Attrs: uwtable +define dso_local void @_ZN1j1oEv(ptr %this) local_unnamed_addr #0 align 2 !dbg !7 { +entry: + %p = alloca %class.a, align 4, !DIAssignID !49 + call void @llvm.dbg.assign(metadata i1 undef, metadata !48, metadata !DIExpression(), metadata !49, metadata ptr %p, metadata !DIExpression()), !dbg !50 + %0 = bitcast ptr %p to ptr, !dbg !51 + call void @llvm.lifetime.start.p0i8(i64 4, ptr nonnull %0) #4, !dbg !51 + %n = getelementptr inbounds %class.j, ptr %this, i64 0, i32 3 + %l = getelementptr inbounds %class.j, ptr %this, i64 0, i32 1 + %ref.tmp.sroa.0.0..sroa_idx = getelementptr inbounds %class.a, ptr %p, i64 0, i32 0 + %m = getelementptr inbounds %class.j, ptr %this, i64 0, i32 2 + %1 = load i8, ptr %n, align 1, !dbg !52 + %tobool.not = icmp eq i8 %1, 0, !dbg !52 + br i1 %tobool.not, label %if.else, label %if.then, !dbg !64 + +if.then: ; preds = %entry + %call = tail call nonnull align 1 dereferenceable(1) ptr @_ZN1e1fEv(ptr nonnull %l), !dbg !65 + %call2 = tail call float @_ZN1c1dEv(ptr nonnull %call), !dbg !66 + store float %call2, ptr %ref.tmp.sroa.0.0..sroa_idx, align 4, !dbg !67, !DIAssignID !71 + call void @llvm.dbg.assign(metadata float %call2, metadata !48, metadata !DIExpression(), metadata !71, metadata ptr %ref.tmp.sroa.0.0..sroa_idx, metadata !DIExpression()), !dbg !50 + br label %for.inc, !dbg !72 + +if.else: ; preds = %entry + %call4 = tail call nonnull align 1 dereferenceable(1) ptr @_ZN1e1fEv(ptr nonnull %m), !dbg !73 + %call5 = tail call float @_ZN1c1dEv(ptr nonnull %call4), !dbg !74 + store float %call5, ptr %ref.tmp.sroa.0.0..sroa_idx, align 4, !dbg !75, !DIAssignID !76 + call void @llvm.dbg.assign(metadata float %call5, metadata !48, metadata !DIExpression(), metadata !76, metadata ptr %ref.tmp.sroa.0.0..sroa_idx, metadata !DIExpression()), !dbg !50 + br label %for.inc + +for.inc: ; preds = %if.then, %if.else + %2 = load i8, ptr %n, align 1, !dbg !52 + %tobool.not.1 = icmp eq i8 %2, 0, !dbg !52 + br i1 %tobool.not.1, label %if.else.1, label %if.then.1, !dbg !64 + +if.then.1: ; preds = %for.inc + %call.1 = tail call nonnull align 1 dereferenceable(1) ptr @_ZN1e1fEv(ptr nonnull %l), !dbg !65 + %call2.1 = tail call float @_ZN1c1dEv(ptr nonnull %call.1), !dbg !66 + store float %call2.1, ptr %ref.tmp.sroa.0.0..sroa_idx, align 4, !dbg !67, !DIAssignID !71 + call void @llvm.dbg.assign(metadata float %call2.1, metadata !48, metadata !DIExpression(), metadata !71, metadata ptr %ref.tmp.sroa.0.0..sroa_idx, metadata !DIExpression()), !dbg !50 + br label %for.inc.1, !dbg !72 + +if.else.1: ; preds = %for.inc + %call4.1 = tail call nonnull align 1 dereferenceable(1) ptr @_ZN1e1fEv(ptr nonnull %m), !dbg !73 + %call5.1 = tail call float @_ZN1c1dEv(ptr nonnull %call4.1), !dbg !74 + store float %call5.1, ptr %ref.tmp.sroa.0.0..sroa_idx, align 4, !dbg !75, !DIAssignID !76 + call void @llvm.dbg.assign(metadata float %call5.1, metadata !48, metadata !DIExpression(), metadata !76, metadata ptr %ref.tmp.sroa.0.0..sroa_idx, metadata !DIExpression()), !dbg !50 + br label %for.inc.1 + +for.inc.1: ; preds = %if.else.1, %if.then.1 + %3 = load i8, ptr %n, align 1, !dbg !52 + %tobool.not.2 = icmp eq i8 %3, 0, !dbg !52 + br i1 %tobool.not.2, label %if.else.2, label %if.then.2, !dbg !64 + +if.then.2: ; preds = %for.inc.1 + %call.2 = tail call nonnull align 1 dereferenceable(1) ptr @_ZN1e1fEv(ptr nonnull %l), !dbg !65 + %call2.2 = tail call float @_ZN1c1dEv(ptr nonnull %call.2), !dbg !66 + store float %call2.2, ptr %ref.tmp.sroa.0.0..sroa_idx, align 4, !dbg !67, !DIAssignID !71 + call void @llvm.dbg.assign(metadata float %call2.2, metadata !48, metadata !DIExpression(), metadata !71, metadata ptr %ref.tmp.sroa.0.0..sroa_idx, metadata !DIExpression()), !dbg !50 + br label %for.inc.2, !dbg !72 + +if.else.2: ; preds = %for.inc.1 + %call4.2 = tail call nonnull align 1 dereferenceable(1) ptr @_ZN1e1fEv(ptr nonnull %m), !dbg !73 + %call5.2 = tail call float @_ZN1c1dEv(ptr nonnull %call4.2), !dbg !74 + store float %call5.2, ptr %ref.tmp.sroa.0.0..sroa_idx, align 4, !dbg !75, !DIAssignID !76 + call void @llvm.dbg.assign(metadata float %call5.2, metadata !48, metadata !DIExpression(), metadata !76, metadata ptr %ref.tmp.sroa.0.0..sroa_idx, metadata !DIExpression()), !dbg !50 + br label %for.inc.2 + +for.inc.2: ; preds = %if.else.2, %if.then.2 + %k = getelementptr inbounds %class.j, ptr %this, i64 0, i32 0, !dbg !77 + call void @_ZN1g1hER1a(ptr %k, ptr nonnull align 4 dereferenceable(4) %p), !dbg !78 + call void @llvm.lifetime.end.p0i8(i64 4, ptr nonnull %0) #4, !dbg !79 + ret void, !dbg !79 +} + +; Function Attrs: argmemonly nofree nosync nounwind willreturn +declare void @llvm.lifetime.start.p0i8(i64 immarg, ptr nocapture) #1 + +declare dso_local nonnull align 1 dereferenceable(1) ptr @_ZN1e1fEv(ptr) local_unnamed_addr #2 + +declare dso_local float @_ZN1c1dEv(ptr) local_unnamed_addr #2 + +; Function Attrs: argmemonly nofree nosync nounwind willreturn +declare void @llvm.lifetime.end.p0i8(i64 immarg, ptr nocapture) #1 + +declare dso_local void @_ZN1g1hER1a(ptr, ptr nonnull align 4 dereferenceable(4)) local_unnamed_addr #2 + +; Function Attrs: nofree nosync nounwind readnone speculatable willreturn +declare void @llvm.dbg.assign(metadata, metadata, metadata, metadata, metadata, metadata) #3 + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 12.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "test.cpp", directory: "/") +!2 = !{} +!3 = !{i32 7, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 12.0.0"} +!7 = distinct !DISubprogram(name: "o", linkageName: "_ZN1j1oEv", scope: !8, file: !1, line: 23, type: !40, scopeLine: 23, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, declaration: !39, retainedNodes: !43) +!8 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "j", file: !1, line: 16, size: 32, flags: DIFlagTypePassByValue, elements: !9, identifier: "_ZTS1j") +!9 = !{!10, !22, !36, !37, !39} +!10 = !DIDerivedType(tag: DW_TAG_member, name: "k", scope: !8, file: !1, line: 17, baseType: !11, size: 8) +!11 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "g", file: !1, line: 12, size: 8, flags: DIFlagTypePassByValue, elements: !12, identifier: "_ZTS1g") +!12 = !{!13} +!13 = !DISubprogram(name: "h", linkageName: "_ZN1g1hER1a", scope: !11, file: !1, line: 14, type: !14, scopeLine: 14, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagOptimized) +!14 = !DISubroutineType(types: !15) +!15 = !{null, !16, !17} +!16 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !11, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) +!17 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !18, size: 64) +!18 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "a", file: !1, line: 1, size: 32, flags: DIFlagTypePassByValue, elements: !19, identifier: "_ZTS1a") +!19 = !{!20} +!20 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !18, file: !1, line: 2, baseType: !21, size: 32) +!21 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float) +!22 = !DIDerivedType(tag: DW_TAG_member, name: "l", scope: !8, file: !1, line: 18, baseType: !23, size: 8, offset: 8) +!23 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "e", file: !1, line: 8, size: 8, flags: DIFlagTypePassByValue, elements: !24, identifier: "_ZTS1e") +!24 = !{!25} +!25 = !DISubprogram(name: "f", linkageName: "_ZN1e1fEv", scope: !23, file: !1, line: 10, type: !26, scopeLine: 10, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagOptimized) +!26 = !DISubroutineType(types: !27) +!27 = !{!28, !35} +!28 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !29, size: 64) +!29 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "c", file: !1, line: 4, size: 8, flags: DIFlagTypePassByValue, elements: !30, identifier: "_ZTS1c") +!30 = !{!31} +!31 = !DISubprogram(name: "d", linkageName: "_ZN1c1dEv", scope: !29, file: !1, line: 6, type: !32, scopeLine: 6, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagOptimized) +!32 = !DISubroutineType(types: !33) +!33 = !{!18, !34} +!34 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !29, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) +!35 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !23, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) +!36 = !DIDerivedType(tag: DW_TAG_member, name: "m", scope: !8, file: !1, line: 19, baseType: !23, size: 8, offset: 16) +!37 = !DIDerivedType(tag: DW_TAG_member, name: "n", scope: !8, file: !1, line: 20, baseType: !38, size: 8, offset: 24) +!38 = !DIBasicType(name: "bool", size: 8, encoding: DW_ATE_boolean) +!39 = !DISubprogram(name: "o", linkageName: "_ZN1j1oEv", scope: !8, file: !1, line: 21, type: !40, scopeLine: 21, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized) +!40 = !DISubroutineType(types: !41) +!41 = !{null, !42} +!42 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !8, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) +!43 = !{!44, !46, !48} +!44 = !DILocalVariable(name: "this", arg: 1, scope: !7, type: !45, flags: DIFlagArtificial | DIFlagObjectPointer) +!45 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !8, size: 64) +!46 = !DILocalVariable(name: "i", scope: !7, file: !1, line: 24, type: !47) +!47 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!48 = !DILocalVariable(name: "p", scope: !7, file: !1, line: 25, type: !18) +!49 = distinct !DIAssignID() +!50 = !DILocation(line: 0, scope: !7) +!51 = !DILocation(line: 25, column: 3, scope: !7) +!52 = !DILocation(line: 28, column: 9, scope: !53) +!53 = distinct !DILexicalBlock(scope: !54, file: !1, line: 28, column: 9) +!54 = distinct !DILexicalBlock(scope: !55, file: !1, line: 27, column: 3) +!55 = distinct !DILexicalBlock(scope: !7, file: !1, line: 27, column: 3) +!64 = !DILocation(line: 28, column: 9, scope: !54) +!65 = !DILocation(line: 29, column: 13, scope: !53) +!66 = !DILocation(line: 29, column: 17, scope: !53) +!67 = !DILocation(line: 29, column: 9, scope: !53) +!71 = distinct !DIAssignID() +!72 = !DILocation(line: 29, column: 7, scope: !53) +!73 = !DILocation(line: 31, column: 13, scope: !53) +!74 = !DILocation(line: 31, column: 17, scope: !53) +!75 = !DILocation(line: 31, column: 9, scope: !53) +!76 = distinct !DIAssignID() +!77 = !DILocation(line: 32, column: 3, scope: !7) +!78 = !DILocation(line: 32, column: 5, scope: !7) +!79 = !DILocation(line: 33, column: 1, scope: !7)