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