Skip to content

Commit 5e40901

Browse files
committed
[MemProf] Allow cloning of callsites in recursive cycles
Optionally (by default) no longer mark callsite nodes as Recursive, which means they would be automatically skipped during cloning. This was too conservative as it prevents cloning of any callsite that showed up in any recursive cycle, even for non-recursive contexts. While this will enable partial cloning of recursive contexts, the recursive calls themselves will not be updated to call the correct clone, possibly leading to some unnecessary but benign cloning and affecting bytes hinted reporting. To prevent this, optional support looks for recursive cycles in contexts during cloning and removes those contexts from cloning. This requires some additional runtime overhead, so is disabled by default for now. Support for correct cloning of recursive cycles is WIP.
1 parent 71ddde8 commit 5e40901

File tree

3 files changed

+343
-5
lines changed

3 files changed

+343
-5
lines changed

llvm/lib/Transforms/IPO/MemProfContextDisambiguation.cpp

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,20 @@ static cl::opt<unsigned>
122122
cl::desc("Max depth to recursively search for missing "
123123
"frames through tail calls."));
124124

125+
// By default enable cloning of callsites involved with recursive cycles
126+
static cl::opt<bool> SkipRecursiveCallsites(
127+
"memprof-skip-recursive-callsites", cl::init(false), cl::Hidden,
128+
cl::desc("Prevent cloning of callsites involved in recursive cycles"));
129+
130+
// When enabled, try to detect and prevent cloning of recursive contexts.
131+
// This is only necessary until we support cloning through recursive cycles.
132+
// Leave off by default for now, as it requires a little bit of compile time
133+
// overhead and doesn't affect correctness, it will just inflate the cold hinted
134+
// bytes reporting a bit when -memprof-report-hinted-sizes is enabled.
135+
static cl::opt<bool> SkipRecursiveContexts(
136+
"memprof-skip-recursive-contexts", cl::init(false), cl::Hidden,
137+
cl::desc("Prevent cloning of contexts through recursive cycles"));
138+
125139
namespace llvm {
126140
cl::opt<bool> EnableMemProfContextDisambiguation(
127141
"enable-memprof-context-disambiguation", cl::init(false), cl::Hidden,
@@ -1236,9 +1250,13 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::addStackNodesForMIB(
12361250
StackEntryIdToContextNodeMap[StackId] = StackNode;
12371251
StackNode->OrigStackOrAllocId = StackId;
12381252
}
1239-
auto Ins = StackIdSet.insert(StackId);
1240-
if (!Ins.second)
1241-
StackNode->Recursive = true;
1253+
// Marking a node recursive will prevent its cloning completely, even for
1254+
// non-recursive contexts flowing through it.
1255+
if (SkipRecursiveCallsites) {
1256+
auto Ins = StackIdSet.insert(StackId);
1257+
if (!Ins.second)
1258+
StackNode->Recursive = true;
1259+
}
12421260
StackNode->AllocTypes |= (uint8_t)AllocType;
12431261
PrevNode->addOrUpdateCallerEdge(StackNode, AllocType, LastContextId);
12441262
PrevNode = StackNode;
@@ -1375,8 +1393,11 @@ static void checkNode(const ContextNode<DerivedCCG, FuncTy, CallTy> *Node,
13751393
set_union(CallerEdgeContextIds, Edge->ContextIds);
13761394
}
13771395
// Node can have more context ids than callers if some contexts terminate at
1378-
// node and some are longer.
1379-
assert(NodeContextIds == CallerEdgeContextIds ||
1396+
// node and some are longer. If we are not skipping recursive callsites but
1397+
// haven't enabled skipping of recursive contexts, this will be violated for
1398+
// incompletely cloned recursive cycles, so skip the checking in that case.
1399+
assert(!(SkipRecursiveCallsites || SkipRecursiveContexts) ||
1400+
NodeContextIds == CallerEdgeContextIds ||
13801401
set_is_subset(CallerEdgeContextIds, NodeContextIds));
13811402
}
13821403
if (Node->CalleeEdges.size()) {
@@ -3370,6 +3391,20 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::identifyClones(
33703391

33713392
assert(Node->AllocTypes != (uint8_t)AllocationType::None);
33723393

3394+
DenseSet<uint32_t> RecursiveContextIds;
3395+
// If we are not skipping recursive callsites, and have also enabled
3396+
// skipping of recursive contexts, look for context ids that show up in
3397+
// multiple caller edges.
3398+
if (!SkipRecursiveCallsites && SkipRecursiveContexts) {
3399+
DenseSet<uint32_t> AllCallerContextIds;
3400+
for (auto &CE : Node->CallerEdges) {
3401+
AllCallerContextIds.reserve(CE->getContextIds().size());
3402+
for (auto Id : CE->getContextIds())
3403+
if (!AllCallerContextIds.insert(Id).second)
3404+
RecursiveContextIds.insert(Id);
3405+
}
3406+
}
3407+
33733408
// Iterate until we find no more opportunities for disambiguating the alloc
33743409
// types via cloning. In most cases this loop will terminate once the Node
33753410
// has a single allocation type, in which case no more cloning is needed.
@@ -3394,6 +3429,9 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::identifyClones(
33943429
// allocation.
33953430
auto CallerEdgeContextsForAlloc =
33963431
set_intersection(CallerEdge->getContextIds(), AllocContextIds);
3432+
if (!RecursiveContextIds.empty())
3433+
CallerEdgeContextsForAlloc =
3434+
set_difference(CallerEdgeContextsForAlloc, RecursiveContextIds);
33973435
if (CallerEdgeContextsForAlloc.empty()) {
33983436
++EI;
33993437
continue;
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
;; Test recursion handling during cloning.
2+
;;
3+
;; See llvm/test/Transforms/MemProfContextDisambiguation/recursive.ll for
4+
;; information on how the test was created.
5+
6+
; RUN: opt -thinlto-bc %s >%t.o
7+
8+
;; By default we should enable cloning of contexts involved with recursive
9+
;; cycles, but not through the cycle itself. I.e. until full support for
10+
;; recursion is added, the cloned recursive call from C back to B (line 12) will
11+
;; not be updated to call a clone.
12+
; RUN: llvm-lto2 run %t.o -enable-memprof-context-disambiguation \
13+
; RUN: -supports-hot-cold-new \
14+
; RUN: -r=%t.o,_Z1Dv,plx \
15+
; RUN: -r=%t.o,_Z1Ci,plx \
16+
; RUN: -r=%t.o,_Z1Bi,plx \
17+
; RUN: -r=%t.o,main,plx \
18+
; RUN: -r=%t.o,_Znam, \
19+
; RUN: -memprof-verify-ccg -memprof-verify-nodes \
20+
; RUN: -pass-remarks=memprof-context-disambiguation \
21+
; RUN: -o %t.out 2>&1 | FileCheck %s \
22+
; RUN: --implicit-check-not "memprof_recursive3.cc:12:10: call in clone _Z1Ci.memprof.1 assigned" \
23+
; RUN: --check-prefix=NOSKIP-RECUR-CALLSITES --check-prefix=NOSKIP-RECUR-CONTEXTS
24+
25+
;; Skipping recursive callsites should result in no cloning.
26+
; RUN: llvm-lto2 run %t.o -enable-memprof-context-disambiguation \
27+
; RUN: -supports-hot-cold-new \
28+
; RUN: -r=%t.o,_Z1Dv,plx \
29+
; RUN: -r=%t.o,_Z1Ci,plx \
30+
; RUN: -r=%t.o,_Z1Bi,plx \
31+
; RUN: -r=%t.o,main,plx \
32+
; RUN: -r=%t.o,_Znam, \
33+
; RUN: -memprof-verify-ccg -memprof-verify-nodes \
34+
; RUN: -pass-remarks=memprof-context-disambiguation \
35+
; RUN: -memprof-skip-recursive-callsites \
36+
; RUN: -o %t.out 2>&1 | FileCheck %s --allow-empty \
37+
; RUN: --implicit-check-not "memprof_recursive3.cc:12:10: call in clone _Z1Ci.memprof.1 assigned" \
38+
; RUN: --implicit-check-not="created clone" \
39+
; RUN: --implicit-check-not="marked with memprof allocation attribute cold"
40+
41+
;; Skipping recursive contexts should prevent spurious call to cloned version of
42+
;; B from the context starting at memprof_recursive.cc:19:13, which is actually
43+
;; recursive (until that support is added).
44+
; RUN: llvm-lto2 run %t.o -enable-memprof-context-disambiguation \
45+
; RUN: -supports-hot-cold-new \
46+
; RUN: -r=%t.o,_Z1Dv,plx \
47+
; RUN: -r=%t.o,_Z1Ci,plx \
48+
; RUN: -r=%t.o,_Z1Bi,plx \
49+
; RUN: -r=%t.o,main,plx \
50+
; RUN: -r=%t.o,_Znam, \
51+
; RUN: -memprof-verify-ccg -memprof-verify-nodes \
52+
; RUN: -pass-remarks=memprof-context-disambiguation \
53+
; RUN: -memprof-skip-recursive-contexts \
54+
; RUN: -o %t.out 2>&1 | FileCheck %s \
55+
; RUN: --implicit-check-not "memprof_recursive3.cc:12:10: call in clone _Z1Ci.memprof.1 assigned" \
56+
; RUN: --check-prefix=NOSKIP-RECUR-CALLSITES --check-prefix=SKIP-RECUR-CONTEXTS
57+
58+
; NOSKIP-RECUR-CALLSITES: memprof_recursive.cc:4:0: created clone _Z1Dv.memprof.1
59+
; NOSKIP-RECUR-CALLSITES: memprof_recursive.cc:5:10: call in clone _Z1Dv marked with memprof allocation attribute notcold
60+
; NOSKIP-RECUR-CALLSITES: memprof_recursive.cc:5:10: call in clone _Z1Dv.memprof.1 marked with memprof allocation attribute cold
61+
; NOSKIP-RECUR-CALLSITES: memprof_recursive.cc:8:0: created clone _Z1Ci.memprof.1
62+
; NOSKIP-RECUR-CALLSITES: memprof_recursive.cc:10:12: call in clone _Z1Ci.memprof.1 assigned to call function clone _Z1Dv.memprof.1
63+
; NOSKIP-RECUR-CALLSITES: memprof_recursive.cc:14:0: created clone _Z1Bi.memprof.1
64+
; NOSKIP-RECUR-CALLSITES: memprof_recursive.cc:15:10: call in clone _Z1Bi.memprof.1 assigned to call function clone _Z1Ci.memprof.1
65+
;; We should only call the cold clone for the recursive context if we haven't
66+
;; enabled skipping of recursive contexts via -memprof-skip-recursive-contexts.
67+
; NOSKIP-RECUR-CONTEXTS: memprof_recursive.cc:19:13: call in clone main assigned to call function clone _Z1Bi.memprof.1
68+
; SKIP-RECUR-CONTEXTS-NOT: memprof_recursive.cc:19:13: call in clone main assigned to call function clone _Z1Bi.memprof.1
69+
; NOSKIP-RECUR-CALLSITES: memprof_recursive.cc:20:13: call in clone main assigned to call function clone _Z1Bi.memprof.1
70+
71+
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
72+
target triple = "x86_64-unknown-linux-gnu"
73+
74+
define ptr @_Z1Dv() !dbg !3 {
75+
entry:
76+
%call = tail call ptr @_Znam(i64 10), !dbg !6, !memprof !7, !callsite !14
77+
ret ptr null
78+
}
79+
80+
define ptr @_Z1Ci(i32 %n) !dbg !15 {
81+
entry:
82+
%call = tail call ptr @_Z1Dv(), !dbg !16, !callsite !17
83+
br label %return
84+
85+
if.end: ; No predecessors!
86+
%call1 = tail call ptr @_Z1Bi(i32 0), !dbg !18, !callsite !19
87+
br label %return
88+
89+
return: ; preds = %if.end, %entry
90+
ret ptr null
91+
}
92+
93+
define ptr @_Z1Bi(i32 %n) !dbg !20 {
94+
entry:
95+
%call = tail call ptr @_Z1Ci(i32 0), !dbg !21, !callsite !22
96+
ret ptr null
97+
}
98+
99+
define i32 @main() {
100+
entry:
101+
%call = tail call ptr @_Z1Bi(i32 0), !dbg !23, !callsite !25
102+
%call1 = tail call ptr @_Z1Bi(i32 0), !dbg !26, !callsite !27
103+
%call2 = tail call ptr @_Z1Bi(i32 0), !dbg !28, !callsite !29
104+
ret i32 0
105+
}
106+
107+
declare ptr @_Znam(i64)
108+
109+
!llvm.dbg.cu = !{!0}
110+
!llvm.module.flags = !{!2}
111+
112+
!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 20.0.0git (https://github.com/llvm/llvm-project.git 7aec6dc477f8148ed066d10dfc7a012a51b6599c)", isOptimized: true, runtimeVersion: 0, emissionKind: LineTablesOnly, splitDebugInlining: false, debugInfoForProfiling: true, nameTableKind: None)
113+
!1 = !DIFile(filename: "memprof_recursive.cc", directory: ".", checksumkind: CSK_MD5, checksum: "2f15f63b187a0e0d40e7fdd18b10576a")
114+
!2 = !{i32 2, !"Debug Info Version", i32 3}
115+
!3 = distinct !DISubprogram(name: "D", linkageName: "_Z1Dv", scope: !1, file: !1, line: 4, type: !4, scopeLine: 4, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0)
116+
!4 = !DISubroutineType(types: !5)
117+
!5 = !{}
118+
!6 = !DILocation(line: 5, column: 10, scope: !3)
119+
!7 = !{!8, !10, !12}
120+
!8 = !{!9, !"cold"}
121+
!9 = !{i64 6541423618768552252, i64 -200552803509692312, i64 -2954124005641725917, i64 6307901912192269588}
122+
!10 = !{!11, !"notcold"}
123+
!11 = !{i64 6541423618768552252, i64 -200552803509692312, i64 -2954124005641725917, i64 -7155190423157709404, i64 -2954124005641725917, i64 8632435727821051414}
124+
!12 = !{!13, !"cold"}
125+
!13 = !{i64 6541423618768552252, i64 -200552803509692312, i64 -2954124005641725917, i64 -7155190423157709404, i64 -2954124005641725917, i64 -3421689549917153178}
126+
!14 = !{i64 6541423618768552252}
127+
!15 = distinct !DISubprogram(name: "C", linkageName: "_Z1Ci", scope: !1, file: !1, line: 8, type: !4, scopeLine: 8, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0)
128+
!16 = !DILocation(line: 10, column: 12, scope: !15)
129+
!17 = !{i64 -200552803509692312}
130+
!18 = !DILocation(line: 12, column: 10, scope: !15)
131+
!19 = !{i64 -7155190423157709404}
132+
!20 = distinct !DISubprogram(name: "B", linkageName: "_Z1Bi", scope: !1, file: !1, line: 14, type: !4, scopeLine: 14, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0)
133+
!21 = !DILocation(line: 15, column: 10, scope: !20)
134+
!22 = !{i64 -2954124005641725917}
135+
!23 = !DILocation(line: 18, column: 13, scope: !24)
136+
!24 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 17, type: !4, scopeLine: 17, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0)
137+
!25 = !{i64 8632435727821051414}
138+
!26 = !DILocation(line: 19, column: 13, scope: !24)
139+
!27 = !{i64 -3421689549917153178}
140+
!28 = !DILocation(line: 20, column: 13, scope: !24)
141+
!29 = !{i64 6307901912192269588}
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
;; Test recursion handling during cloning.
2+
;;
3+
;; Original code looks like:
4+
;;
5+
;; #include <stdlib.h>
6+
;; #include <string.h>
7+
;; #include <unistd.h>
8+
;; __attribute((noinline)) char *D() {
9+
;; return new char[10];
10+
;; }
11+
;; __attribute((noinline)) char *B(int n);
12+
;; __attribute((noinline)) char *C(int n) {
13+
;; if (!n) {
14+
;; return D();
15+
;; }
16+
;; return B(n-1);
17+
;; }
18+
;; __attribute((noinline)) char *B(int n) {
19+
;; return C(n);
20+
;; }
21+
;; int main(int argc, char **argv) {
22+
;; char *x = B(1);
23+
;; char *y = B(1);
24+
;; char *z = B(0);
25+
;; memset(x, 0, 10);
26+
;; memset(y, 0, 10);
27+
;; memset(z, 0, 10);
28+
;; free(x);
29+
;; sleep(200);
30+
;; free(y);
31+
;; free(z);
32+
;; return 0;
33+
;; }
34+
;;
35+
;; The IR was then reduced using llvm-reduce with the expected FileCheck input.
36+
37+
;; By default we should enable cloning of contexts involved with recursive
38+
;; cycles, but not through the cycle itself. I.e. until full support for
39+
;; recursion is added, the cloned recursive call from C back to B (line 12) will
40+
;; not be updated to call a clone.
41+
; RUN: opt -passes=memprof-context-disambiguation -supports-hot-cold-new \
42+
; RUN: -memprof-verify-ccg -memprof-verify-nodes \
43+
; RUN: -pass-remarks=memprof-context-disambiguation \
44+
; RUN: %s -S 2>&1 | FileCheck %s \
45+
; RUN: --implicit-check-not "memprof_recursive3.cc:12:10: call in clone _Z1Ci.memprof.1 assigned" \
46+
; RUN: --check-prefix=ALL --check-prefix=NOSKIP-RECUR-CALLSITES --check-prefix=NOSKIP-RECUR-CONTEXTS
47+
48+
;; Skipping recursive callsites should result in no cloning.
49+
; RUN: opt -passes=memprof-context-disambiguation -supports-hot-cold-new \
50+
; RUN: -memprof-verify-ccg -memprof-verify-nodes \
51+
; RUN: -pass-remarks=memprof-context-disambiguation \
52+
; RUN: -memprof-skip-recursive-callsites \
53+
; RUN: %s -S 2>&1 | FileCheck %s \
54+
; RUN: --implicit-check-not "memprof_recursive3.cc:12:10: call in clone _Z1Ci.memprof.1 assigned" \
55+
; RUN: --implicit-check-not="created clone" \
56+
; RUN: --implicit-check-not="marked with memprof allocation attribute cold" \
57+
; RUN: --check-prefix=ALL
58+
59+
;; Skipping recursive contexts should prevent spurious call to cloned version of
60+
;; B from the context starting at memprof_recursive.cc:19:13, which is actually
61+
;; recursive (until that support is added).
62+
; RUN: opt -passes=memprof-context-disambiguation -supports-hot-cold-new \
63+
; RUN: -memprof-verify-ccg -memprof-verify-nodes \
64+
; RUN: -pass-remarks=memprof-context-disambiguation \
65+
; RUN: -memprof-skip-recursive-contexts \
66+
; RUN: %s -S 2>&1 | FileCheck %s \
67+
; RUN: --implicit-check-not "memprof_recursive3.cc:12:10: call in clone _Z1Ci.memprof.1 assigned" \
68+
; RUN: --check-prefix=ALL --check-prefix=NOSKIP-RECUR-CALLSITES --check-prefix=SKIP-RECUR-CONTEXTS
69+
70+
; NOSKIP-RECUR-CALLSITES: memprof_recursive.cc:4:0: created clone _Z1Dv.memprof.1
71+
; NOSKIP-RECUR-CALLSITES: memprof_recursive.cc:8:0: created clone _Z1Ci.memprof.1
72+
; NOSKIP-RECUR-CALLSITES: memprof_recursive.cc:14:0: created clone _Z1Bi.memprof.1
73+
; NOSKIP-RECUR-CALLSITES: memprof_recursive.cc:20:13: call in clone main assigned to call function clone _Z1Bi.memprof.1
74+
;; We should only call the cold clone for the recursive context if we haven't
75+
;; enabled skipping of recursive contexts via -memprof-skip-recursive-contexts.
76+
; NOSKIP-RECUR-CONTEXTS: memprof_recursive.cc:19:13: call in clone main assigned to call function clone _Z1Bi.memprof.1
77+
; NOSKIP-RECUR-CALLSITES: memprof_recursive.cc:15:10: call in clone _Z1Bi.memprof.1 assigned to call function clone _Z1Ci.memprof.1
78+
; NOSKIP-RECUR-CALLSITES: memprof_recursive.cc:10:12: call in clone _Z1Ci.memprof.1 assigned to call function clone _Z1Dv.memprof.1
79+
; NOSKIP-RECUR-CALLSITES: memprof_recursive.cc:5:10: call in clone _Z1Dv.memprof.1 marked with memprof allocation attribute cold
80+
;; We should call the original B for the recursive context if we have
81+
;; enabled skipping of recursive contexts via -memprof-skip-recursive-contexts.
82+
; SKIP-RECUR-CONTEXTS: memprof_recursive.cc:19:13: call in clone main assigned to call function clone _Z1Bi
83+
; NOSKIP-RECUR-CALLSITES: memprof_recursive.cc:12:10: call in clone _Z1Ci assigned to call function clone _Z1Bi
84+
; NOSKIP-RECUR-CALLSITES: memprof_recursive.cc:18:13: call in clone main assigned to call function clone _Z1Bi
85+
; NOSKIP-RECUR-CALLSITES: memprof_recursive.cc:15:10: call in clone _Z1Bi assigned to call function clone _Z1Ci
86+
; NOSKIP-RECUR-CALLSITES: memprof_recursive.cc:10:12: call in clone _Z1Ci assigned to call function clone _Z1Dv
87+
; ALL: memprof_recursive.cc:5:10: call in clone _Z1Dv marked with memprof allocation attribute notcold
88+
89+
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
90+
target triple = "x86_64-unknown-linux-gnu"
91+
92+
define ptr @_Z1Dv() !dbg !3 {
93+
entry:
94+
%call = tail call ptr @_Znam(i64 10), !dbg !6, !memprof !7, !callsite !14
95+
ret ptr null
96+
}
97+
98+
define ptr @_Z1Ci(i32 %n) !dbg !15 {
99+
entry:
100+
%call = tail call ptr @_Z1Dv(), !dbg !16, !callsite !17
101+
br label %return
102+
103+
if.end: ; No predecessors!
104+
%call1 = tail call ptr @_Z1Bi(i32 0), !dbg !18, !callsite !19
105+
br label %return
106+
107+
return: ; preds = %if.end, %entry
108+
ret ptr null
109+
}
110+
111+
define ptr @_Z1Bi(i32 %n) !dbg !20 {
112+
entry:
113+
%call = tail call ptr @_Z1Ci(i32 0), !dbg !21, !callsite !22
114+
ret ptr null
115+
}
116+
117+
define i32 @main() {
118+
entry:
119+
%call = tail call ptr @_Z1Bi(i32 0), !dbg !23, !callsite !25
120+
%call1 = tail call ptr @_Z1Bi(i32 0), !dbg !26, !callsite !27
121+
%call2 = tail call ptr @_Z1Bi(i32 0), !dbg !28, !callsite !29
122+
ret i32 0
123+
}
124+
125+
declare ptr @_Znam(i64)
126+
127+
!llvm.dbg.cu = !{!0}
128+
!llvm.module.flags = !{!2}
129+
130+
!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 20.0.0git (https://github.com/llvm/llvm-project.git 7aec6dc477f8148ed066d10dfc7a012a51b6599c)", isOptimized: true, runtimeVersion: 0, emissionKind: LineTablesOnly, splitDebugInlining: false, debugInfoForProfiling: true, nameTableKind: None)
131+
!1 = !DIFile(filename: "memprof_recursive.cc", directory: ".", checksumkind: CSK_MD5, checksum: "2f15f63b187a0e0d40e7fdd18b10576a")
132+
!2 = !{i32 2, !"Debug Info Version", i32 3}
133+
!3 = distinct !DISubprogram(name: "D", linkageName: "_Z1Dv", scope: !1, file: !1, line: 4, type: !4, scopeLine: 4, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0)
134+
!4 = !DISubroutineType(types: !5)
135+
!5 = !{}
136+
!6 = !DILocation(line: 5, column: 10, scope: !3)
137+
!7 = !{!8, !10, !12}
138+
!8 = !{!9, !"cold"}
139+
!9 = !{i64 6541423618768552252, i64 -200552803509692312, i64 -2954124005641725917, i64 6307901912192269588}
140+
!10 = !{!11, !"notcold"}
141+
!11 = !{i64 6541423618768552252, i64 -200552803509692312, i64 -2954124005641725917, i64 -7155190423157709404, i64 -2954124005641725917, i64 8632435727821051414}
142+
!12 = !{!13, !"cold"}
143+
!13 = !{i64 6541423618768552252, i64 -200552803509692312, i64 -2954124005641725917, i64 -7155190423157709404, i64 -2954124005641725917, i64 -3421689549917153178}
144+
!14 = !{i64 6541423618768552252}
145+
!15 = distinct !DISubprogram(name: "C", linkageName: "_Z1Ci", scope: !1, file: !1, line: 8, type: !4, scopeLine: 8, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0)
146+
!16 = !DILocation(line: 10, column: 12, scope: !15)
147+
!17 = !{i64 -200552803509692312}
148+
!18 = !DILocation(line: 12, column: 10, scope: !15)
149+
!19 = !{i64 -7155190423157709404}
150+
!20 = distinct !DISubprogram(name: "B", linkageName: "_Z1Bi", scope: !1, file: !1, line: 14, type: !4, scopeLine: 14, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0)
151+
!21 = !DILocation(line: 15, column: 10, scope: !20)
152+
!22 = !{i64 -2954124005641725917}
153+
!23 = !DILocation(line: 18, column: 13, scope: !24)
154+
!24 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 17, type: !4, scopeLine: 17, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0)
155+
!25 = !{i64 8632435727821051414}
156+
!26 = !DILocation(line: 19, column: 13, scope: !24)
157+
!27 = !{i64 -3421689549917153178}
158+
!28 = !DILocation(line: 20, column: 13, scope: !24)
159+
!29 = !{i64 6307901912192269588}

0 commit comments

Comments
 (0)