1 ;; This test ensures that the logic which assigns calls to stack nodes
2 ;; correctly handles cloning of a callsite for a trimmed cold context
3 ;; that partially overlaps with a longer context for a different allocation.
5 ;; The profile data and call stacks were all manually added, but the code
6 ;; would be structured something like the following (fairly contrived to
7 ;; result in the type of control flow needed to test):
11 ;; // cold: stack ids 10, 12, 13, 15 (trimmed ids 19, 20)
12 ;; // not cold: stack ids 10, 12, 13, 14 (trimmed id 21)
13 ;; new char[10]; // stack id 10
15 ;; // not cold: stack ids 11, 12, 13, 15, 16, 17 (trimmed id 22)
16 ;; // cold: stack ids 11, 12, 13, 15, 16, 18 (trimmed id 23)
17 ;; new char[10]; // stack id 11
21 ;; A(b); // stack ids 12
25 ;; X(b); // stack id 13
29 ;; B(true); // stack id 14
33 ;; B(b); // stack id 15
37 ;; C(b); // stack id 16
41 ;; E(false); // stack id 17
45 ;; E(false); // stack id 18
49 ;; C(true); // stack id 19
53 ;; D(); // stack id 20 (leads to not cold allocation)
54 ;; M(); // stack id 21 (leads to cold allocation)
55 ;; F(); // stack id 22 (leads to not cold allocation)
56 ;; G(); // stack id 23 (leads to cold allocation)
59 ;; -stats requires asserts
62 ; RUN: opt -passes=memprof-context-disambiguation -supports-hot-cold-new \
63 ; RUN: -memprof-verify-ccg -memprof-verify-nodes \
64 ; RUN: -stats -pass-remarks=memprof-context-disambiguation \
65 ; RUN: %s -S 2>&1 | FileCheck %s --check-prefix=IR \
66 ; RUN: --check-prefix=STATS --check-prefix=REMARKS
68 ; REMARKS: created clone _Z1Ab.memprof.1
69 ; REMARKS: created clone _Z1Xb.memprof.1
70 ; REMARKS: created clone _Z1Bb.memprof.1
71 ; REMARKS: created clone _Z1Cb.memprof.1
72 ; REMARKS: created clone _Z1Eb.memprof.1
73 ; REMARKS: call in clone _Z1Gv assigned to call function clone _Z1Eb.memprof.1
74 ; REMARKS: call in clone _Z1Eb.memprof.1 assigned to call function clone _Z1Cb.memprof.1
75 ;; If we don't perform cloning for each allocation separately, we will miss
76 ;; cloning _Z1Cb for the trimmed cold allocation context leading to the
77 ;; allocation at stack id 10.
78 ; REMARKS: call in clone _Z1Cb.memprof.1 assigned to call function clone _Z1Bb.memprof.1
79 ; REMARKS: call in clone _Z1Fv assigned to call function clone _Z1Eb
80 ; REMARKS: call in clone _Z1Eb assigned to call function clone _Z1Cb
81 ; REMARKS: call in clone _Z1Cb assigned to call function clone _Z1Bb.memprof.1
82 ; REMARKS: call in clone _Z1Bb.memprof.1 assigned to call function clone _Z1Xb.memprof.1
83 ; REMARKS: call in clone _Z1Xb.memprof.1 assigned to call function clone _Z1Ab.memprof.1
84 ; REMARKS: call in clone _Z1Ab.memprof.1 marked with memprof allocation attribute cold
85 ; REMARKS: call in clone _Z1Bb.memprof.1 assigned to call function clone _Z1Xb
86 ; REMARKS: call in clone _Z1Dv assigned to call function clone _Z1Bb
87 ; REMARKS: call in clone _Z1Bb assigned to call function clone _Z1Xb
88 ; REMARKS: call in clone _Z1Xb assigned to call function clone _Z1Ab
89 ; REMARKS: call in clone _Z1Ab marked with memprof allocation attribute notcold
90 ; REMARKS: call in clone _Z1Ab.memprof.1 marked with memprof allocation attribute cold
91 ; REMARKS: call in clone _Z1Ab marked with memprof allocation attribute notcold
94 target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
95 target triple = "x86_64-unknown-linux-gnu"
97 define dso_local void @_Z1Ab(i1 noundef zeroext %b) {
99 br i1 %b, label %if.then, label %if.else
102 %call = call noalias noundef nonnull ptr @_Znam(i64 noundef 10) #7, !memprof !0, !callsite !10
106 %call2 = call noalias noundef nonnull ptr @_Znam(i64 noundef 10) #7, !memprof !5, !callsite !11
113 ; Function Attrs: nobuiltin
114 declare ptr @_Znam(i64) #0
116 define dso_local void @_Z1Xb(i1 noundef zeroext %b) {
118 tail call void @_Z1Ab(i1 noundef zeroext %b), !callsite !12
122 define dso_local void @_Z1Bb(i1 noundef zeroext %b) {
124 tail call void @_Z1Xb(i1 noundef zeroext %b), !callsite !13
128 define dso_local void @_Z1Dv() {
130 tail call void @_Z1Bb(i1 noundef zeroext true), !callsite !14
134 define dso_local void @_Z1Cb(i1 noundef zeroext %b) {
136 tail call void @_Z1Bb(i1 noundef zeroext %b), !callsite !15
140 define dso_local void @_Z1Eb(i1 noundef zeroext %b) {
142 tail call void @_Z1Cb(i1 noundef zeroext %b), !callsite !16
146 define dso_local void @_Z1Fv() {
148 tail call void @_Z1Eb(i1 noundef zeroext false), !callsite !17
152 define dso_local void @_Z1Gv() {
154 tail call void @_Z1Eb(i1 noundef zeroext false), !callsite !18
158 define dso_local void @_Z1Mv() {
160 tail call void @_Z1Cb(i1 noundef zeroext true), !callsite !19
164 define dso_local noundef i32 @main() local_unnamed_addr {
166 tail call void @_Z1Dv(), !callsite !20 ;; Not cold context
167 tail call void @_Z1Mv(), !callsite !21 ;; Cold context
168 tail call void @_Z1Fv(), !callsite !22 ;; Not cold context
169 tail call void @_Z1Gv(), !callsite !23 ;; Cold context
173 attributes #0 = { nobuiltin }
174 attributes #7 = { builtin }
177 ;; Cold (trimmed) context via call to _Z1Dv in main
179 !2 = !{i64 10, i64 12, i64 13, i64 15}
180 ;; Not cold (trimmed) context via call to _Z1Mv in main
181 !3 = !{!4, !"notcold"}
182 !4 = !{i64 10, i64 12, i64 13, i64 14}
184 ;; Not cold (trimmed) context via call to _Z1Fv in main
185 !6 = !{!7, !"notcold"}
186 !7 = !{i64 11, i64 12, i64 13, i64 15, i64 16, i64 17}
187 ;; Cold (trimmed) context via call to _Z1Gv in main
189 !9 = !{i64 11, i64 12, i64 13, i64 15, i64 16, i64 18}
205 ; IR: define {{.*}} @_Z1Cb(i1 noundef zeroext %b)
207 ; IR-NEXT: call {{.*}} @_Z1Bb.memprof.1(i1 noundef zeroext %b)
209 ; IR: define {{.*}} @_Z1Ab.memprof.1(i1 noundef zeroext %b)
211 ; IR-NEXT: br i1 %b, label %if.then, label %if.else
214 ; IR-NEXT: call {{.*}} @_Znam(i64 noundef 10) #[[COLD:[0-9]+]]
215 ; IR-NEXT: br label %if.end
218 ; IR-NEXT: call {{.*}} @_Znam(i64 noundef 10) #[[COLD]]
220 ; IR: define {{.*}} @_Z1Xb.memprof.1(i1 noundef zeroext %b)
222 ; IR-NEXT: call {{.*}} @_Z1Ab.memprof.1(i1 noundef zeroext %b)
224 ; IR: define {{.*}} @_Z1Bb.memprof.1(i1 noundef zeroext %b)
226 ; IR-NEXT: call {{.*}} @_Z1Xb.memprof.1(i1 noundef zeroext %b)
228 ; IR: attributes #[[COLD]] = { builtin "memprof"="cold" }
230 ; STATS: 2 memprof-context-disambiguation - Number of cold static allocations (possibly cloned)
231 ; STATS: 2 memprof-context-disambiguation - Number of not cold static allocations (possibly cloned)
232 ; STATS: 5 memprof-context-disambiguation - Number of function clones created during whole program analysis