xref: /llvm-project/llvm/test/CodeGen/AArch64/shift-logic.ll (revision 345e419483d69cbfdd89c0d6475a19614323eb8b)
1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2; RUN: llc < %s -mtriple=aarch64-- | FileCheck %s
3; RUN: llc < %s -mtriple=aarch64-- -global-isel -global-isel-abort=1 | FileCheck %s --check-prefix=CHECK-GISEL
4
5define i8 @shl_and(i8 %x, i8 %y) nounwind {
6; CHECK-LABEL: shl_and:
7; CHECK:       // %bb.0:
8; CHECK-NEXT:    lsl w8, w0, #5
9; CHECK-NEXT:    and w0, w8, w1, lsl #2
10; CHECK-NEXT:    ret
11;
12; CHECK-GISEL-LABEL: shl_and:
13; CHECK-GISEL:       // %bb.0:
14; CHECK-GISEL-NEXT:    lsl w8, w1, #2
15; CHECK-GISEL-NEXT:    and w0, w8, w0, lsl #5
16; CHECK-GISEL-NEXT:    ret
17  %sh0 = shl i8 %x, 3
18  %r = and i8 %sh0, %y
19  %sh1 = shl i8 %r, 2
20  ret i8 %sh1
21}
22
23define i16 @shl_or(i16 %x, i16 %y) nounwind {
24; CHECK-LABEL: shl_or:
25; CHECK:       // %bb.0:
26; CHECK-NEXT:    lsl w8, w0, #12
27; CHECK-NEXT:    orr w0, w8, w1, lsl #7
28; CHECK-NEXT:    ret
29;
30; CHECK-GISEL-LABEL: shl_or:
31; CHECK-GISEL:       // %bb.0:
32; CHECK-GISEL-NEXT:    lsl w8, w1, #7
33; CHECK-GISEL-NEXT:    orr w0, w8, w0, lsl #12
34; CHECK-GISEL-NEXT:    ret
35  %sh0 = shl i16 %x, 5
36  %r = or i16 %y, %sh0
37  %sh1 = shl i16 %r, 7
38  ret i16 %sh1
39}
40
41define i32 @shl_xor(i32 %x, i32 %y) nounwind {
42; CHECK-LABEL: shl_xor:
43; CHECK:       // %bb.0:
44; CHECK-NEXT:    lsl w8, w0, #12
45; CHECK-NEXT:    eor w0, w8, w1, lsl #7
46; CHECK-NEXT:    ret
47;
48; CHECK-GISEL-LABEL: shl_xor:
49; CHECK-GISEL:       // %bb.0:
50; CHECK-GISEL-NEXT:    lsl w8, w1, #7
51; CHECK-GISEL-NEXT:    eor w0, w8, w0, lsl #12
52; CHECK-GISEL-NEXT:    ret
53  %sh0 = shl i32 %x, 5
54  %r = xor i32 %sh0, %y
55  %sh1 = shl i32 %r, 7
56  ret i32 %sh1
57}
58
59define i64 @lshr_and(i64 %x, i64 %y) nounwind {
60; CHECK-LABEL: lshr_and:
61; CHECK:       // %bb.0:
62; CHECK-NEXT:    lsr x8, x0, #12
63; CHECK-NEXT:    and x0, x8, x1, lsr #7
64; CHECK-NEXT:    ret
65;
66; CHECK-GISEL-LABEL: lshr_and:
67; CHECK-GISEL:       // %bb.0:
68; CHECK-GISEL-NEXT:    lsr x8, x1, #7
69; CHECK-GISEL-NEXT:    and x0, x8, x0, lsr #12
70; CHECK-GISEL-NEXT:    ret
71  %sh0 = lshr i64 %x, 5
72  %r = and i64 %y, %sh0
73  %sh1 = lshr i64 %r, 7
74  ret i64 %sh1
75}
76
77define <4 x i32> @lshr_or(<4 x i32> %x, <4 x i32> %y) nounwind {
78; CHECK-LABEL: lshr_or:
79; CHECK:       // %bb.0:
80; CHECK-NEXT:    ushr v1.4s, v1.4s, #7
81; CHECK-NEXT:    ushr v0.4s, v0.4s, #12
82; CHECK-NEXT:    orr v0.16b, v0.16b, v1.16b
83; CHECK-NEXT:    ret
84;
85; CHECK-GISEL-LABEL: lshr_or:
86; CHECK-GISEL:       // %bb.0:
87; CHECK-GISEL-NEXT:    ushr v0.4s, v0.4s, #5
88; CHECK-GISEL-NEXT:    orr v0.16b, v0.16b, v1.16b
89; CHECK-GISEL-NEXT:    ushr v0.4s, v0.4s, #7
90; CHECK-GISEL-NEXT:    ret
91  %sh0 = lshr <4 x i32> %x, <i32 5, i32 5, i32 5, i32 5>
92  %r = or <4 x i32> %sh0, %y
93  %sh1 = lshr <4 x i32> %r, <i32 7, i32 7, i32 7, i32 7>
94  ret <4 x i32> %sh1
95}
96
97define <8 x i16> @lshr_xor(<8 x i16> %x, <8 x i16> %y) nounwind {
98; CHECK-LABEL: lshr_xor:
99; CHECK:       // %bb.0:
100; CHECK-NEXT:    ushr v1.8h, v1.8h, #7
101; CHECK-NEXT:    ushr v0.8h, v0.8h, #12
102; CHECK-NEXT:    eor v0.16b, v0.16b, v1.16b
103; CHECK-NEXT:    ret
104;
105; CHECK-GISEL-LABEL: lshr_xor:
106; CHECK-GISEL:       // %bb.0:
107; CHECK-GISEL-NEXT:    ushr v0.8h, v0.8h, #5
108; CHECK-GISEL-NEXT:    eor v0.16b, v1.16b, v0.16b
109; CHECK-GISEL-NEXT:    ushr v0.8h, v0.8h, #7
110; CHECK-GISEL-NEXT:    ret
111  %sh0 = lshr <8 x i16> %x, <i16 5, i16 5, i16 5, i16 5, i16 5, i16 5, i16 5, i16 5>
112  %r = xor <8 x i16> %y, %sh0
113  %sh1 = lshr <8 x i16> %r, <i16 7, i16 7, i16 7, i16 7, i16 7, i16 7, i16 7, i16 7>
114  ret <8 x i16> %sh1
115}
116
117
118define <16 x i8> @ashr_and(<16 x i8> %x, <16 x i8> %y) nounwind {
119; CHECK-LABEL: ashr_and:
120; CHECK:       // %bb.0:
121; CHECK-NEXT:    sshr v1.16b, v1.16b, #2
122; CHECK-NEXT:    sshr v0.16b, v0.16b, #5
123; CHECK-NEXT:    and v0.16b, v0.16b, v1.16b
124; CHECK-NEXT:    ret
125;
126; CHECK-GISEL-LABEL: ashr_and:
127; CHECK-GISEL:       // %bb.0:
128; CHECK-GISEL-NEXT:    sshr v0.16b, v0.16b, #3
129; CHECK-GISEL-NEXT:    and v0.16b, v1.16b, v0.16b
130; CHECK-GISEL-NEXT:    sshr v0.16b, v0.16b, #2
131; CHECK-GISEL-NEXT:    ret
132  %sh0 = ashr <16 x i8> %x, <i8 3, i8 3, i8 3, i8 3, i8 3, i8 3, i8 3, i8 3, i8 3, i8 3, i8 3, i8 3, i8 3, i8 3, i8 3, i8 3>
133  %r = and <16 x i8> %y, %sh0
134  %sh1 = ashr <16 x i8> %r, <i8 2, i8 2, i8 2, i8 2, i8 2, i8 2, i8 2, i8 2, i8 2, i8 2, i8 2, i8 2, i8 2, i8 2, i8 2, i8 2>
135  ret <16 x i8> %sh1
136}
137
138define <2 x i64> @ashr_or(<2 x i64> %x, <2 x i64> %y) nounwind {
139; CHECK-LABEL: ashr_or:
140; CHECK:       // %bb.0:
141; CHECK-NEXT:    sshr v1.2d, v1.2d, #7
142; CHECK-NEXT:    sshr v0.2d, v0.2d, #12
143; CHECK-NEXT:    orr v0.16b, v0.16b, v1.16b
144; CHECK-NEXT:    ret
145;
146; CHECK-GISEL-LABEL: ashr_or:
147; CHECK-GISEL:       // %bb.0:
148; CHECK-GISEL-NEXT:    sshr v0.2d, v0.2d, #5
149; CHECK-GISEL-NEXT:    orr v0.16b, v0.16b, v1.16b
150; CHECK-GISEL-NEXT:    sshr v0.2d, v0.2d, #7
151; CHECK-GISEL-NEXT:    ret
152  %sh0 = ashr <2 x i64> %x, <i64 5, i64 5>
153  %r = or <2 x i64> %sh0, %y
154  %sh1 = ashr <2 x i64> %r, <i64 7, i64 7>
155  ret <2 x i64> %sh1
156}
157
158define i32 @ashr_xor(i32 %x, i32 %y) nounwind {
159; CHECK-LABEL: ashr_xor:
160; CHECK:       // %bb.0:
161; CHECK-NEXT:    asr w8, w0, #12
162; CHECK-NEXT:    eor w0, w8, w1, asr #7
163; CHECK-NEXT:    ret
164;
165; CHECK-GISEL-LABEL: ashr_xor:
166; CHECK-GISEL:       // %bb.0:
167; CHECK-GISEL-NEXT:    asr w8, w1, #7
168; CHECK-GISEL-NEXT:    eor w0, w8, w0, asr #12
169; CHECK-GISEL-NEXT:    ret
170  %sh0 = ashr i32 %x, 5
171  %r = xor i32 %y, %sh0
172  %sh1 = ashr i32 %r, 7
173  ret i32 %sh1
174}
175
176define i32 @shr_mismatch_xor(i32 %x, i32 %y) nounwind {
177; CHECK-LABEL: shr_mismatch_xor:
178; CHECK:       // %bb.0:
179; CHECK-NEXT:    eor w8, w1, w0, asr #5
180; CHECK-NEXT:    lsr w0, w8, #7
181; CHECK-NEXT:    ret
182;
183; CHECK-GISEL-LABEL: shr_mismatch_xor:
184; CHECK-GISEL:       // %bb.0:
185; CHECK-GISEL-NEXT:    eor w8, w1, w0, asr #5
186; CHECK-GISEL-NEXT:    lsr w0, w8, #7
187; CHECK-GISEL-NEXT:    ret
188  %sh0 = ashr i32 %x, 5
189  %r = xor i32 %y, %sh0
190  %sh1 = lshr i32 %r, 7
191  ret i32 %sh1
192}
193
194define i32 @ashr_overshift_xor(i32 %x, i32 %y) nounwind {
195; CHECK-LABEL: ashr_overshift_xor:
196; CHECK:       // %bb.0:
197; CHECK-NEXT:    eor w8, w1, w0, asr #15
198; CHECK-NEXT:    asr w0, w8, #17
199; CHECK-NEXT:    ret
200;
201; CHECK-GISEL-LABEL: ashr_overshift_xor:
202; CHECK-GISEL:       // %bb.0:
203; CHECK-GISEL-NEXT:    eor w8, w1, w0, asr #15
204; CHECK-GISEL-NEXT:    asr w0, w8, #17
205; CHECK-GISEL-NEXT:    ret
206  %sh0 = ashr i32 %x, 15
207  %r = xor i32 %y, %sh0
208  %sh1 = ashr i32 %r, 17
209  ret i32 %sh1
210}
211
212define i32 @lshr_or_extra_use(i32 %x, i32 %y, ptr %p) nounwind {
213; CHECK-LABEL: lshr_or_extra_use:
214; CHECK:       // %bb.0:
215; CHECK-NEXT:    orr w8, w1, w0, lsr #5
216; CHECK-NEXT:    lsr w0, w8, #7
217; CHECK-NEXT:    str w8, [x2]
218; CHECK-NEXT:    ret
219;
220; CHECK-GISEL-LABEL: lshr_or_extra_use:
221; CHECK-GISEL:       // %bb.0:
222; CHECK-GISEL-NEXT:    orr w8, w1, w0, lsr #5
223; CHECK-GISEL-NEXT:    lsr w0, w8, #7
224; CHECK-GISEL-NEXT:    str w8, [x2]
225; CHECK-GISEL-NEXT:    ret
226  %sh0 = lshr i32 %x, 5
227  %r = or i32 %sh0, %y
228  store i32 %r, ptr %p
229  %sh1 = lshr i32 %r, 7
230  ret i32 %sh1
231}
232
233define i64 @desirable_to_commute1(i64 %x) {
234; CHECK-LABEL: desirable_to_commute1:
235; CHECK:       // %bb.0:
236; CHECK-NEXT:    and x0, x0, #0x7fff8
237; CHECK-NEXT:    ret
238;
239; CHECK-GISEL-LABEL: desirable_to_commute1:
240; CHECK-GISEL:       // %bb.0:
241; CHECK-GISEL-NEXT:    ubfx x8, x0, #3, #16
242; CHECK-GISEL-NEXT:    lsl x0, x8, #3
243; CHECK-GISEL-NEXT:    ret
244  %s1 = lshr i64 %x, 3
245  %a = and i64 %s1, 65535
246  %s2 = shl i64 %a, 3
247  ret i64 %s2
248}
249
250define i64 @desirable_to_commute2(ptr %p, i64 %i) {
251; CHECK-LABEL: desirable_to_commute2:
252; CHECK:       // %bb.0:
253; CHECK-NEXT:    and x8, x1, #0x1ff8
254; CHECK-NEXT:    ldr x0, [x0, x8]
255; CHECK-NEXT:    ret
256;
257; CHECK-GISEL-LABEL: desirable_to_commute2:
258; CHECK-GISEL:       // %bb.0:
259; CHECK-GISEL-NEXT:    ubfx x8, x1, #3, #10
260; CHECK-GISEL-NEXT:    ldr x0, [x0, x8, lsl #3]
261; CHECK-GISEL-NEXT:    ret
262  %lshr = lshr i64 %i, 3
263  %and = and i64 %lshr, 1023
264  %pidx = getelementptr i64, ptr %p, i64 %and
265  %r = load i64, ptr %pidx
266  ret i64 %r
267}
268
269; Shrink demanded op will shrink the shl to i32,
270; Lshr and shl will have different shift amount type.
271; Compare apint will cause crash when type is different.
272define void @apint_type_mismatch(i16 %a, ptr %p) {
273; CHECK-LABEL: apint_type_mismatch:
274; CHECK:       // %bb.0: // %entry
275; CHECK-NEXT:    and w8, w0, #0x7f8
276; CHECK-NEXT:    str w8, [x1]
277; CHECK-NEXT:    ret
278;
279; CHECK-GISEL-LABEL: apint_type_mismatch:
280; CHECK-GISEL:       // %bb.0: // %entry
281; CHECK-GISEL-NEXT:    ubfx w8, w0, #3, #13
282; CHECK-GISEL-NEXT:    and w8, w8, #0xff
283; CHECK-GISEL-NEXT:    lsl w8, w8, #3
284; CHECK-GISEL-NEXT:    str w8, [x1]
285; CHECK-GISEL-NEXT:    ret
286entry:
287  %lshr = lshr i16 %a, 3
288  %and = and i16 %lshr, 255
289  %zext = zext i16 %and to i64
290  %shl = shl i64 %zext, 3
291  %trunc = trunc i64 %shl to i32
292  store i32 %trunc, ptr %p
293  ret void
294}
295