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