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
3
4; We are looking for the following pattern here:
5;   (X & (C l>> Y)) ==/!= 0
6; It may be optimal to hoist the constant:
7;   ((X << Y) & C) ==/!= 0
8
9;------------------------------------------------------------------------------;
10; A few scalar test
11;------------------------------------------------------------------------------;
12
13; i8 scalar
14
15define i1 @scalar_i8_signbit_eq(i8 %x, i8 %y) nounwind {
16; CHECK-LABEL: scalar_i8_signbit_eq:
17; CHECK:       // %bb.0:
18; CHECK-NEXT:    // kill: def $w1 killed $w1 def $x1
19; CHECK-NEXT:    lsl w8, w0, w1
20; CHECK-NEXT:    tst w8, #0x80
21; CHECK-NEXT:    cset w0, eq
22; CHECK-NEXT:    ret
23  %t0 = lshr i8 128, %y
24  %t1 = and i8 %t0, %x
25  %res = icmp eq i8 %t1, 0
26  ret i1 %res
27}
28
29define i1 @scalar_i8_lowestbit_eq(i8 %x, i8 %y) nounwind {
30; CHECK-LABEL: scalar_i8_lowestbit_eq:
31; CHECK:       // %bb.0:
32; CHECK-NEXT:    // kill: def $w1 killed $w1 def $x1
33; CHECK-NEXT:    lsl w8, w0, w1
34; CHECK-NEXT:    tst w8, #0x1
35; CHECK-NEXT:    cset w0, eq
36; CHECK-NEXT:    ret
37  %t0 = lshr i8 1, %y
38  %t1 = and i8 %t0, %x
39  %res = icmp eq i8 %t1, 0
40  ret i1 %res
41}
42
43define i1 @scalar_i8_bitsinmiddle_eq(i8 %x, i8 %y) nounwind {
44; CHECK-LABEL: scalar_i8_bitsinmiddle_eq:
45; CHECK:       // %bb.0:
46; CHECK-NEXT:    // kill: def $w1 killed $w1 def $x1
47; CHECK-NEXT:    lsl w8, w0, w1
48; CHECK-NEXT:    tst w8, #0x18
49; CHECK-NEXT:    cset w0, eq
50; CHECK-NEXT:    ret
51  %t0 = lshr i8 24, %y
52  %t1 = and i8 %t0, %x
53  %res = icmp eq i8 %t1, 0
54  ret i1 %res
55}
56
57; i16 scalar
58
59define i1 @scalar_i16_signbit_eq(i16 %x, i16 %y) nounwind {
60; CHECK-LABEL: scalar_i16_signbit_eq:
61; CHECK:       // %bb.0:
62; CHECK-NEXT:    // kill: def $w1 killed $w1 def $x1
63; CHECK-NEXT:    lsl w8, w0, w1
64; CHECK-NEXT:    tst w8, #0x8000
65; CHECK-NEXT:    cset w0, eq
66; CHECK-NEXT:    ret
67  %t0 = lshr i16 32768, %y
68  %t1 = and i16 %t0, %x
69  %res = icmp eq i16 %t1, 0
70  ret i1 %res
71}
72
73define i1 @scalar_i16_lowestbit_eq(i16 %x, i16 %y) nounwind {
74; CHECK-LABEL: scalar_i16_lowestbit_eq:
75; CHECK:       // %bb.0:
76; CHECK-NEXT:    // kill: def $w1 killed $w1 def $x1
77; CHECK-NEXT:    lsl w8, w0, w1
78; CHECK-NEXT:    tst w8, #0x1
79; CHECK-NEXT:    cset w0, eq
80; CHECK-NEXT:    ret
81  %t0 = lshr i16 1, %y
82  %t1 = and i16 %t0, %x
83  %res = icmp eq i16 %t1, 0
84  ret i1 %res
85}
86
87define i1 @scalar_i16_bitsinmiddle_eq(i16 %x, i16 %y) nounwind {
88; CHECK-LABEL: scalar_i16_bitsinmiddle_eq:
89; CHECK:       // %bb.0:
90; CHECK-NEXT:    // kill: def $w1 killed $w1 def $x1
91; CHECK-NEXT:    lsl w8, w0, w1
92; CHECK-NEXT:    tst w8, #0xff0
93; CHECK-NEXT:    cset w0, eq
94; CHECK-NEXT:    ret
95  %t0 = lshr i16 4080, %y
96  %t1 = and i16 %t0, %x
97  %res = icmp eq i16 %t1, 0
98  ret i1 %res
99}
100
101; i32 scalar
102
103define i1 @scalar_i32_signbit_eq(i32 %x, i32 %y) nounwind {
104; CHECK-LABEL: scalar_i32_signbit_eq:
105; CHECK:       // %bb.0:
106; CHECK-NEXT:    lsl w8, w0, w1
107; CHECK-NEXT:    tst w8, #0x80000000
108; CHECK-NEXT:    cset w0, eq
109; CHECK-NEXT:    ret
110  %t0 = lshr i32 2147483648, %y
111  %t1 = and i32 %t0, %x
112  %res = icmp eq i32 %t1, 0
113  ret i1 %res
114}
115
116define i1 @scalar_i32_lowestbit_eq(i32 %x, i32 %y) nounwind {
117; CHECK-LABEL: scalar_i32_lowestbit_eq:
118; CHECK:       // %bb.0:
119; CHECK-NEXT:    lsl w8, w0, w1
120; CHECK-NEXT:    tst w8, #0x1
121; CHECK-NEXT:    cset w0, eq
122; CHECK-NEXT:    ret
123  %t0 = lshr i32 1, %y
124  %t1 = and i32 %t0, %x
125  %res = icmp eq i32 %t1, 0
126  ret i1 %res
127}
128
129define i1 @scalar_i32_bitsinmiddle_eq(i32 %x, i32 %y) nounwind {
130; CHECK-LABEL: scalar_i32_bitsinmiddle_eq:
131; CHECK:       // %bb.0:
132; CHECK-NEXT:    lsl w8, w0, w1
133; CHECK-NEXT:    tst w8, #0xffff00
134; CHECK-NEXT:    cset w0, eq
135; CHECK-NEXT:    ret
136  %t0 = lshr i32 16776960, %y
137  %t1 = and i32 %t0, %x
138  %res = icmp eq i32 %t1, 0
139  ret i1 %res
140}
141
142; i64 scalar
143
144define i1 @scalar_i64_signbit_eq(i64 %x, i64 %y) nounwind {
145; CHECK-LABEL: scalar_i64_signbit_eq:
146; CHECK:       // %bb.0:
147; CHECK-NEXT:    lsl x8, x0, x1
148; CHECK-NEXT:    tst x8, #0x8000000000000000
149; CHECK-NEXT:    cset w0, eq
150; CHECK-NEXT:    ret
151  %t0 = lshr i64 9223372036854775808, %y
152  %t1 = and i64 %t0, %x
153  %res = icmp eq i64 %t1, 0
154  ret i1 %res
155}
156
157define i1 @scalar_i64_lowestbit_eq(i64 %x, i64 %y) nounwind {
158; CHECK-LABEL: scalar_i64_lowestbit_eq:
159; CHECK:       // %bb.0:
160; CHECK-NEXT:    lsl x8, x0, x1
161; CHECK-NEXT:    tst x8, #0x1
162; CHECK-NEXT:    cset w0, eq
163; CHECK-NEXT:    ret
164  %t0 = lshr i64 1, %y
165  %t1 = and i64 %t0, %x
166  %res = icmp eq i64 %t1, 0
167  ret i1 %res
168}
169
170define i1 @scalar_i64_bitsinmiddle_eq(i64 %x, i64 %y) nounwind {
171; CHECK-LABEL: scalar_i64_bitsinmiddle_eq:
172; CHECK:       // %bb.0:
173; CHECK-NEXT:    lsl x8, x0, x1
174; CHECK-NEXT:    tst x8, #0xffffffff0000
175; CHECK-NEXT:    cset w0, eq
176; CHECK-NEXT:    ret
177  %t0 = lshr i64 281474976645120, %y
178  %t1 = and i64 %t0, %x
179  %res = icmp eq i64 %t1, 0
180  ret i1 %res
181}
182
183;------------------------------------------------------------------------------;
184; A few trivial vector tests
185;------------------------------------------------------------------------------;
186
187define <4 x i1> @vec_4xi32_splat_eq(<4 x i32> %x, <4 x i32> %y) nounwind {
188; CHECK-LABEL: vec_4xi32_splat_eq:
189; CHECK:       // %bb.0:
190; CHECK-NEXT:    movi v2.4s, #1
191; CHECK-NEXT:    ushl v0.4s, v0.4s, v1.4s
192; CHECK-NEXT:    and v0.16b, v0.16b, v2.16b
193; CHECK-NEXT:    cmeq v0.4s, v0.4s, #0
194; CHECK-NEXT:    xtn v0.4h, v0.4s
195; CHECK-NEXT:    ret
196  %t0 = lshr <4 x i32> <i32 1, i32 1, i32 1, i32 1>, %y
197  %t1 = and <4 x i32> %t0, %x
198  %res = icmp eq <4 x i32> %t1, <i32 0, i32 0, i32 0, i32 0>
199  ret <4 x i1> %res
200}
201
202define <4 x i1> @vec_4xi32_nonsplat_eq(<4 x i32> %x, <4 x i32> %y) nounwind {
203; CHECK-LABEL: vec_4xi32_nonsplat_eq:
204; CHECK:       // %bb.0:
205; CHECK-NEXT:    adrp x8, .LCPI13_0
206; CHECK-NEXT:    ldr q2, [x8, :lo12:.LCPI13_0]
207; CHECK-NEXT:    neg v1.4s, v1.4s
208; CHECK-NEXT:    ushl v1.4s, v2.4s, v1.4s
209; CHECK-NEXT:    and v0.16b, v1.16b, v0.16b
210; CHECK-NEXT:    cmeq v0.4s, v0.4s, #0
211; CHECK-NEXT:    xtn v0.4h, v0.4s
212; CHECK-NEXT:    ret
213  %t0 = lshr <4 x i32> <i32 0, i32 1, i32 16776960, i32 2147483648>, %y
214  %t1 = and <4 x i32> %t0, %x
215  %res = icmp eq <4 x i32> %t1, <i32 0, i32 0, i32 0, i32 0>
216  ret <4 x i1> %res
217}
218
219define <4 x i1> @vec_4xi32_nonsplat_undef0_eq(<4 x i32> %x, <4 x i32> %y) nounwind {
220; CHECK-LABEL: vec_4xi32_nonsplat_undef0_eq:
221; CHECK:       // %bb.0:
222; CHECK-NEXT:    movi v2.4s, #1
223; CHECK-NEXT:    ushl v0.4s, v0.4s, v1.4s
224; CHECK-NEXT:    and v0.16b, v0.16b, v2.16b
225; CHECK-NEXT:    cmeq v0.4s, v0.4s, #0
226; CHECK-NEXT:    xtn v0.4h, v0.4s
227; CHECK-NEXT:    ret
228  %t0 = lshr <4 x i32> <i32 1, i32 1, i32 undef, i32 1>, %y
229  %t1 = and <4 x i32> %t0, %x
230  %res = icmp eq <4 x i32> %t1, <i32 0, i32 0, i32 0, i32 0>
231  ret <4 x i1> %res
232}
233define <4 x i1> @vec_4xi32_nonsplat_undef1_eq(<4 x i32> %x, <4 x i32> %y) nounwind {
234; CHECK-LABEL: vec_4xi32_nonsplat_undef1_eq:
235; CHECK:       // %bb.0:
236; CHECK-NEXT:    neg v1.4s, v1.4s
237; CHECK-NEXT:    movi v2.4s, #1
238; CHECK-NEXT:    ushl v1.4s, v2.4s, v1.4s
239; CHECK-NEXT:    and v0.16b, v1.16b, v0.16b
240; CHECK-NEXT:    cmeq v0.4s, v0.4s, #0
241; CHECK-NEXT:    xtn v0.4h, v0.4s
242; CHECK-NEXT:    ret
243  %t0 = lshr <4 x i32> <i32 1, i32 1, i32 1, i32 1>, %y
244  %t1 = and <4 x i32> %t0, %x
245  %res = icmp eq <4 x i32> %t1, <i32 0, i32 0, i32 undef, i32 0>
246  ret <4 x i1> %res
247}
248define <4 x i1> @vec_4xi32_nonsplat_undef2_eq(<4 x i32> %x, <4 x i32> %y) nounwind {
249; CHECK-LABEL: vec_4xi32_nonsplat_undef2_eq:
250; CHECK:       // %bb.0:
251; CHECK-NEXT:    neg v1.4s, v1.4s
252; CHECK-NEXT:    movi v2.4s, #1
253; CHECK-NEXT:    ushl v1.4s, v2.4s, v1.4s
254; CHECK-NEXT:    and v0.16b, v1.16b, v0.16b
255; CHECK-NEXT:    cmeq v0.4s, v0.4s, #0
256; CHECK-NEXT:    xtn v0.4h, v0.4s
257; CHECK-NEXT:    ret
258  %t0 = lshr <4 x i32> <i32 1, i32 1, i32 undef, i32 1>, %y
259  %t1 = and <4 x i32> %t0, %x
260  %res = icmp eq <4 x i32> %t1, <i32 0, i32 0, i32 undef, i32 0>
261  ret <4 x i1> %res
262}
263
264;------------------------------------------------------------------------------;
265; A special tests
266;------------------------------------------------------------------------------;
267
268define i1 @scalar_i8_signbit_ne(i8 %x, i8 %y) nounwind {
269; CHECK-LABEL: scalar_i8_signbit_ne:
270; CHECK:       // %bb.0:
271; CHECK-NEXT:    // kill: def $w1 killed $w1 def $x1
272; CHECK-NEXT:    lsl w8, w0, w1
273; CHECK-NEXT:    ubfx w0, w8, #7, #1
274; CHECK-NEXT:    ret
275  %t0 = lshr i8 128, %y
276  %t1 = and i8 %t0, %x
277  %res = icmp ne i8 %t1, 0 ;  we are perfectly happy with 'ne' predicate
278  ret i1 %res
279}
280
281;------------------------------------------------------------------------------;
282; What if X is a constant too?
283;------------------------------------------------------------------------------;
284
285define i1 @scalar_i32_x_is_const_eq(i32 %y) nounwind {
286; CHECK-LABEL: scalar_i32_x_is_const_eq:
287; CHECK:       // %bb.0:
288; CHECK-NEXT:    mov w8, #43605
289; CHECK-NEXT:    movk w8, #43605, lsl #16
290; CHECK-NEXT:    lsr w8, w8, w0
291; CHECK-NEXT:    tst w8, #0x1
292; CHECK-NEXT:    cset w0, eq
293; CHECK-NEXT:    ret
294  %t0 = lshr i32 2857740885, %y
295  %t1 = and i32 %t0, 1
296  %res = icmp eq i32 %t1, 0
297  ret i1 %res
298}
299define i1 @scalar_i32_x_is_const2_eq(i32 %y) nounwind {
300; CHECK-LABEL: scalar_i32_x_is_const2_eq:
301; CHECK:       // %bb.0:
302; CHECK-NEXT:    mov w8, #1
303; CHECK-NEXT:    lsr w8, w8, w0
304; CHECK-NEXT:    cmp w8, #0 // =0
305; CHECK-NEXT:    cset w0, eq
306; CHECK-NEXT:    ret
307  %t0 = lshr i32 1, %y
308  %t1 = and i32 %t0, 2857740885
309  %res = icmp eq i32 %t1, 0
310  ret i1 %res
311}
312
313;------------------------------------------------------------------------------;
314; A few negative tests
315;------------------------------------------------------------------------------;
316
317define i1 @negative_scalar_i8_bitsinmiddle_slt(i8 %x, i8 %y) nounwind {
318; CHECK-LABEL: negative_scalar_i8_bitsinmiddle_slt:
319; CHECK:       // %bb.0:
320; CHECK-NEXT:    mov w8, #24
321; CHECK-NEXT:    // kill: def $w1 killed $w1 def $x1
322; CHECK-NEXT:    lsr w8, w8, w1
323; CHECK-NEXT:    tst w8, w0
324; CHECK-NEXT:    cset w0, lt
325; CHECK-NEXT:    ret
326  %t0 = lshr i8 24, %y
327  %t1 = and i8 %t0, %x
328  %res = icmp slt i8 %t1, 0
329  ret i1 %res
330}
331
332define i1 @scalar_i8_signbit_eq_with_nonzero(i8 %x, i8 %y) nounwind {
333; CHECK-LABEL: scalar_i8_signbit_eq_with_nonzero:
334; CHECK:       // %bb.0:
335; CHECK-NEXT:    mov w8, #128
336; CHECK-NEXT:    // kill: def $w1 killed $w1 def $x1
337; CHECK-NEXT:    lsr w8, w8, w1
338; CHECK-NEXT:    and w8, w8, w0
339; CHECK-NEXT:    cmp w8, #1 // =1
340; CHECK-NEXT:    cset w0, eq
341; CHECK-NEXT:    ret
342  %t0 = lshr i8 128, %y
343  %t1 = and i8 %t0, %x
344  %res = icmp eq i8 %t1, 1 ; should be comparing with 0
345  ret i1 %res
346}
347