1 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2 ; RUN: llc -mtriple=aarch64-linux-gnu -mattr=+sve2 < %s | FileCheck %s
4 define void @add_lshr_rshrnb_b_6(ptr %ptr, ptr %dst, i64 %index){
5 ; CHECK-LABEL: add_lshr_rshrnb_b_6:
7 ; CHECK-NEXT: ptrue p0.h
8 ; CHECK-NEXT: ld1h { z0.h }, p0/z, [x0]
9 ; CHECK-NEXT: rshrnb z0.b, z0.h, #6
10 ; CHECK-NEXT: st1b { z0.h }, p0, [x1, x2]
12 %load = load <vscale x 8 x i16>, ptr %ptr, align 2
13 %1 = add <vscale x 8 x i16> %load, trunc (<vscale x 8 x i32> splat (i32 32) to <vscale x 8 x i16>)
14 %2 = lshr <vscale x 8 x i16> %1, trunc (<vscale x 8 x i32> splat (i32 6) to <vscale x 8 x i16>)
15 %3 = trunc <vscale x 8 x i16> %2 to <vscale x 8 x i8>
16 %4 = getelementptr inbounds i8, ptr %dst, i64 %index
17 store <vscale x 8 x i8> %3, ptr %4, align 1
21 define void @neg_add_lshr_rshrnb_b_6(ptr %ptr, ptr %dst, i64 %index){
22 ; CHECK-LABEL: neg_add_lshr_rshrnb_b_6:
24 ; CHECK-NEXT: ptrue p0.h
25 ; CHECK-NEXT: ld1h { z0.h }, p0/z, [x0]
26 ; CHECK-NEXT: add z0.h, z0.h, #1 // =0x1
27 ; CHECK-NEXT: lsr z0.h, z0.h, #6
28 ; CHECK-NEXT: st1b { z0.h }, p0, [x1, x2]
30 %load = load <vscale x 8 x i16>, ptr %ptr, align 2
31 %1 = add <vscale x 8 x i16> %load, trunc (<vscale x 8 x i32> splat (i32 1) to <vscale x 8 x i16>)
32 %2 = lshr <vscale x 8 x i16> %1, trunc (<vscale x 8 x i32> splat (i32 6) to <vscale x 8 x i16>)
33 %3 = trunc <vscale x 8 x i16> %2 to <vscale x 8 x i8>
34 %4 = getelementptr inbounds i8, ptr %dst, i64 %index
35 store <vscale x 8 x i8> %3, ptr %4, align 1
39 define void @add_lshr_rshrnb_h_7(ptr %ptr, ptr %dst, i64 %index){
40 ; CHECK-LABEL: add_lshr_rshrnb_h_7:
42 ; CHECK-NEXT: ptrue p0.h
43 ; CHECK-NEXT: ld1h { z0.h }, p0/z, [x0]
44 ; CHECK-NEXT: rshrnb z0.b, z0.h, #7
45 ; CHECK-NEXT: st1b { z0.h }, p0, [x1, x2]
47 %load = load <vscale x 8 x i16>, ptr %ptr, align 2
48 %1 = add <vscale x 8 x i16> %load, trunc (<vscale x 8 x i32> splat (i32 64) to <vscale x 8 x i16>)
49 %2 = lshr <vscale x 8 x i16> %1, trunc (<vscale x 8 x i32> splat (i32 7) to <vscale x 8 x i16>)
50 %3 = trunc <vscale x 8 x i16> %2 to <vscale x 8 x i8>
51 %4 = getelementptr inbounds i8, ptr %dst, i64 %index
52 store <vscale x 8 x i8> %3, ptr %4, align 1
56 define void @add_lshr_rshrn_h_6(ptr %ptr, ptr %dst, i64 %index){
57 ; CHECK-LABEL: add_lshr_rshrn_h_6:
59 ; CHECK-NEXT: ptrue p0.s
60 ; CHECK-NEXT: ld1w { z0.s }, p0/z, [x0]
61 ; CHECK-NEXT: rshrnb z0.h, z0.s, #6
62 ; CHECK-NEXT: st1h { z0.s }, p0, [x1, x2, lsl #1]
64 %load = load <vscale x 4 x i32>, ptr %ptr, align 2
65 %1 = add <vscale x 4 x i32> %load, trunc (<vscale x 4 x i64> splat (i64 32) to <vscale x 4 x i32>)
66 %2 = lshr <vscale x 4 x i32> %1, trunc (<vscale x 4 x i64> splat (i64 6) to <vscale x 4 x i32>)
67 %3 = trunc <vscale x 4 x i32> %2 to <vscale x 4 x i16>
68 %4 = getelementptr inbounds i16, ptr %dst, i64 %index
69 store <vscale x 4 x i16> %3, ptr %4, align 1
73 define void @add_lshr_rshrnb_h_2(ptr %ptr, ptr %dst, i64 %index){
74 ; CHECK-LABEL: add_lshr_rshrnb_h_2:
76 ; CHECK-NEXT: ptrue p0.s
77 ; CHECK-NEXT: ld1w { z0.s }, p0/z, [x0]
78 ; CHECK-NEXT: rshrnb z0.h, z0.s, #2
79 ; CHECK-NEXT: st1h { z0.s }, p0, [x1, x2, lsl #1]
81 %load = load <vscale x 4 x i32>, ptr %ptr, align 2
82 %1 = add <vscale x 4 x i32> %load, trunc (<vscale x 4 x i64> splat (i64 2) to <vscale x 4 x i32>)
83 %2 = lshr <vscale x 4 x i32> %1, trunc (<vscale x 4 x i64> splat (i64 2) to <vscale x 4 x i32>)
84 %3 = trunc <vscale x 4 x i32> %2 to <vscale x 4 x i16>
85 %4 = getelementptr inbounds i16, ptr %dst, i64 %index
86 store <vscale x 4 x i16> %3, ptr %4, align 1
90 define void @neg_add_lshr_rshrnb_h_0(ptr %ptr, ptr %dst, i64 %index){
91 ; CHECK-LABEL: neg_add_lshr_rshrnb_h_0:
94 %load = load <vscale x 4 x i32>, ptr %ptr, align 2
95 %1 = add <vscale x 4 x i32> %load, trunc (<vscale x 4 x i64> splat (i64 1) to <vscale x 4 x i32>)
96 %2 = lshr <vscale x 4 x i32> %1, trunc (<vscale x 4 x i64> splat (i64 -1) to <vscale x 4 x i32>)
97 %3 = trunc <vscale x 4 x i32> %2 to <vscale x 4 x i16>
98 %4 = getelementptr inbounds i16, ptr %dst, i64 %index
99 store <vscale x 4 x i16> %3, ptr %4, align 1
103 define void @neg_zero_shift(ptr %ptr, ptr %dst, i64 %index){
104 ; CHECK-LABEL: neg_zero_shift:
106 ; CHECK-NEXT: ptrue p0.s
107 ; CHECK-NEXT: ld1w { z0.s }, p0/z, [x0]
108 ; CHECK-NEXT: add z0.s, z0.s, #1 // =0x1
109 ; CHECK-NEXT: st1h { z0.s }, p0, [x1, x2, lsl #1]
111 %load = load <vscale x 4 x i32>, ptr %ptr, align 2
112 %1 = add <vscale x 4 x i32> %load, trunc (<vscale x 4 x i64> splat (i64 1) to <vscale x 4 x i32>)
113 %2 = lshr <vscale x 4 x i32> %1, trunc (<vscale x 4 x i64> splat (i64 0) to <vscale x 4 x i32>)
114 %3 = trunc <vscale x 4 x i32> %2 to <vscale x 4 x i16>
115 %4 = getelementptr inbounds i16, ptr %dst, i64 %index
116 store <vscale x 4 x i16> %3, ptr %4, align 1
120 define void @wide_add_shift_add_rshrnb_b(ptr %dest, i64 %index, <vscale x 16 x i16> %arg1){
121 ; CHECK-LABEL: wide_add_shift_add_rshrnb_b:
123 ; CHECK-NEXT: rshrnb z1.b, z1.h, #6
124 ; CHECK-NEXT: rshrnb z0.b, z0.h, #6
125 ; CHECK-NEXT: ptrue p0.b
126 ; CHECK-NEXT: ld1b { z2.b }, p0/z, [x0, x1]
127 ; CHECK-NEXT: uzp1 z0.b, z0.b, z1.b
128 ; CHECK-NEXT: add z0.b, z2.b, z0.b
129 ; CHECK-NEXT: st1b { z0.b }, p0, [x0, x1]
131 %1 = add <vscale x 16 x i16> %arg1, splat (i16 32)
132 %2 = lshr <vscale x 16 x i16> %1, splat (i16 6)
133 %3 = getelementptr inbounds i8, ptr %dest, i64 %index
134 %load = load <vscale x 16 x i8>, ptr %3, align 2
135 %4 = trunc <vscale x 16 x i16> %2 to <vscale x 16 x i8>
136 %5 = add <vscale x 16 x i8> %load, %4
137 store <vscale x 16 x i8> %5, ptr %3, align 2
141 define void @wide_add_shift_add_rshrnb_h(ptr %dest, i64 %index, <vscale x 8 x i32> %arg1){
142 ; CHECK-LABEL: wide_add_shift_add_rshrnb_h:
144 ; CHECK-NEXT: rshrnb z1.h, z1.s, #6
145 ; CHECK-NEXT: rshrnb z0.h, z0.s, #6
146 ; CHECK-NEXT: ptrue p0.h
147 ; CHECK-NEXT: ld1h { z2.h }, p0/z, [x0, x1, lsl #1]
148 ; CHECK-NEXT: uzp1 z0.h, z0.h, z1.h
149 ; CHECK-NEXT: add z0.h, z2.h, z0.h
150 ; CHECK-NEXT: st1h { z0.h }, p0, [x0, x1, lsl #1]
152 %1 = add <vscale x 8 x i32> %arg1, splat (i32 32)
153 %2 = lshr <vscale x 8 x i32> %1, splat (i32 6)
154 %3 = getelementptr inbounds i16, ptr %dest, i64 %index
155 %load = load <vscale x 8 x i16>, ptr %3, align 2
156 %4 = trunc <vscale x 8 x i32> %2 to <vscale x 8 x i16>
157 %5 = add <vscale x 8 x i16> %load, %4
158 store <vscale x 8 x i16> %5, ptr %3, align 2
162 define void @wide_add_shift_add_rshrnb_d(ptr %dest, i64 %index, <vscale x 4 x i64> %arg1){
163 ; CHECK-LABEL: wide_add_shift_add_rshrnb_d:
165 ; CHECK-NEXT: rshrnb z1.s, z1.d, #32
166 ; CHECK-NEXT: rshrnb z0.s, z0.d, #32
167 ; CHECK-NEXT: ptrue p0.s
168 ; CHECK-NEXT: ld1w { z2.s }, p0/z, [x0, x1, lsl #2]
169 ; CHECK-NEXT: uzp1 z0.s, z0.s, z1.s
170 ; CHECK-NEXT: add z0.s, z2.s, z0.s
171 ; CHECK-NEXT: st1w { z0.s }, p0, [x0, x1, lsl #2]
173 %1 = add <vscale x 4 x i64> %arg1, splat (i64 2147483648)
174 %2 = lshr <vscale x 4 x i64> %1, splat (i64 32)
175 %3 = getelementptr inbounds i32, ptr %dest, i64 %index
176 %load = load <vscale x 4 x i32>, ptr %3, align 4
177 %4 = trunc <vscale x 4 x i64> %2 to <vscale x 4 x i32>
178 %5 = add <vscale x 4 x i32> %load, %4
179 store <vscale x 4 x i32> %5, ptr %3, align 4
183 ; Do not emit rshrnb if the shift amount is larger than the dest eltsize in bits
184 define void @neg_wide_add_shift_add_rshrnb_d(ptr %dest, i64 %index, <vscale x 4 x i64> %arg1){
185 ; CHECK-LABEL: neg_wide_add_shift_add_rshrnb_d:
187 ; CHECK-NEXT: mov z2.d, #0x800000000000
188 ; CHECK-NEXT: ptrue p0.s
189 ; CHECK-NEXT: add z0.d, z0.d, z2.d
190 ; CHECK-NEXT: add z1.d, z1.d, z2.d
191 ; CHECK-NEXT: ld1w { z2.s }, p0/z, [x0, x1, lsl #2]
192 ; CHECK-NEXT: lsr z1.d, z1.d, #48
193 ; CHECK-NEXT: lsr z0.d, z0.d, #48
194 ; CHECK-NEXT: uzp1 z0.s, z0.s, z1.s
195 ; CHECK-NEXT: add z0.s, z2.s, z0.s
196 ; CHECK-NEXT: st1w { z0.s }, p0, [x0, x1, lsl #2]
198 %1 = add <vscale x 4 x i64> %arg1, splat (i64 140737488355328)
199 %2 = lshr <vscale x 4 x i64> %1, splat (i64 48)
200 %3 = getelementptr inbounds i32, ptr %dest, i64 %index
201 %load = load <vscale x 4 x i32>, ptr %3, align 4
202 %4 = trunc <vscale x 4 x i64> %2 to <vscale x 4 x i32>
203 %5 = add <vscale x 4 x i32> %load, %4
204 store <vscale x 4 x i32> %5, ptr %3, align 4
208 define void @neg_trunc_lsr_add_op1_not_splat(ptr %ptr, ptr %dst, i64 %index, <vscale x 8 x i16> %add_op1){
209 ; CHECK-LABEL: neg_trunc_lsr_add_op1_not_splat:
211 ; CHECK-NEXT: ptrue p0.h
212 ; CHECK-NEXT: ld1h { z1.h }, p0/z, [x0]
213 ; CHECK-NEXT: add z0.h, z1.h, z0.h
214 ; CHECK-NEXT: lsr z0.h, z0.h, #6
215 ; CHECK-NEXT: st1b { z0.h }, p0, [x1, x2]
217 %load = load <vscale x 8 x i16>, ptr %ptr, align 2
218 %1 = add <vscale x 8 x i16> %load, %add_op1
219 %2 = lshr <vscale x 8 x i16> %1, splat (i16 6)
220 %3 = trunc <vscale x 8 x i16> %2 to <vscale x 8 x i8>
221 %4 = getelementptr inbounds i8, ptr %dst, i64 %index
222 store <vscale x 8 x i8> %3, ptr %4, align 1
226 define void @neg_trunc_lsr_op1_not_splat(ptr %ptr, ptr %dst, i64 %index, <vscale x 8 x i16> %lshr_op1){
227 ; CHECK-LABEL: neg_trunc_lsr_op1_not_splat:
229 ; CHECK-NEXT: ptrue p0.h
230 ; CHECK-NEXT: ld1h { z1.h }, p0/z, [x0]
231 ; CHECK-NEXT: add z1.h, z1.h, #32 // =0x20
232 ; CHECK-NEXT: lsrr z0.h, p0/m, z0.h, z1.h
233 ; CHECK-NEXT: st1b { z0.h }, p0, [x1, x2]
235 %load = load <vscale x 8 x i16>, ptr %ptr, align 2
236 %1 = add <vscale x 8 x i16> %load, splat (i16 32)
237 %2 = lshr <vscale x 8 x i16> %1, %lshr_op1
238 %3 = trunc <vscale x 8 x i16> %2 to <vscale x 8 x i8>
239 %4 = getelementptr inbounds i8, ptr %dst, i64 %index
240 store <vscale x 8 x i8> %3, ptr %4, align 1
244 define void @neg_add_has_two_uses(ptr %ptr, ptr %dst, ptr %dst2, i64 %index){
245 ; CHECK-LABEL: neg_add_has_two_uses:
247 ; CHECK-NEXT: ptrue p0.h
248 ; CHECK-NEXT: ld1h { z0.h }, p0/z, [x0]
249 ; CHECK-NEXT: add z0.h, z0.h, #32 // =0x20
250 ; CHECK-NEXT: add z1.h, z0.h, z0.h
251 ; CHECK-NEXT: lsr z0.h, z0.h, #6
252 ; CHECK-NEXT: st1h { z1.h }, p0, [x2, x3, lsl #1]
253 ; CHECK-NEXT: st1b { z0.h }, p0, [x1, x3]
255 %load = load <vscale x 8 x i16>, ptr %ptr, align 2
256 %1 = add <vscale x 8 x i16> %load, trunc (<vscale x 8 x i32> splat (i32 32) to <vscale x 8 x i16>)
257 %2 = lshr <vscale x 8 x i16> %1, trunc (<vscale x 8 x i32> splat (i32 6) to <vscale x 8 x i16>)
258 %3 = add <vscale x 8 x i16> %1, %1
259 %4 = getelementptr inbounds i16, ptr %dst2, i64 %index
260 %5 = trunc <vscale x 8 x i16> %2 to <vscale x 8 x i8>
261 %6 = getelementptr inbounds i8, ptr %dst, i64 %index
262 store <vscale x 8 x i16> %3, ptr %4, align 1
263 store <vscale x 8 x i8> %5, ptr %6, align 1
267 define void @add_lshr_rshrnb_s(ptr %ptr, ptr %dst, i64 %index){
268 ; CHECK-LABEL: add_lshr_rshrnb_s:
270 ; CHECK-NEXT: ptrue p0.d
271 ; CHECK-NEXT: ld1d { z0.d }, p0/z, [x0]
272 ; CHECK-NEXT: rshrnb z0.s, z0.d, #6
273 ; CHECK-NEXT: st1w { z0.d }, p0, [x1, x2, lsl #2]
275 %load = load <vscale x 2 x i64>, ptr %ptr, align 2
276 %1 = add <vscale x 2 x i64> %load, splat (i64 32)
277 %2 = lshr <vscale x 2 x i64> %1, splat (i64 6)
278 %3 = trunc <vscale x 2 x i64> %2 to <vscale x 2 x i32>
279 %4 = getelementptr inbounds i32, ptr %dst, i64 %index
280 store <vscale x 2 x i32> %3, ptr %4, align 1
284 define void @neg_add_lshr_rshrnb_s(ptr %ptr, ptr %dst, i64 %index){
285 ; CHECK-LABEL: neg_add_lshr_rshrnb_s:
287 ; CHECK-NEXT: ptrue p0.d
288 ; CHECK-NEXT: ld1d { z0.d }, p0/z, [x0]
289 ; CHECK-NEXT: add z0.d, z0.d, #32 // =0x20
290 ; CHECK-NEXT: lsr z0.d, z0.d, #6
291 ; CHECK-NEXT: st1h { z0.d }, p0, [x1, x2, lsl #1]
293 %load = load <vscale x 2 x i64>, ptr %ptr, align 2
294 %1 = add <vscale x 2 x i64> %load, splat (i64 32)
295 %2 = lshr <vscale x 2 x i64> %1, splat (i64 6)
296 %3 = trunc <vscale x 2 x i64> %2 to <vscale x 2 x i16>
297 %4 = getelementptr inbounds i16, ptr %dst, i64 %index
298 store <vscale x 2 x i16> %3, ptr %4, align 1
302 define void @masked_store_rshrnb(ptr %ptr, ptr %dst, i64 %index, <vscale x 8 x i1> %mask) { ; preds = %vector.body, %vector.ph
303 ; CHECK-LABEL: masked_store_rshrnb:
305 ; CHECK-NEXT: ld1h { z0.h }, p0/z, [x0]
306 ; CHECK-NEXT: rshrnb z0.b, z0.h, #6
307 ; CHECK-NEXT: st1b { z0.h }, p0, [x1, x2]
309 %wide.masked.load = tail call <vscale x 8 x i16> @llvm.masked.load.nxv8i16.p0(ptr %ptr, i32 2, <vscale x 8 x i1> %mask, <vscale x 8 x i16> poison)
310 %1 = add <vscale x 8 x i16> %wide.masked.load, trunc (<vscale x 8 x i32> splat (i32 32) to <vscale x 8 x i16>)
311 %2 = lshr <vscale x 8 x i16> %1, trunc (<vscale x 8 x i32> splat (i32 6) to <vscale x 8 x i16>)
312 %3 = trunc <vscale x 8 x i16> %2 to <vscale x 8 x i8>
313 %4 = getelementptr inbounds i8, ptr %dst, i64 %index
314 tail call void @llvm.masked.store.nxv8i8.p0(<vscale x 8 x i8> %3, ptr %4, i32 1, <vscale x 8 x i1> %mask)
318 declare void @llvm.masked.store.nxv8i8.p0(<vscale x 8 x i8>, ptr, i32, <vscale x 8 x i1>)
319 declare <vscale x 8 x i16> @llvm.masked.load.nxv8i16.p0(ptr, i32, <vscale x 8 x i1>, <vscale x 8 x i16>)