xref: /llvm-project/llvm/test/Transforms/MemProfContextDisambiguation/basic.ll (revision 9513f2fdf2ad50f55726154a6b6a4aa463bc457f)
1;; Test callsite context graph generation for simple call graph with
2;; two memprof contexts and no inlining, as well as graph and IR cloning.
3;;
4;; Original code looks like:
5;;
6;; char *bar() {
7;;   return new char[10];
8;; }
9;;
10;; char *baz() {
11;;   return bar();
12;; }
13;;
14;; char *foo() {
15;;   return baz();
16;; }
17;;
18;; int main(int argc, char **argv) {
19;;   char *x = foo();
20;;   char *y = foo();
21;;   memset(x, 0, 10);
22;;   memset(y, 0, 10);
23;;   delete[] x;
24;;   sleep(10);
25;;   delete[] y;
26;;   return 0;
27;; }
28;;
29;; Code compiled with -mllvm -memprof-ave-lifetime-cold-threshold=5 so that the
30;; memory freed after sleep(10) results in cold lifetimes.
31;;
32;; The IR was then reduced using llvm-reduce with the expected FileCheck input.
33
34;; -stats requires asserts
35; REQUIRES: asserts
36
37; RUN: opt -passes=memprof-context-disambiguation -supports-hot-cold-new \
38; RUN:	-memprof-verify-ccg -memprof-verify-nodes -memprof-dump-ccg \
39; RUN:	-memprof-export-to-dot -memprof-dot-file-path-prefix=%t. \
40; RUN:	-stats -pass-remarks=memprof-context-disambiguation \
41; RUN:  -memprof-report-hinted-sizes \
42; RUN:	%s -S 2>&1 | FileCheck %s --check-prefix=DUMP --check-prefix=IR \
43; RUN:	--check-prefix=STATS --check-prefix=REMARKS --check-prefix=SIZES
44
45; RUN:	cat %t.ccg.postbuild.dot | FileCheck %s --check-prefix=DOT
46;; We should have cloned bar, baz, and foo, for the cold memory allocation.
47; RUN:	cat %t.ccg.cloned.dot | FileCheck %s --check-prefix=DOTCLONED
48
49;; Check again without -supports-hot-cold-new and ensure all MIB are cold and
50;; that there is no cloning.
51; RUN: opt -passes=memprof-context-disambiguation \
52; RUN:	-memprof-verify-ccg -memprof-verify-nodes -memprof-dump-ccg \
53; RUN:	-memprof-export-to-dot -memprof-dot-file-path-prefix=%t. \
54; RUN:	-stats -pass-remarks=memprof-context-disambiguation \
55; RUN:	%s -S 2>&1 | FileCheck %s --implicit-check-not="Callsite Context Graph" \
56; RUN:	--implicit-check-not="created clone"
57
58target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
59target triple = "x86_64-unknown-linux-gnu"
60
61define i32 @main() #0 {
62entry:
63  %call = call noundef ptr @_Z3foov(), !callsite !0
64  %call1 = call noundef ptr @_Z3foov(), !callsite !1
65  ret i32 0
66}
67
68; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: write)
69declare void @llvm.memset.p0.i64(ptr nocapture writeonly, i8, i64, i1 immarg) #1
70
71; Function Attrs: nobuiltin
72declare void @_ZdaPv() #2
73
74define internal ptr @_Z3barv() #3 {
75entry:
76  %call = call noalias noundef nonnull ptr @_Znam(i64 noundef 10) #6, !memprof !2, !callsite !7
77  ret ptr null
78}
79
80declare ptr @_Znam(i64)
81
82define internal ptr @_Z3bazv() #4 {
83entry:
84  %call = call noundef ptr @_Z3barv(), !callsite !8
85  ret ptr null
86}
87
88; Function Attrs: noinline
89define internal ptr @_Z3foov() #5 {
90entry:
91  %call = call noundef ptr @_Z3bazv(), !callsite !9
92  ret ptr null
93}
94
95; uselistorder directives
96uselistorder ptr @_Z3foov, { 1, 0 }
97
98attributes #0 = { "tune-cpu"="generic" }
99attributes #1 = { nocallback nofree nounwind willreturn memory(argmem: write) }
100attributes #2 = { nobuiltin }
101attributes #3 = { "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" }
102attributes #4 = { "stack-protector-buffer-size"="8" }
103attributes #5 = { noinline }
104attributes #6 = { builtin }
105
106!0 = !{i64 8632435727821051414}
107!1 = !{i64 -3421689549917153178}
108!2 = !{!3, !5}
109!3 = !{!4, !"notcold", !10}
110!4 = !{i64 9086428284934609951, i64 -5964873800580613432, i64 2732490490862098848, i64 8632435727821051414}
111!5 = !{!6, !"cold", !11, !12}
112!6 = !{i64 9086428284934609951, i64 -5964873800580613432, i64 2732490490862098848, i64 -3421689549917153178}
113!7 = !{i64 9086428284934609951}
114!8 = !{i64 -5964873800580613432}
115!9 = !{i64 2732490490862098848}
116!10 = !{i64 123, i64 100}
117!11 = !{i64 456, i64 200}
118!12 = !{i64 789, i64 300}
119
120
121; DUMP: CCG before cloning:
122; DUMP: Callsite Context Graph:
123; DUMP: Node [[BAR:0x[a-z0-9]+]]
124; DUMP: 	  %call = call noalias noundef nonnull ptr @_Znam(i64 noundef 10) #6	(clone 0)
125; DUMP: 	AllocTypes: NotColdCold
126; DUMP: 	ContextIds: 1 2
127; DUMP: 	CalleeEdges:
128; DUMP: 	CallerEdges:
129; DUMP: 		Edge from Callee [[BAR]] to Caller: [[BAZ:0x[a-z0-9]+]] AllocTypes: NotColdCold ContextIds: 1 2
130
131; DUMP: Node [[BAZ]]
132; DUMP: 	  %call = call noundef ptr @_Z3barv()	(clone 0)
133; DUMP: 	AllocTypes: NotColdCold
134; DUMP: 	ContextIds: 1 2
135; DUMP: 	CalleeEdges:
136; DUMP: 		Edge from Callee [[BAR]] to Caller: [[BAZ]] AllocTypes: NotColdCold ContextIds: 1 2
137; DUMP: 	CallerEdges:
138; DUMP: 		Edge from Callee [[BAZ]] to Caller: [[FOO:0x[a-z0-9]+]] AllocTypes: NotColdCold ContextIds: 1 2
139
140; DUMP: Node [[FOO]]
141; DUMP: 	  %call = call noundef ptr @_Z3bazv()	(clone 0)
142; DUMP: 	AllocTypes: NotColdCold
143; DUMP: 	ContextIds: 1 2
144; DUMP: 	CalleeEdges:
145; DUMP: 		Edge from Callee [[BAZ]] to Caller: [[FOO]] AllocTypes: NotColdCold ContextIds: 1 2
146; DUMP: 	CallerEdges:
147; DUMP: 		Edge from Callee [[FOO]] to Caller: [[MAIN1:0x[a-z0-9]+]] AllocTypes: NotCold ContextIds: 1
148; DUMP: 		Edge from Callee [[FOO]] to Caller: [[MAIN2:0x[a-z0-9]+]] AllocTypes: Cold ContextIds: 2
149
150; DUMP: Node [[MAIN1]]
151; DUMP: 	  %call = call noundef ptr @_Z3foov()	(clone 0)
152; DUMP: 	AllocTypes: NotCold
153; DUMP: 	ContextIds: 1
154; DUMP: 	CalleeEdges:
155; DUMP: 		Edge from Callee [[FOO]] to Caller: [[MAIN1]] AllocTypes: NotCold ContextIds: 1
156; DUMP: 	CallerEdges:
157
158; DUMP: Node [[MAIN2]]
159; DUMP: 	  %call1 = call noundef ptr @_Z3foov()	(clone 0)
160; DUMP: 	AllocTypes: Cold
161; DUMP: 	ContextIds: 2
162; DUMP: 	CalleeEdges:
163; DUMP: 		Edge from Callee [[FOO]] to Caller: [[MAIN2]] AllocTypes: Cold ContextIds: 2
164; DUMP: 	CallerEdges:
165
166; DUMP: CCG after cloning:
167; DUMP: Callsite Context Graph:
168; DUMP: Node [[BAR:0x[a-z0-9]+]]
169; DUMP: 	  %call = call noalias noundef nonnull ptr @_Znam(i64 noundef 10) #6	(clone 0)
170; DUMP: 	AllocTypes: NotCold
171; DUMP: 	ContextIds: 1
172; DUMP: 	CalleeEdges:
173; DUMP: 	CallerEdges:
174; DUMP: 		Edge from Callee [[BAR]] to Caller: [[BAZ:0x[a-z0-9]+]] AllocTypes: NotCold ContextIds: 1
175; DUMP:		Clones: [[BAR2:0x[a-z0-9]+]]
176
177; DUMP: Node [[BAZ]]
178; DUMP: 	  %call = call noundef ptr @_Z3barv()	(clone 0)
179; DUMP: 	AllocTypes: NotCold
180; DUMP: 	ContextIds: 1
181; DUMP: 	CalleeEdges:
182; DUMP: 		Edge from Callee [[BAR]] to Caller: [[BAZ]] AllocTypes: NotCold ContextIds: 1
183; DUMP: 	CallerEdges:
184; DUMP: 		Edge from Callee [[BAZ]] to Caller: [[FOO:0x[a-z0-9]+]] AllocTypes: NotCold ContextIds: 1
185; DUMP:		Clones: [[BAZ2:0x[a-z0-9]+]]
186
187; DUMP: Node [[FOO]]
188; DUMP: 	  %call = call noundef ptr @_Z3bazv()	(clone 0)
189; DUMP: 	AllocTypes: NotCold
190; DUMP: 	ContextIds: 1
191; DUMP: 	CalleeEdges:
192; DUMP: 		Edge from Callee [[BAZ]] to Caller: [[FOO]] AllocTypes: NotCold ContextIds: 1
193; DUMP: 	CallerEdges:
194; DUMP: 		Edge from Callee [[FOO]] to Caller: [[MAIN1:0x[a-z0-9]+]] AllocTypes: NotCold ContextIds: 1
195; DUMP:		Clones: [[FOO2:0x[a-z0-9]+]]
196
197; DUMP: Node [[MAIN1]]
198; DUMP: 	  %call = call noundef ptr @_Z3foov()	(clone 0)
199; DUMP: 	AllocTypes: NotCold
200; DUMP: 	ContextIds: 1
201; DUMP: 	CalleeEdges:
202; DUMP: 		Edge from Callee [[FOO]] to Caller: [[MAIN1]] AllocTypes: NotCold ContextIds: 1
203; DUMP: 	CallerEdges:
204
205; DUMP: Node [[MAIN2]]
206; DUMP: 	  %call1 = call noundef ptr @_Z3foov()	(clone 0)
207; DUMP: 	AllocTypes: Cold
208; DUMP: 	ContextIds: 2
209; DUMP: 	CalleeEdges:
210; DUMP: 		Edge from Callee [[FOO2]] to Caller: [[MAIN2]] AllocTypes: Cold ContextIds: 2
211; DUMP: 	CallerEdges:
212
213; DUMP: Node [[FOO2]]
214; DUMP: 	  %call = call noundef ptr @_Z3bazv()	(clone 0)
215; DUMP: 	AllocTypes: Cold
216; DUMP: 	ContextIds: 2
217; DUMP: 	CalleeEdges:
218; DUMP: 		Edge from Callee [[BAZ2]] to Caller: [[FOO2]] AllocTypes: Cold ContextIds: 2
219; DUMP: 	CallerEdges:
220; DUMP: 		Edge from Callee [[FOO2]] to Caller: [[MAIN2:0x[a-z0-9]+]] AllocTypes: Cold ContextIds: 2
221; DUMP:		Clone of [[FOO]]
222
223; DUMP: Node [[BAZ2]]
224; DUMP: 	  %call = call noundef ptr @_Z3barv()	(clone 0)
225; DUMP: 	AllocTypes: Cold
226; DUMP: 	ContextIds: 2
227; DUMP: 	CalleeEdges:
228; DUMP: 		Edge from Callee [[BAR2]] to Caller: [[BAZ2]] AllocTypes: Cold ContextIds: 2
229; DUMP: 	CallerEdges:
230; DUMP: 		Edge from Callee [[BAZ2]] to Caller: [[FOO2]] AllocTypes: Cold ContextIds: 2
231; DUMP:		Clone of [[BAZ]]
232
233; DUMP: Node [[BAR2]]
234; DUMP: 	  %call = call noalias noundef nonnull ptr @_Znam(i64 noundef 10) #6	(clone 0)
235; DUMP: 	AllocTypes: Cold
236; DUMP: 	ContextIds: 2
237; DUMP: 	CalleeEdges:
238; DUMP: 	CallerEdges:
239; DUMP: 		Edge from Callee [[BAR2]] to Caller: [[BAZ2]] AllocTypes: Cold ContextIds: 2
240; DUMP:		Clone of [[BAR]]
241
242
243; REMARKS: created clone _Z3barv.memprof.1
244; REMARKS: created clone _Z3bazv.memprof.1
245; REMARKS: created clone _Z3foov.memprof.1
246; REMARKS: call in clone main assigned to call function clone _Z3foov.memprof.1
247; REMARKS: call in clone _Z3foov.memprof.1 assigned to call function clone _Z3bazv.memprof.1
248; REMARKS: call in clone _Z3bazv.memprof.1 assigned to call function clone _Z3barv.memprof.1
249; REMARKS: call in clone _Z3barv.memprof.1 marked with memprof allocation attribute cold
250; REMARKS: call in clone main assigned to call function clone _Z3foov
251; REMARKS: call in clone _Z3foov assigned to call function clone _Z3bazv
252; REMARKS: call in clone _Z3bazv assigned to call function clone _Z3barv
253; REMARKS: call in clone _Z3barv marked with memprof allocation attribute notcold
254
255; SIZES: NotCold full allocation context 123 with total size 100 is NotCold after cloning
256; SIZES: Cold full allocation context 456 with total size 200 is Cold after cloning
257; SIZES: Cold full allocation context 789 with total size 300 is Cold after cloning
258
259; IR: define {{.*}} @main
260;; The first call to foo does not allocate cold memory. It should call the
261;; original functions, which ultimately call the original allocation decorated
262;; with a "notcold" attribute.
263; IR:   call {{.*}} @_Z3foov()
264;; The second call to foo allocates cold memory. It should call cloned functions
265;; which ultimately call a cloned allocation decorated with a "cold" attribute.
266; IR:   call {{.*}} @_Z3foov.memprof.1()
267; IR: define internal {{.*}} @_Z3barv()
268; IR:   call {{.*}} @_Znam(i64 noundef 10) #[[NOTCOLD:[0-9]+]]
269; IR: define internal {{.*}} @_Z3bazv()
270; IR:   call {{.*}} @_Z3barv()
271; IR: define internal {{.*}} @_Z3foov()
272; IR:   call {{.*}} @_Z3bazv()
273; IR: define internal {{.*}} @_Z3barv.memprof.1()
274; IR:   call {{.*}} @_Znam(i64 noundef 10) #[[COLD:[0-9]+]]
275; IR: define internal {{.*}} @_Z3bazv.memprof.1()
276; IR:   call {{.*}} @_Z3barv.memprof.1()
277; IR: define internal {{.*}} @_Z3foov.memprof.1()
278; IR:   call {{.*}} @_Z3bazv.memprof.1()
279; IR: attributes #[[NOTCOLD]] = { builtin "memprof"="notcold" }
280; IR: attributes #[[COLD]] = { builtin "memprof"="cold" }
281
282
283; STATS: 1 memprof-context-disambiguation - Number of cold static allocations (possibly cloned)
284; STATS: 1 memprof-context-disambiguation - Number of not cold static allocations (possibly cloned)
285; STATS: 3 memprof-context-disambiguation - Number of function clones created during whole program analysis
286
287
288; DOT: digraph "postbuild" {
289; DOT: 	label="postbuild";
290; DOT: 	Node[[BAR:0x[a-z0-9]+]] [shape=record,tooltip="N[[BAR]] ContextIds: 1 2",fillcolor="mediumorchid1",style="filled",style="filled",label="{OrigId: Alloc0\n_Z3barv -\> _Znam}"];
291; DOT: 	Node[[BAZ:0x[a-z0-9]+]] [shape=record,tooltip="N[[BAZ]] ContextIds: 1 2",fillcolor="mediumorchid1",style="filled",style="filled",label="{OrigId: 12481870273128938184\n_Z3bazv -\> _Z3barv}"];
292; DOT: 	Node[[BAZ]] -> Node[[BAR]][tooltip="ContextIds: 1 2",fillcolor="mediumorchid1"];
293; DOT: 	Node[[FOO:0x[a-z0-9]+]] [shape=record,tooltip="N[[FOO]] ContextIds: 1 2",fillcolor="mediumorchid1",style="filled",style="filled",label="{OrigId: 2732490490862098848\n_Z3foov -\> _Z3bazv}"];
294; DOT: 	Node[[FOO]] -> Node[[BAZ]][tooltip="ContextIds: 1 2",fillcolor="mediumorchid1"];
295; DOT: 	Node[[MAIN1:0x[a-z0-9]+]] [shape=record,tooltip="N[[MAIN1]] ContextIds: 1",fillcolor="brown1",style="filled",style="filled",label="{OrigId: 8632435727821051414\nmain -\> _Z3foov}"];
296; DOT: 	Node[[MAIN1]] -> Node[[FOO]][tooltip="ContextIds: 1",fillcolor="brown1"];
297; DOT: 	Node[[MAIN2:0x[a-z0-9]+]] [shape=record,tooltip="N[[MAIN2]] ContextIds: 2",fillcolor="cyan",style="filled",style="filled",label="{OrigId: 15025054523792398438\nmain -\> _Z3foov}"];
298; DOT: 	Node[[MAIN2]] -> Node[[FOO]][tooltip="ContextIds: 2",fillcolor="cyan"];
299; DOT: }
300
301
302; DOTCLONED: digraph "cloned" {
303; DOTCLONED: 	label="cloned";
304; DOTCLONED: 	Node[[BAR:0x[a-z0-9]+]] [shape=record,tooltip="N[[BAR]] ContextIds: 1",fillcolor="brown1",style="filled",style="filled",label="{OrigId: Alloc0\n_Z3barv -\> _Znam}"];
305; DOTCLONED: 	Node[[BAZ:0x[a-z0-9]+]] [shape=record,tooltip="N[[BAZ]] ContextIds: 1",fillcolor="brown1",style="filled",style="filled",label="{OrigId: 12481870273128938184\n_Z3bazv -\> _Z3barv}"];
306; DOTCLONED: 	Node[[BAZ]] -> Node[[BAR]][tooltip="ContextIds: 1",fillcolor="brown1"];
307; DOTCLONED: 	Node[[FOO:0x[a-z0-9]+]] [shape=record,tooltip="N[[FOO]] ContextIds: 1",fillcolor="brown1",style="filled",style="filled",label="{OrigId: 2732490490862098848\n_Z3foov -\> _Z3bazv}"];
308; DOTCLONED: 	Node[[FOO]] -> Node[[BAZ]][tooltip="ContextIds: 1",fillcolor="brown1"];
309; DOTCLONED: 	Node[[MAIN1:0x[a-z0-9]+]] [shape=record,tooltip="N[[MAIN1]] ContextIds: 1",fillcolor="brown1",style="filled",style="filled",label="{OrigId: 8632435727821051414\nmain -\> _Z3foov}"];
310; DOTCLONED: 	Node[[MAIN1]] -> Node[[FOO]][tooltip="ContextIds: 1",fillcolor="brown1"];
311; DOTCLONED: 	Node[[MAIN2:0x[a-z0-9]+]] [shape=record,tooltip="N[[MAIN2]] ContextIds: 2",fillcolor="cyan",style="filled",style="filled",label="{OrigId: 15025054523792398438\nmain -\> _Z3foov}"];
312; DOTCLONED: 	Node[[MAIN2]] -> Node[[FOO2:0x[a-z0-9]+]][tooltip="ContextIds: 2",fillcolor="cyan"];
313; DOTCLONED: 	Node[[FOO2]] [shape=record,tooltip="N[[FOO2]] ContextIds: 2",fillcolor="cyan",style="filled",color="blue",style="filled,bold,dashed",label="{OrigId: 0\n_Z3foov -\> _Z3bazv}"];
314; DOTCLONED: 	Node[[FOO2]] -> Node[[BAZ2:0x[a-z0-9]+]][tooltip="ContextIds: 2",fillcolor="cyan"];
315; DOTCLONED: 	Node[[BAZ2]] [shape=record,tooltip="N[[BAZ2]] ContextIds: 2",fillcolor="cyan",style="filled",color="blue",style="filled,bold,dashed",label="{OrigId: 0\n_Z3bazv -\> _Z3barv}"];
316; DOTCLONED: 	Node[[BAZ2]] -> Node[[BAR2:0x[a-z0-9]+]][tooltip="ContextIds: 2",fillcolor="cyan"];
317; DOTCLONED: 	Node[[BAR2]] [shape=record,tooltip="N[[BAR2]] ContextIds: 2",fillcolor="cyan",style="filled",color="blue",style="filled,bold,dashed",label="{OrigId: Alloc0\n_Z3barv -\> _Znam}"];
318; DOTCLONED: }
319