]> git.sesse.net Git - x264/blob - common/arm/mc-a.S
3a16d0db5031987cd07a7e8902ffbf47f91a53ad
[x264] / common / arm / mc-a.S
1 /*****************************************************************************
2  * mc.S: arm motion compensation
3  *****************************************************************************
4  * Copyright (C) 2009-2014 x264 project
5  *
6  * Authors: David Conrad <lessen42@gmail.com>
7  *          Mans Rullgard <mans@mansr.com>
8  *          Stefan Groenroos <stefan.gronroos@gmail.com>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111, USA.
23  *
24  * This program is also available under a commercial proprietary license.
25  * For more information, contact us at licensing@x264.com.
26  *****************************************************************************/
27
28 #include "asm.S"
29
30 .text
31
32 // note: prefetch stuff assumes 64-byte cacheline, true for the Cortex-A8
33 // They also use nothing above armv5te, but we don't care about pre-armv6
34
35 // void prefetch_ref( uint8_t *pix, intptr_t stride, int parity )
36 function x264_prefetch_ref_arm
37     sub         r2, r2, #1
38     add         r0, r0, #64
39     and         r2, r2, r1
40     add         r0, r0, r2, lsl #3
41     add         r2, r1, r1, lsl #1
42     pld         [r0]
43     pld         [r0, r1]
44     pld         [r0, r1, lsl #1]
45     add         r3, r0, r1, lsl #2
46     pld         [r0, r2]
47     pld         [r3]
48     pld         [r3, r1]
49     pld         [r3, r1, lsl #1]
50     pld         [r3, r2]
51     bx          lr
52 .endfunc
53
54 // void prefetch_fenc( uint8_t *pix_y,  intptr_t stride_y,
55 //                     uint8_t *pix_uv, intptr_t stride_uv, int mb_x )
56 function x264_prefetch_fenc_arm
57     ldr         ip, [sp]
58     push        {lr}
59     and         lr, ip, #3
60     smulbb      lr, lr, r1      // note: this assumes stride_y is <= 16 bits signed
61     and         ip, ip, #6
62     smulbb      ip, ip, r3
63     add         r0, r0, #64
64     add         r2, r2, #64
65     add         r0, r0, lr, lsl #2
66     pld         [r0]
67     add         lr, r0, r1, lsl #1
68     pld         [r0, r1]
69     pld         [lr]
70     add         r2, r2, ip, lsl #2
71     pld         [lr, r1]
72     pld         [r2]
73     add         ip, r2, r3, lsl #1
74     pld         [r2, r3]
75     pld         [ip]
76     pld         [ip, r3]
77     pop         {pc}
78 .endfunc
79
80
81 // void *x264_memcpy_aligned( void *dst, const void *src, size_t n )
82 function x264_memcpy_aligned_neon
83     orr         r3,  r0,  r1,  lsr #1
84     movrel      ip,  memcpy_table
85     and         r3,  r3,  #0xc
86     ldr         pc,  [ip, r3]
87 .endfunc
88
89 .macro MEMCPY_ALIGNED srcalign dstalign
90 function memcpy_aligned_\dstalign\()_\srcalign\()_neon, export=0
91     mov         r3, r0
92 .if \srcalign == 8 && \dstalign == 8
93     sub         r2, #16
94     vld1.64     {d0}, [r1,:64]!
95     vst1.64     {d0}, [r3,:64]!
96     .set r1align, 128
97     .set r3align, 128
98 .else
99     .set r1align, \srcalign * 8
100     .set r3align, \dstalign * 8
101 .endif
102     tst         r2, #16
103     beq         32f
104     sub         r2, #16
105     vld1.64     {d0-d1}, [r1,:r1align]!
106     vst1.64     {d0-d1}, [r3,:r3align]!
107 32: // n is a multiple of 32
108     tst         r2, #32
109     beq         640f
110     sub         r2, #32
111     vld1.64     {d0-d3}, [r1,:r1align]!
112     vst1.64     {d0-d3}, [r3,:r3align]!
113 640: // n is a multiple of 64
114     cmp         r2, #0
115     beq         1f
116 64:
117     subs        r2, #64
118     vld1.64     {d0-d3}, [r1,:r1align]!
119     vld1.64     {d4-d7}, [r1,:r1align]!
120     vst1.64     {d0-d3}, [r3,:r3align]!
121     vst1.64     {d4-d7}, [r3,:r3align]!
122     bgt         64b
123 1:   // end
124 .if \srcalign == 8 && \dstalign == 8
125     vld1.64     {d0}, [r1,:64]!
126     vst1.64     {d0}, [r3,:64]!
127 .endif
128     bx          lr
129 .endfunc
130 .endm
131
132 MEMCPY_ALIGNED 16, 16
133 MEMCPY_ALIGNED 16, 8
134 MEMCPY_ALIGNED  8, 16
135 MEMCPY_ALIGNED  8, 8
136
137 .section .rodata
138 memcpy_table:
139 .word memcpy_aligned_16_16_neon
140 .word memcpy_aligned_16_8_neon
141 .word memcpy_aligned_8_16_neon
142 .word memcpy_aligned_8_8_neon
143 .text
144
145 .ltorg
146
147 // void x264_memzero_aligned( void *dst, size_t n )
148 function x264_memzero_aligned_neon
149     vmov.i8     q0, #0
150     vmov.i8     q1, #0
151 memzero_loop:
152     subs        r1, #128
153 .rept 4
154     vst1.64     {d0-d3}, [r0,:128]!
155 .endr
156     bgt         memzero_loop
157     bx          lr
158 .endfunc
159
160
161 // void pixel_avg( uint8_t *dst,  intptr_t dst_stride,
162 //                 uint8_t *src1, intptr_t src1_stride,
163 //                 uint8_t *src2, intptr_t src2_stride, int weight );
164 .macro AVGH w h
165 function x264_pixel_avg_\w\()x\h\()_neon
166     ldr         ip, [sp, #8]
167     push        {r4-r6,lr}
168     cmp         ip, #32
169     ldrd        r4, r5, [sp, #16]
170     mov         lr, #\h
171     beq         x264_pixel_avg_w\w\()_neon
172     rsbs        r6,  ip,  #64
173     blt         x264_pixel_avg_weight_w\w\()_add_sub_neon     // weight > 64
174     cmp         ip,  #0
175     bge         x264_pixel_avg_weight_w\w\()_add_add_neon
176     b           x264_pixel_avg_weight_w\w\()_sub_add_neon     // weight < 0
177 .endfunc
178 .endm
179
180 AVGH  4, 2
181 AVGH  4, 4
182 AVGH  4, 8
183 AVGH  4, 16
184 AVGH  8, 4
185 AVGH  8, 8
186 AVGH  8, 16
187 AVGH 16, 8
188 AVGH 16, 16
189
190 // 0 < weight < 64
191 .macro load_weights_add_add
192     vdup.8      d30, ip
193     vdup.8      d31, r6
194 .endm
195
196 .macro load_add_add d1 d2
197     vld1.32     {\d1}, [r2], r3
198     vld1.32     {\d2}, [r4], r5
199 .endm
200
201 .macro weight_add_add dst s1 s2
202     vmull.u8    \dst, \s1, d30
203     vmlal.u8    \dst, \s2, d31
204 .endm
205
206 // weight > 64
207 .macro load_weights_add_sub
208     rsb         r6,  #0
209     vdup.8      d30, ip
210     vdup.8      d31, r6
211 .endm
212
213 .macro load_add_sub d1 d2
214     vld1.32     {\d1}, [r2], r3
215     vld1.32     {\d2}, [r4], r5
216 .endm
217
218 .macro weight_add_sub dst s1 s2
219     vmull.u8    \dst, \s1, d30
220     vmlsl.u8    \dst, \s2, d31
221 .endm
222
223 // weight < 0
224 .macro load_weights_sub_add
225     rsb         ip,  #0
226     vdup.8      d31, r6
227     vdup.8      d30, ip
228 .endm
229
230 .macro load_sub_add d1 d2
231     vld1.32     {\d2}, [r4], r5
232     vld1.32     {\d1}, [r2], r3
233 .endm
234
235 .macro weight_sub_add dst s1 s2
236     vmull.u8    \dst, \s2, d31
237     vmlsl.u8    \dst, \s1, d30
238 .endm
239
240 .macro AVG_WEIGHT ext
241 function x264_pixel_avg_weight_w4_\ext\()_neon, export=0
242     load_weights_\ext
243 1:  // height loop
244     subs            lr,  lr,  #2
245     load_\ext       d0[], d1[]
246     weight_\ext     q8,  d0,  d1
247     load_\ext       d2[], d3[]
248     vqrshrun.s16    d0,  q8,  #6
249     weight_\ext     q9,  d2,  d3
250     vst1.32         {d0[0]}, [r0,:32], r1
251     vqrshrun.s16    d1,  q9,  #6
252     vst1.32         {d1[0]}, [r0,:32], r1
253     bgt             1b
254     pop             {r4-r6,pc}
255 .endfunc
256
257 function x264_pixel_avg_weight_w8_\ext\()_neon, export=0
258     load_weights_\ext
259 1:  // height loop
260     subs            lr,  lr,  #4
261     load_\ext       d0,  d1
262     weight_\ext     q8,  d0,  d1
263     load_\ext       d2,  d3
264     weight_\ext     q9,  d2,  d3
265     load_\ext       d4,  d5
266     weight_\ext     q10, d4,  d5
267     load_\ext       d6,  d7
268     weight_\ext     q11, d6,  d7
269     vqrshrun.s16    d0,  q8,  #6
270     vqrshrun.s16    d1,  q9,  #6
271     vqrshrun.s16    d2,  q10, #6
272     vqrshrun.s16    d3,  q11, #6
273     vst1.64         {d0}, [r0,:64], r1
274     vst1.64         {d1}, [r0,:64], r1
275     vst1.64         {d2}, [r0,:64], r1
276     vst1.64         {d3}, [r0,:64], r1
277     bgt             1b
278     pop             {r4-r6,pc}
279 .endfunc
280
281 function x264_pixel_avg_weight_w16_\ext\()_neon, export=0
282     load_weights_\ext
283 1:  // height loop
284     subs            lr,  lr,  #2
285     load_\ext       d0-d1, d2-d3
286     weight_\ext     q8,  d0,  d2
287     weight_\ext     q9,  d1,  d3
288     load_\ext       d4-d5, d6-d7
289     weight_\ext     q10, d4,  d6
290     weight_\ext     q11, d5,  d7
291     vqrshrun.s16    d0,  q8,  #6
292     vqrshrun.s16    d1,  q9,  #6
293     vqrshrun.s16    d2,  q10, #6
294     vqrshrun.s16    d3,  q11, #6
295     vst1.64         {d0-d1}, [r0,:128], r1
296     vst1.64         {d2-d3}, [r0,:128], r1
297     bgt             1b
298     pop             {r4-r6,pc}
299 .endfunc
300 .endm
301
302 AVG_WEIGHT add_add
303 AVG_WEIGHT add_sub
304 AVG_WEIGHT sub_add
305
306 function x264_pixel_avg_w4_neon, export=0
307     subs        lr,  lr,  #2
308     vld1.32     {d0[]}, [r2], r3
309     vld1.32     {d2[]}, [r4], r5
310     vrhadd.u8   d0,  d0,  d2
311     vld1.32     {d1[]}, [r2], r3
312     vld1.32     {d3[]}, [r4], r5
313     vrhadd.u8   d1,  d1,  d3
314     vst1.32     {d0[0]}, [r0,:32], r1
315     vst1.32     {d1[0]}, [r0,:32], r1
316     bgt         x264_pixel_avg_w4_neon
317     pop         {r4-r6,pc}
318 .endfunc
319
320 function x264_pixel_avg_w8_neon, export=0
321     subs        lr,  lr,  #4
322     vld1.64     {d0}, [r2], r3
323     vld1.64     {d2}, [r4], r5
324     vrhadd.u8   d0,  d0,  d2
325     vld1.64     {d1}, [r2], r3
326     vld1.64     {d3}, [r4], r5
327     vrhadd.u8   d1,  d1,  d3
328     vst1.64     {d0}, [r0,:64], r1
329     vld1.64     {d2}, [r2], r3
330     vld1.64     {d4}, [r4], r5
331     vrhadd.u8   d2,  d2,  d4
332     vst1.64     {d1}, [r0,:64], r1
333     vld1.64     {d3}, [r2], r3
334     vld1.64     {d5}, [r4], r5
335     vrhadd.u8   d3,  d3,  d5
336     vst1.64     {d2}, [r0,:64], r1
337     vst1.64     {d3}, [r0,:64], r1
338     bgt         x264_pixel_avg_w8_neon
339     pop         {r4-r6,pc}
340 .endfunc
341
342 function x264_pixel_avg_w16_neon, export=0
343     subs        lr,  lr,  #4
344     vld1.64     {d0-d1}, [r2], r3
345     vld1.64     {d2-d3}, [r4], r5
346     vrhadd.u8   q0,  q0,  q1
347     vld1.64     {d2-d3}, [r2], r3
348     vld1.64     {d4-d5}, [r4], r5
349     vrhadd.u8   q1,  q1,  q2
350     vst1.64     {d0-d1}, [r0,:128], r1
351     vld1.64     {d4-d5}, [r2], r3
352     vld1.64     {d6-d7}, [r4], r5
353     vrhadd.u8   q2,  q2,  q3
354     vst1.64     {d2-d3}, [r0,:128], r1
355     vld1.64     {d6-d7}, [r2], r3
356     vld1.64     {d0-d1}, [r4], r5
357     vrhadd.u8   q3,  q3,  q0
358     vst1.64     {d4-d5}, [r0,:128], r1
359     vst1.64     {d6-d7}, [r0,:128], r1
360     bgt         x264_pixel_avg_w16_neon
361     pop         {r4-r6,pc}
362 .endfunc
363
364
365 function x264_pixel_avg2_w4_neon
366     ldr         ip,  [sp, #4]
367     push        {lr}
368     ldr         lr,  [sp, #4]
369 avg2_w4_loop:
370     subs        ip,  ip,  #2
371     vld1.32     {d0[]},  [r2], r3
372     vld1.32     {d2[]},  [lr], r3
373     vrhadd.u8   d0,  d0,  d2
374     vld1.32     {d1[]},  [r2], r3
375     vld1.32     {d3[]},  [lr], r3
376     vrhadd.u8   d1,  d1,  d3
377     vst1.32     {d0[0]}, [r0,:32], r1
378     vst1.32     {d1[0]}, [r0,:32], r1
379     bgt         avg2_w4_loop
380     pop         {pc}
381 .endfunc
382
383 function x264_pixel_avg2_w8_neon
384     ldr         ip,  [sp, #4]
385     push        {lr}
386     ldr         lr,  [sp, #4]
387 avg2_w8_loop:
388     subs        ip,  ip,  #2
389     vld1.64     {d0}, [r2], r3
390     vld1.64     {d2}, [lr], r3
391     vrhadd.u8   d0,  d0,  d2
392     vld1.64     {d1}, [r2], r3
393     vld1.64     {d3}, [lr], r3
394     vrhadd.u8   d1,  d1,  d3
395     vst1.64     {d0}, [r0,:64], r1
396     vst1.64     {d1}, [r0,:64], r1
397     bgt         avg2_w8_loop
398     pop         {pc}
399 .endfunc
400
401 function x264_pixel_avg2_w16_neon
402     ldr         ip,  [sp, #4]
403     push        {lr}
404     ldr         lr,  [sp, #4]
405 avg2_w16_loop:
406     subs        ip,  ip,  #2
407     vld1.64     {d0-d1}, [r2], r3
408     vld1.64     {d2-d3}, [lr], r3
409     vrhadd.u8   q0,  q0,  q1
410     vld1.64     {d4-d5}, [r2], r3
411     vld1.64     {d6-d7}, [lr], r3
412     vrhadd.u8   q2,  q2,  q3
413     vst1.64     {d0-d1}, [r0,:128], r1
414     vst1.64     {d4-d5}, [r0,:128], r1
415     bgt         avg2_w16_loop
416     pop         {pc}
417 .endfunc
418
419 function x264_pixel_avg2_w20_neon
420     ldr         ip,  [sp, #4]
421     push        {lr}
422     sub         r1,  r1,  #16
423     ldr         lr,  [sp, #4]
424 avg2_w20_loop:
425     subs        ip,  ip,  #2
426     vld1.64     {d0-d2},  [r2], r3
427     vld1.64     {d4-d6},  [lr], r3
428     vrhadd.u8   q0,  q0,  q2
429     vrhadd.u8   d2,  d2,  d6
430     vld1.64     {d4-d6},  [r2], r3
431     vld1.64     {d16-d18},[lr], r3
432     vrhadd.u8   q2,  q2,  q8
433     vst1.64     {d0-d1},  [r0,:128]!
434     vrhadd.u8   d6,  d6,  d18
435     vst1.32     {d2[0]},  [r0,:32], r1
436     vst1.64     {d4-d5},  [r0,:128]!
437     vst1.32     {d6[0]},  [r0,:32], r1
438     bgt         avg2_w20_loop
439     pop         {pc}
440 .endfunc
441
442
443 .macro weight_prologue type
444     push        {r4-r5,lr}
445     ldr         r4,  [sp, #4*3]     // weight_t
446     ldr         ip,  [sp, #4*3+4]   // h
447 .ifc \type, full
448     ldr         lr,  [r4, #32]      // denom
449 .endif
450     ldrd        r4,  r5,  [r4, #32+4]    // scale, offset
451     vdup.16     q0,  r4
452     vdup.16     q1,  r5
453 .ifc \type, full
454     rsb         lr,  lr,  #0
455     vdup.16     q2,  lr
456 .endif
457 .endm
458
459 // void mc_weight( uint8_t *src, intptr_t src_stride, uint8_t *dst, intptr_t dst_stride,
460 //                 const x264_weight_t *weight, int height )
461 function x264_mc_weight_w20_neon
462     weight_prologue full
463     sub         r1, #16
464 weight20_loop:
465     subs        ip,  #2
466     vld1.8      {d17-d19}, [r2], r3
467     vmovl.u8    q10, d17
468     vmovl.u8    q11, d18
469     vmovl.u8    q14, d19
470     vld1.8      {d16-d18}, [r2], r3
471     vmovl.u8    q12, d16
472     vmovl.u8    q13, d17
473     vmovl.u8    q15, d18
474     vmul.s16    q10, q10, q0
475     vmul.s16    q11, q11, q0
476     vmul.s16    q12, q12, q0
477     vmul.s16    q13, q13, q0
478     vmul.s16    d28, d28, d0
479     vmul.s16    d29, d30, d0
480     vrshl.s16   q10, q10, q2
481     vrshl.s16   q11, q11, q2
482     vrshl.s16   q12, q12, q2
483     vrshl.s16   q13, q13, q2
484     vrshl.s16   q14, q14, q2
485     vadd.s16    q10, q10, q1
486     vadd.s16    q11, q11, q1
487     vadd.s16    q12, q12, q1
488     vadd.s16    q13, q13, q1
489     vadd.s16    q14, q14, q1
490     vqmovun.s16 d16, q10
491     vqmovun.s16 d17, q11
492     vqmovun.s16 d18, q12
493     vqmovun.s16 d19, q13
494     vqmovun.s16 d20, q14
495     vst1.8      {d16-d17}, [r0,:128]!
496     vst1.32     {d20[0]},  [r0,:32], r1
497     vst1.8      {d18-d19}, [r0,:128]!
498     vst1.32     {d20[1]},  [r0,:32], r1
499     bgt         weight20_loop
500     pop         {r4-r5,pc}
501 .endfunc
502
503 function x264_mc_weight_w16_neon
504     weight_prologue full
505 weight16_loop:
506     subs        ip,  #2
507     vld1.8      {d16-d17}, [r2], r3
508     vld1.8      {d18-d19}, [r2], r3
509     vmovl.u8    q10, d16
510     vmovl.u8    q11, d17
511     vmovl.u8    q12, d18
512     vmovl.u8    q13, d19
513     vmul.s16    q10, q10, q0
514     vmul.s16    q11, q11, q0
515     vmul.s16    q12, q12, q0
516     vmul.s16    q13, q13, q0
517     vrshl.s16   q10, q10, q2
518     vrshl.s16   q11, q11, q2
519     vrshl.s16   q12, q12, q2
520     vrshl.s16   q13, q13, q2
521     vadd.s16    q10, q10, q1
522     vadd.s16    q11, q11, q1
523     vadd.s16    q12, q12, q1
524     vadd.s16    q13, q13, q1
525     vqmovun.s16 d16, q10
526     vqmovun.s16 d17, q11
527     vqmovun.s16 d18, q12
528     vqmovun.s16 d19, q13
529     vst1.8      {d16-d17}, [r0,:128], r1
530     vst1.8      {d18-d19}, [r0,:128], r1
531     bgt         weight16_loop
532     pop         {r4-r5,pc}
533 .endfunc
534
535 function x264_mc_weight_w8_neon
536     weight_prologue full
537 weight8_loop:
538     subs        ip,  #2
539     vld1.8      {d16}, [r2], r3
540     vld1.8      {d18}, [r2], r3
541     vmovl.u8    q8,  d16
542     vmovl.u8    q9,  d18
543     vmul.s16    q8,  q8,  q0
544     vmul.s16    q9,  q9,  q0
545     vrshl.s16   q8,  q8,  q2
546     vrshl.s16   q9,  q9,  q2
547     vadd.s16    q8,  q8,  q1
548     vadd.s16    q9,  q9,  q1
549     vqmovun.s16 d16, q8
550     vqmovun.s16 d18, q9
551     vst1.8      {d16}, [r0,:64], r1
552     vst1.8      {d18}, [r0,:64], r1
553     bgt         weight8_loop
554     pop         {r4-r5,pc}
555 .endfunc
556
557 function x264_mc_weight_w4_neon
558     weight_prologue full
559 weight4_loop:
560     subs        ip,  #2
561     vld1.32     {d16[]}, [r2], r3
562     vld1.32     {d18[]}, [r2], r3
563     vmovl.u8    q8,  d16
564     vmovl.u8    q9,  d18
565     vmul.s16    d16, d16, d0
566     vmul.s16    d17, d18, d0
567     vrshl.s16   q8,  q8,  q2
568     vadd.s16    q8,  q8,  q1
569     vqmovun.s16 d16, q8
570     vst1.32     {d16[0]}, [r0,:32], r1
571     vst1.32     {d16[1]}, [r0,:32], r1
572     bgt         weight4_loop
573     pop         {r4-r5,pc}
574 .endfunc
575
576 function x264_mc_weight_w20_nodenom_neon
577     weight_prologue nodenom
578     sub         r1, #16
579 weight20_nodenom_loop:
580     subs        ip,  #2
581     vld1.8      {d17-d19}, [r2], r3
582     vmovl.u8    q10, d17
583     vmovl.u8    q11, d18
584     vmovl.u8    q14, d19
585     vld1.8      {d16-d18}, [r2], r3
586     vmovl.u8    q12, d16
587     vmovl.u8    q13, d17
588     vmovl.u8    q15, d18
589     vmov        q8,  q1
590     vmov        q9,  q1
591     vmla.s16    q8,  q10, q0
592     vmla.s16    q9,  q11, q0
593     vmov        q10, q1
594     vmov        q11, q1
595     vmla.s16    q10, q12, q0
596     vmla.s16    q11, q13, q0
597     vmov        q12, q1
598     vmla.s16    d24, d28, d0
599     vmla.s16    d25, d30, d0
600     vqmovun.s16 d16, q8
601     vqmovun.s16 d17, q9
602     vqmovun.s16 d18, q10
603     vqmovun.s16 d19, q11
604     vqmovun.s16 d20, q12
605     vst1.8      {d16-d17}, [r0,:128]!
606     vst1.32     {d20[0]},  [r0,:32], r1
607     vst1.8      {d18-d19}, [r0,:128]!
608     vst1.32     {d20[1]},  [r0,:32], r1
609     bgt         weight20_nodenom_loop
610     pop         {r4-r5,pc}
611 .endfunc
612
613 function x264_mc_weight_w16_nodenom_neon
614     weight_prologue nodenom
615 weight16_nodenom_loop:
616     subs        ip,  #2
617     vld1.8      {d16-d17}, [r2], r3
618     vld1.8      {d18-d19}, [r2], r3
619     vmovl.u8    q12, d16
620     vmovl.u8    q13, d17
621     vmovl.u8    q14, d18
622     vmovl.u8    q15, d19
623     vmov        q8,  q1
624     vmov        q9,  q1
625     vmov        q10, q1
626     vmov        q11, q1
627     vmla.s16    q8,  q12, q0
628     vmla.s16    q9,  q13, q0
629     vmla.s16    q10, q14, q0
630     vmla.s16    q11, q15, q0
631     vqmovun.s16 d16, q8
632     vqmovun.s16 d17, q9
633     vqmovun.s16 d18, q10
634     vqmovun.s16 d19, q11
635     vst1.8      {d16-d17}, [r0,:128], r1
636     vst1.8      {d18-d19}, [r0,:128], r1
637     bgt         weight16_nodenom_loop
638     pop         {r4-r5,pc}
639 .endfunc
640
641 function x264_mc_weight_w8_nodenom_neon
642     weight_prologue nodenom
643 weight8_nodenom_loop:
644     subs        ip,  #2
645     vld1.8      {d16}, [r2], r3
646     vld1.8      {d18}, [r2], r3
647     vmovl.u8    q8,  d16
648     vmovl.u8    q9,  d18
649     vmov        q10, q1
650     vmov        q11, q1
651     vmla.s16    q10, q8,  q0
652     vmla.s16    q11, q9,  q0
653     vqmovun.s16 d16, q10
654     vqmovun.s16 d17, q11
655     vst1.8      {d16}, [r0,:64], r1
656     vst1.8      {d17}, [r0,:64], r1
657     bgt         weight8_nodenom_loop
658     pop         {r4-r5,pc}
659 .endfunc
660
661 function x264_mc_weight_w4_nodenom_neon
662     weight_prologue nodenom
663 weight4_nodenom_loop:
664     subs        ip,  #2
665     vld1.32     {d16[]}, [r2], r3
666     vld1.32     {d18[]}, [r2], r3
667     vmovl.u8    q8,  d16
668     vmovl.u8    q9,  d18
669     vmov        q10, q1
670     vmla.s16    d20, d16, d0
671     vmla.s16    d21, d18, d0
672     vqmovun.s16 d16, q10
673     vst1.32     {d16[0]}, [r0,:32], r1
674     vst1.32     {d16[1]}, [r0,:32], r1
675     bgt         weight4_nodenom_loop
676     pop         {r4-r5,pc}
677 .endfunc
678
679 .macro weight_simple_prologue
680     push        {lr}
681     ldr         lr,  [sp, #4]       // weight_t
682     ldr         ip,  [sp, #8]       // h
683     ldr         lr,  [lr]           // offset
684     vdup.8      q1,  lr
685 .endm
686
687 .macro weight_simple name op
688 function x264_mc_weight_w20_\name\()_neon
689     weight_simple_prologue
690 weight20_\name\()_loop:
691     subs        ip,  #2
692     vld1.8      {d16-d18}, [r2], r3
693     vld1.8      {d19-d21}, [r2], r3
694     \op         q8,  q8,  q1
695     \op         q9,  q9,  q1
696     \op         q10, q10, q1
697     vst1.8      {d16-d18}, [r0,:64], r1
698     vst1.8      {d19-d21}, [r0,:64], r1
699     bgt         weight20_\name\()_loop
700     pop         {pc}
701 .endfunc
702
703 function x264_mc_weight_w16_\name\()_neon
704     weight_simple_prologue
705 weight16_\name\()_loop:
706     subs        ip,  #2
707     vld1.8      {d16-d17}, [r2], r3
708     vld1.8      {d18-d19}, [r2], r3
709     \op         q8,  q8,  q1
710     \op         q9,  q9,  q1
711     vst1.8      {d16-d17}, [r0,:128], r1
712     vst1.8      {d18-d19}, [r0,:128], r1
713     bgt         weight16_\name\()_loop
714     pop         {pc}
715 .endfunc
716
717 function x264_mc_weight_w8_\name\()_neon
718     weight_simple_prologue
719 weight8_\name\()_loop:
720     subs        ip,  #2
721     vld1.8      {d16}, [r2], r3
722     vld1.8      {d17}, [r2], r3
723     \op         q8,  q8,  q1
724     vst1.8      {d16}, [r0,:64], r1
725     vst1.8      {d17}, [r0,:64], r1
726     bgt         weight8_\name\()_loop
727     pop         {pc}
728 .endfunc
729
730 function x264_mc_weight_w4_\name\()_neon
731     weight_simple_prologue
732 weight4_\name\()_loop:
733     subs        ip,  #2
734     vld1.32     {d16[]}, [r2], r3
735     vld1.32     {d17[]}, [r2], r3
736     \op         q8,  q8,  q1
737     vst1.32     {d16[0]}, [r0,:32], r1
738     vst1.32     {d17[0]}, [r0,:32], r1
739     bgt         weight4_\name\()_loop
740     pop         {pc}
741 .endfunc
742 .endm
743
744 weight_simple offsetadd, vqadd.u8
745 weight_simple offsetsub, vqsub.u8
746
747
748 // void mc_copy( uint8_t *dst, intptr_t dst_stride, uint8_t *src, intptr_t src_stride, int height )
749 function x264_mc_copy_w4_neon
750     ldr         ip,  [sp]
751 copy_w4_loop:
752     subs        ip,  ip,  #4
753     vld1.32     {d0[]},  [r2], r3
754     vld1.32     {d1[]},  [r2], r3
755     vld1.32     {d2[]},  [r2], r3
756     vld1.32     {d3[]},  [r2], r3
757     vst1.32     {d0[0]}, [r0,:32], r1
758     vst1.32     {d1[0]}, [r0,:32], r1
759     vst1.32     {d2[0]}, [r0,:32], r1
760     vst1.32     {d3[0]}, [r0,:32], r1
761     bgt         copy_w4_loop
762     bx          lr
763 .endfunc
764
765 function x264_mc_copy_w8_neon
766     ldr         ip,  [sp]
767 copy_w8_loop:
768     subs        ip,  ip,  #4
769     vld1.32     {d0}, [r2], r3
770     vld1.32     {d1}, [r2], r3
771     vld1.32     {d2}, [r2], r3
772     vld1.32     {d3}, [r2], r3
773     vst1.32     {d0}, [r0,:64], r1
774     vst1.32     {d1}, [r0,:64], r1
775     vst1.32     {d2}, [r0,:64], r1
776     vst1.32     {d3}, [r0,:64], r1
777     bgt         copy_w8_loop
778     bx          lr
779 .endfunc
780
781 function x264_mc_copy_w16_neon
782     ldr         ip,  [sp]
783 copy_w16_loop:
784     subs        ip,  ip,  #4
785     vld1.32     {d0-d1}, [r2], r3
786     vld1.32     {d2-d3}, [r2], r3
787     vld1.32     {d4-d5}, [r2], r3
788     vld1.32     {d6-d7}, [r2], r3
789     vst1.32     {d0-d1}, [r0,:128], r1
790     vst1.32     {d2-d3}, [r0,:128], r1
791     vst1.32     {d4-d5}, [r0,:128], r1
792     vst1.32     {d6-d7}, [r0,:128], r1
793     bgt         copy_w16_loop
794     bx          lr
795 .endfunc
796
797 function x264_mc_copy_w16_aligned_neon
798     ldr         ip,  [sp]
799 copy_w16_aligned_loop:
800     subs        ip,  ip,  #4
801     vld1.32     {d0-d1}, [r2,:128], r3
802     vld1.32     {d2-d3}, [r2,:128], r3
803     vld1.32     {d4-d5}, [r2,:128], r3
804     vld1.32     {d6-d7}, [r2,:128], r3
805     vst1.32     {d0-d1}, [r0,:128], r1
806     vst1.32     {d2-d3}, [r0,:128], r1
807     vst1.32     {d4-d5}, [r0,:128], r1
808     vst1.32     {d6-d7}, [r0,:128], r1
809     bgt         copy_w16_aligned_loop
810     bx          lr
811 .endfunc
812
813
814 // void x264_mc_chroma_neon( uint8_t *dst, intptr_t i_dst_stride,
815 //                           uint8_t *src, intptr_t i_src_stride,
816 //                           int dx, int dy, int i_width, int i_height );
817
818 function x264_mc_chroma_neon
819     push            {r4-r8, lr}
820     vpush           {d8-d11}
821     ldrd            r4, r5, [sp, #56]
822     ldrd            r6, r7, [sp, #64]
823
824     asr             lr, r6, #3
825     mul             lr, r4, lr
826     add             r3, r3, r5, asr #2
827     cmp             r7, #4
828
829     and             r5, r5, #7
830     and             r6, r6, #7
831
832     add             r3, r3, lr
833     bic             r3, r3, #0x1
834
835     pld             [r3]
836     pld             [r3, r4]
837
838     bgt             mc_chroma_w8
839     beq             mc_chroma_w4
840
841 .macro CHROMA_MC_START r00, r01, r10, r11
842     muls            lr, r5, r6
843     rsb             r7, lr, r6, lsl #3
844     rsb             ip, lr, r5, lsl #3
845     sub             r5, lr, r5, lsl #3
846     sub             r5, r5, r6, lsl #3
847     add             r5, r5, #64
848
849     beq             2f
850     vld2.8          {\r00-\r01}, [r3], r4
851
852     vdup.8          d0,    r5
853     vdup.8          d1,    ip
854
855     vdup.8          d2,    r7
856     vld2.8          {\r10-\r11}, [r3], r4
857     vdup.8          d3,    lr
858     ldr             r5,    [sp, #72]
859 .endm
860
861 .macro CHROMA_MC width, align
862 mc_chroma_w\width:
863     CHROMA_MC_START d4, d5,  d8, d9
864     vext.8          d6,  d4,  d6,  #1
865     vext.8          d7,  d5,  d7,  #1
866     vext.8          d10, d8,  d10, #1
867     vext.8          d11, d9,  d11, #1
868 // since the element size varies, there's a different index for the 2nd store
869 .if \width == 4
870     .set st2, 1
871 .else
872     .set st2, 2
873 .endif
874
875     vtrn.32         d4, d6
876     vtrn.32         d5, d7
877     vtrn.32         d8, d10
878     vtrn.32         d9, d11
879
880     vtrn.32         d0, d1
881     vtrn.32         d2, d3
882
883 1:  // height loop, interpolate xy
884
885     vmull.u8        q8,  d4,  d0
886     vmlal.u8        q8,  d8,  d2
887     vmull.u8        q9,  d5,  d0
888     vmlal.u8        q9,  d9,  d2
889
890     vld2.8          {d4-d5},  [r3], r4
891
892     vext.8          d6,  d4,  d6,  #1
893     vext.8          d7,  d5,  d7,  #1
894
895     vadd.i16        d16, d16, d17
896     vadd.i16        d17, d18, d19
897
898     vtrn.32         d4,  d6
899     vtrn.32         d5,  d7
900
901     vmull.u8        q10, d8,  d0
902     vmlal.u8        q10, d4,  d2
903     vmull.u8        q11, d9,  d0
904     vmlal.u8        q11, d5,  d2
905
906     vld2.8          {d8-d9},  [r3], r4
907
908     vrshrn.u16      d16, q8,  #6
909
910     vext.8          d10, d8,  d10,  #1
911     vext.8          d11, d9,  d11,  #1
912
913     vadd.i16        d18, d20, d21
914     vadd.i16        d19, d22, d23
915
916     vtrn.32         d8, d10
917     vtrn.32         d9, d11
918
919     vrshrn.u16      d18, q9,  #6
920
921     subs            r5,  r5,  #2
922
923     pld             [r3]
924     pld             [r3, r4]
925
926     vst1.\align     {d16[0]},   [r0,:\align], r2
927     vst1.\align     {d16[st2]}, [r1,:\align], r2
928     vst1.\align     {d18[0]},   [r0,:\align], r2
929     vst1.\align     {d18[st2]}, [r1,:\align], r2
930     bgt             1b
931
932     vpop            {d8-d11}
933     pop             {r4-r8, pc}
934
935 2:  // dx or dy are 0
936     tst             r7,  r7
937     add             ip,  ip,  r7
938     vdup.8          d0,  r5
939     ldr             r5,  [sp, #72]
940     vdup.8          d1,  ip
941
942     beq             4f
943
944     vld1.64          {d4}, [r3], r4
945     vld1.64          {d6}, [r3], r4
946
947 3:  // vertical interpolation loop
948
949     vmull.u8        q8,  d4,  d0
950     vmlal.u8        q8,  d6,  d1
951     vmull.u8        q9,  d6,  d0
952     vld1.64         {d4}, [r3], r4
953     vmlal.u8        q9,  d4,  d1
954     vld1.64         {d6}, [r3], r4
955
956     vrshrn.u16      d16, q8,  #6 // uvuvuvuv
957     vrshrn.u16      d17, q9,  #6 // uvuvuvuv
958     subs            r5,  r5,  #2
959     vuzp.8          d16, d17 // d16=uuuu|uuuu, d17=vvvv|vvvv
960
961     pld             [r3]
962     pld             [r3, r4]
963
964     vst1.\align     {d16[0]},   [r0,:\align], r2
965     vst1.\align     {d16[st2]}, [r0,:\align], r2
966     vst1.\align     {d17[0]},   [r1,:\align], r2
967     vst1.\align     {d17[st2]}, [r1,:\align], r2
968     bgt             3b
969
970     vpop            {d8-d11}
971     pop             {r4-r8, pc}
972
973 4:  // dy is 0
974
975     vld1.64         {d4-d5},  [r3], r4
976     vld1.64         {d6-d7},  [r3], r4
977
978     vext.8          d5,  d4,  d5,  #2
979     vext.8          d7,  d6,  d7,  #2
980
981 5:  // horizontal interpolation loop
982
983     vmull.u8        q8,  d4,  d0
984     vmlal.u8        q8,  d5,  d1
985     vmull.u8        q9,  d6,  d0
986     vmlal.u8        q9,  d7,  d1
987
988     subs            r5,  r5,  #2
989     vld1.64         {d4-d5},  [r3], r4
990     vld1.64         {d6-d7},  [r3], r4
991     vext.8          d5,  d4,  d5,  #2
992     vrshrn.u16      d16, q8,  #6
993     vrshrn.u16      d17, q9,  #6
994     vext.8          d7,  d6,  d7,  #2
995     vuzp.8          d16, d17
996
997     pld             [r3]
998     pld             [r3, r4]
999
1000     vst1.\align     {d16[0]},   [r0,:\align], r2
1001     vst1.\align     {d16[st2]}, [r0,:\align], r2
1002     vst1.\align     {d17[0]},   [r1,:\align], r2
1003     vst1.\align     {d17[st2]}, [r1,:\align], r2
1004     bgt             5b
1005
1006     vpop            {d8-d11}
1007     pop             {r4-r8, pc}
1008 .endm
1009
1010    CHROMA_MC 2, 16
1011    CHROMA_MC 4, 32
1012
1013 mc_chroma_w8:
1014     CHROMA_MC_START d4, d7, d8, d11
1015     vext.8          d5,  d4,  d5,  #1
1016     vext.8          d9,  d8,  d9,  #1
1017     vext.8          d7,  d6,  d7,  #1
1018     vext.8          d11, d10, d11,  #1
1019
1020 1:  // height loop, interpolate xy
1021     vmull.u8        q8,  d4,  d0
1022     vmlal.u8        q8,  d5,  d1
1023     vmlal.u8        q8,  d8,  d2
1024     vmlal.u8        q8,  d9,  d3
1025
1026     vmull.u8        q9,  d6,  d0
1027     vmlal.u8        q9,  d7,  d1
1028     vmlal.u8        q9,  d10,  d2
1029     vmlal.u8        q9,  d11,  d3
1030
1031     vld2.8          {d4-d7}, [r3], r4
1032
1033     vext.8          d5,  d4,  d5,  #1
1034     vext.8          d7,  d6,  d7,  #1
1035
1036     vmull.u8        q10, d8,   d0
1037     vmlal.u8        q10, d9,   d1
1038     vmlal.u8        q10, d4,   d2
1039     vmlal.u8        q10, d5,   d3
1040
1041     vmull.u8        q11, d10,  d0
1042     vmlal.u8        q11, d11,  d1
1043     vmlal.u8        q11, d6,   d2
1044     vmlal.u8        q11, d7,   d3
1045
1046     subs            r5,  r5,   #2
1047     vld2.8          {d8-d11}, [r3], r4
1048
1049     vrshrn.u16      d16, q8,  #6
1050     vrshrn.u16      d17, q9,  #6
1051     vrshrn.u16      d18, q10, #6
1052     vext.8          d9,  d8,  d9,  #1
1053     vrshrn.u16      d19, q11, #6
1054     vext.8          d11, d10, d11,  #1
1055
1056     pld             [r3]
1057     pld             [r3, r4]
1058
1059     vst1.64         {d16}, [r0,:64], r2
1060     vst1.64         {d17}, [r1,:64], r2
1061     vst1.64         {d18}, [r0,:64], r2
1062     vst1.64         {d19}, [r1,:64], r2
1063
1064     bgt             1b
1065
1066     vpop            {d8-d11}
1067     pop             {r4-r8, pc}
1068
1069 2:  // dx or dy are 0
1070     tst             r7,  r7
1071     add             ip,  ip,  r7
1072     vdup.8          d0,  r5
1073     ldr             r5,  [sp, #72]
1074     vdup.8          d1,  ip
1075
1076     beq             4f
1077
1078     vld2.8          {d4-d5}, [r3], r4
1079     vld2.8          {d6-d7}, [r3], r4
1080
1081 3:  // vertical interpolation loop
1082     vmull.u8        q8,  d4,  d0 //U
1083     vmlal.u8        q8,  d6,  d1
1084     vmull.u8        q9,  d5,  d0 //V
1085     vmlal.u8        q9,  d7,  d1
1086
1087     vld2.8          {d4-d5}, [r3], r4
1088
1089     vmull.u8        q10, d6,  d0
1090     vmlal.u8        q10, d4,  d1
1091     vmull.u8        q11, d7,  d0
1092     vmlal.u8        q11, d5,  d1
1093
1094     vld2.8          {d6-d7}, [r3], r4
1095
1096     vrshrn.u16      d16, q8,  #6
1097     vrshrn.u16      d17, q9,  #6
1098     vrshrn.u16      d18, q10, #6
1099     vrshrn.u16      d19, q11, #6
1100     subs            r5,  r5,  #2
1101
1102     pld             [r3]
1103     pld             [r3, r4]
1104
1105     vst1.64         {d16}, [r0,:64], r2
1106     vst1.64         {d17}, [r1,:64], r2
1107     vst1.64         {d18}, [r0,:64], r2
1108     vst1.64         {d19}, [r1,:64], r2
1109
1110     bgt             3b
1111
1112     vpop            {d8-d11}
1113     pop             {r4-r8, pc}
1114
1115 4:  // dy is 0
1116
1117     vld2.8          {d4-d7},  [r3], r4
1118     vld2.8          {d8-d11}, [r3], r4
1119     vext.8          d5,  d4,  d5,  #1
1120     vext.8          d7,  d6,  d7,  #1
1121     vext.8          d9,  d8,  d9,  #1
1122     vext.8          d11, d10, d11, #1
1123
1124 5:  // horizontal interpolation loop
1125     subs            r5,  r5,  #2
1126     vmull.u8        q8,  d4,  d0 //U
1127     vmlal.u8        q8,  d5,  d1
1128     vmull.u8        q9,  d6,  d0 //V
1129     vmlal.u8        q9,  d7,  d1
1130
1131     vld2.8          {d4-d7}, [r3], r4
1132
1133     vmull.u8        q10, d8,  d0
1134     vmlal.u8        q10, d9,  d1
1135     vmull.u8        q11, d10, d0
1136     vmlal.u8        q11, d11, d1
1137
1138     vld2.8          {d8-d11}, [r3], r4
1139
1140     vext.8          d5,  d4,  d5,  #1
1141     vrshrn.u16      d16, q8,  #6
1142     vext.8          d7,  d6,  d7,  #1
1143     vrshrn.u16      d17, q9,  #6
1144     vext.8          d9,  d8,  d9,  #1
1145     vrshrn.u16      d18, q10, #6
1146     vext.8          d11, d10, d11, #1
1147     vrshrn.u16      d19, q11, #6
1148
1149     pld             [r3]
1150     pld             [r3, r4]
1151
1152     vst1.64         {d16}, [r0,:64], r2
1153     vst1.64         {d17}, [r1,:64], r2
1154     vst1.64         {d18}, [r0,:64], r2
1155     vst1.64         {d19}, [r1,:64], r2
1156     bgt             5b
1157
1158     vpop            {d8-d11}
1159     pop             {r4-r8, pc}
1160
1161 .endfunc
1162
1163
1164 // hpel_filter_v( uint8_t *dst, uint8_t *src, int16_t *buf, intptr_t stride, int width )
1165 function x264_hpel_filter_v_neon
1166     ldr             ip,  [sp]
1167     sub             r1,  r1,  r3,  lsl #1
1168     push            {lr}
1169     add             lr,  r1,  ip
1170     vmov.u8         d30, #5
1171     vmov.u8         d31, #20
1172
1173 filter_v_loop:
1174     subs            ip,  ip,  #16
1175     vld1.64         {d0-d1},   [r1,:128], r3
1176     vld1.64         {d2-d3},   [r1,:128], r3
1177     vld1.64         {d4-d5},   [r1,:128], r3
1178     vld1.64         {d6-d7},   [r1,:128], r3
1179     vld1.64         {d16-d17}, [r1,:128], r3
1180     vld1.64         {d18-d19}, [r1,:128], r3
1181     sub             r1,  lr,  ip
1182
1183     vaddl.u8        q10, d0,  d18
1184     vmlsl.u8        q10, d2,  d30
1185     vmlal.u8        q10, d4,  d31
1186     vmlal.u8        q10, d6,  d31
1187     vmlsl.u8        q10, d16, d30
1188
1189     vaddl.u8        q11, d1,  d19
1190     vmlsl.u8        q11, d3,  d30
1191     vmlal.u8        q11, d5,  d31
1192     vmlal.u8        q11, d7,  d31
1193     vmlsl.u8        q11, d17, d30
1194
1195     vqrshrun.s16    d0,  q10, #5
1196     vst1.64         {d20-d21}, [r2,:128]!
1197     vqrshrun.s16    d1,  q11, #5
1198     vst1.64         {d22-d23}, [r2,:128]!
1199     vst1.64         {d0-d1},   [r0,:128]!
1200     bgt             filter_v_loop
1201     pop             {pc}
1202 .endfunc
1203
1204 // hpel_filter_c( uint8_t *dst, int16_t *buf, int width );
1205 function x264_hpel_filter_c_neon
1206     sub             r1,  #16
1207     vld1.64         {d0-d3}, [r1,:128]!
1208
1209     // unrolled 2x: 4% faster
1210 filter_c_loop:
1211     subs            r2,  r2,  #16
1212     vld1.64         {d4-d7}, [r1,:128]!
1213     vext.16         q8,  q0,  q1,  #6
1214     vext.16         q12, q1,  q2,  #3
1215     vadd.s16        q8,  q8,  q12
1216     vext.16         q9,  q0,  q1,  #7
1217     vext.16         q11, q1,  q2,  #2
1218     vadd.s16        q9,  q9,  q11
1219     vext.16         q10, q1,  q2,  #1
1220     vext.16         q11, q1,  q2,  #6
1221     vadd.s16        q10, q1,  q10
1222     vsub.s16        q8,  q8,  q9    // a-b
1223     vext.16         q15, q2,  q3,  #3
1224     vsub.s16        q9,  q9,  q10   // b-c
1225
1226     vext.16         q12, q1,  q2,  #7
1227     vshr.s16        q8,  q8,  #2    // (a-b)/4
1228     vadd.s16        q11, q11, q15
1229     vext.16         q14, q2,  q3,  #2
1230     vsub.s16        q8,  q8,  q9    // (a-b)/4-b+c
1231     vadd.s16        q12, q12, q14
1232     vext.16         q13, q2,  q3,  #1
1233
1234     vshr.s16        q8,  q8,  #2    // ((a-b)/4-b+c)/4
1235     vadd.s16        q13, q2,  q13
1236     vadd.s16        q8,  q8,  q10   // ((a-b)/4-b+c)/4+c = (a-5*b+20*c)/16
1237     vsub.s16        q11, q11, q12   // a-b
1238     vsub.s16        q12, q12, q13   // b-c
1239     vshr.s16        q11, q11, #2    // (a-b)/4
1240     vqrshrun.s16    d30, q8,  #6
1241     vsub.s16        q11, q11, q12   // (a-b)/4-b+c
1242     vshr.s16        q11, q11, #2    // ((a-b)/4-b+c)/4
1243     vld1.64         {d0-d3}, [r1,:128]!
1244     vadd.s16        q11, q11, q13   // ((a-b)/4-b+c)/4+c = (a-5*b+20*c)/16
1245
1246     vext.16         q8,  q2,  q3,  #6
1247     vqrshrun.s16    d31, q11,  #6
1248     vext.16         q12, q3,  q0,  #3
1249     vadd.s16        q8,  q8,  q12
1250     vext.16         q9,  q2,  q3,  #7
1251     vst1.64         {d30-d31}, [r0,:128]!
1252     bxle            lr
1253     subs            r2,  r2,  #16
1254
1255     vext.16         q11, q3,  q0,  #2
1256     vadd.s16        q9,  q9,  q11
1257     vext.16         q10, q3,  q0,  #1
1258     vext.16         q11, q3,  q0,  #6
1259     vadd.s16        q10, q3,  q10
1260     vsub.s16        q8,  q8,  q9    // a-b
1261     vext.16         q15, q0,  q1,  #3
1262     vsub.s16        q9,  q9,  q10   // b-c
1263
1264     vext.16         q12, q3,  q0,  #7
1265     vshr.s16        q8,  q8,  #2    // (a-b)/4
1266     vadd.s16        q11, q11, q15
1267     vext.16         q14, q0,  q1,  #2
1268     vsub.s16        q8,  q8,  q9    // (a-b)/4-b+c
1269     vadd.s16        q12, q12, q14
1270     vext.16         q13, q0,  q1,  #1
1271
1272     vshr.s16        q8,  q8,  #2    // ((a-b)/4-b+c)/4
1273     vadd.s16        q13, q0,  q13
1274     vadd.s16        q8,  q8,  q10   // ((a-b)/4-b+c)/4+c = (a-5*b+20*c)/16
1275     vsub.s16        q11, q11, q12   // a-b
1276     vsub.s16        q12, q12, q13   // b-c
1277     vshr.s16        q11, q11, #2    // (a-b)/4
1278     vqrshrun.s16    d30, q8,  #6
1279     vsub.s16        q11, q11, q12   // (a-b)/4-b+c
1280     vshr.s16        q11, q11, #2    // ((a-b)/4-b+c)/4
1281     vadd.s16        q11, q11, q13   // ((a-b)/4-b+c)/4+c = (a-5*b+20*c)/16
1282
1283     vqrshrun.s16    d31, q11,  #6
1284     vst1.64         {d30-d31}, [r0,:128]!
1285     bgt             filter_c_loop
1286     bx              lr
1287 .endfunc
1288
1289 // hpel_filter_h( uint8_t *dst, uint8_t *src, int width );
1290 function x264_hpel_filter_h_neon
1291     sub             r1,  #16
1292     vmov.u8         d30, #5
1293     vld1.64         {d0-d3}, [r1,:128]!
1294     vmov.u8         d31, #20
1295
1296     // unrolled 3x because it's 5% faster, due to mitigating
1297     // the high latency of multiplication and vqrshrun
1298 filter_h_loop:
1299     subs            r2,  r2,  #16
1300     vld1.64         {d4-d5}, [r1,:128]!
1301     vext.8          q8,  q0,  q1,  #14
1302     vext.8          q12, q1,  q2,  #3
1303     vaddl.u8        q13, d16, d24
1304     vext.8          q9,  q0,  q1,  #15
1305     vaddl.u8        q14, d17, d25
1306
1307     vext.8          q10, q1,  q2,  #1
1308     vmlal.u8        q13, d2,  d31
1309     vmlsl.u8        q13, d18, d30
1310     vext.8          q11, q1,  q2,  #2
1311     vmlal.u8        q13, d20, d31
1312     vmlsl.u8        q13, d22, d30
1313
1314     vmlsl.u8        q14, d19, d30
1315     vmlal.u8        q14, d3,  d31
1316     vmlal.u8        q14, d21, d31
1317     vmlsl.u8        q14, d23, d30
1318     vqrshrun.s16    d6,  q13, #5
1319
1320     vld1.64         {d0-d1}, [r1,:128]!
1321     vext.8          q8,  q1,  q2,  #14
1322     vext.8          q12, q2,  q0,  #3
1323     vaddl.u8        q13, d16, d24
1324     vqrshrun.s16    d7,  q14, #5
1325     vext.8          q9,  q1,  q2,  #15
1326     vaddl.u8        q14, d17, d25
1327
1328     vst1.64         {d6-d7}, [r0,:128]!
1329     bxle            lr
1330     subs            r2,  r2,  #16
1331
1332     vext.8          q10, q2,  q0,  #1
1333     vmlal.u8        q13, d4,  d31
1334     vmlsl.u8        q13, d18, d30
1335     vext.8          q11, q2,  q0,  #2
1336     vmlal.u8        q13, d20, d31
1337     vmlsl.u8        q13, d22, d30
1338
1339     vmlsl.u8        q14, d19, d30
1340     vmlal.u8        q14, d5,  d31
1341     vmlal.u8        q14, d21, d31
1342     vmlsl.u8        q14, d23, d30
1343     vqrshrun.s16    d6,  q13, #5
1344
1345     vld1.64         {d2-d3}, [r1,:128]!
1346     vext.8          q8,  q2,  q0,  #14
1347     vext.8          q12, q0,  q1,  #3
1348     vaddl.u8        q13, d16, d24
1349     vqrshrun.s16    d7,  q14, #5
1350     vext.8          q9,  q2,  q0,  #15
1351     vaddl.u8        q14, d17, d25
1352
1353     vst1.64         {d6-d7}, [r0,:128]!
1354     bxle            lr
1355     subs            r2,  r2,  #16
1356
1357     vext.8          q10, q0,  q1,  #1
1358     vmlal.u8        q13, d0,  d31
1359     vmlsl.u8        q13, d18, d30
1360     vext.8          q11, q0,  q1,  #2
1361     vmlal.u8        q13, d20, d31
1362     vmlsl.u8        q13, d22, d30
1363
1364     vmlsl.u8        q14, d19, d30
1365     vmlal.u8        q14, d1,  d31
1366     vmlal.u8        q14, d21, d31
1367     vmlsl.u8        q14, d23, d30
1368
1369     vqrshrun.s16    d6, q13, #5
1370     vqrshrun.s16    d7, q14, #5
1371     vst1.64         {d6-d7}, [r0,:128]!
1372     bgt             filter_h_loop
1373     bx              lr
1374 .endfunc
1375
1376
1377 // frame_init_lowres_core( uint8_t *src0, uint8_t *dst0, uint8_t *dsth, uint8_t *dstv,
1378 //                         uint8_t *dstc, intptr_t src_stride, intptr_t dst_stride, int width,
1379 //                         int height )
1380 function x264_frame_init_lowres_core_neon
1381     push            {r4-r10,lr}
1382     vpush           {d8-d15}
1383     ldrd            r4,  r5,  [sp, #96]
1384     ldrd            r6,  r7,  [sp, #104]
1385     ldr             lr,  [sp, #112]
1386     sub             r10, r6,  r7            // dst_stride - width
1387     and             r10, r10, #~15
1388
1389 lowres_yloop:
1390     mov             ip,  r7                 // width
1391     mov             r6,  r0                 // src0
1392     add             r8,  r0,  r5            // src1 = src0 + src_stride
1393     add             r9,  r0,  r5,  lsl #1   // src2 = src1 + src_stride
1394
1395     vld2.8          {d8, d10}, [r6,:128]!
1396     vld2.8          {d12,d14}, [r8,:128]!
1397     vld2.8          {d16,d18}, [r9,:128]!
1398
1399 lowres_xloop:
1400     subs            ip,  ip,  #16
1401
1402     vld2.8          {d9, d11}, [r6,:128]!
1403     vld2.8          {d13,d15}, [r8,:128]!
1404     vrhadd.u8       q0,  q4,  q6
1405     vld2.8          {d17,d19}, [r9,:128]!
1406     vrhadd.u8       q5,  q5,  q7
1407     vld2.8          {d20,d22}, [r6,:128]!
1408     vrhadd.u8       q1,  q6,  q8
1409     vld2.8          {d24,d26}, [r8,:128]!
1410     vrhadd.u8       q7,  q7,  q9
1411     vext.8          q4,  q4,  q10, #1
1412     vrhadd.u8       q0,  q0,  q5
1413     vext.8          q6,  q6,  q12, #1
1414     vrhadd.u8       q1,  q1,  q7
1415     vld2.8          {d28,d30}, [r9,:128]!
1416     vrhadd.u8       q4,  q4,  q6
1417     vext.8          q8,  q8,  q14, #1
1418     vrhadd.u8       q6,  q6,  q8
1419     vst1.64         {d0-d1},   [r1,:128]!
1420     vrhadd.u8       q2,  q4,  q5
1421     vst1.64         {d2-d3},   [r3,:128]!
1422     vrhadd.u8       q3,  q6,  q7
1423     vst1.64         {d4-d5},   [r2,:128]!
1424     vst1.64         {d6-d7},   [r4,:128]!
1425
1426     ble             lowres_xloop_end
1427     subs            ip,  ip,  #16
1428
1429     vld2.8          {d21,d23}, [r6,:128]!
1430     vld2.8          {d25,d27}, [r8,:128]!
1431     vrhadd.u8       q0,  q10, q12
1432     vld2.8          {d29,d31}, [r9,:128]!
1433     vrhadd.u8       q11, q11, q13
1434     vld2.8          {d8, d10}, [r6,:128]!
1435     vrhadd.u8       q1,  q12, q14
1436     vld2.8          {d12,d14}, [r8,:128]!
1437     vrhadd.u8       q13, q13, q15
1438     vext.8          q10, q10, q4,  #1
1439     vrhadd.u8       q0,  q0,  q11
1440     vext.8          q12, q12, q6,  #1
1441     vrhadd.u8       q1,  q1,  q13
1442     vld2.8          {d16,d18}, [r9,:128]!
1443     vrhadd.u8       q10, q10, q12
1444     vext.8          q14, q14, q8,  #1
1445     vrhadd.u8       q12, q12, q14
1446     vst1.64         {d0-d1},   [r1,:128]!
1447     vrhadd.u8       q2,  q10, q11
1448     vst1.64         {d2-d3},   [r3,:128]!
1449     vrhadd.u8       q3,  q12, q13
1450     vst1.64         {d4-d5},   [r2,:128]!
1451     vst1.64         {d6-d7},   [r4,:128]!
1452
1453     bgt             lowres_xloop
1454
1455 lowres_xloop_end:
1456     subs            lr,  lr,  #1
1457     add             r0,  r0,  r5,  lsl #1
1458     add             r1,  r1,  r10
1459     add             r2,  r2,  r10
1460     add             r3,  r3,  r10
1461     add             r4,  r4,  r10
1462     bgt             lowres_yloop
1463
1464     vpop            {d8-d15}
1465     pop             {r4-r10,pc}
1466 .endfunc
1467
1468 function x264_load_deinterleave_chroma_fdec_neon
1469     mov             ip,  #FDEC_STRIDE/2
1470 1:
1471     vld2.8          {d0-d1}, [r1,:128], r2
1472     subs            r3,  r3,  #1
1473     pld             [r1]
1474     vst1.8          {d0},    [r0,:64], ip
1475     vst1.8          {d1},    [r0,:64], ip
1476     bgt             1b
1477
1478     bx              lr
1479 .endfunc
1480
1481 function x264_load_deinterleave_chroma_fenc_neon
1482     mov             ip,  #FENC_STRIDE/2
1483 1:
1484     vld2.8          {d0-d1}, [r1,:128], r2
1485     subs            r3,  r3,  #1
1486     pld             [r1]
1487     vst1.8          {d0},    [r0,:64], ip
1488     vst1.8          {d1},    [r0,:64], ip
1489     bgt             1b
1490
1491     bx              lr
1492 .endfunc
1493
1494 function x264_plane_copy_deinterleave_neon
1495     push            {r4-r7, lr}
1496     ldrd            r6, r7, [sp, #28]
1497     ldrd            r4, r5, [sp, #20]
1498     add             lr,  r6,  #15
1499     bic             lr,  lr,  #15
1500     sub             r1,  r1,  lr
1501     sub             r3,  r3,  lr
1502     sub             r5,  r5,  lr, lsl #1
1503 block:
1504     vld2.8          {d0-d3}, [r4,:128]!
1505     subs            lr,  lr,  #16
1506     vst1.8          {q0},    [r0]!
1507     vst1.8          {q1},    [r2]!
1508     bgt             block
1509
1510     add             r4,  r4,  r5
1511     subs            r7,  r7,  #1
1512     add             r0,  r0,  r1
1513     add             r2,  r2,  r3
1514     mov             lr,  r6
1515     bgt             block
1516
1517     pop             {r4-r7, pc}
1518 .endfunc
1519
1520 function x264_plane_copy_deinterleave_rgb_neon
1521     push            {r4-r8, r10, r11, lr}
1522     ldrd            r4,  r5,  [sp, #32]
1523     ldrd            r6,  r7,  [sp, #40]
1524     ldr             r8,  [sp, #48]
1525     ldrd            r10, r11, [sp, #52]
1526     add             lr,  r10, #7
1527     subs            r8,  r8,  #3
1528     bic             lr,  lr,  #7
1529     sub             r7,  r7,  lr, lsl #1
1530     sub             r1,  r1,  lr
1531     sub             r3,  r3,  lr
1532     sub             r5,  r5,  lr
1533     subne           r7,  r7,  lr, lsl #1
1534     subeq           r7,  r7,  lr
1535     bne             block4
1536 block3:
1537     vld3.8          {d0,d1,d2}, [r6]!
1538     subs            lr,  lr,  #8
1539     vst1.8          {d0},    [r0]!
1540     vst1.8          {d1},    [r2]!
1541     vst1.8          {d2},    [r4]!
1542     bgt             block3
1543
1544     subs            r11, r11, #1
1545     add             r0,  r0,  r1
1546     add             r2,  r2,  r3
1547     add             r4,  r4,  r5
1548     add             r6,  r6,  r7
1549     mov             lr,  r10
1550     bgt             block3
1551
1552     pop             {r4-r8, r10, r11, pc}
1553 block4:
1554     vld4.8          {d0,d1,d2,d3}, [r6]!
1555     subs            lr,  lr,  #8
1556     vst1.8          {d0},    [r0]!
1557     vst1.8          {d1},    [r2]!
1558     vst1.8          {d2},    [r4]!
1559     bgt             block4
1560
1561     subs            r11, r11, #1
1562     add             r0,  r0,  r1
1563     add             r2,  r2,  r3
1564     add             r4,  r4,  r5
1565     add             r6,  r6,  r7
1566     mov             lr,  r10
1567     bgt             block4
1568
1569     pop             {r4-r8, r10, r11, pc}
1570 .endfunc
1571
1572 function x264_plane_copy_interleave_neon
1573     push            {r4-r7, lr}
1574     ldrd            r6, r7, [sp, #28]
1575     ldrd            r4, r5, [sp, #20]
1576     add             lr,  r6,  #15
1577     bic             lr,  lr,  #15
1578     sub             r1,  r1,  lr, lsl #1
1579     sub             r3,  r3,  lr
1580     sub             r5,  r5,  lr
1581 blocki:
1582     vld1.8          {q0}, [r2]!
1583     vld1.8          {q1}, [r4]!
1584     subs            lr,  lr,  #16
1585     vst2.8          {d0,d2}, [r0]!
1586     vst2.8          {d1,d3}, [r0]!
1587     bgt             blocki
1588
1589     subs            r7,  r7,  #1
1590     add             r0,  r0,  r1
1591     add             r2,  r2,  r3
1592     add             r4,  r4,  r5
1593     mov             lr,  r6
1594     bgt             blocki
1595
1596     pop             {r4-r7, pc}
1597 .endfunc
1598
1599 function x264_store_interleave_chroma_neon
1600     push            {lr}
1601     ldr             lr,  [sp, #4]
1602     mov             ip,  #FDEC_STRIDE
1603 1:
1604     vld1.8          {d0}, [r2], ip
1605     vld1.8          {d1}, [r3], ip
1606     subs            lr,  lr,  #1
1607     vst2.8          {d0,d1}, [r0,:128], r1
1608     bgt             1b
1609
1610     pop             {pc}
1611 .endfunc