]> git.sesse.net Git - x264/blob - common/arm/mc-a.S
Various ARM-related fixes
[x264] / common / arm / mc-a.S
1 /*****************************************************************************
2  * mc.S: h264 encoder
3  *****************************************************************************
4  * Copyright (C) 2009 x264 project
5  *
6  * Authors: David Conrad <lessen42@gmail.com>
7  *          Mans Rullgard <mans@mansr.com>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 #include "asm.S"
25
26 .fpu neon
27 .text
28
29 // note: prefetch stuff assumes 64-byte cacheline, true for the Cortex-A8
30 // They also use nothing above armv5te, but we don't care about pre-armv6
31
32 // void prefetch_ref( uint8_t *pix, int stride, int parity )
33 function x264_prefetch_ref_arm
34     sub         r2, r2, #1
35     add         r0, r0, #64
36     and         r2, r2, r1
37     add         r0, r0, r2, lsl #3
38     add         r2, r1, r1, lsl #1
39     pld         [r0]
40     pld         [r0, r1]
41     pld         [r0, r1, lsl #1]
42     add         r3, r0, r1, lsl #2
43     pld         [r0, r2]
44     pld         [r3]
45     pld         [r3, r1]
46     pld         [r3, r1, lsl #1]
47     pld         [r3, r2]
48     bx          lr
49 .endfunc
50
51 // void prefetch_fenc( uint8_t *pix_y, int stride_y,
52 //                     uint8_t *pix_uv, int stride_uv, int mb_x )
53 function x264_prefetch_fenc_arm
54     ldr         ip, [sp]
55     push        {lr}
56     and         lr, ip, #3
57     smulbb      lr, lr, r1      // note: this assumes stride_y is <= 16 bits signed
58     and         ip, ip, #6
59     smulbb      ip, ip, r3
60     add         r0, r0, #64
61     add         r2, r2, #64
62     add         r0, r0, lr, lsl #2
63     pld         [r0]
64     add         lr, r0, r1, lsl #1
65     pld         [r0, r1]
66     pld         [lr]
67     add         r2, r2, ip, lsl #2
68     pld         [lr, r1]
69     pld         [r2]
70     add         ip, r2, r3, lsl #1
71     pld         [r2, r3]
72     pld         [ip]
73     pld         [ip, r3]
74     pop         {pc}
75 .endfunc
76
77
78 // void *x264_memcpy_aligned( void * dst, const void * src, size_t n )
79 function x264_memcpy_aligned_neon
80     orr         r3,  r0,  r1,  lsr #1
81     movrel      ip,  memcpy_table
82     and         r3,  r3,  #0xc
83     ldr         pc,  [ip, r3]
84 .endfunc
85
86 .macro MEMCPY_ALIGNED srcalign dstalign
87 function memcpy_aligned_\dstalign\()_\srcalign\()_neon
88     mov         r3, r0
89 .if \srcalign == 8 && \dstalign == 8
90     sub         r2, #16
91     vld1.64     {d0}, [r1,:64]!
92     vst1.64     {d0}, [r3,:64]!
93     .set r1align, 128
94     .set r3align, 128
95 .else
96     .set r1align, \srcalign * 8
97     .set r3align, \dstalign * 8
98 .endif
99     tst         r2, #16
100     beq         32f
101     sub         r2, #16
102     vld1.64     {d0-d1}, [r1,:r1align]!
103     vst1.64     {d0-d1}, [r3,:r3align]!
104 32: // n is a multiple of 32
105     tst         r2, #32
106     beq         64f
107     sub         r2, #32
108     vld1.64     {d0-d3}, [r1,:r1align]!
109     vst1.64     {d0-d3}, [r3,:r3align]!
110 64: // n is a multiple of 64
111     subs        r2, #64
112     vld1.64     {d0-d3}, [r1,:r1align]!
113     vld1.64     {d4-d7}, [r1,:r1align]!
114     vst1.64     {d0-d3}, [r3,:r3align]!
115     vst1.64     {d4-d7}, [r3,:r3align]!
116     bgt         64b
117 .if \srcalign == 8 && \dstalign == 8
118     vld1.64     {d0}, [r1,:64]!
119     vst1.64     {d0}, [r3,:64]!
120 .endif
121     bx          lr
122 .endfunc
123 .endm
124
125 MEMCPY_ALIGNED 16, 16
126 MEMCPY_ALIGNED 16, 8
127 MEMCPY_ALIGNED  8, 16
128 MEMCPY_ALIGNED  8, 8
129
130 .section .rodata
131 memcpy_table:
132 .word memcpy_aligned_16_16_neon
133 .word memcpy_aligned_16_8_neon
134 .word memcpy_aligned_8_16_neon
135 .word memcpy_aligned_8_8_neon
136 .text
137
138 .ltorg
139
140 // void x264_memzero_aligned( void *dst, size_t n )
141 function x264_memzero_aligned_neon
142     vmov.i8     q0, #0
143     vmov.i8     q1, #0
144 memzero_loop:
145     subs        r1, #128
146 .rept 4
147     vst1.64     {d0-d3}, [r0,:128]!
148 .endr
149     bgt         memzero_loop
150     bx          lr
151 .endfunc
152
153
154 // void pixel_avg( uint8_t *dst, int dst_stride,
155 //                 uint8_t *src1, int src1_stride,
156 //                 uint8_t *src2, int src2_stride, int weight );
157 .macro AVGH w h
158 function x264_pixel_avg_\w\()x\h\()_neon
159     ldr         ip, [sp, #8]
160     push        {r4-r6,lr}
161     cmp         ip, #32
162     ldrd        r4, [sp, #16]
163     mov         lr, #\h
164     beq         x264_pixel_avg_w\w\()_neon
165     rsbs        r6,  ip,  #64
166     blt         x264_pixel_avg_weight_w\w\()_add_sub_neon     // weight > 64
167     cmp         ip,  #0
168     bge         x264_pixel_avg_weight_w\w\()_add_add_neon
169     b           x264_pixel_avg_weight_w\w\()_sub_add_neon     // weight < 0
170 .endfunc
171 .endm
172
173 AVGH  4, 2
174 AVGH  4, 4
175 AVGH  4, 8
176 AVGH  8, 4
177 AVGH  8, 8
178 AVGH  8, 16
179 AVGH 16, 8
180 AVGH 16, 16
181
182 // 0 < weight < 64
183 .macro load_weights_add_add
184     vdup.8      d30, ip
185     vdup.8      d31, r6
186 .endm
187
188 .macro load_add_add d1 d2
189     vld1.32     {\d1}, [r2], r3
190     vld1.32     {\d2}, [r4], r5
191 .endm
192
193 .macro weight_add_add dst s1 s2
194     vmull.u8    \dst, \s1, d30
195     vmlal.u8    \dst, \s2, d31
196 .endm
197
198 // weight > 64
199 .macro load_weights_add_sub
200     rsb         r6,  #0
201     vdup.8      d30, ip
202     vdup.8      d31, r6
203 .endm
204
205 .macro load_add_sub d1 d2
206     vld1.32     {\d1}, [r2], r3
207     vld1.32     {\d2}, [r4], r5
208 .endm
209
210 .macro weight_add_sub dst s1 s2
211     vmull.u8    \dst, \s1, d30
212     vmlsl.u8    \dst, \s2, d31
213 .endm
214
215 // weight < 0
216 .macro load_weights_sub_add
217     rsb         ip,  #0
218     vdup.8      d31, r6
219     vdup.8      d30, ip
220 .endm
221
222 .macro load_sub_add d1 d2
223     vld1.32     {\d2}, [r4], r5
224     vld1.32     {\d1}, [r2], r3
225 .endm
226
227 .macro weight_sub_add dst s1 s2
228     vmull.u8    \dst, \s2, d31
229     vmlsl.u8    \dst, \s1, d30
230 .endm
231
232 .macro AVG_WEIGHT ext
233 function x264_pixel_avg_weight_w4_\ext\()_neon
234     load_weights_\ext
235 1:  // height loop
236     subs            lr,  lr,  #2
237     load_\ext       d0[], d1[]
238     weight_\ext     q8,  d0,  d1
239     load_\ext       d2[], d3[]
240     vqrshrun.s16    d0,  q8,  #6
241     weight_\ext     q9,  d2,  d3
242     vst1.32         {d0[0]}, [r0,:32], r1
243     vqrshrun.s16    d1,  q9,  #6
244     vst1.32         {d1[0]}, [r0,:32], r1
245     bgt             1b
246     pop             {r4-r6,pc}
247 .endfunc
248
249 function x264_pixel_avg_weight_w8_\ext\()_neon
250     load_weights_\ext
251 1:  // height loop
252     subs            lr,  lr,  #4
253     load_\ext       d0,  d1
254     weight_\ext     q8,  d0,  d1
255     load_\ext       d2,  d3
256     weight_\ext     q9,  d2,  d3
257     load_\ext       d4,  d5
258     weight_\ext     q10, d4,  d5
259     load_\ext       d6,  d7
260     weight_\ext     q11, d6,  d7
261     vqrshrun.s16    d0,  q8,  #6
262     vqrshrun.s16    d1,  q9,  #6
263     vqrshrun.s16    d2,  q10, #6
264     vqrshrun.s16    d3,  q11, #6
265     vst1.64         {d0}, [r0,:64], r1
266     vst1.64         {d1}, [r0,:64], r1
267     vst1.64         {d2}, [r0,:64], r1
268     vst1.64         {d3}, [r0,:64], r1
269     bgt             1b
270     pop             {r4-r6,pc}
271 .endfunc
272
273 function x264_pixel_avg_weight_w16_\ext\()_neon
274     load_weights_\ext
275 1:  // height loop
276     subs            lr,  lr,  #2
277     load_\ext       d0-d1, d2-d3
278     weight_\ext     q8,  d0,  d2
279     weight_\ext     q9,  d1,  d3
280     load_\ext       d4-d5, d6-d7
281     weight_\ext     q10, d4,  d6
282     weight_\ext     q11, d5,  d7
283     vqrshrun.s16    d0,  q8,  #6
284     vqrshrun.s16    d1,  q9,  #6
285     vqrshrun.s16    d2,  q10, #6
286     vqrshrun.s16    d3,  q11, #6
287     vst1.64         {d0-d1}, [r0,:128], r1
288     vst1.64         {d2-d3}, [r0,:128], r1
289     bgt             1b
290     pop             {r4-r6,pc}
291 .endfunc
292 .endm
293
294 AVG_WEIGHT add_add
295 AVG_WEIGHT add_sub
296 AVG_WEIGHT sub_add
297
298 function x264_pixel_avg_w4_neon
299     subs        lr,  lr,  #2
300     vld1.32     {d0[]}, [r2], r3
301     vld1.32     {d2[]}, [r4], r5
302     vrhadd.u8   d0,  d0,  d2
303     vld1.32     {d1[]}, [r2], r3
304     vld1.32     {d3[]}, [r4], r5
305     vrhadd.u8   d1,  d1,  d3
306     vst1.32     {d0[0]}, [r0,:32], r1
307     vst1.32     {d1[0]}, [r0,:32], r1
308     bgt         x264_pixel_avg_w4_neon
309     pop         {r4-r6,pc}
310 .endfunc
311
312 function x264_pixel_avg_w8_neon
313     subs        lr,  lr,  #4
314     vld1.64     {d0}, [r2], r3
315     vld1.64     {d2}, [r4], r5
316     vrhadd.u8   d0,  d0,  d2
317     vld1.64     {d1}, [r2], r3
318     vld1.64     {d3}, [r4], r5
319     vrhadd.u8   d1,  d1,  d3
320     vst1.64     {d0}, [r0,:64], r1
321     vld1.64     {d2}, [r2], r3
322     vld1.64     {d4}, [r4], r5
323     vrhadd.u8   d2,  d2,  d4
324     vst1.64     {d1}, [r0,:64], r1
325     vld1.64     {d3}, [r2], r3
326     vld1.64     {d5}, [r4], r5
327     vrhadd.u8   d3,  d3,  d5
328     vst1.64     {d2}, [r0,:64], r1
329     vst1.64     {d3}, [r0,:64], r1
330     bgt         x264_pixel_avg_w8_neon
331     pop         {r4-r6,pc}
332 .endfunc
333
334 function x264_pixel_avg_w16_neon
335     subs        lr,  lr,  #4
336     vld1.64     {d0-d1}, [r2], r3
337     vld1.64     {d2-d3}, [r4], r5
338     vrhadd.u8   q0,  q0,  q1
339     vld1.64     {d2-d3}, [r2], r3
340     vld1.64     {d4-d5}, [r4], r5
341     vrhadd.u8   q1,  q1,  q2
342     vst1.64     {d0-d1}, [r0,:128], r1
343     vld1.64     {d4-d5}, [r2], r3
344     vld1.64     {d6-d7}, [r4], r5
345     vrhadd.u8   q2,  q2,  q3
346     vst1.64     {d2-d3}, [r0,:128], r1
347     vld1.64     {d6-d7}, [r2], r3
348     vld1.64     {d0-d1}, [r4], r5
349     vrhadd.u8   q3,  q3,  q0
350     vst1.64     {d4-d5}, [r0,:128], r1
351     vst1.64     {d6-d7}, [r0,:128], r1
352     bgt         x264_pixel_avg_w16_neon
353     pop         {r4-r6,pc}
354 .endfunc
355
356
357 function x264_pixel_avg2_w4_neon
358     ldr         ip,  [sp, #4]
359     push        {lr}
360     ldr         lr,  [sp, #4]
361 avg2_w4_loop:
362     subs        ip,  ip,  #2
363     vld1.32     {d0[]},  [r2], r3
364     vld1.32     {d2[]},  [lr], r3
365     vrhadd.u8   d0,  d0,  d2
366     vld1.32     {d1[]},  [r2], r3
367     vld1.32     {d3[]},  [lr], r3
368     vrhadd.u8   d1,  d1,  d3
369     vst1.32     {d0[0]}, [r0,:32], r1
370     vst1.32     {d1[0]}, [r0,:32], r1
371     bgt         avg2_w4_loop
372     pop         {pc}
373 .endfunc
374
375 function x264_pixel_avg2_w8_neon
376     ldr         ip,  [sp, #4]
377     push        {lr}
378     ldr         lr,  [sp, #4]
379 avg2_w8_loop:
380     subs        ip,  ip,  #2
381     vld1.64     {d0}, [r2], r3
382     vld1.64     {d2}, [lr], r3
383     vrhadd.u8   d0,  d0,  d2
384     vld1.64     {d1}, [r2], r3
385     vld1.64     {d3}, [lr], r3
386     vrhadd.u8   d1,  d1,  d3
387     vst1.64     {d0}, [r0,:64], r1
388     vst1.64     {d1}, [r0,:64], r1
389     bgt         avg2_w8_loop
390     pop         {pc}
391 .endfunc
392
393 function x264_pixel_avg2_w16_neon
394     ldr         ip,  [sp, #4]
395     push        {lr}
396     ldr         lr,  [sp, #4]
397 avg2_w16_loop:
398     subs        ip,  ip,  #2
399     vld1.64     {d0-d1}, [r2], r3
400     vld1.64     {d2-d3}, [lr], r3
401     vrhadd.u8   q0,  q0,  q1
402     vld1.64     {d4-d5}, [r2], r3
403     vld1.64     {d6-d7}, [lr], r3
404     vrhadd.u8   q2,  q2,  q3
405     vst1.64     {d0-d1}, [r0,:128], r1
406     vst1.64     {d4-d5}, [r0,:128], r1
407     bgt         avg2_w16_loop
408     pop         {pc}
409 .endfunc
410
411 function x264_pixel_avg2_w20_neon
412     ldr         ip,  [sp, #4]
413     push        {lr}
414     sub         r1,  r1,  #16
415     ldr         lr,  [sp, #4]
416 avg2_w20_loop:
417     subs        ip,  ip,  #2
418     vld1.64     {d0-d2},  [r2], r3
419     vld1.64     {d4-d6},  [lr], r3
420     vrhadd.u8   q0,  q0,  q2
421     vrhadd.u8   d2,  d2,  d6
422     vld1.64     {d4-d6},  [r2], r3
423     vld1.64     {d16-d18},[lr], r3
424     vrhadd.u8   q2,  q2,  q8
425     vst1.64     {d0-d1},  [r0,:128]!
426     vrhadd.u8   d6,  d6,  d18
427     vst1.32     {d2[0]},  [r0,:32], r1
428     vst1.64     {d4-d5},  [r0,:128]!
429     vst1.32     {d6[0]},  [r0,:32], r1
430     bgt         avg2_w20_loop
431     pop         {pc}
432 .endfunc
433
434
435 // void mc_copy( uint8_t *dst, int dst_stride, uint8_t *src, int src_stride, int height )
436 function x264_mc_copy_w4_neon
437     ldr         ip,  [sp]
438 copy_w4_loop:
439     subs        ip,  ip,  #4
440     vld1.32     {d0[]},  [r2], r3
441     vld1.32     {d1[]},  [r2], r3
442     vld1.32     {d2[]},  [r2], r3
443     vld1.32     {d3[]},  [r2], r3
444     vst1.32     {d0[0]}, [r0,:32], r1
445     vst1.32     {d1[0]}, [r0,:32], r1
446     vst1.32     {d2[0]}, [r0,:32], r1
447     vst1.32     {d3[0]}, [r0,:32], r1
448     bgt         copy_w4_loop
449     bx          lr
450 .endfunc
451
452 function x264_mc_copy_w8_neon
453     ldr         ip,  [sp]
454 copy_w8_loop:
455     subs        ip,  ip,  #4
456     vld1.32     {d0}, [r2], r3
457     vld1.32     {d1}, [r2], r3
458     vld1.32     {d2}, [r2], r3
459     vld1.32     {d3}, [r2], r3
460     vst1.32     {d0}, [r0,:64], r1
461     vst1.32     {d1}, [r0,:64], r1
462     vst1.32     {d2}, [r0,:64], r1
463     vst1.32     {d3}, [r0,:64], r1
464     bgt         copy_w8_loop
465     bx          lr
466 .endfunc
467
468 function x264_mc_copy_w16_neon
469     ldr         ip,  [sp]
470 copy_w16_loop:
471     subs        ip,  ip,  #4
472     vld1.32     {d0-d1}, [r2], r3
473     vld1.32     {d2-d3}, [r2], r3
474     vld1.32     {d4-d5}, [r2], r3
475     vld1.32     {d6-d7}, [r2], r3
476     vst1.32     {d0-d1}, [r0,:128], r1
477     vst1.32     {d2-d3}, [r0,:128], r1
478     vst1.32     {d4-d5}, [r0,:128], r1
479     vst1.32     {d6-d7}, [r0,:128], r1
480     bgt         copy_w16_loop
481     bx          lr
482 .endfunc
483
484 function x264_mc_copy_w16_aligned_neon
485     ldr         ip,  [sp]
486 copy_w16_aligned_loop:
487     subs        ip,  ip,  #4
488     vld1.32     {d0-d1}, [r2,:128], r3
489     vld1.32     {d2-d3}, [r2,:128], r3
490     vld1.32     {d4-d5}, [r2,:128], r3
491     vld1.32     {d6-d7}, [r2,:128], r3
492     vst1.32     {d0-d1}, [r0,:128], r1
493     vst1.32     {d2-d3}, [r0,:128], r1
494     vst1.32     {d4-d5}, [r0,:128], r1
495     vst1.32     {d6-d7}, [r0,:128], r1
496     bgt         copy_w16_aligned_loop
497     bx          lr
498 .endfunc
499
500
501 // void x264_mc_chroma_neon( uint8_t *dst, int i_dst_stride,
502 //                           uint8_t *src, int i_src_stride,
503 //                           int dx, int dy, int i_width, int i_height );
504 function x264_mc_chroma_neon
505     push            {r4-r6, lr}
506     ldrd            r4,  [sp, #16]
507     ldr             r6,  [sp, #24]
508
509     asr             lr,  r5,  #3
510     mul             lr,  r3,  lr
511     add             r2,  r2,  r4,  asr #3
512     cmp             r6, #4
513     add             r2,  r2,  lr
514
515     and             r4, r4, #7
516     and             r5, r5, #7
517     pld             [r2]
518     pld             [r2, r3]
519
520     bgt             mc_chroma_w8
521     beq             mc_chroma_w4
522
523 // calculate cA cB cC cD
524 .macro CHROMA_MC_START r0 r1
525     muls            lr,  r4,  r5
526     rsb             r6,  lr,  r5,  lsl #3
527     rsb             ip,  lr,  r4,  lsl #3
528     sub             r4,  lr,  r4,  lsl #3
529     sub             r4,  r4,  r5,  lsl #3
530     add             r4,  r4,  #64
531
532     beq             2f
533
534     add             r5,  r2,  r3
535
536     vdup.8          d0,  r4
537     lsl             r3,  r3,  #1
538     vdup.8          d1,  ip
539     vld1.64         {\r0}, [r2], r3
540     vdup.8          d2,  r6
541     vld1.64         {\r1}, [r5], r3
542     vdup.8          d3,  lr
543     ldr             r4,  [sp, #28]
544
545     vext.8          d5,  d4,  d5,  #1
546     vext.8          d7,  d6,  d7,  #1
547 .endm
548
549 .macro CHROMA_MC width, align
550 mc_chroma_w\width:
551     CHROMA_MC_START d4,  d6
552 // since the element size varies, there's a different index for the 2nd store
553 .if \width == 4
554     .set st2, 1
555 .else
556     .set st2, 2
557 .endif
558
559     vtrn.32         d4,  d5
560     vtrn.32         d6,  d7
561
562     vtrn.32         d0,  d1
563     vtrn.32         d2,  d3
564
565 1:  // height loop, interpolate xy
566     pld             [r5]
567     vmull.u8        q8,  d4,  d0
568     vmlal.u8        q8,  d6,  d2
569     vld1.64         {d4},     [r2], r3
570     vext.8          d5,  d4,  d5,  #1
571     vtrn.32         d4,  d5
572     vmull.u8        q9,  d6,  d0
573     vmlal.u8        q9,  d4,  d2
574     vld1.64         {d6},     [r5], r3
575     vadd.i16        d16, d16, d17
576     vadd.i16        d17, d18, d19
577     vrshrn.u16      d16, q8,  #6
578     subs            r4,  r4,  #2
579     pld             [r2]
580     vext.8          d7,  d6,  d7,  #1
581     vtrn.32         d6,  d7
582     vst1.\align     {d16[0]},   [r0,:\align], r1
583     vst1.\align     {d16[st2]}, [r0,:\align], r1
584     bgt             1b
585
586     pop             {r4-r6, pc}
587
588 2:  // dx or dy are 0
589     tst             r6,  r6
590     add             ip,  ip,  r6
591     vdup.8          d0,  r4
592     vdup.8          d1,  ip
593     vtrn.32         d0,  d1
594     ldr             r4,  [sp, #28]
595
596     beq             4f
597
598     vext.32         d1,  d0,  d1,  #1
599     add             r5,  r2,  r3
600     lsl             r3,  r3,  #1
601     vld1.32         {d4[0]},  [r2], r3
602     vld1.32         {d4[1]},  [r5], r3
603
604 3:  // vertical interpolation loop
605     pld             [r5]
606     vmull.u8        q8,  d4,  d0
607     vld1.32         {d4[0]},  [r2], r3
608     vmull.u8        q9,  d4,  d1
609     vld1.32         {d4[1]},  [r5], r3
610     vadd.i16        d16, d16, d17
611     vadd.i16        d17, d18, d19
612     vrshrn.u16      d16, q8,  #6
613     subs            r4,  r4,  #2
614     pld             [r2]
615     vst1.\align     {d16[0]},   [r0,:\align], r1
616     vst1.\align     {d16[st2]}, [r0,:\align], r1
617     bgt             3b
618
619     pop             {r4-r6, pc}
620
621 4:  // dy is 0
622     vld1.64         {d4},     [r2], r3
623     vld1.64         {d6},     [r2], r3
624     vext.8          d5,  d4,  d5,  #1
625     vext.8          d7,  d6,  d7,  #1
626     vtrn.32         d4,  d5
627     vtrn.32         d6,  d7
628
629 5:  // horizontal interpolation loop
630     vmull.u8        q8,  d4,  d0
631     vmull.u8        q9,  d6,  d0
632     subs            r4,  r4,  #2
633     vld1.64         {d4},     [r2], r3
634     vext.8          d5,  d4,  d5,  #1
635     vtrn.32         d4,  d5
636     vadd.i16        d16, d16, d17
637     vadd.i16        d17, d18, d19
638     pld             [r2]
639     vrshrn.u16      d16, q8,  #6
640     vld1.64         {d6},     [r2], r3
641     vext.8          d7,  d6,  d7,  #1
642     vtrn.32         d6,  d7
643     pld             [r2]
644     vst1.\align     {d16[0]},   [r0,:\align], r1
645     vst1.\align     {d16[st2]}, [r0,:\align], r1
646     bgt             5b
647
648     pop             {r4-r6, pc}
649 .endm
650
651     CHROMA_MC 2, 16
652     CHROMA_MC 4, 32
653
654 // the optimial timing for width 8 is different enough that it's not
655 // readable to put it in the same macro as width 2/4
656 mc_chroma_w8:
657     CHROMA_MC_START d4-d5, d6-d7
658
659 1:  // height loop, interpolate xy
660     pld             [r5]
661     vmull.u8        q8,  d4,  d0
662     vmlal.u8        q8,  d5,  d1
663     vld1.64         {d4, d5}, [r2], r3
664     vmlal.u8        q8,  d6,  d2
665     vext.8          d5,  d4,  d5,  #1
666     vmlal.u8        q8,  d7,  d3
667     vmull.u8        q9,  d6,  d0
668     subs            r4,  r4,  #2
669     vmlal.u8        q9,  d7,  d1
670     vmlal.u8        q9,  d4,  d2
671     vmlal.u8        q9,  d5,  d3
672     vrshrn.u16      d16, q8,  #6
673     vld1.64         {d6, d7}, [r5], r3
674     pld             [r2]
675     vrshrn.u16      d17, q9,  #6
676     vext.8          d7,  d6,  d7,  #1
677     vst1.64         {d16}, [r0,:64], r1
678     vst1.64         {d17}, [r0,:64], r1
679     bgt             1b
680
681     pop             {r4-r6, pc}
682
683 2:  // dx or dy are 0
684     tst             r6,  r6
685     add             ip,  ip,  r6
686     vdup.8          d0,  r4
687     vdup.8          d1,  ip
688     ldr             r4,  [sp, #28]
689
690     beq             4f
691
692     add             r5,  r2,  r3
693     lsl             r3,  r3,  #1
694     vld1.64         {d4}, [r2], r3
695     vld1.64         {d6}, [r5], r3
696
697 3:  // vertical interpolation loop
698     pld             [r5]
699     vmull.u8        q8,  d4,  d0
700     vmlal.u8        q8,  d6,  d1
701     vld1.64         {d4}, [r2], r3
702     vmull.u8        q9,  d6,  d0
703     vmlal.u8        q9,  d4,  d1
704     vld1.64         {d6}, [r5], r3
705     vrshrn.u16      d16, q8,  #6
706     vrshrn.u16      d17, q9,  #6
707     subs            r4,  r4,  #2
708     pld             [r2]
709     vst1.64         {d16}, [r0,:64], r1
710     vst1.64         {d17}, [r0,:64], r1
711     bgt             3b
712
713     pop             {r4-r6, pc}
714
715 4:  // dy is 0
716     vld1.64         {d4, d5}, [r2], r3
717     vld1.64         {d6, d7}, [r2], r3
718     vext.8          d5,  d4,  d5,  #1
719     vext.8          d7,  d6,  d7,  #1
720
721 5:  // horizontal interpolation loop
722     pld             [r2]
723     subs            r4,  r4,  #2
724     vmull.u8        q8,  d4,  d0
725     vmlal.u8        q8,  d5,  d1
726     vld1.64         {d4,  d5}, [r2], r3
727     vmull.u8        q9,  d6,  d0
728     vmlal.u8        q9,  d7,  d1
729     pld             [r2]
730     vext.8          d5,  d4,  d5,  #1
731     vrshrn.u16      d16, q8,  #6
732     vrshrn.u16      d17, q9,  #6
733     vld1.64         {d6, d7}, [r2], r3
734     vext.8          d7,  d6,  d7,  #1
735     vst1.64         {d16}, [r0,:64], r1
736     vst1.64         {d17}, [r0,:64], r1
737     bgt             5b
738
739     pop             {r4-r6, pc}
740 .endfunc
741
742
743 // hpel_filter_v( uint8_t *dst, uint8_t *src, int16_t *buf, int stride, int width)
744 function x264_hpel_filter_v_neon
745     ldr             ip,  [sp]
746     sub             r1,  r1,  r3,  lsl #1
747     push            {lr}
748     add             lr,  r1,  ip
749     vmov.u8         d30, #5
750     vmov.u8         d31, #20
751
752 filter_v_loop:
753     subs            ip,  ip,  #16
754     vld1.64         {d0-d1},   [r1,:128], r3
755     vld1.64         {d2-d3},   [r1,:128], r3
756     vld1.64         {d4-d5},   [r1,:128], r3
757     vld1.64         {d6-d7},   [r1,:128], r3
758     vld1.64         {d16-d17}, [r1,:128], r3
759     vld1.64         {d18-d19}, [r1,:128], r3
760     sub             r1,  lr,  ip
761
762     vaddl.u8        q10, d0,  d18
763     vmlsl.u8        q10, d2,  d30
764     vmlal.u8        q10, d4,  d31
765     vmlal.u8        q10, d6,  d31
766     vmlsl.u8        q10, d16, d30
767
768     vaddl.u8        q11, d1,  d19
769     vmlsl.u8        q11, d3,  d30
770     vmlal.u8        q11, d5,  d31
771     vmlal.u8        q11, d7,  d31
772     vmlsl.u8        q11, d17, d30
773
774     vqrshrun.s16    d0,  q10, #5
775     vst1.64         {d20-d21}, [r2,:128]!
776     vqrshrun.s16    d1,  q11, #5
777     vst1.64         {d22-d23}, [r2,:128]!
778     vst1.64         {d0-d1},   [r0,:128]!
779     bgt             filter_v_loop
780     pop             {pc}
781 .endfunc
782
783 // hpel_filter_c( uint8_t *dst, int16_t *buf, int width );
784 function x264_hpel_filter_c_neon
785     sub             r1,  #16
786     vld1.64         {d0-d3}, [r1,:128]!
787
788     // unrolled 2x: 4% faster
789 filter_c_loop:
790     subs            r2,  r2,  #16
791     vld1.64         {d4-d7}, [r1,:128]!
792     vext.16         q8,  q0,  q1,  #6
793     vext.16         q12, q1,  q2,  #3
794     vadd.s16        q8,  q8,  q12
795     vext.16         q9,  q0,  q1,  #7
796     vext.16         q11, q1,  q2,  #2
797     vadd.s16        q9,  q9,  q11
798     vext.16         q10, q1,  q2,  #1
799     vext.16         q11, q1,  q2,  #6
800     vadd.s16        q10, q1,  q10
801     vsub.s16        q8,  q8,  q9    // a-b
802     vext.16         q15, q2,  q3,  #3
803     vsub.s16        q9,  q9,  q10   // b-c
804
805     vext.16         q12, q1,  q2,  #7
806     vshr.s16        q8,  q8,  #2    // (a-b)/4
807     vadd.s16        q11, q11, q15
808     vext.16         q14, q2,  q3,  #2
809     vsub.s16        q8,  q8,  q9    // (a-b)/4-b+c
810     vadd.s16        q12, q12, q14
811     vext.16         q13, q2,  q3,  #1
812
813     vshr.s16        q8,  q8,  #2    // ((a-b)/4-b+c)/4
814     vadd.s16        q13, q2,  q13
815     vadd.s16        q8,  q8,  q10   // ((a-b)/4-b+c)/4+c = (a-5*b+20*c)/16
816     vsub.s16        q11, q11, q12   // a-b
817     vsub.s16        q12, q12, q13   // b-c
818     vshr.s16        q11, q11, #2    // (a-b)/4
819     vqrshrun.s16    d30, q8,  #6
820     vsub.s16        q11, q11, q12   // (a-b)/4-b+c
821     vshr.s16        q11, q11, #2    // ((a-b)/4-b+c)/4
822     vld1.64         {d0-d3}, [r1,:128]!
823     vadd.s16        q11, q11, q13   // ((a-b)/4-b+c)/4+c = (a-5*b+20*c)/16
824
825     vext.16         q8,  q2,  q3,  #6
826     vqrshrun.s16    d31, q11,  #6
827     vext.16         q12, q3,  q0,  #3
828     vadd.s16        q8,  q8,  q12
829     vext.16         q9,  q2,  q3,  #7
830     vst1.64         {d30-d31}, [r0,:128]!
831     bxle            lr
832     subs            r2,  r2,  #16
833
834     vext.16         q11, q3,  q0,  #2
835     vadd.s16        q9,  q9,  q11
836     vext.16         q10, q3,  q0,  #1
837     vext.16         q11, q3,  q0,  #6
838     vadd.s16        q10, q3,  q10
839     vsub.s16        q8,  q8,  q9    // a-b
840     vext.16         q15, q0,  q1,  #3
841     vsub.s16        q9,  q9,  q10   // b-c
842
843     vext.16         q12, q3,  q0,  #7
844     vshr.s16        q8,  q8,  #2    // (a-b)/4
845     vadd.s16        q11, q11, q15
846     vext.16         q14, q0,  q1,  #2
847     vsub.s16        q8,  q8,  q9    // (a-b)/4-b+c
848     vadd.s16        q12, q12, q14
849     vext.16         q13, q0,  q1,  #1
850
851     vshr.s16        q8,  q8,  #2    // ((a-b)/4-b+c)/4
852     vadd.s16        q13, q0,  q13
853     vadd.s16        q8,  q8,  q10   // ((a-b)/4-b+c)/4+c = (a-5*b+20*c)/16
854     vsub.s16        q11, q11, q12   // a-b
855     vsub.s16        q12, q12, q13   // b-c
856     vshr.s16        q11, q11, #2    // (a-b)/4
857     vqrshrun.s16    d30, q8,  #6
858     vsub.s16        q11, q11, q12   // (a-b)/4-b+c
859     vshr.s16        q11, q11, #2    // ((a-b)/4-b+c)/4
860     vadd.s16        q11, q11, q13   // ((a-b)/4-b+c)/4+c = (a-5*b+20*c)/16
861
862     vqrshrun.s16    d31, q11,  #6
863     vst1.64         {d30-d31}, [r0,:128]!
864     bgt             filter_c_loop
865     bx              lr
866 .endfunc
867
868 // hpel_filter_h( uint8_t *dst, uint8_t *src, int width );
869 function x264_hpel_filter_h_neon
870     sub             r1,  #16
871     vmov.u8         d30, #5
872     vld1.64         {d0-d3}, [r1,:128]!
873     vmov.u8         d31, #20
874
875     // unrolled 3x because it's 5% faster, due to mitigating
876     // the high latency of multiplication and vqrshrun
877 filter_h_loop:
878     subs            r2,  r2,  #16
879     vld1.64         {d4-d5}, [r1,:128]!
880     vext.8          q8,  q0,  q1,  #14
881     vext.8          q12, q1,  q2,  #3
882     vaddl.u8        q13, d16, d24
883     vext.8          q9,  q0,  q1,  #15
884     vaddl.u8        q14, d17, d25
885
886     vext.8          q10, q1,  q2,  #1
887     vmlal.u8        q13, d2,  d31
888     vmlsl.u8        q13, d18, d30
889     vext.8          q11, q1,  q2,  #2
890     vmlal.u8        q13, d20, d31
891     vmlsl.u8        q13, d22, d30
892
893     vmlsl.u8        q14, d19, d30
894     vmlal.u8        q14, d3,  d31
895     vmlal.u8        q14, d21, d31
896     vmlsl.u8        q14, d23, d30
897     vqrshrun.s16    d6,  q13, #5
898
899     vld1.64         {d0-d1}, [r1,:128]!
900     vext.8          q8,  q1,  q2,  #14
901     vext.8          q12, q2,  q0,  #3
902     vaddl.u8        q13, d16, d24
903     vqrshrun.s16    d7,  q14, #5
904     vext.8          q9,  q1,  q2,  #15
905     vaddl.u8        q14, d17, d25
906
907     vst1.64         {d6-d7}, [r0,:128]!
908     bxle            lr
909     subs            r2,  r2,  #16
910
911     vext.8          q10, q2,  q0,  #1
912     vmlal.u8        q13, d4,  d31
913     vmlsl.u8        q13, d18, d30
914     vext.8          q11, q2,  q0,  #2
915     vmlal.u8        q13, d20, d31
916     vmlsl.u8        q13, d22, d30
917
918     vmlsl.u8        q14, d19, d30
919     vmlal.u8        q14, d5,  d31
920     vmlal.u8        q14, d21, d31
921     vmlsl.u8        q14, d23, d30
922     vqrshrun.s16    d6,  q13, #5
923
924     vld1.64         {d2-d3}, [r1,:128]!
925     vext.8          q8,  q2,  q0,  #14
926     vext.8          q12, q0,  q1,  #3
927     vaddl.u8        q13, d16, d24
928     vqrshrun.s16    d7,  q14, #5
929     vext.8          q9,  q2,  q0,  #15
930     vaddl.u8        q14, d17, d25
931
932     vst1.64         {d6-d7}, [r0,:128]!
933     bxle            lr
934     subs            r2,  r2,  #16
935
936     vext.8          q10, q0,  q1,  #1
937     vmlal.u8        q13, d0,  d31
938     vmlsl.u8        q13, d18, d30
939     vext.8          q11, q0,  q1,  #2
940     vmlal.u8        q13, d20, d31
941     vmlsl.u8        q13, d22, d30
942
943     vmlsl.u8        q14, d19, d30
944     vmlal.u8        q14, d1,  d31
945     vmlal.u8        q14, d21, d31
946     vmlsl.u8        q14, d23, d30
947
948     vqrshrun.s16    d6, q13, #5
949     vqrshrun.s16    d7, q14, #5
950     vst1.64         {d6-d7}, [r0,:128]!
951     bgt             filter_h_loop
952     bx              lr
953 .endfunc
954
955
956 // frame_init_lowres_core( uint8_t *src0, uint8_t *dst0, uint8_t *dsth, uint8_t *dstv,
957 //                         uint8_t *dstc, int src_stride, int dst_stride, int width,
958 //                         int height )
959 function x264_frame_init_lowres_core_neon
960     push            {r4-r10,lr}
961     vpush           {d8-d15}
962     ldrd            r4,  [sp, #96]
963     ldrd            r6,  [sp, #104]
964     ldr             lr,  [sp, #112]
965     sub             r10, r6,  r7            // dst_stride - width
966     and             r10, r10, #~15
967
968 lowres_yloop:
969     mov             ip,  r7                 // width
970     mov             r6,  r0                 // src0
971     add             r8,  r0,  r5            // src1 = src0 + src_stride
972     add             r9,  r0,  r5,  lsl #1   // src2 = src1 + src_stride
973
974     vld2.8          {d8, d10}, [r6,:128]!
975     vld2.8          {d12,d14}, [r8,:128]!
976     vld2.8          {d16,d18}, [r9,:128]!
977
978 lowres_xloop:
979     subs            ip,  ip,  #16
980
981     vld2.8          {d9, d11}, [r6,:128]!
982     vld2.8          {d13,d15}, [r8,:128]!
983     vrhadd.u8       q0,  q4,  q6
984     vld2.8          {d17,d19}, [r9,:128]!
985     vrhadd.u8       q5,  q5,  q7
986     vld2.8          {d20,d22}, [r6,:128]!
987     vrhadd.u8       q1,  q6,  q8
988     vld2.8          {d24,d26}, [r8,:128]!
989     vrhadd.u8       q7,  q7,  q9
990     vext.8          q4,  q4,  q10, #1
991     vrhadd.u8       q0,  q0,  q5
992     vext.8          q6,  q6,  q12, #1
993     vrhadd.u8       q1,  q1,  q7
994     vld2.8          {d28,d30}, [r9,:128]!
995     vrhadd.u8       q4,  q4,  q6
996     vext.8          q8,  q8,  q14, #1
997     vrhadd.u8       q6,  q6,  q8
998     vst1.64         {d0-d1},   [r1,:128]!
999     vrhadd.u8       q2,  q4,  q5
1000     vst1.64         {d2-d3},   [r3,:128]!
1001     vrhadd.u8       q3,  q6,  q7
1002     vst1.64         {d4-d5},   [r2,:128]!
1003     vst1.64         {d6-d7},   [r4,:128]!
1004
1005     ble             lowres_xloop_end
1006     subs            ip,  ip,  #16
1007
1008     vld2.8          {d21,d23}, [r6,:128]!
1009     vld2.8          {d25,d27}, [r8,:128]!
1010     vrhadd.u8       q0,  q10, q12
1011     vld2.8          {d29,d31}, [r9,:128]!
1012     vrhadd.u8       q11, q11, q13
1013     vld2.8          {d8, d10}, [r6,:128]!
1014     vrhadd.u8       q1,  q12, q14
1015     vld2.8          {d12,d14}, [r8,:128]!
1016     vrhadd.u8       q13, q13, q15
1017     vext.8          q10, q10, q4,  #1
1018     vrhadd.u8       q0,  q0,  q11
1019     vext.8          q12, q12, q6,  #1
1020     vrhadd.u8       q1,  q1,  q13
1021     vld2.8          {d16,d18}, [r9,:128]!
1022     vrhadd.u8       q10, q10, q12
1023     vext.8          q14, q14, q8,  #1
1024     vrhadd.u8       q12, q12, q14
1025     vst1.64         {d0-d1},   [r1,:128]!
1026     vrhadd.u8       q2,  q10, q11
1027     vst1.64         {d2-d3},   [r3,:128]!
1028     vrhadd.u8       q3,  q12, q13
1029     vst1.64         {d4-d5},   [r2,:128]!
1030     vst1.64         {d6-d7},   [r4,:128]!
1031
1032     bgt             lowres_xloop
1033
1034 lowres_xloop_end:
1035     subs            lr,  lr,  #1
1036     add             r0,  r0,  r5,  lsl #1
1037     add             r1,  r1,  r10
1038     add             r2,  r2,  r10
1039     add             r3,  r3,  r10
1040     add             r4,  r4,  r10
1041     bgt             lowres_yloop
1042
1043     vpop            {d8-d15}
1044     pop             {r4-r10,pc}
1045 .endfunc