1 /*
2  * Copyright (c) 2016, Alliance for Open Media. All rights reserved
3  *
4  * This source code is subject to the terms of the BSD 2 Clause License and
5  * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6  * was not distributed with this source code in the LICENSE file, you can
7  * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8  * Media Patent License 1.0 was not distributed with this source code in the
9  * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
10  */
11 
12 #include <arm_neon.h>
13 #include <assert.h>
14 
15 #include "./aom_config.h"
16 #include "./aom_dsp_rtcd.h"
17 #include "aom/aom_integer.h"
18 #include "aom_ports/mem.h"
19 
MULTIPLY_BY_Q0(int16x4_t dsrc0,int16x4_t dsrc1,int16x4_t dsrc2,int16x4_t dsrc3,int16x4_t dsrc4,int16x4_t dsrc5,int16x4_t dsrc6,int16x4_t dsrc7,int16x8_t q0s16)20 static INLINE int32x4_t MULTIPLY_BY_Q0(int16x4_t dsrc0, int16x4_t dsrc1,
21                                        int16x4_t dsrc2, int16x4_t dsrc3,
22                                        int16x4_t dsrc4, int16x4_t dsrc5,
23                                        int16x4_t dsrc6, int16x4_t dsrc7,
24                                        int16x8_t q0s16) {
25   int32x4_t qdst;
26   int16x4_t d0s16, d1s16;
27 
28   d0s16 = vget_low_s16(q0s16);
29   d1s16 = vget_high_s16(q0s16);
30 
31   qdst = vmull_lane_s16(dsrc0, d0s16, 0);
32   qdst = vmlal_lane_s16(qdst, dsrc1, d0s16, 1);
33   qdst = vmlal_lane_s16(qdst, dsrc2, d0s16, 2);
34   qdst = vmlal_lane_s16(qdst, dsrc3, d0s16, 3);
35   qdst = vmlal_lane_s16(qdst, dsrc4, d1s16, 0);
36   qdst = vmlal_lane_s16(qdst, dsrc5, d1s16, 1);
37   qdst = vmlal_lane_s16(qdst, dsrc6, d1s16, 2);
38   qdst = vmlal_lane_s16(qdst, dsrc7, d1s16, 3);
39   return qdst;
40 }
41 
aom_convolve8_horiz_neon(const uint8_t * src,ptrdiff_t src_stride,uint8_t * dst,ptrdiff_t dst_stride,const int16_t * filter_x,int x_step_q4,const int16_t * filter_y,int y_step_q4,int w,int h)42 void aom_convolve8_horiz_neon(const uint8_t *src, ptrdiff_t src_stride,
43                               uint8_t *dst, ptrdiff_t dst_stride,
44                               const int16_t *filter_x, int x_step_q4,
45                               const int16_t *filter_y,  // unused
46                               int y_step_q4,            // unused
47                               int w, int h) {
48   int width;
49   const uint8_t *s, *psrc;
50   uint8_t *d, *pdst;
51   uint8x8_t d2u8, d3u8, d24u8, d25u8, d26u8, d27u8, d28u8, d29u8;
52   uint32x2_t d2u32, d3u32, d28u32, d29u32, d30u32, d31u32;
53   uint8x16_t q12u8, q13u8, q14u8, q15u8;
54   int16x4_t d16s16, d17s16, d18s16, d19s16, d20s16, d22s16, d23s16;
55   int16x4_t d24s16, d25s16, d26s16, d27s16;
56   uint16x4_t d2u16, d3u16, d4u16, d5u16, d16u16, d17u16, d18u16, d19u16;
57   int16x8_t q0s16;
58   uint16x8_t q1u16, q2u16, q8u16, q9u16, q10u16, q11u16, q12u16, q13u16;
59   int32x4_t q1s32, q2s32, q14s32, q15s32;
60   uint16x8x2_t q0x2u16;
61   uint8x8x2_t d0x2u8, d1x2u8;
62   uint32x2x2_t d0x2u32;
63   uint16x4x2_t d0x2u16, d1x2u16;
64   uint32x4x2_t q0x2u32;
65 
66   assert(x_step_q4 == 16);
67 
68   (void)x_step_q4;
69   (void)y_step_q4;
70   (void)filter_y;
71 
72   q0s16 = vld1q_s16(filter_x);
73 
74   src -= 3;  // adjust for taps
75   for (; h > 0; h -= 4, src += src_stride * 4,
76                 dst += dst_stride * 4) {  // loop_horiz_v
77     s = src;
78     d24u8 = vld1_u8(s);
79     s += src_stride;
80     d25u8 = vld1_u8(s);
81     s += src_stride;
82     d26u8 = vld1_u8(s);
83     s += src_stride;
84     d27u8 = vld1_u8(s);
85 
86     q12u8 = vcombine_u8(d24u8, d25u8);
87     q13u8 = vcombine_u8(d26u8, d27u8);
88 
89     q0x2u16 =
90         vtrnq_u16(vreinterpretq_u16_u8(q12u8), vreinterpretq_u16_u8(q13u8));
91     d24u8 = vreinterpret_u8_u16(vget_low_u16(q0x2u16.val[0]));
92     d25u8 = vreinterpret_u8_u16(vget_high_u16(q0x2u16.val[0]));
93     d26u8 = vreinterpret_u8_u16(vget_low_u16(q0x2u16.val[1]));
94     d27u8 = vreinterpret_u8_u16(vget_high_u16(q0x2u16.val[1]));
95     d0x2u8 = vtrn_u8(d24u8, d25u8);
96     d1x2u8 = vtrn_u8(d26u8, d27u8);
97 
98     __builtin_prefetch(src + src_stride * 4);
99     __builtin_prefetch(src + src_stride * 5);
100     __builtin_prefetch(src + src_stride * 6);
101 
102     q8u16 = vmovl_u8(d0x2u8.val[0]);
103     q9u16 = vmovl_u8(d0x2u8.val[1]);
104     q10u16 = vmovl_u8(d1x2u8.val[0]);
105     q11u16 = vmovl_u8(d1x2u8.val[1]);
106 
107     d16u16 = vget_low_u16(q8u16);
108     d17u16 = vget_high_u16(q8u16);
109     d18u16 = vget_low_u16(q9u16);
110     d19u16 = vget_high_u16(q9u16);
111     q8u16 = vcombine_u16(d16u16, d18u16);  // vswp 17 18
112     q9u16 = vcombine_u16(d17u16, d19u16);
113 
114     d20s16 = vreinterpret_s16_u16(vget_low_u16(q10u16));
115     d23s16 = vreinterpret_s16_u16(vget_high_u16(q10u16));  // vmov 23 21
116     for (width = w, psrc = src + 7, pdst = dst; width > 0;
117          width -= 4, psrc += 4, pdst += 4) {  // loop_horiz
118       s = psrc;
119       d28u32 = vld1_dup_u32((const uint32_t *)s);
120       s += src_stride;
121       d29u32 = vld1_dup_u32((const uint32_t *)s);
122       s += src_stride;
123       d31u32 = vld1_dup_u32((const uint32_t *)s);
124       s += src_stride;
125       d30u32 = vld1_dup_u32((const uint32_t *)s);
126 
127       __builtin_prefetch(psrc + 64);
128 
129       d0x2u16 =
130           vtrn_u16(vreinterpret_u16_u32(d28u32), vreinterpret_u16_u32(d31u32));
131       d1x2u16 =
132           vtrn_u16(vreinterpret_u16_u32(d29u32), vreinterpret_u16_u32(d30u32));
133       d0x2u8 = vtrn_u8(vreinterpret_u8_u16(d0x2u16.val[0]),   // d28
134                        vreinterpret_u8_u16(d1x2u16.val[0]));  // d29
135       d1x2u8 = vtrn_u8(vreinterpret_u8_u16(d0x2u16.val[1]),   // d31
136                        vreinterpret_u8_u16(d1x2u16.val[1]));  // d30
137 
138       __builtin_prefetch(psrc + 64 + src_stride);
139 
140       q14u8 = vcombine_u8(d0x2u8.val[0], d0x2u8.val[1]);
141       q15u8 = vcombine_u8(d1x2u8.val[1], d1x2u8.val[0]);
142       q0x2u32 =
143           vtrnq_u32(vreinterpretq_u32_u8(q14u8), vreinterpretq_u32_u8(q15u8));
144 
145       d28u8 = vreinterpret_u8_u32(vget_low_u32(q0x2u32.val[0]));
146       d29u8 = vreinterpret_u8_u32(vget_high_u32(q0x2u32.val[0]));
147       q12u16 = vmovl_u8(d28u8);
148       q13u16 = vmovl_u8(d29u8);
149 
150       __builtin_prefetch(psrc + 64 + src_stride * 2);
151 
152       d16s16 = vreinterpret_s16_u16(vget_low_u16(q8u16));
153       d17s16 = vreinterpret_s16_u16(vget_high_u16(q8u16));
154       d18s16 = vreinterpret_s16_u16(vget_low_u16(q9u16));
155       d19s16 = vreinterpret_s16_u16(vget_high_u16(q9u16));
156       d22s16 = vreinterpret_s16_u16(vget_low_u16(q11u16));
157       d24s16 = vreinterpret_s16_u16(vget_low_u16(q12u16));
158       d25s16 = vreinterpret_s16_u16(vget_high_u16(q12u16));
159       d26s16 = vreinterpret_s16_u16(vget_low_u16(q13u16));
160       d27s16 = vreinterpret_s16_u16(vget_high_u16(q13u16));
161 
162       q1s32 = MULTIPLY_BY_Q0(d16s16, d17s16, d20s16, d22s16, d18s16, d19s16,
163                              d23s16, d24s16, q0s16);
164       q2s32 = MULTIPLY_BY_Q0(d17s16, d20s16, d22s16, d18s16, d19s16, d23s16,
165                              d24s16, d26s16, q0s16);
166       q14s32 = MULTIPLY_BY_Q0(d20s16, d22s16, d18s16, d19s16, d23s16, d24s16,
167                               d26s16, d27s16, q0s16);
168       q15s32 = MULTIPLY_BY_Q0(d22s16, d18s16, d19s16, d23s16, d24s16, d26s16,
169                               d27s16, d25s16, q0s16);
170 
171       __builtin_prefetch(psrc + 60 + src_stride * 3);
172 
173       d2u16 = vqrshrun_n_s32(q1s32, 7);
174       d3u16 = vqrshrun_n_s32(q2s32, 7);
175       d4u16 = vqrshrun_n_s32(q14s32, 7);
176       d5u16 = vqrshrun_n_s32(q15s32, 7);
177 
178       q1u16 = vcombine_u16(d2u16, d3u16);
179       q2u16 = vcombine_u16(d4u16, d5u16);
180 
181       d2u8 = vqmovn_u16(q1u16);
182       d3u8 = vqmovn_u16(q2u16);
183 
184       d0x2u16 = vtrn_u16(vreinterpret_u16_u8(d2u8), vreinterpret_u16_u8(d3u8));
185       d0x2u32 = vtrn_u32(vreinterpret_u32_u16(d0x2u16.val[0]),
186                          vreinterpret_u32_u16(d0x2u16.val[1]));
187       d0x2u8 = vtrn_u8(vreinterpret_u8_u32(d0x2u32.val[0]),
188                        vreinterpret_u8_u32(d0x2u32.val[1]));
189 
190       d2u32 = vreinterpret_u32_u8(d0x2u8.val[0]);
191       d3u32 = vreinterpret_u32_u8(d0x2u8.val[1]);
192 
193       d = pdst;
194       vst1_lane_u32((uint32_t *)d, d2u32, 0);
195       d += dst_stride;
196       vst1_lane_u32((uint32_t *)d, d3u32, 0);
197       d += dst_stride;
198       vst1_lane_u32((uint32_t *)d, d2u32, 1);
199       d += dst_stride;
200       vst1_lane_u32((uint32_t *)d, d3u32, 1);
201 
202       q8u16 = q9u16;
203       d20s16 = d23s16;
204       q11u16 = q12u16;
205       q9u16 = q13u16;
206       d23s16 = vreinterpret_s16_u16(vget_high_u16(q11u16));
207     }
208   }
209   return;
210 }
211 
aom_convolve8_vert_neon(const uint8_t * src,ptrdiff_t src_stride,uint8_t * dst,ptrdiff_t dst_stride,const int16_t * filter_x,int x_step_q4,const int16_t * filter_y,int y_step_q4,int w,int h)212 void aom_convolve8_vert_neon(const uint8_t *src, ptrdiff_t src_stride,
213                              uint8_t *dst, ptrdiff_t dst_stride,
214                              const int16_t *filter_x,  // unused
215                              int x_step_q4,            // unused
216                              const int16_t *filter_y, int y_step_q4, int w,
217                              int h) {
218   int height;
219   const uint8_t *s;
220   uint8_t *d;
221   uint32x2_t d2u32, d3u32;
222   uint32x2_t d16u32, d18u32, d20u32, d22u32, d24u32, d26u32;
223   int16x4_t d16s16, d17s16, d18s16, d19s16, d20s16, d21s16, d22s16;
224   int16x4_t d24s16, d25s16, d26s16, d27s16;
225   uint16x4_t d2u16, d3u16, d4u16, d5u16;
226   int16x8_t q0s16;
227   uint16x8_t q1u16, q2u16, q8u16, q9u16, q10u16, q11u16, q12u16, q13u16;
228   int32x4_t q1s32, q2s32, q14s32, q15s32;
229 
230   assert(y_step_q4 == 16);
231 
232   (void)x_step_q4;
233   (void)y_step_q4;
234   (void)filter_x;
235 
236   src -= src_stride * 3;
237   q0s16 = vld1q_s16(filter_y);
238   for (; w > 0; w -= 4, src += 4, dst += 4) {  // loop_vert_h
239     s = src;
240     d16u32 = vld1_lane_u32((const uint32_t *)s, d16u32, 0);
241     s += src_stride;
242     d16u32 = vld1_lane_u32((const uint32_t *)s, d16u32, 1);
243     s += src_stride;
244     d18u32 = vld1_lane_u32((const uint32_t *)s, d18u32, 0);
245     s += src_stride;
246     d18u32 = vld1_lane_u32((const uint32_t *)s, d18u32, 1);
247     s += src_stride;
248     d20u32 = vld1_lane_u32((const uint32_t *)s, d20u32, 0);
249     s += src_stride;
250     d20u32 = vld1_lane_u32((const uint32_t *)s, d20u32, 1);
251     s += src_stride;
252     d22u32 = vld1_lane_u32((const uint32_t *)s, d22u32, 0);
253     s += src_stride;
254 
255     q8u16 = vmovl_u8(vreinterpret_u8_u32(d16u32));
256     q9u16 = vmovl_u8(vreinterpret_u8_u32(d18u32));
257     q10u16 = vmovl_u8(vreinterpret_u8_u32(d20u32));
258     q11u16 = vmovl_u8(vreinterpret_u8_u32(d22u32));
259 
260     d18s16 = vreinterpret_s16_u16(vget_low_u16(q9u16));
261     d19s16 = vreinterpret_s16_u16(vget_high_u16(q9u16));
262     d22s16 = vreinterpret_s16_u16(vget_low_u16(q11u16));
263     d = dst;
264     for (height = h; height > 0; height -= 4) {  // loop_vert
265       d24u32 = vld1_lane_u32((const uint32_t *)s, d24u32, 0);
266       s += src_stride;
267       d26u32 = vld1_lane_u32((const uint32_t *)s, d26u32, 0);
268       s += src_stride;
269       d26u32 = vld1_lane_u32((const uint32_t *)s, d26u32, 1);
270       s += src_stride;
271       d24u32 = vld1_lane_u32((const uint32_t *)s, d24u32, 1);
272       s += src_stride;
273 
274       q12u16 = vmovl_u8(vreinterpret_u8_u32(d24u32));
275       q13u16 = vmovl_u8(vreinterpret_u8_u32(d26u32));
276 
277       d16s16 = vreinterpret_s16_u16(vget_low_u16(q8u16));
278       d17s16 = vreinterpret_s16_u16(vget_high_u16(q8u16));
279       d20s16 = vreinterpret_s16_u16(vget_low_u16(q10u16));
280       d21s16 = vreinterpret_s16_u16(vget_high_u16(q10u16));
281       d24s16 = vreinterpret_s16_u16(vget_low_u16(q12u16));
282       d25s16 = vreinterpret_s16_u16(vget_high_u16(q12u16));
283       d26s16 = vreinterpret_s16_u16(vget_low_u16(q13u16));
284       d27s16 = vreinterpret_s16_u16(vget_high_u16(q13u16));
285 
286       __builtin_prefetch(d);
287       __builtin_prefetch(d + dst_stride);
288       q1s32 = MULTIPLY_BY_Q0(d16s16, d17s16, d18s16, d19s16, d20s16, d21s16,
289                              d22s16, d24s16, q0s16);
290       __builtin_prefetch(d + dst_stride * 2);
291       __builtin_prefetch(d + dst_stride * 3);
292       q2s32 = MULTIPLY_BY_Q0(d17s16, d18s16, d19s16, d20s16, d21s16, d22s16,
293                              d24s16, d26s16, q0s16);
294       __builtin_prefetch(s);
295       __builtin_prefetch(s + src_stride);
296       q14s32 = MULTIPLY_BY_Q0(d18s16, d19s16, d20s16, d21s16, d22s16, d24s16,
297                               d26s16, d27s16, q0s16);
298       __builtin_prefetch(s + src_stride * 2);
299       __builtin_prefetch(s + src_stride * 3);
300       q15s32 = MULTIPLY_BY_Q0(d19s16, d20s16, d21s16, d22s16, d24s16, d26s16,
301                               d27s16, d25s16, q0s16);
302 
303       d2u16 = vqrshrun_n_s32(q1s32, 7);
304       d3u16 = vqrshrun_n_s32(q2s32, 7);
305       d4u16 = vqrshrun_n_s32(q14s32, 7);
306       d5u16 = vqrshrun_n_s32(q15s32, 7);
307 
308       q1u16 = vcombine_u16(d2u16, d3u16);
309       q2u16 = vcombine_u16(d4u16, d5u16);
310 
311       d2u32 = vreinterpret_u32_u8(vqmovn_u16(q1u16));
312       d3u32 = vreinterpret_u32_u8(vqmovn_u16(q2u16));
313 
314       vst1_lane_u32((uint32_t *)d, d2u32, 0);
315       d += dst_stride;
316       vst1_lane_u32((uint32_t *)d, d2u32, 1);
317       d += dst_stride;
318       vst1_lane_u32((uint32_t *)d, d3u32, 0);
319       d += dst_stride;
320       vst1_lane_u32((uint32_t *)d, d3u32, 1);
321       d += dst_stride;
322 
323       q8u16 = q10u16;
324       d18s16 = d22s16;
325       d19s16 = d24s16;
326       q10u16 = q13u16;
327       d22s16 = d25s16;
328     }
329   }
330   return;
331 }
332