1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt -S -simplifycfg -mtriple=x86_64-unknown-unknown -mattr=+bmi < %s | FileCheck %s --check-prefix=ALL --check-prefix=BMI
3 ; RUN: opt -S -simplifycfg -mtriple=x86_64-unknown-unknown -mattr=+lzcnt < %s | FileCheck %s --check-prefix=ALL --check-prefix=LZCNT
4 ; RUN: opt -S -simplifycfg -mtriple=x86_64-unknown-unknown < %s | FileCheck %s --check-prefix=ALL --check-prefix=GENERIC
7 define i64 @test1(i64 %A) {
10 ; BMI-NEXT: [[TOBOOL:%.*]] = icmp eq i64 [[A:%.*]], 0
11 ; BMI-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.ctlz.i64(i64 [[A]], i1 true)
12 ; BMI-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i64 64, i64 [[TMP0]]
13 ; BMI-NEXT: ret i64 [[COND]]
15 ; LZCNT-LABEL: @test1(
17 ; LZCNT-NEXT: [[TOBOOL:%.*]] = icmp eq i64 [[A:%.*]], 0
18 ; LZCNT-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.ctlz.i64(i64 [[A]], i1 true)
19 ; LZCNT-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[TOBOOL]], i64 64, i64 [[TMP0]]
20 ; LZCNT-NEXT: ret i64 [[SPEC_SELECT]]
22 ; GENERIC-LABEL: @test1(
23 ; GENERIC-NEXT: entry:
24 ; GENERIC-NEXT: [[TOBOOL:%.*]] = icmp eq i64 [[A:%.*]], 0
25 ; GENERIC-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.ctlz.i64(i64 [[A]], i1 true)
26 ; GENERIC-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i64 64, i64 [[TMP0]]
27 ; GENERIC-NEXT: ret i64 [[COND]]
30 %tobool = icmp eq i64 %A, 0
31 br i1 %tobool, label %cond.end, label %cond.true
33 cond.true: ; preds = %entry
34 %0 = tail call i64 @llvm.ctlz.i64(i64 %A, i1 true)
37 cond.end: ; preds = %entry, %cond.true
38 %cond = phi i64 [ %0, %cond.true ], [ 64, %entry ]
42 define i32 @test2(i32 %A) {
45 ; BMI-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[A:%.*]], 0
46 ; BMI-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.ctlz.i32(i32 [[A]], i1 true)
47 ; BMI-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i32 32, i32 [[TMP0]]
48 ; BMI-NEXT: ret i32 [[COND]]
50 ; LZCNT-LABEL: @test2(
52 ; LZCNT-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[A:%.*]], 0
53 ; LZCNT-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.ctlz.i32(i32 [[A]], i1 true)
54 ; LZCNT-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[TOBOOL]], i32 32, i32 [[TMP0]]
55 ; LZCNT-NEXT: ret i32 [[SPEC_SELECT]]
57 ; GENERIC-LABEL: @test2(
58 ; GENERIC-NEXT: entry:
59 ; GENERIC-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[A:%.*]], 0
60 ; GENERIC-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.ctlz.i32(i32 [[A]], i1 true)
61 ; GENERIC-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i32 32, i32 [[TMP0]]
62 ; GENERIC-NEXT: ret i32 [[COND]]
65 %tobool = icmp eq i32 %A, 0
66 br i1 %tobool, label %cond.end, label %cond.true
68 cond.true: ; preds = %entry
69 %0 = tail call i32 @llvm.ctlz.i32(i32 %A, i1 true)
72 cond.end: ; preds = %entry, %cond.true
73 %cond = phi i32 [ %0, %cond.true ], [ 32, %entry ]
78 define signext i16 @test3(i16 signext %A) {
81 ; BMI-NEXT: [[TOBOOL:%.*]] = icmp eq i16 [[A:%.*]], 0
82 ; BMI-NEXT: [[TMP0:%.*]] = tail call i16 @llvm.ctlz.i16(i16 [[A]], i1 true)
83 ; BMI-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i16 16, i16 [[TMP0]]
84 ; BMI-NEXT: ret i16 [[COND]]
86 ; LZCNT-LABEL: @test3(
88 ; LZCNT-NEXT: [[TOBOOL:%.*]] = icmp eq i16 [[A:%.*]], 0
89 ; LZCNT-NEXT: [[TMP0:%.*]] = tail call i16 @llvm.ctlz.i16(i16 [[A]], i1 true)
90 ; LZCNT-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[TOBOOL]], i16 16, i16 [[TMP0]]
91 ; LZCNT-NEXT: ret i16 [[SPEC_SELECT]]
93 ; GENERIC-LABEL: @test3(
94 ; GENERIC-NEXT: entry:
95 ; GENERIC-NEXT: [[TOBOOL:%.*]] = icmp eq i16 [[A:%.*]], 0
96 ; GENERIC-NEXT: [[TMP0:%.*]] = tail call i16 @llvm.ctlz.i16(i16 [[A]], i1 true)
97 ; GENERIC-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i16 16, i16 [[TMP0]]
98 ; GENERIC-NEXT: ret i16 [[COND]]
101 %tobool = icmp eq i16 %A, 0
102 br i1 %tobool, label %cond.end, label %cond.true
104 cond.true: ; preds = %entry
105 %0 = tail call i16 @llvm.ctlz.i16(i16 %A, i1 true)
108 cond.end: ; preds = %entry, %cond.true
109 %cond = phi i16 [ %0, %cond.true ], [ 16, %entry ]
114 define i64 @test1b(i64 %A) {
115 ; BMI-LABEL: @test1b(
117 ; BMI-NEXT: [[TOBOOL:%.*]] = icmp eq i64 [[A:%.*]], 0
118 ; BMI-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.cttz.i64(i64 [[A]], i1 true)
119 ; BMI-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[TOBOOL]], i64 64, i64 [[TMP0]]
120 ; BMI-NEXT: ret i64 [[SPEC_SELECT]]
122 ; LZCNT-LABEL: @test1b(
124 ; LZCNT-NEXT: [[TOBOOL:%.*]] = icmp eq i64 [[A:%.*]], 0
125 ; LZCNT-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.cttz.i64(i64 [[A]], i1 true)
126 ; LZCNT-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i64 64, i64 [[TMP0]]
127 ; LZCNT-NEXT: ret i64 [[COND]]
129 ; GENERIC-LABEL: @test1b(
130 ; GENERIC-NEXT: entry:
131 ; GENERIC-NEXT: [[TOBOOL:%.*]] = icmp eq i64 [[A:%.*]], 0
132 ; GENERIC-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.cttz.i64(i64 [[A]], i1 true)
133 ; GENERIC-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i64 64, i64 [[TMP0]]
134 ; GENERIC-NEXT: ret i64 [[COND]]
137 %tobool = icmp eq i64 %A, 0
138 br i1 %tobool, label %cond.end, label %cond.true
140 cond.true: ; preds = %entry
141 %0 = tail call i64 @llvm.cttz.i64(i64 %A, i1 true)
144 cond.end: ; preds = %entry, %cond.true
145 %cond = phi i64 [ %0, %cond.true ], [ 64, %entry ]
150 define i32 @test2b(i32 %A) {
151 ; BMI-LABEL: @test2b(
153 ; BMI-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[A:%.*]], 0
154 ; BMI-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.cttz.i32(i32 [[A]], i1 true)
155 ; BMI-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[TOBOOL]], i32 32, i32 [[TMP0]]
156 ; BMI-NEXT: ret i32 [[SPEC_SELECT]]
158 ; LZCNT-LABEL: @test2b(
160 ; LZCNT-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[A:%.*]], 0
161 ; LZCNT-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.cttz.i32(i32 [[A]], i1 true)
162 ; LZCNT-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i32 32, i32 [[TMP0]]
163 ; LZCNT-NEXT: ret i32 [[COND]]
165 ; GENERIC-LABEL: @test2b(
166 ; GENERIC-NEXT: entry:
167 ; GENERIC-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[A:%.*]], 0
168 ; GENERIC-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.cttz.i32(i32 [[A]], i1 true)
169 ; GENERIC-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i32 32, i32 [[TMP0]]
170 ; GENERIC-NEXT: ret i32 [[COND]]
173 %tobool = icmp eq i32 %A, 0
174 br i1 %tobool, label %cond.end, label %cond.true
176 cond.true: ; preds = %entry
177 %0 = tail call i32 @llvm.cttz.i32(i32 %A, i1 true)
180 cond.end: ; preds = %entry, %cond.true
181 %cond = phi i32 [ %0, %cond.true ], [ 32, %entry ]
186 define signext i16 @test3b(i16 signext %A) {
187 ; BMI-LABEL: @test3b(
189 ; BMI-NEXT: [[TOBOOL:%.*]] = icmp eq i16 [[A:%.*]], 0
190 ; BMI-NEXT: [[TMP0:%.*]] = tail call i16 @llvm.cttz.i16(i16 [[A]], i1 true)
191 ; BMI-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[TOBOOL]], i16 16, i16 [[TMP0]]
192 ; BMI-NEXT: ret i16 [[SPEC_SELECT]]
194 ; LZCNT-LABEL: @test3b(
196 ; LZCNT-NEXT: [[TOBOOL:%.*]] = icmp eq i16 [[A:%.*]], 0
197 ; LZCNT-NEXT: [[TMP0:%.*]] = tail call i16 @llvm.cttz.i16(i16 [[A]], i1 true)
198 ; LZCNT-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i16 16, i16 [[TMP0]]
199 ; LZCNT-NEXT: ret i16 [[COND]]
201 ; GENERIC-LABEL: @test3b(
202 ; GENERIC-NEXT: entry:
203 ; GENERIC-NEXT: [[TOBOOL:%.*]] = icmp eq i16 [[A:%.*]], 0
204 ; GENERIC-NEXT: [[TMP0:%.*]] = tail call i16 @llvm.cttz.i16(i16 [[A]], i1 true)
205 ; GENERIC-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i16 16, i16 [[TMP0]]
206 ; GENERIC-NEXT: ret i16 [[COND]]
209 %tobool = icmp eq i16 %A, 0
210 br i1 %tobool, label %cond.end, label %cond.true
212 cond.true: ; preds = %entry
213 %0 = tail call i16 @llvm.cttz.i16(i16 %A, i1 true)
216 cond.end: ; preds = %entry, %cond.true
217 %cond = phi i16 [ %0, %cond.true ], [ 16, %entry ]
221 ; The following tests verify that calls to cttz/ctlz are speculated even if
222 ; basic block %cond.true has an extra zero extend/truncate which is "free"
225 define i64 @test1e(i32 %x) {
226 ; ALL-LABEL: @test1e(
228 ; ALL-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[X:%.*]], 0
229 ; ALL-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.cttz.i32(i32 [[X]], i1 true)
230 ; ALL-NEXT: [[PHITMP2:%.*]] = zext i32 [[TMP0]] to i64
231 ; ALL-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i64 32, i64 [[PHITMP2]]
232 ; ALL-NEXT: ret i64 [[COND]]
235 %tobool = icmp eq i32 %x, 0
236 br i1 %tobool, label %cond.end, label %cond.true
238 cond.true: ; preds = %entry
239 %0 = tail call i32 @llvm.cttz.i32(i32 %x, i1 true)
240 %phitmp2 = zext i32 %0 to i64
243 cond.end: ; preds = %entry, %cond.true
244 %cond = phi i64 [ %phitmp2, %cond.true ], [ 32, %entry ]
248 define i32 @test2e(i64 %x) {
249 ; ALL-LABEL: @test2e(
251 ; ALL-NEXT: [[TOBOOL:%.*]] = icmp eq i64 [[X:%.*]], 0
252 ; ALL-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.cttz.i64(i64 [[X]], i1 true)
253 ; ALL-NEXT: [[CAST:%.*]] = trunc i64 [[TMP0]] to i32
254 ; ALL-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i32 64, i32 [[CAST]]
255 ; ALL-NEXT: ret i32 [[COND]]
258 %tobool = icmp eq i64 %x, 0
259 br i1 %tobool, label %cond.end, label %cond.true
261 cond.true: ; preds = %entry
262 %0 = tail call i64 @llvm.cttz.i64(i64 %x, i1 true)
263 %cast = trunc i64 %0 to i32
266 cond.end: ; preds = %entry, %cond.true
267 %cond = phi i32 [ %cast, %cond.true ], [ 64, %entry ]
271 define i64 @test3e(i32 %x) {
272 ; ALL-LABEL: @test3e(
274 ; ALL-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[X:%.*]], 0
275 ; ALL-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.ctlz.i32(i32 [[X]], i1 true)
276 ; ALL-NEXT: [[PHITMP2:%.*]] = zext i32 [[TMP0]] to i64
277 ; ALL-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i64 32, i64 [[PHITMP2]]
278 ; ALL-NEXT: ret i64 [[COND]]
281 %tobool = icmp eq i32 %x, 0
282 br i1 %tobool, label %cond.end, label %cond.true
284 cond.true: ; preds = %entry
285 %0 = tail call i32 @llvm.ctlz.i32(i32 %x, i1 true)
286 %phitmp2 = zext i32 %0 to i64
289 cond.end: ; preds = %entry, %cond.true
290 %cond = phi i64 [ %phitmp2, %cond.true ], [ 32, %entry ]
294 define i32 @test4e(i64 %x) {
295 ; ALL-LABEL: @test4e(
297 ; ALL-NEXT: [[TOBOOL:%.*]] = icmp eq i64 [[X:%.*]], 0
298 ; ALL-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.ctlz.i64(i64 [[X]], i1 true)
299 ; ALL-NEXT: [[CAST:%.*]] = trunc i64 [[TMP0]] to i32
300 ; ALL-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i32 64, i32 [[CAST]]
301 ; ALL-NEXT: ret i32 [[COND]]
304 %tobool = icmp eq i64 %x, 0
305 br i1 %tobool, label %cond.end, label %cond.true
307 cond.true: ; preds = %entry
308 %0 = tail call i64 @llvm.ctlz.i64(i64 %x, i1 true)
309 %cast = trunc i64 %0 to i32
312 cond.end: ; preds = %entry, %cond.true
313 %cond = phi i32 [ %cast, %cond.true ], [ 64, %entry ]
317 define i16 @test5e(i64 %x) {
318 ; ALL-LABEL: @test5e(
320 ; ALL-NEXT: [[TOBOOL:%.*]] = icmp eq i64 [[X:%.*]], 0
321 ; ALL-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.ctlz.i64(i64 [[X]], i1 true)
322 ; ALL-NEXT: [[CAST:%.*]] = trunc i64 [[TMP0]] to i16
323 ; ALL-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i16 64, i16 [[CAST]]
324 ; ALL-NEXT: ret i16 [[COND]]
327 %tobool = icmp eq i64 %x, 0
328 br i1 %tobool, label %cond.end, label %cond.true
330 cond.true: ; preds = %entry
331 %0 = tail call i64 @llvm.ctlz.i64(i64 %x, i1 true)
332 %cast = trunc i64 %0 to i16
335 cond.end: ; preds = %entry, %cond.true
336 %cond = phi i16 [ %cast, %cond.true ], [ 64, %entry ]
340 define i16 @test6e(i32 %x) {
341 ; ALL-LABEL: @test6e(
343 ; ALL-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[X:%.*]], 0
344 ; ALL-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.ctlz.i32(i32 [[X]], i1 true)
345 ; ALL-NEXT: [[CAST:%.*]] = trunc i32 [[TMP0]] to i16
346 ; ALL-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i16 32, i16 [[CAST]]
347 ; ALL-NEXT: ret i16 [[COND]]
350 %tobool = icmp eq i32 %x, 0
351 br i1 %tobool, label %cond.end, label %cond.true
353 cond.true: ; preds = %entry
354 %0 = tail call i32 @llvm.ctlz.i32(i32 %x, i1 true)
355 %cast = trunc i32 %0 to i16
358 cond.end: ; preds = %entry, %cond.true
359 %cond = phi i16 [ %cast, %cond.true ], [ 32, %entry ]
363 define i16 @test7e(i64 %x) {
364 ; ALL-LABEL: @test7e(
366 ; ALL-NEXT: [[TOBOOL:%.*]] = icmp eq i64 [[X:%.*]], 0
367 ; ALL-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.cttz.i64(i64 [[X]], i1 true)
368 ; ALL-NEXT: [[CAST:%.*]] = trunc i64 [[TMP0]] to i16
369 ; ALL-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i16 64, i16 [[CAST]]
370 ; ALL-NEXT: ret i16 [[COND]]
373 %tobool = icmp eq i64 %x, 0
374 br i1 %tobool, label %cond.end, label %cond.true
376 cond.true: ; preds = %entry
377 %0 = tail call i64 @llvm.cttz.i64(i64 %x, i1 true)
378 %cast = trunc i64 %0 to i16
381 cond.end: ; preds = %entry, %cond.true
382 %cond = phi i16 [ %cast, %cond.true ], [ 64, %entry ]
386 define i16 @test8e(i32 %x) {
387 ; ALL-LABEL: @test8e(
389 ; ALL-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[X:%.*]], 0
390 ; ALL-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.cttz.i32(i32 [[X]], i1 true)
391 ; ALL-NEXT: [[CAST:%.*]] = trunc i32 [[TMP0]] to i16
392 ; ALL-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i16 32, i16 [[CAST]]
393 ; ALL-NEXT: ret i16 [[COND]]
396 %tobool = icmp eq i32 %x, 0
397 br i1 %tobool, label %cond.end, label %cond.true
399 cond.true: ; preds = %entry
400 %0 = tail call i32 @llvm.cttz.i32(i32 %x, i1 true)
401 %cast = trunc i32 %0 to i16
404 cond.end: ; preds = %entry, %cond.true
405 %cond = phi i16 [ %cast, %cond.true ], [ 32, %entry ]
410 declare i64 @llvm.ctlz.i64(i64, i1)
411 declare i32 @llvm.ctlz.i32(i32, i1)
412 declare i16 @llvm.ctlz.i16(i16, i1)
413 declare i64 @llvm.cttz.i64(i64, i1)
414 declare i32 @llvm.cttz.i32(i32, i1)
415 declare i16 @llvm.cttz.i16(i16, i1)