xref: /llvm-project/clang/test/CodeGenCXX/attr-likelihood-if-branch-weights.cpp (revision f8431a0e4008db374dfb17a21119178fb960e334)
1 // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
2 // RUN: %clang_cc1 -O1 -disable-llvm-passes -emit-llvm %s -o - -triple=x86_64-- | FileCheck %s
3 
4 extern volatile bool b;
5 extern volatile int i;
6 extern bool A();
7 extern bool B();
8 
9 // CHECK-LABEL: @_Z1fv(
10 // CHECK-NEXT:  entry:
11 // CHECK-NEXT:    [[RETVAL:%.*]] = alloca i1, align 1
12 // CHECK-NEXT:    [[TMP0:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2:![0-9]+]], !range [[RNG6:![0-9]+]]
13 // CHECK-NEXT:    [[TOBOOL:%.*]] = trunc i8 [[TMP0]] to i1
14 // CHECK-NEXT:    [[TOBOOL_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[TOBOOL]], i1 true)
15 // CHECK-NEXT:    br i1 [[TOBOOL_EXPVAL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
16 // CHECK:       if.then:
17 // CHECK-NEXT:    [[CALL:%.*]] = call noundef zeroext i1 @_Z1Av()
18 // CHECK-NEXT:    store i1 [[CALL]], ptr [[RETVAL]], align 1
19 // CHECK-NEXT:    br label [[RETURN:%.*]]
20 // CHECK:       if.end:
21 // CHECK-NEXT:    [[CALL1:%.*]] = call noundef zeroext i1 @_Z1Bv()
22 // CHECK-NEXT:    store i1 [[CALL1]], ptr [[RETVAL]], align 1
23 // CHECK-NEXT:    br label [[RETURN]]
24 // CHECK:       return:
25 // CHECK-NEXT:    [[TMP1:%.*]] = load i1, ptr [[RETVAL]], align 1
26 // CHECK-NEXT:    ret i1 [[TMP1]]
27 //
f()28 bool f() {
29   if (b)
30     [[likely]] {
31       return A();
32     }
33   return B();
34 }
35 
36 // CHECK-LABEL: @_Z1gv(
37 // CHECK-NEXT:  entry:
38 // CHECK-NEXT:    [[RETVAL:%.*]] = alloca i1, align 1
39 // CHECK-NEXT:    [[TMP0:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
40 // CHECK-NEXT:    [[TOBOOL:%.*]] = trunc i8 [[TMP0]] to i1
41 // CHECK-NEXT:    [[TOBOOL_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[TOBOOL]], i1 false)
42 // CHECK-NEXT:    br i1 [[TOBOOL_EXPVAL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
43 // CHECK:       if.then:
44 // CHECK-NEXT:    [[CALL:%.*]] = call noundef zeroext i1 @_Z1Av()
45 // CHECK-NEXT:    store i1 [[CALL]], ptr [[RETVAL]], align 1
46 // CHECK-NEXT:    br label [[RETURN:%.*]]
47 // CHECK:       if.end:
48 // CHECK-NEXT:    [[CALL1:%.*]] = call noundef zeroext i1 @_Z1Bv()
49 // CHECK-NEXT:    store i1 [[CALL1]], ptr [[RETVAL]], align 1
50 // CHECK-NEXT:    br label [[RETURN]]
51 // CHECK:       return:
52 // CHECK-NEXT:    [[TMP1:%.*]] = load i1, ptr [[RETVAL]], align 1
53 // CHECK-NEXT:    ret i1 [[TMP1]]
54 //
g()55 bool g() {
56   if (b)
57     [[unlikely]] {
58       return A();
59     }
60 
61   return B();
62 }
63 
64 // CHECK-LABEL: @_Z1hv(
65 // CHECK-NEXT:  entry:
66 // CHECK-NEXT:    [[RETVAL:%.*]] = alloca i1, align 1
67 // CHECK-NEXT:    [[TMP0:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
68 // CHECK-NEXT:    [[TOBOOL:%.*]] = trunc i8 [[TMP0]] to i1
69 // CHECK-NEXT:    [[TOBOOL_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[TOBOOL]], i1 false)
70 // CHECK-NEXT:    br i1 [[TOBOOL_EXPVAL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
71 // CHECK:       if.then:
72 // CHECK-NEXT:    [[CALL:%.*]] = call noundef zeroext i1 @_Z1Av()
73 // CHECK-NEXT:    store i1 [[CALL]], ptr [[RETVAL]], align 1
74 // CHECK-NEXT:    br label [[RETURN:%.*]]
75 // CHECK:       if.end:
76 // CHECK-NEXT:    [[CALL1:%.*]] = call noundef zeroext i1 @_Z1Bv()
77 // CHECK-NEXT:    store i1 [[CALL1]], ptr [[RETVAL]], align 1
78 // CHECK-NEXT:    br label [[RETURN]]
79 // CHECK:       return:
80 // CHECK-NEXT:    [[TMP1:%.*]] = load i1, ptr [[RETVAL]], align 1
81 // CHECK-NEXT:    ret i1 [[TMP1]]
82 //
h()83 bool h() {
84   if (b)
85     [[unlikely]] return A();
86 
87   return B();
88 }
89 
90 // CHECK-LABEL: @_Z8NullStmtv(
91 // CHECK-NEXT:  entry:
92 // CHECK-NEXT:    [[TMP0:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
93 // CHECK-NEXT:    [[TOBOOL:%.*]] = trunc i8 [[TMP0]] to i1
94 // CHECK-NEXT:    [[TOBOOL_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[TOBOOL]], i1 false)
95 // CHECK-NEXT:    br i1 [[TOBOOL_EXPVAL]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
96 // CHECK:       if.then:
97 // CHECK-NEXT:    br label [[IF_END:%.*]]
98 // CHECK:       if.else:
99 // CHECK-NEXT:    store volatile i8 1, ptr @b, align 1, !tbaa [[TBAA2]]
100 // CHECK-NEXT:    br label [[IF_END]]
101 // CHECK:       if.end:
102 // CHECK-NEXT:    ret void
103 //
NullStmt()104 void NullStmt() {
105   if (b)
106     [[unlikely]];
107   else {
108     // Make sure the branches aren't optimized away.
109     b = true;
110   }
111 }
112 
113 // CHECK-LABEL: @_Z6IfStmtv(
114 // CHECK-NEXT:  entry:
115 // CHECK-NEXT:    [[TMP0:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
116 // CHECK-NEXT:    [[TOBOOL:%.*]] = trunc i8 [[TMP0]] to i1
117 // CHECK-NEXT:    [[TOBOOL_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[TOBOOL]], i1 false)
118 // CHECK-NEXT:    br i1 [[TOBOOL_EXPVAL]], label [[IF_THEN:%.*]], label [[IF_END2:%.*]]
119 // CHECK:       if.then:
120 // CHECK-NEXT:    [[CALL:%.*]] = call noundef zeroext i1 @_Z1Bv()
121 // CHECK-NEXT:    br i1 [[CALL]], label [[IF_THEN1:%.*]], label [[IF_END:%.*]]
122 // CHECK:       if.then1:
123 // CHECK-NEXT:    br label [[IF_END]]
124 // CHECK:       if.end:
125 // CHECK-NEXT:    br label [[IF_END2]]
126 // CHECK:       if.end2:
127 // CHECK-NEXT:    [[TMP1:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
128 // CHECK-NEXT:    [[TOBOOL3:%.*]] = trunc i8 [[TMP1]] to i1
129 // CHECK-NEXT:    br i1 [[TOBOOL3]], label [[IF_THEN4:%.*]], label [[IF_END8:%.*]]
130 // CHECK:       if.then4:
131 // CHECK-NEXT:    [[CALL5:%.*]] = call noundef zeroext i1 @_Z1Bv()
132 // CHECK-NEXT:    [[CALL5_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[CALL5]], i1 false)
133 // CHECK-NEXT:    br i1 [[CALL5_EXPVAL]], label [[IF_THEN6:%.*]], label [[IF_END7:%.*]]
134 // CHECK:       if.then6:
135 // CHECK-NEXT:    store volatile i8 0, ptr @b, align 1, !tbaa [[TBAA2]]
136 // CHECK-NEXT:    br label [[IF_END7]]
137 // CHECK:       if.end7:
138 // CHECK-NEXT:    br label [[IF_END8]]
139 // CHECK:       if.end8:
140 // CHECK-NEXT:    ret void
141 //
IfStmt()142 void IfStmt() {
143   if (b)
144     [[unlikely]] if (B()) {}
145 
146   if (b) {
147     if (B())
148       [[unlikely]] { b = false; }
149   }
150 }
151 
152 // CHECK-LABEL: @_Z9WhileStmtv(
153 // CHECK-NEXT:  entry:
154 // CHECK-NEXT:    [[TMP0:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
155 // CHECK-NEXT:    [[TOBOOL:%.*]] = trunc i8 [[TMP0]] to i1
156 // CHECK-NEXT:    [[TOBOOL_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[TOBOOL]], i1 false)
157 // CHECK-NEXT:    br i1 [[TOBOOL_EXPVAL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
158 // CHECK:       if.then:
159 // CHECK-NEXT:    br label [[WHILE_COND:%.*]]
160 // CHECK:       while.cond:
161 // CHECK-NEXT:    [[CALL:%.*]] = call noundef zeroext i1 @_Z1Bv()
162 // CHECK-NEXT:    br i1 [[CALL]], label [[WHILE_BODY:%.*]], label [[WHILE_END:%.*]]
163 // CHECK:       while.body:
164 // CHECK-NEXT:    br label [[WHILE_COND]], !llvm.loop [[LOOP7:![0-9]+]]
165 // CHECK:       while.end:
166 // CHECK-NEXT:    br label [[IF_END]]
167 // CHECK:       if.end:
168 // CHECK-NEXT:    [[TMP1:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
169 // CHECK-NEXT:    [[TOBOOL1:%.*]] = trunc i8 [[TMP1]] to i1
170 // CHECK-NEXT:    br i1 [[TOBOOL1]], label [[IF_THEN2:%.*]], label [[IF_END7:%.*]]
171 // CHECK:       if.then2:
172 // CHECK-NEXT:    br label [[WHILE_COND3:%.*]]
173 // CHECK:       while.cond3:
174 // CHECK-NEXT:    [[CALL4:%.*]] = call noundef zeroext i1 @_Z1Bv()
175 // CHECK-NEXT:    [[CALL4_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[CALL4]], i1 false)
176 // CHECK-NEXT:    br i1 [[CALL4_EXPVAL]], label [[WHILE_BODY5:%.*]], label [[WHILE_END6:%.*]]
177 // CHECK:       while.body5:
178 // CHECK-NEXT:    store volatile i8 0, ptr @b, align 1, !tbaa [[TBAA2]]
179 // CHECK-NEXT:    br label [[WHILE_COND3]], !llvm.loop [[LOOP10:![0-9]+]]
180 // CHECK:       while.end6:
181 // CHECK-NEXT:    br label [[IF_END7]]
182 // CHECK:       if.end7:
183 // CHECK-NEXT:    ret void
184 //
WhileStmt()185 void WhileStmt() {
186   if (b)
187     [[unlikely]] while (B()) {}
188 
189   if (b)
190     while (B())
191       [[unlikely]] { b = false; }
192 }
193 
194 // CHECK-LABEL: @_Z6DoStmtv(
195 // CHECK-NEXT:  entry:
196 // CHECK-NEXT:    [[TMP0:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
197 // CHECK-NEXT:    [[TOBOOL:%.*]] = trunc i8 [[TMP0]] to i1
198 // CHECK-NEXT:    [[TOBOOL_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[TOBOOL]], i1 false)
199 // CHECK-NEXT:    br i1 [[TOBOOL_EXPVAL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
200 // CHECK:       if.then:
201 // CHECK-NEXT:    br label [[DO_BODY:%.*]]
202 // CHECK:       do.body:
203 // CHECK-NEXT:    br label [[DO_COND:%.*]]
204 // CHECK:       do.cond:
205 // CHECK-NEXT:    [[CALL:%.*]] = call noundef zeroext i1 @_Z1Bv()
206 // CHECK-NEXT:    br i1 [[CALL]], label [[DO_BODY]], label [[DO_END:%.*]], !llvm.loop [[LOOP11:![0-9]+]]
207 // CHECK:       do.end:
208 // CHECK-NEXT:    br label [[IF_END]]
209 // CHECK:       if.end:
210 // CHECK-NEXT:    [[TMP1:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
211 // CHECK-NEXT:    [[TOBOOL1:%.*]] = trunc i8 [[TMP1]] to i1
212 // CHECK-NEXT:    br i1 [[TOBOOL1]], label [[IF_THEN2:%.*]], label [[IF_END7:%.*]]
213 // CHECK:       if.then2:
214 // CHECK-NEXT:    br label [[DO_BODY3:%.*]]
215 // CHECK:       do.body3:
216 // CHECK-NEXT:    br label [[DO_COND4:%.*]]
217 // CHECK:       do.cond4:
218 // CHECK-NEXT:    [[CALL5:%.*]] = call noundef zeroext i1 @_Z1Bv()
219 // CHECK-NEXT:    br i1 [[CALL5]], label [[DO_BODY3]], label [[DO_END6:%.*]], !llvm.loop [[LOOP12:![0-9]+]]
220 // CHECK:       do.end6:
221 // CHECK-NEXT:    br label [[IF_END7]]
222 // CHECK:       if.end7:
223 // CHECK-NEXT:    ret void
224 //
DoStmt()225 void DoStmt() {
226   if (b)
227     [[unlikely]] do {}
228     while (B())
229       ;
230 
231   if (b)
232     do
233       [[unlikely]] {}
234     while (B());
235 }
236 
237 // CHECK-LABEL: @_Z7ForStmtv(
238 // CHECK-NEXT:  entry:
239 // CHECK-NEXT:    [[TMP0:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
240 // CHECK-NEXT:    [[TOBOOL:%.*]] = trunc i8 [[TMP0]] to i1
241 // CHECK-NEXT:    [[TOBOOL_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[TOBOOL]], i1 false)
242 // CHECK-NEXT:    br i1 [[TOBOOL_EXPVAL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
243 // CHECK:       if.then:
244 // CHECK-NEXT:    br label [[FOR_COND:%.*]]
245 // CHECK:       for.cond:
246 // CHECK-NEXT:    [[CALL:%.*]] = call noundef zeroext i1 @_Z1Bv()
247 // CHECK-NEXT:    br i1 [[CALL]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]]
248 // CHECK:       for.body:
249 // CHECK-NEXT:    br label [[FOR_COND]], !llvm.loop [[LOOP13:![0-9]+]]
250 // CHECK:       for.end:
251 // CHECK-NEXT:    br label [[IF_END]]
252 // CHECK:       if.end:
253 // CHECK-NEXT:    [[TMP1:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
254 // CHECK-NEXT:    [[TOBOOL1:%.*]] = trunc i8 [[TMP1]] to i1
255 // CHECK-NEXT:    br i1 [[TOBOOL1]], label [[IF_THEN2:%.*]], label [[IF_END7:%.*]]
256 // CHECK:       if.then2:
257 // CHECK-NEXT:    br label [[FOR_COND3:%.*]]
258 // CHECK:       for.cond3:
259 // CHECK-NEXT:    [[CALL4:%.*]] = call noundef zeroext i1 @_Z1Bv()
260 // CHECK-NEXT:    [[CALL4_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[CALL4]], i1 false)
261 // CHECK-NEXT:    br i1 [[CALL4_EXPVAL]], label [[FOR_BODY5:%.*]], label [[FOR_END6:%.*]]
262 // CHECK:       for.body5:
263 // CHECK-NEXT:    br label [[FOR_COND3]], !llvm.loop [[LOOP14:![0-9]+]]
264 // CHECK:       for.end6:
265 // CHECK-NEXT:    br label [[IF_END7]]
266 // CHECK:       if.end7:
267 // CHECK-NEXT:    ret void
268 //
ForStmt()269 void ForStmt() {
270   if (b)
271     [[unlikely]] for (; B();) {}
272 
273   if (b)
274     for (; B();)
275       [[unlikely]] {}
276 }
277 
278 // CHECK-LABEL: @_Z8GotoStmtv(
279 // CHECK-NEXT:  entry:
280 // CHECK-NEXT:    [[TMP0:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
281 // CHECK-NEXT:    [[TOBOOL:%.*]] = trunc i8 [[TMP0]] to i1
282 // CHECK-NEXT:    [[TOBOOL_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[TOBOOL]], i1 false)
283 // CHECK-NEXT:    br i1 [[TOBOOL_EXPVAL]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
284 // CHECK:       if.then:
285 // CHECK-NEXT:    br label [[END:%.*]]
286 // CHECK:       if.else:
287 // CHECK-NEXT:    store volatile i8 1, ptr @b, align 1, !tbaa [[TBAA2]]
288 // CHECK-NEXT:    br label [[IF_END:%.*]]
289 // CHECK:       if.end:
290 // CHECK-NEXT:    br label [[END]]
291 // CHECK:       end:
292 // CHECK-NEXT:    ret void
293 //
GotoStmt()294 void GotoStmt() {
295   if (b)
296     [[unlikely]] goto end;
297   else {
298     // Make sure the branches aren't optimized away.
299     b = true;
300   }
301 end:;
302 }
303 
304 // CHECK-LABEL: @_Z10ReturnStmtv(
305 // CHECK-NEXT:  entry:
306 // CHECK-NEXT:    [[TMP0:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
307 // CHECK-NEXT:    [[TOBOOL:%.*]] = trunc i8 [[TMP0]] to i1
308 // CHECK-NEXT:    [[TOBOOL_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[TOBOOL]], i1 false)
309 // CHECK-NEXT:    br i1 [[TOBOOL_EXPVAL]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
310 // CHECK:       if.then:
311 // CHECK-NEXT:    br label [[IF_END:%.*]]
312 // CHECK:       if.else:
313 // CHECK-NEXT:    store volatile i8 1, ptr @b, align 1, !tbaa [[TBAA2]]
314 // CHECK-NEXT:    br label [[IF_END]]
315 // CHECK:       if.end:
316 // CHECK-NEXT:    ret void
317 //
ReturnStmt()318 void ReturnStmt() {
319   if (b)
320     [[unlikely]] return;
321   else {
322     // Make sure the branches aren't optimized away.
323     b = true;
324   }
325 }
326 
327 // CHECK-LABEL: @_Z10SwitchStmtv(
328 // CHECK-NEXT:  entry:
329 // CHECK-NEXT:    [[TMP0:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
330 // CHECK-NEXT:    [[TOBOOL:%.*]] = trunc i8 [[TMP0]] to i1
331 // CHECK-NEXT:    [[TOBOOL_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[TOBOOL]], i1 false)
332 // CHECK-NEXT:    br i1 [[TOBOOL_EXPVAL]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
333 // CHECK:       if.then:
334 // CHECK-NEXT:    [[TMP1:%.*]] = load volatile i32, ptr @i, align 4, !tbaa [[TBAA15:![0-9]+]]
335 // CHECK-NEXT:    switch i32 [[TMP1]], label [[SW_EPILOG:%.*]] [
336 // CHECK-NEXT:    ]
337 // CHECK:       sw.epilog:
338 // CHECK-NEXT:    br label [[IF_END:%.*]]
339 // CHECK:       if.else:
340 // CHECK-NEXT:    store volatile i8 1, ptr @b, align 1, !tbaa [[TBAA2]]
341 // CHECK-NEXT:    br label [[IF_END]]
342 // CHECK:       if.end:
343 // CHECK-NEXT:    [[TMP2:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
344 // CHECK-NEXT:    [[TOBOOL1:%.*]] = trunc i8 [[TMP2]] to i1
345 // CHECK-NEXT:    br i1 [[TOBOOL1]], label [[IF_THEN2:%.*]], label [[IF_ELSE4:%.*]]
346 // CHECK:       if.then2:
347 // CHECK-NEXT:    [[TMP3:%.*]] = load volatile i32, ptr @i, align 4, !tbaa [[TBAA15]]
348 // CHECK-NEXT:    switch i32 [[TMP3]], label [[SW_EPILOG3:%.*]] [
349 // CHECK-NEXT:    ]
350 // CHECK:       sw.epilog3:
351 // CHECK-NEXT:    br label [[IF_END5:%.*]]
352 // CHECK:       if.else4:
353 // CHECK-NEXT:    store volatile i8 1, ptr @b, align 1, !tbaa [[TBAA2]]
354 // CHECK-NEXT:    br label [[IF_END5]]
355 // CHECK:       if.end5:
356 // CHECK-NEXT:    ret void
357 //
SwitchStmt()358 void SwitchStmt() {
359   if (b)
360     [[unlikely]] switch (i) {}
361   else {
362     // Make sure the branches aren't optimized away.
363     b = true;
364   }
365   if (b)
366     switch (i)
367       [[unlikely]] {}
368   else {
369     // Make sure the branches aren't optimized away.
370     b = true;
371   }
372 }
373 
374