1 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2 ; RUN: llc -mtriple=aarch64-unknown-unknown < %s | FileCheck %s --check-prefixes=CHECK,AARCH64
4 ; We are looking for the following pattern here:
5 ; (X & (C << Y)) ==/!= 0
6 ; It may be optimal to hoist the constant:
7 ; ((X l>> Y) & C) ==/!= 0
9 ;------------------------------------------------------------------------------;
11 ;------------------------------------------------------------------------------;
15 define i1 @scalar_i8_signbit_eq(i8 %x, i8 %y) nounwind {
16 ; CHECK-LABEL: scalar_i8_signbit_eq:
18 ; CHECK-NEXT: mov w8, #-128
19 ; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1
20 ; CHECK-NEXT: lsl w8, w8, w1
21 ; CHECK-NEXT: and w8, w8, w0
22 ; CHECK-NEXT: tst w8, #0xff
23 ; CHECK-NEXT: cset w0, eq
27 %res = icmp eq i8 %t1, 0
31 define i1 @scalar_i8_lowestbit_eq(i8 %x, i8 %y) nounwind {
32 ; CHECK-LABEL: scalar_i8_lowestbit_eq:
34 ; CHECK-NEXT: mov w8, #1
35 ; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1
36 ; CHECK-NEXT: lsl w8, w8, w1
37 ; CHECK-NEXT: and w8, w8, w0
38 ; CHECK-NEXT: tst w8, #0xff
39 ; CHECK-NEXT: cset w0, eq
43 %res = icmp eq i8 %t1, 0
47 define i1 @scalar_i8_bitsinmiddle_eq(i8 %x, i8 %y) nounwind {
48 ; CHECK-LABEL: scalar_i8_bitsinmiddle_eq:
50 ; CHECK-NEXT: mov w8, #24
51 ; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1
52 ; CHECK-NEXT: lsl w8, w8, w1
53 ; CHECK-NEXT: and w8, w8, w0
54 ; CHECK-NEXT: tst w8, #0xff
55 ; CHECK-NEXT: cset w0, eq
59 %res = icmp eq i8 %t1, 0
65 define i1 @scalar_i16_signbit_eq(i16 %x, i16 %y) nounwind {
66 ; CHECK-LABEL: scalar_i16_signbit_eq:
68 ; CHECK-NEXT: mov w8, #-32768
69 ; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1
70 ; CHECK-NEXT: lsl w8, w8, w1
71 ; CHECK-NEXT: and w8, w8, w0
72 ; CHECK-NEXT: tst w8, #0xffff
73 ; CHECK-NEXT: cset w0, eq
75 %t0 = shl i16 32768, %y
77 %res = icmp eq i16 %t1, 0
81 define i1 @scalar_i16_lowestbit_eq(i16 %x, i16 %y) nounwind {
82 ; CHECK-LABEL: scalar_i16_lowestbit_eq:
84 ; CHECK-NEXT: mov w8, #1
85 ; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1
86 ; CHECK-NEXT: lsl w8, w8, w1
87 ; CHECK-NEXT: and w8, w8, w0
88 ; CHECK-NEXT: tst w8, #0xffff
89 ; CHECK-NEXT: cset w0, eq
93 %res = icmp eq i16 %t1, 0
97 define i1 @scalar_i16_bitsinmiddle_eq(i16 %x, i16 %y) nounwind {
98 ; CHECK-LABEL: scalar_i16_bitsinmiddle_eq:
100 ; CHECK-NEXT: mov w8, #4080
101 ; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1
102 ; CHECK-NEXT: lsl w8, w8, w1
103 ; CHECK-NEXT: and w8, w8, w0
104 ; CHECK-NEXT: tst w8, #0xffff
105 ; CHECK-NEXT: cset w0, eq
107 %t0 = shl i16 4080, %y
108 %t1 = and i16 %t0, %x
109 %res = icmp eq i16 %t1, 0
115 define i1 @scalar_i32_signbit_eq(i32 %x, i32 %y) nounwind {
116 ; CHECK-LABEL: scalar_i32_signbit_eq:
118 ; CHECK-NEXT: mov w8, #-2147483648
119 ; CHECK-NEXT: lsl w8, w8, w1
120 ; CHECK-NEXT: tst w8, w0
121 ; CHECK-NEXT: cset w0, eq
123 %t0 = shl i32 2147483648, %y
124 %t1 = and i32 %t0, %x
125 %res = icmp eq i32 %t1, 0
129 define i1 @scalar_i32_lowestbit_eq(i32 %x, i32 %y) nounwind {
130 ; CHECK-LABEL: scalar_i32_lowestbit_eq:
132 ; CHECK-NEXT: mov w8, #1
133 ; CHECK-NEXT: lsl w8, w8, w1
134 ; CHECK-NEXT: tst w8, w0
135 ; CHECK-NEXT: cset w0, eq
138 %t1 = and i32 %t0, %x
139 %res = icmp eq i32 %t1, 0
143 define i1 @scalar_i32_bitsinmiddle_eq(i32 %x, i32 %y) nounwind {
144 ; CHECK-LABEL: scalar_i32_bitsinmiddle_eq:
146 ; CHECK-NEXT: mov w8, #16776960
147 ; CHECK-NEXT: lsl w8, w8, w1
148 ; CHECK-NEXT: tst w8, w0
149 ; CHECK-NEXT: cset w0, eq
151 %t0 = shl i32 16776960, %y
152 %t1 = and i32 %t0, %x
153 %res = icmp eq i32 %t1, 0
159 define i1 @scalar_i64_signbit_eq(i64 %x, i64 %y) nounwind {
160 ; CHECK-LABEL: scalar_i64_signbit_eq:
162 ; CHECK-NEXT: mov x8, #-9223372036854775808
163 ; CHECK-NEXT: lsl x8, x8, x1
164 ; CHECK-NEXT: tst x8, x0
165 ; CHECK-NEXT: cset w0, eq
167 %t0 = shl i64 9223372036854775808, %y
168 %t1 = and i64 %t0, %x
169 %res = icmp eq i64 %t1, 0
173 define i1 @scalar_i64_lowestbit_eq(i64 %x, i64 %y) nounwind {
174 ; CHECK-LABEL: scalar_i64_lowestbit_eq:
176 ; CHECK-NEXT: mov w8, #1
177 ; CHECK-NEXT: lsl x8, x8, x1
178 ; CHECK-NEXT: tst x8, x0
179 ; CHECK-NEXT: cset w0, eq
182 %t1 = and i64 %t0, %x
183 %res = icmp eq i64 %t1, 0
187 define i1 @scalar_i64_bitsinmiddle_eq(i64 %x, i64 %y) nounwind {
188 ; CHECK-LABEL: scalar_i64_bitsinmiddle_eq:
190 ; CHECK-NEXT: mov x8, #281474976645120
191 ; CHECK-NEXT: lsl x8, x8, x1
192 ; CHECK-NEXT: tst x8, x0
193 ; CHECK-NEXT: cset w0, eq
195 %t0 = shl i64 281474976645120, %y
196 %t1 = and i64 %t0, %x
197 %res = icmp eq i64 %t1, 0
201 ;------------------------------------------------------------------------------;
202 ; A few trivial vector tests
203 ;------------------------------------------------------------------------------;
205 define <4 x i1> @vec_4xi32_splat_eq(<4 x i32> %x, <4 x i32> %y) nounwind {
206 ; CHECK-LABEL: vec_4xi32_splat_eq:
208 ; CHECK-NEXT: movi v2.4s, #1
209 ; CHECK-NEXT: ushl v1.4s, v2.4s, v1.4s
210 ; CHECK-NEXT: and v0.16b, v1.16b, v0.16b
211 ; CHECK-NEXT: cmeq v0.4s, v0.4s, #0
212 ; CHECK-NEXT: xtn v0.4h, v0.4s
214 %t0 = shl <4 x i32> <i32 1, i32 1, i32 1, i32 1>, %y
215 %t1 = and <4 x i32> %t0, %x
216 %res = icmp eq <4 x i32> %t1, <i32 0, i32 0, i32 0, i32 0>
220 define <4 x i1> @vec_4xi32_nonsplat_eq(<4 x i32> %x, <4 x i32> %y) nounwind {
221 ; CHECK-LABEL: vec_4xi32_nonsplat_eq:
223 ; CHECK-NEXT: adrp x8, .LCPI13_0
224 ; CHECK-NEXT: ldr q2, [x8, :lo12:.LCPI13_0]
225 ; CHECK-NEXT: ushl v1.4s, v2.4s, v1.4s
226 ; CHECK-NEXT: and v0.16b, v1.16b, v0.16b
227 ; CHECK-NEXT: cmeq v0.4s, v0.4s, #0
228 ; CHECK-NEXT: xtn v0.4h, v0.4s
230 %t0 = shl <4 x i32> <i32 0, i32 1, i32 16776960, i32 2147483648>, %y
231 %t1 = and <4 x i32> %t0, %x
232 %res = icmp eq <4 x i32> %t1, <i32 0, i32 0, i32 0, i32 0>
236 define <4 x i1> @vec_4xi32_nonsplat_undef0_eq(<4 x i32> %x, <4 x i32> %y) nounwind {
237 ; CHECK-LABEL: vec_4xi32_nonsplat_undef0_eq:
239 ; CHECK-NEXT: movi v2.4s, #1
240 ; CHECK-NEXT: ushl v1.4s, v2.4s, v1.4s
241 ; CHECK-NEXT: and v0.16b, v1.16b, v0.16b
242 ; CHECK-NEXT: cmeq v0.4s, v0.4s, #0
243 ; CHECK-NEXT: xtn v0.4h, v0.4s
245 %t0 = shl <4 x i32> <i32 1, i32 1, i32 undef, i32 1>, %y
246 %t1 = and <4 x i32> %t0, %x
247 %res = icmp eq <4 x i32> %t1, <i32 0, i32 0, i32 0, i32 0>
250 define <4 x i1> @vec_4xi32_nonsplat_undef1_eq(<4 x i32> %x, <4 x i32> %y) nounwind {
251 ; CHECK-LABEL: vec_4xi32_nonsplat_undef1_eq:
253 ; CHECK-NEXT: movi v2.4s, #1
254 ; CHECK-NEXT: ushl v1.4s, v2.4s, v1.4s
255 ; CHECK-NEXT: and v0.16b, v1.16b, v0.16b
256 ; CHECK-NEXT: cmeq v0.4s, v0.4s, #0
257 ; CHECK-NEXT: xtn v0.4h, v0.4s
259 %t0 = shl <4 x i32> <i32 1, i32 1, i32 1, i32 1>, %y
260 %t1 = and <4 x i32> %t0, %x
261 %res = icmp eq <4 x i32> %t1, <i32 0, i32 0, i32 undef, i32 0>
264 define <4 x i1> @vec_4xi32_nonsplat_undef2_eq(<4 x i32> %x, <4 x i32> %y) nounwind {
265 ; CHECK-LABEL: vec_4xi32_nonsplat_undef2_eq:
267 ; CHECK-NEXT: movi v2.4s, #1
268 ; CHECK-NEXT: ushl v1.4s, v2.4s, v1.4s
269 ; CHECK-NEXT: and v0.16b, v1.16b, v0.16b
270 ; CHECK-NEXT: cmeq v0.4s, v0.4s, #0
271 ; CHECK-NEXT: xtn v0.4h, v0.4s
273 %t0 = shl <4 x i32> <i32 1, i32 1, i32 undef, i32 1>, %y
274 %t1 = and <4 x i32> %t0, %x
275 %res = icmp eq <4 x i32> %t1, <i32 0, i32 0, i32 undef, i32 0>
279 ;------------------------------------------------------------------------------;
281 ;------------------------------------------------------------------------------;
283 define i1 @scalar_i8_signbit_ne(i8 %x, i8 %y) nounwind {
284 ; CHECK-LABEL: scalar_i8_signbit_ne:
286 ; CHECK-NEXT: mov w8, #-128
287 ; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1
288 ; CHECK-NEXT: lsl w8, w8, w1
289 ; CHECK-NEXT: and w8, w8, w0
290 ; CHECK-NEXT: tst w8, #0xff
291 ; CHECK-NEXT: cset w0, ne
295 %res = icmp ne i8 %t1, 0 ; we are perfectly happy with 'ne' predicate
299 ;------------------------------------------------------------------------------;
300 ; What if X is a constant too?
301 ;------------------------------------------------------------------------------;
303 define i1 @scalar_i32_x_is_const_eq(i32 %y) nounwind {
304 ; CHECK-LABEL: scalar_i32_x_is_const_eq:
306 ; CHECK-NEXT: mov w8, #43605
307 ; CHECK-NEXT: movk w8, #43605, lsl #16
308 ; CHECK-NEXT: lsl w8, w8, w0
309 ; CHECK-NEXT: tst w8, #0x1
310 ; CHECK-NEXT: cset w0, eq
312 %t0 = shl i32 2857740885, %y
314 %res = icmp eq i32 %t1, 0
317 define i1 @scalar_i32_x_is_const2_eq(i32 %y) nounwind {
318 ; CHECK-LABEL: scalar_i32_x_is_const2_eq:
320 ; CHECK-NEXT: mov w8, #1
321 ; CHECK-NEXT: mov w9, #43605
322 ; CHECK-NEXT: lsl w8, w8, w0
323 ; CHECK-NEXT: movk w9, #43605, lsl #16
324 ; CHECK-NEXT: tst w8, w9
325 ; CHECK-NEXT: cset w0, eq
328 %t1 = and i32 %t0, 2857740885
329 %res = icmp eq i32 %t1, 0
333 ;------------------------------------------------------------------------------;
334 ; A few negative tests
335 ;------------------------------------------------------------------------------;
337 define i1 @negative_scalar_i8_bitsinmiddle_slt(i8 %x, i8 %y) nounwind {
338 ; CHECK-LABEL: negative_scalar_i8_bitsinmiddle_slt:
340 ; CHECK-NEXT: mov w8, #24
341 ; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1
342 ; CHECK-NEXT: lsl w8, w8, w1
343 ; CHECK-NEXT: and w8, w8, w0
344 ; CHECK-NEXT: sxtb w8, w8
345 ; CHECK-NEXT: cmp w8, #0 // =0
346 ; CHECK-NEXT: cset w0, lt
350 %res = icmp slt i8 %t1, 0
354 define i1 @scalar_i8_signbit_eq_with_nonzero(i8 %x, i8 %y) nounwind {
355 ; CHECK-LABEL: scalar_i8_signbit_eq_with_nonzero:
357 ; CHECK-NEXT: mov w8, #-128
358 ; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1
359 ; CHECK-NEXT: lsl w8, w8, w1
360 ; CHECK-NEXT: and w8, w8, w0
361 ; CHECK-NEXT: and w8, w8, #0xff
362 ; CHECK-NEXT: cmp w8, #1 // =1
363 ; CHECK-NEXT: cset w0, eq
367 %res = icmp eq i8 %t1, 1 ; should be comparing with 0