1; RUN: llc -march=arm64 -aarch64-neon-syntax=apple < %s -asm-verbose=false -mcpu=cyclone | FileCheck %s
2
3define signext i8 @test_vaddv_s8(<8 x i8> %a1) {
4; CHECK-LABEL: test_vaddv_s8:
5; CHECK: addv.8b b[[REGNUM:[0-9]+]], v0
6; CHECK-NEXT: smov.b w0, v[[REGNUM]][0]
7; CHECK-NEXT: ret
8entry:
9  %vaddv.i = tail call i32 @llvm.aarch64.neon.saddv.i32.v8i8(<8 x i8> %a1)
10  %0 = trunc i32 %vaddv.i to i8
11  ret i8 %0
12}
13
14define <8 x i8> @test_vaddv_s8_used_by_laneop(<8 x i8> %a1, <8 x i8> %a2) {
15; CHECK-LABEL: test_vaddv_s8_used_by_laneop:
16; CHECK: addv.8b b[[REGNUM:[0-9]+]], v1
17; CHECK-NEXT: ins.b v0[3], v[[REGNUM]][0]
18; CHECK-NEXT: ret
19entry:
20  %0 = tail call i32 @llvm.aarch64.neon.saddv.i32.v8i8(<8 x i8> %a2)
21  %1 = trunc i32 %0 to i8
22  %2 = insertelement <8 x i8> %a1, i8 %1, i32 3
23  ret <8 x i8> %2
24}
25
26define signext i16 @test_vaddv_s16(<4 x i16> %a1) {
27; CHECK-LABEL: test_vaddv_s16:
28; CHECK: addv.4h h[[REGNUM:[0-9]+]], v0
29; CHECK-NEXT: smov.h w0, v[[REGNUM]][0]
30; CHECK-NEXT: ret
31entry:
32  %vaddv.i = tail call i32 @llvm.aarch64.neon.saddv.i32.v4i16(<4 x i16> %a1)
33  %0 = trunc i32 %vaddv.i to i16
34  ret i16 %0
35}
36
37define <4 x i16> @test_vaddv_s16_used_by_laneop(<4 x i16> %a1, <4 x i16> %a2) {
38; CHECK-LABEL: test_vaddv_s16_used_by_laneop:
39; CHECK: addv.4h h[[REGNUM:[0-9]+]], v1
40; CHECK-NEXT: ins.h v0[3], v[[REGNUM]][0]
41; CHECK-NEXT: ret
42entry:
43  %0 = tail call i32 @llvm.aarch64.neon.saddv.i32.v4i16(<4 x i16> %a2)
44  %1 = trunc i32 %0 to i16
45  %2 = insertelement <4 x i16> %a1, i16 %1, i32 3
46  ret <4 x i16> %2
47}
48
49define i32 @test_vaddv_s32(<2 x i32> %a1) {
50; CHECK-LABEL: test_vaddv_s32:
51; 2 x i32 is not supported by the ISA, thus, this is a special case
52; CHECK: addp.2s v[[REGNUM:[0-9]+]], v0, v0
53; CHECK-NEXT: fmov w0, s[[REGNUM]]
54; CHECK-NEXT: ret
55entry:
56  %vaddv.i = tail call i32 @llvm.aarch64.neon.saddv.i32.v2i32(<2 x i32> %a1)
57  ret i32 %vaddv.i
58}
59
60define <2 x i32> @test_vaddv_s32_used_by_laneop(<2 x i32> %a1, <2 x i32> %a2) {
61; CHECK-LABEL: test_vaddv_s32_used_by_laneop:
62; CHECK: addp.2s v[[REGNUM:[0-9]+]], v1, v1
63; CHECK-NEXT: ins.s v0[1], v[[REGNUM]][0]
64; CHECK-NEXT: ret
65entry:
66  %0 = tail call i32 @llvm.aarch64.neon.saddv.i32.v2i32(<2 x i32> %a2)
67  %1 = insertelement <2 x i32> %a1, i32 %0, i32 1
68  ret <2 x i32> %1
69}
70
71define i64 @test_vaddv_s64(<2 x i64> %a1) {
72; CHECK-LABEL: test_vaddv_s64:
73; CHECK: addp.2d [[REGNUM:d[0-9]+]], v0
74; CHECK-NEXT: fmov x0, [[REGNUM]]
75; CHECK-NEXT: ret
76entry:
77  %vaddv.i = tail call i64 @llvm.aarch64.neon.saddv.i64.v2i64(<2 x i64> %a1)
78  ret i64 %vaddv.i
79}
80
81define <2 x i64> @test_vaddv_s64_used_by_laneop(<2 x i64> %a1, <2 x i64> %a2) {
82; CHECK-LABEL: test_vaddv_s64_used_by_laneop:
83; CHECK: addp.2d d[[REGNUM:[0-9]+]], v1
84; CHECK-NEXT: ins.d v0[1], v[[REGNUM]][0]
85; CHECK-NEXT: ret
86entry:
87  %0 = tail call i64 @llvm.aarch64.neon.saddv.i64.v2i64(<2 x i64> %a2)
88  %1 = insertelement <2 x i64> %a1, i64 %0, i64 1
89  ret <2 x i64> %1
90}
91
92define zeroext i8 @test_vaddv_u8(<8 x i8> %a1) {
93; CHECK-LABEL: test_vaddv_u8:
94; CHECK: addv.8b b[[REGNUM:[0-9]+]], v0
95; CHECK-NEXT: fmov w0, s[[REGNUM]]
96; CHECK-NEXT: ret
97entry:
98  %vaddv.i = tail call i32 @llvm.aarch64.neon.uaddv.i32.v8i8(<8 x i8> %a1)
99  %0 = trunc i32 %vaddv.i to i8
100  ret i8 %0
101}
102
103define <8 x i8> @test_vaddv_u8_used_by_laneop(<8 x i8> %a1, <8 x i8> %a2) {
104; CHECK-LABEL: test_vaddv_u8_used_by_laneop:
105; CHECK: addv.8b b[[REGNUM:[0-9]+]], v1
106; CHECK-NEXT: ins.b v0[3], v[[REGNUM]][0]
107; CHECK-NEXT: ret
108entry:
109  %0 = tail call i32 @llvm.aarch64.neon.uaddv.i32.v8i8(<8 x i8> %a2)
110  %1 = trunc i32 %0 to i8
111  %2 = insertelement <8 x i8> %a1, i8 %1, i32 3
112  ret <8 x i8> %2
113}
114
115define i32 @test_vaddv_u8_masked(<8 x i8> %a1) {
116; CHECK-LABEL: test_vaddv_u8_masked:
117; CHECK: addv.8b b[[REGNUM:[0-9]+]], v0
118; CHECK-NEXT: fmov w0, s[[REGNUM]]
119; CHECK-NEXT: ret
120entry:
121  %vaddv.i = tail call i32 @llvm.aarch64.neon.uaddv.i32.v8i8(<8 x i8> %a1)
122  %0 = and i32 %vaddv.i, 511 ; 0x1ff
123  ret i32 %0
124}
125
126define zeroext i16 @test_vaddv_u16(<4 x i16> %a1) {
127; CHECK-LABEL: test_vaddv_u16:
128; CHECK: addv.4h h[[REGNUM:[0-9]+]], v0
129; CHECK-NEXT: fmov w0, s[[REGNUM]]
130; CHECK-NEXT: ret
131entry:
132  %vaddv.i = tail call i32 @llvm.aarch64.neon.uaddv.i32.v4i16(<4 x i16> %a1)
133  %0 = trunc i32 %vaddv.i to i16
134  ret i16 %0
135}
136
137define <4 x i16> @test_vaddv_u16_used_by_laneop(<4 x i16> %a1, <4 x i16> %a2) {
138; CHECK-LABEL: test_vaddv_u16_used_by_laneop:
139; CHECK: addv.4h h[[REGNUM:[0-9]+]], v1
140; CHECK-NEXT: ins.h v0[3], v[[REGNUM]][0]
141; CHECK-NEXT: ret
142entry:
143  %0 = tail call i32 @llvm.aarch64.neon.uaddv.i32.v4i16(<4 x i16> %a2)
144  %1 = trunc i32 %0 to i16
145  %2 = insertelement <4 x i16> %a1, i16 %1, i32 3
146  ret <4 x i16> %2
147}
148
149define i32 @test_vaddv_u16_masked(<4 x i16> %a1) {
150; CHECK-LABEL: test_vaddv_u16_masked:
151; CHECK: addv.4h h[[REGNUM:[0-9]+]], v0
152; CHECK-NEXT: fmov w0, s[[REGNUM]]
153; CHECK-NEXT: ret
154entry:
155  %vaddv.i = tail call i32 @llvm.aarch64.neon.uaddv.i32.v4i16(<4 x i16> %a1)
156  %0 = and i32 %vaddv.i, 3276799 ; 0x31ffff
157  ret i32 %0
158}
159
160define i32 @test_vaddv_u32(<2 x i32> %a1) {
161; CHECK-LABEL: test_vaddv_u32:
162; 2 x i32 is not supported by the ISA, thus, this is a special case
163; CHECK: addp.2s v[[REGNUM:[0-9]+]], v0, v0
164; CHECK-NEXT: fmov w0, s[[REGNUM]]
165; CHECK-NEXT: ret
166entry:
167  %vaddv.i = tail call i32 @llvm.aarch64.neon.uaddv.i32.v2i32(<2 x i32> %a1)
168  ret i32 %vaddv.i
169}
170
171define <2 x i32> @test_vaddv_u32_used_by_laneop(<2 x i32> %a1, <2 x i32> %a2) {
172; CHECK-LABEL: test_vaddv_u32_used_by_laneop:
173; CHECK: addp.2s v[[REGNUM:[0-9]+]], v1, v1
174; CHECK-NEXT: ins.s v0[1], v[[REGNUM]][0]
175; CHECK-NEXT: ret
176entry:
177  %0 = tail call i32 @llvm.aarch64.neon.uaddv.i32.v2i32(<2 x i32> %a2)
178  %1 = insertelement <2 x i32> %a1, i32 %0, i32 1
179  ret <2 x i32> %1
180}
181
182define float @test_vaddv_f32(<2 x float> %a1) {
183; CHECK-LABEL: test_vaddv_f32:
184; CHECK: faddp.2s s0, v0
185; CHECK-NEXT: ret
186entry:
187  %vaddv.i = tail call float @llvm.aarch64.neon.faddv.f32.v2f32(<2 x float> %a1)
188  ret float %vaddv.i
189}
190
191define float @test_vaddv_v4f32(<4 x float> %a1) {
192; CHECK-LABEL: test_vaddv_v4f32:
193; CHECK: faddp.4s [[REGNUM:v[0-9]+]], v0, v0
194; CHECK: faddp.2s s0, [[REGNUM]]
195; CHECK-NEXT: ret
196entry:
197  %vaddv.i = tail call float @llvm.aarch64.neon.faddv.f32.v4f32(<4 x float> %a1)
198  ret float %vaddv.i
199}
200
201define double @test_vaddv_f64(<2 x double> %a1) {
202; CHECK-LABEL: test_vaddv_f64:
203; CHECK: faddp.2d d0, v0
204; CHECK-NEXT: ret
205entry:
206  %vaddv.i = tail call double @llvm.aarch64.neon.faddv.f64.v2f64(<2 x double> %a1)
207  ret double %vaddv.i
208}
209
210define i64 @test_vaddv_u64(<2 x i64> %a1) {
211; CHECK-LABEL: test_vaddv_u64:
212; CHECK: addp.2d [[REGNUM:d[0-9]+]], v0
213; CHECK-NEXT: fmov x0, [[REGNUM]]
214; CHECK-NEXT: ret
215entry:
216  %vaddv.i = tail call i64 @llvm.aarch64.neon.uaddv.i64.v2i64(<2 x i64> %a1)
217  ret i64 %vaddv.i
218}
219
220define <2 x i64> @test_vaddv_u64_used_by_laneop(<2 x i64> %a1, <2 x i64> %a2) {
221; CHECK-LABEL: test_vaddv_u64_used_by_laneop:
222; CHECK: addp.2d d[[REGNUM:[0-9]+]], v1
223; CHECK-NEXT: ins.d v0[1], v[[REGNUM]][0]
224; CHECK-NEXT: ret
225entry:
226  %0 = tail call i64 @llvm.aarch64.neon.uaddv.i64.v2i64(<2 x i64> %a2)
227  %1 = insertelement <2 x i64> %a1, i64 %0, i64 1
228  ret <2 x i64> %1
229}
230
231define <1 x i64> @test_vaddv_u64_to_vec(<2 x i64> %a1) {
232; CHECK-LABEL: test_vaddv_u64_to_vec:
233; CHECK: addp.2d d0, v0
234; CHECK-NOT: fmov
235; CHECK-NOT: ins
236; CHECK: ret
237entry:
238  %vaddv.i = tail call i64 @llvm.aarch64.neon.uaddv.i64.v2i64(<2 x i64> %a1)
239  %vec = insertelement <1 x i64> undef, i64 %vaddv.i, i32 0
240  ret <1 x i64> %vec
241}
242
243define signext i8 @test_vaddvq_s8(<16 x i8> %a1) {
244; CHECK-LABEL: test_vaddvq_s8:
245; CHECK: addv.16b b[[REGNUM:[0-9]+]], v0
246; CHECK-NEXT: smov.b w0, v[[REGNUM]][0]
247; CHECK-NEXT: ret
248entry:
249  %vaddv.i = tail call i32 @llvm.aarch64.neon.saddv.i32.v16i8(<16 x i8> %a1)
250  %0 = trunc i32 %vaddv.i to i8
251  ret i8 %0
252}
253
254define <16 x i8> @test_vaddvq_s8_used_by_laneop(<16 x i8> %a1, <16 x i8> %a2) {
255; CHECK-LABEL: test_vaddvq_s8_used_by_laneop:
256; CHECK: addv.16b b[[REGNUM:[0-9]+]], v1
257; CHECK-NEXT: ins.b v0[3], v[[REGNUM]][0]
258; CHECK-NEXT: ret
259entry:
260  %0 = tail call i32 @llvm.aarch64.neon.saddv.i32.v16i8(<16 x i8> %a2)
261  %1 = trunc i32 %0 to i8
262  %2 = insertelement <16 x i8> %a1, i8 %1, i32 3
263  ret <16 x i8> %2
264}
265
266define signext i16 @test_vaddvq_s16(<8 x i16> %a1) {
267; CHECK-LABEL: test_vaddvq_s16:
268; CHECK: addv.8h h[[REGNUM:[0-9]+]], v0
269; CHECK-NEXT: smov.h w0, v[[REGNUM]][0]
270; CHECK-NEXT: ret
271entry:
272  %vaddv.i = tail call i32 @llvm.aarch64.neon.saddv.i32.v8i16(<8 x i16> %a1)
273  %0 = trunc i32 %vaddv.i to i16
274  ret i16 %0
275}
276
277define <8 x i16> @test_vaddvq_s16_used_by_laneop(<8 x i16> %a1, <8 x i16> %a2) {
278; CHECK-LABEL: test_vaddvq_s16_used_by_laneop:
279; CHECK: addv.8h h[[REGNUM:[0-9]+]], v1
280; CHECK-NEXT: ins.h v0[3], v[[REGNUM]][0]
281; CHECK-NEXT: ret
282entry:
283  %0 = tail call i32 @llvm.aarch64.neon.saddv.i32.v8i16(<8 x i16> %a2)
284  %1 = trunc i32 %0 to i16
285  %2 = insertelement <8 x i16> %a1, i16 %1, i32 3
286  ret <8 x i16> %2
287}
288
289define i32 @test_vaddvq_s32(<4 x i32> %a1) {
290; CHECK-LABEL: test_vaddvq_s32:
291; CHECK: addv.4s [[REGNUM:s[0-9]+]], v0
292; CHECK-NEXT: fmov w0, [[REGNUM]]
293; CHECK-NEXT: ret
294entry:
295  %vaddv.i = tail call i32 @llvm.aarch64.neon.saddv.i32.v4i32(<4 x i32> %a1)
296  ret i32 %vaddv.i
297}
298
299define <4 x i32> @test_vaddvq_s32_used_by_laneop(<4 x i32> %a1, <4 x i32> %a2) {
300; CHECK-LABEL: test_vaddvq_s32_used_by_laneop:
301; CHECK: addv.4s s[[REGNUM:[0-9]+]], v1
302; CHECK-NEXT: ins.s v0[3], v[[REGNUM]][0]
303; CHECK-NEXT: ret
304entry:
305  %0 = tail call i32 @llvm.aarch64.neon.saddv.i32.v4i32(<4 x i32> %a2)
306  %1 = insertelement <4 x i32> %a1, i32 %0, i32 3
307  ret <4 x i32> %1
308}
309
310define zeroext i8 @test_vaddvq_u8(<16 x i8> %a1) {
311; CHECK-LABEL: test_vaddvq_u8:
312; CHECK: addv.16b b[[REGNUM:[0-9]+]], v0
313; CHECK-NEXT: fmov w0, s[[REGNUM]]
314; CHECK-NEXT: ret
315entry:
316  %vaddv.i = tail call i32 @llvm.aarch64.neon.uaddv.i32.v16i8(<16 x i8> %a1)
317  %0 = trunc i32 %vaddv.i to i8
318  ret i8 %0
319}
320
321define <16 x i8> @test_vaddvq_u8_used_by_laneop(<16 x i8> %a1, <16 x i8> %a2) {
322; CHECK-LABEL: test_vaddvq_u8_used_by_laneop:
323; CHECK: addv.16b b[[REGNUM:[0-9]+]], v1
324; CHECK-NEXT: ins.b v0[3], v[[REGNUM]][0]
325; CHECK-NEXT: ret
326entry:
327  %0 = tail call i32 @llvm.aarch64.neon.uaddv.i32.v16i8(<16 x i8> %a2)
328  %1 = trunc i32 %0 to i8
329  %2 = insertelement <16 x i8> %a1, i8 %1, i32 3
330  ret <16 x i8> %2
331}
332
333define zeroext i16 @test_vaddvq_u16(<8 x i16> %a1) {
334; CHECK-LABEL: test_vaddvq_u16:
335; CHECK: addv.8h h[[REGNUM:[0-9]+]], v0
336; CHECK-NEXT: fmov w0, s[[REGNUM]]
337; CHECK-NEXT: ret
338entry:
339  %vaddv.i = tail call i32 @llvm.aarch64.neon.uaddv.i32.v8i16(<8 x i16> %a1)
340  %0 = trunc i32 %vaddv.i to i16
341  ret i16 %0
342}
343
344define <8 x i16> @test_vaddvq_u16_used_by_laneop(<8 x i16> %a1, <8 x i16> %a2) {
345; CHECK-LABEL: test_vaddvq_u16_used_by_laneop:
346; CHECK: addv.8h h[[REGNUM:[0-9]+]], v1
347; CHECK-NEXT: ins.h v0[3], v[[REGNUM]][0]
348; CHECK-NEXT: ret
349entry:
350  %0 = tail call i32 @llvm.aarch64.neon.uaddv.i32.v8i16(<8 x i16> %a2)
351  %1 = trunc i32 %0 to i16
352  %2 = insertelement <8 x i16> %a1, i16 %1, i32 3
353  ret <8 x i16> %2
354}
355
356define i32 @test_vaddvq_u32(<4 x i32> %a1) {
357; CHECK-LABEL: test_vaddvq_u32:
358; CHECK: addv.4s [[REGNUM:s[0-9]+]], v0
359; CHECK-NEXT: fmov [[FMOVRES:w[0-9]+]], [[REGNUM]]
360; CHECK-NEXT: ret
361entry:
362  %vaddv.i = tail call i32 @llvm.aarch64.neon.uaddv.i32.v4i32(<4 x i32> %a1)
363  ret i32 %vaddv.i
364}
365
366define <4 x i32> @test_vaddvq_u32_used_by_laneop(<4 x i32> %a1, <4 x i32> %a2) {
367; CHECK-LABEL: test_vaddvq_u32_used_by_laneop:
368; CHECK: addv.4s s[[REGNUM:[0-9]+]], v1
369; CHECK-NEXT: ins.s v0[3], v[[REGNUM]][0]
370; CHECK-NEXT: ret
371entry:
372  %0 = tail call i32 @llvm.aarch64.neon.uaddv.i32.v4i32(<4 x i32> %a2)
373  %1 = insertelement <4 x i32> %a1, i32 %0, i32 3
374  ret <4 x i32> %1
375}
376
377declare i32 @llvm.aarch64.neon.uaddv.i32.v4i32(<4 x i32>)
378
379declare i32 @llvm.aarch64.neon.uaddv.i32.v8i16(<8 x i16>)
380
381declare i32 @llvm.aarch64.neon.uaddv.i32.v16i8(<16 x i8>)
382
383declare i32 @llvm.aarch64.neon.saddv.i32.v4i32(<4 x i32>)
384
385declare i32 @llvm.aarch64.neon.saddv.i32.v8i16(<8 x i16>)
386
387declare i32 @llvm.aarch64.neon.saddv.i32.v16i8(<16 x i8>)
388
389declare i64 @llvm.aarch64.neon.uaddv.i64.v2i64(<2 x i64>)
390
391declare i32 @llvm.aarch64.neon.uaddv.i32.v2i32(<2 x i32>)
392
393declare i32 @llvm.aarch64.neon.uaddv.i32.v4i16(<4 x i16>)
394
395declare i32 @llvm.aarch64.neon.uaddv.i32.v8i8(<8 x i8>)
396
397declare i32 @llvm.aarch64.neon.saddv.i32.v2i32(<2 x i32>)
398
399declare i64 @llvm.aarch64.neon.saddv.i64.v2i64(<2 x i64>)
400
401declare i32 @llvm.aarch64.neon.saddv.i32.v4i16(<4 x i16>)
402
403declare i32 @llvm.aarch64.neon.saddv.i32.v8i8(<8 x i8>)
404
405declare float @llvm.aarch64.neon.faddv.f32.v2f32(<2 x float> %a1)
406declare float @llvm.aarch64.neon.faddv.f32.v4f32(<4 x float> %a1)
407declare double @llvm.aarch64.neon.faddv.f64.v2f64(<2 x double> %a1)
408