Skip to content

Commit b8ad6fb

Browse files
[MemProf] Allow cloning of callsites in recursive cycles (llvm#121985)
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 45d4698 commit b8ad6fb

File tree

3 files changed

+344
-5
lines changed

3 files changed

+344
-5
lines changed

llvm/lib/Transforms/IPO/MemProfContextDisambiguation.cpp

Lines changed: 44 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> AllowRecursiveCallsites(
127+
"memprof-allow-recursive-callsites", cl::init(true), cl::Hidden,
128+
cl::desc("Allow cloning of callsites involved in recursive cycles"));
129+
130+
// When disabled, try to detect and prevent cloning of recursive contexts.
131+
// This is only necessary until we support cloning through recursive cycles.
132+
// Leave on by default for now, as disabling requires a little bit of compile
133+
// time overhead and doesn't affect correctness, it will just inflate the cold
134+
// hinted bytes reporting a bit when -memprof-report-hinted-sizes is enabled.
135+
static cl::opt<bool> AllowRecursiveContexts(
136+
"memprof-allow-recursive-contexts", cl::init(true), cl::Hidden,
137+
cl::desc("Allow 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 (!AllowRecursiveCallsites) {
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 allowing recursive callsites but
1397+
// haven't disabled recursive contexts, this will be violated for
1398+
// incompletely cloned recursive cycles, so skip the checking in that case.
1399+
assert((AllowRecursiveCallsites && AllowRecursiveContexts) ||
1400+
NodeContextIds == CallerEdgeContextIds ||
13801401
set_is_subset(CallerEdgeContextIds, NodeContextIds));
13811402
}
13821403
if (Node->CalleeEdges.size()) {
@@ -3370,6 +3391,21 @@ 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 allowing recursive callsites, but have also disabled recursive
3396+
// contexts, look for context ids that show up in multiple caller edges.
3397+
if (AllowRecursiveCallsites && !AllowRecursiveContexts) {
3398+
DenseSet<uint32_t> AllCallerContextIds;
3399+
for (auto &CE : Node->CallerEdges) {
3400+
// Resize to the largest set of caller context ids, since we know the
3401+
// final set will be at least that large.
3402+
AllCallerContextIds.reserve(CE->getContextIds().size());
3403+
for (auto Id : CE->getContextIds())
3404+
if (!AllCallerContextIds.insert(Id).second)
3405+
RecursiveContextIds.insert(Id);
3406+
}
3407+
}
3408+
33733409
// Iterate until we find no more opportunities for disambiguating the alloc
33743410
// types via cloning. In most cases this loop will terminate once the Node
33753411
// has a single allocation type, in which case no more cloning is needed.
@@ -3394,6 +3430,9 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::identifyClones(
33943430
// allocation.
33953431
auto CallerEdgeContextsForAlloc =
33963432
set_intersection(CallerEdge->getContextIds(), AllocContextIds);
3433+
if (!RecursiveContextIds.empty())
3434+
CallerEdgeContextsForAlloc =
3435+
set_difference(CallerEdgeContextsForAlloc, RecursiveContextIds);
33973436
if (CallerEdgeContextsForAlloc.empty()) {
33983437
++EI;
33993438
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=ALLOW-RECUR-CALLSITES --check-prefix=ALLOW-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-allow-recursive-callsites=false \
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-allow-recursive-contexts=false \
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=ALLOW-RECUR-CALLSITES --check-prefix=SKIP-RECUR-CONTEXTS
57+
58+
; ALLOW-RECUR-CALLSITES: memprof_recursive.cc:4:0: created clone _Z1Dv.memprof.1
59+
; ALLOW-RECUR-CALLSITES: memprof_recursive.cc:5:10: call in clone _Z1Dv marked with memprof allocation attribute notcold
60+
; ALLOW-RECUR-CALLSITES: memprof_recursive.cc:5:10: call in clone _Z1Dv.memprof.1 marked with memprof allocation attribute cold
61+
; ALLOW-RECUR-CALLSITES: memprof_recursive.cc:8:0: created clone _Z1Ci.memprof.1
62+
; ALLOW-RECUR-CALLSITES: memprof_recursive.cc:10:12: call in clone _Z1Ci.memprof.1 assigned to call function clone _Z1Dv.memprof.1
63+
; ALLOW-RECUR-CALLSITES: memprof_recursive.cc:14:0: created clone _Z1Bi.memprof.1
64+
; ALLOW-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 enabled
66+
;; recursive contexts via -memprof-allow-recursive-contexts=true (default).
67+
; ALLOW-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+
; ALLOW-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=ALLOW-RECUR-CALLSITES --check-prefix=ALLOW-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-allow-recursive-callsites=false \
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-allow-recursive-contexts=false \
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=ALLOW-RECUR-CALLSITES --check-prefix=SKIP-RECUR-CONTEXTS
69+
70+
; ALLOW-RECUR-CALLSITES: memprof_recursive.cc:4:0: created clone _Z1Dv.memprof.1
71+
; ALLOW-RECUR-CALLSITES: memprof_recursive.cc:8:0: created clone _Z1Ci.memprof.1
72+
; ALLOW-RECUR-CALLSITES: memprof_recursive.cc:14:0: created clone _Z1Bi.memprof.1
73+
; ALLOW-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 enabled
75+
;; recursive contexts via -memprof-allow-recursive-contexts=true (default).
76+
; ALLOW-RECUR-CONTEXTS: memprof_recursive.cc:19:13: call in clone main assigned to call function clone _Z1Bi.memprof.1
77+
; ALLOW-RECUR-CALLSITES: memprof_recursive.cc:15:10: call in clone _Z1Bi.memprof.1 assigned to call function clone _Z1Ci.memprof.1
78+
; ALLOW-RECUR-CALLSITES: memprof_recursive.cc:10:12: call in clone _Z1Ci.memprof.1 assigned to call function clone _Z1Dv.memprof.1
79+
; ALLOW-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+
;; disabled recursive contexts via -memprof-allow-recursive-contexts=false.
82+
; SKIP-RECUR-CONTEXTS: memprof_recursive.cc:19:13: call in clone main assigned to call function clone _Z1Bi
83+
; ALLOW-RECUR-CALLSITES: memprof_recursive.cc:12:10: call in clone _Z1Ci assigned to call function clone _Z1Bi
84+
; ALLOW-RECUR-CALLSITES: memprof_recursive.cc:18:13: call in clone main assigned to call function clone _Z1Bi
85+
; ALLOW-RECUR-CALLSITES: memprof_recursive.cc:15:10: call in clone _Z1Bi assigned to call function clone _Z1Ci
86+
; ALLOW-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)