1 /*****************************************************************************
2 * mc.S: arm motion compensation
3 *****************************************************************************
4 * Copyright (C) 2009-2015 x264 project
6 * Authors: David Conrad <lessen42@gmail.com>
7 * Mans Rullgard <mans@mansr.com>
8 * Stefan Groenroos <stefan.gronroos@gmail.com>
9 * Janne Grunau <janne-x264@jannau.net>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
25 * This program is also available under a commercial proprietary license.
26 * For more information, contact us at licensing@x264.com.
27 *****************************************************************************/
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
36 // void prefetch_ref( uint8_t *pix, intptr_t stride, int parity )
37 function x264_prefetch_ref_arm
41 add r0, r0, r2, lsl #3
42 add r2, r1, r1, lsl #1
46 add r3, r0, r1, lsl #2
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
61 smulbb lr, lr, r1 // note: this assumes stride_y is <= 16 bits signed
66 add r0, r0, lr, lsl #2
68 add lr, r0, r1, lsl #1
71 add r2, r2, ip, lsl #2
74 add ip, r2, r3, lsl #1
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
90 .macro MEMCPY_ALIGNED srcalign dstalign
91 function memcpy_aligned_\dstalign\()_\srcalign\()_neon, export=0
93 .if \srcalign == 8 && \dstalign == 8
95 vld1.64 {d0}, [r1,:64]!
96 vst1.64 {d0}, [r3,:64]!
100 .set r1align, \srcalign * 8
101 .set r3align, \dstalign * 8
106 vld1.64 {d0-d1}, [r1,:r1align]!
107 vst1.64 {d0-d1}, [r3,:r3align]!
108 32: // n is a multiple of 32
112 vld1.64 {d0-d3}, [r1,:r1align]!
113 vst1.64 {d0-d3}, [r3,:r3align]!
114 640: // n is a multiple of 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]!
125 .if \srcalign == 8 && \dstalign == 8
126 vld1.64 {d0}, [r1,:64]!
127 vst1.64 {d0}, [r3,:64]!
133 MEMCPY_ALIGNED 16, 16
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
148 // void x264_memzero_aligned( void *dst, size_t n )
149 function x264_memzero_aligned_neon
155 vst1.64 {d0-d3}, [r0,:128]!
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 );
166 function x264_pixel_avg_\w\()x\h\()_neon
170 ldrd r4, r5, [sp, #16]
172 beq x264_pixel_avg_w\w\()_neon
174 blt x264_pixel_avg_weight_w\w\()_add_sub_neon // weight > 64
176 bge x264_pixel_avg_weight_w\w\()_add_add_neon
177 b x264_pixel_avg_weight_w\w\()_sub_add_neon // weight < 0
192 .macro load_weights_add_add
197 .macro load_add_add d1 d2
198 vld1.32 {\d1}, [r2], r3
199 vld1.32 {\d2}, [r4], r5
202 .macro weight_add_add dst s1 s2
203 vmull.u8 \dst, \s1, d30
204 vmlal.u8 \dst, \s2, d31
208 .macro load_weights_add_sub
214 .macro load_add_sub d1 d2
215 vld1.32 {\d1}, [r2], r3
216 vld1.32 {\d2}, [r4], r5
219 .macro weight_add_sub dst s1 s2
220 vmull.u8 \dst, \s1, d30
221 vmlsl.u8 \dst, \s2, d31
225 .macro load_weights_sub_add
231 .macro load_sub_add d1 d2
232 vld1.32 {\d2}, [r4], r5
233 vld1.32 {\d1}, [r2], r3
236 .macro weight_sub_add dst s1 s2
237 vmull.u8 \dst, \s2, d31
238 vmlsl.u8 \dst, \s1, d30
241 .macro AVG_WEIGHT ext
242 function x264_pixel_avg_weight_w4_\ext\()_neon, export=0
247 weight_\ext q8, d0, d1
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
258 function x264_pixel_avg_weight_w8_\ext\()_neon, export=0
263 weight_\ext q8, d0, d1
265 weight_\ext q9, d2, d3
267 weight_\ext q10, d4, d5
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
282 function x264_pixel_avg_weight_w16_\ext\()_neon, export=0
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
307 function x264_pixel_avg_w4_neon, export=0
309 vld1.32 {d0[]}, [r2], r3
310 vld1.32 {d2[]}, [r4], r5
312 vld1.32 {d1[]}, [r2], r3
313 vld1.32 {d3[]}, [r4], r5
315 vst1.32 {d0[0]}, [r0,:32], r1
316 vst1.32 {d1[0]}, [r0,:32], r1
317 bgt x264_pixel_avg_w4_neon
321 function x264_pixel_avg_w8_neon, export=0
323 vld1.64 {d0}, [r2], r3
324 vld1.64 {d2}, [r4], r5
326 vld1.64 {d1}, [r2], r3
327 vld1.64 {d3}, [r4], r5
329 vst1.64 {d0}, [r0,:64], r1
330 vld1.64 {d2}, [r2], r3
331 vld1.64 {d4}, [r4], r5
333 vst1.64 {d1}, [r0,:64], r1
334 vld1.64 {d3}, [r2], r3
335 vld1.64 {d5}, [r4], r5
337 vst1.64 {d2}, [r0,:64], r1
338 vst1.64 {d3}, [r0,:64], r1
339 bgt x264_pixel_avg_w8_neon
343 function x264_pixel_avg_w16_neon, export=0
345 vld1.64 {d0-d1}, [r2], r3
346 vld1.64 {d2-d3}, [r4], r5
348 vld1.64 {d2-d3}, [r2], r3
349 vld1.64 {d4-d5}, [r4], r5
351 vst1.64 {d0-d1}, [r0,:128], r1
352 vld1.64 {d4-d5}, [r2], r3
353 vld1.64 {d6-d7}, [r4], r5
355 vst1.64 {d2-d3}, [r0,:128], r1
356 vld1.64 {d6-d7}, [r2], r3
357 vld1.64 {d0-d1}, [r4], r5
359 vst1.64 {d4-d5}, [r0,:128], r1
360 vst1.64 {d6-d7}, [r0,:128], r1
361 bgt x264_pixel_avg_w16_neon
366 function x264_pixel_avg2_w4_neon
372 vld1.32 {d0[]}, [r2], r3
373 vld1.32 {d2[]}, [lr], r3
375 vld1.32 {d1[]}, [r2], r3
376 vld1.32 {d3[]}, [lr], r3
378 vst1.32 {d0[0]}, [r0,:32], r1
379 vst1.32 {d1[0]}, [r0,:32], r1
384 function x264_pixel_avg2_w8_neon
390 vld1.64 {d0}, [r2], r3
391 vld1.64 {d2}, [lr], r3
393 vld1.64 {d1}, [r2], r3
394 vld1.64 {d3}, [lr], r3
396 vst1.64 {d0}, [r0,:64], r1
397 vst1.64 {d1}, [r0,:64], r1
402 function x264_pixel_avg2_w16_neon
408 vld1.64 {d0-d1}, [r2], r3
409 vld1.64 {d2-d3}, [lr], r3
411 vld1.64 {d4-d5}, [r2], r3
412 vld1.64 {d6-d7}, [lr], r3
414 vst1.64 {d0-d1}, [r0,:128], r1
415 vst1.64 {d4-d5}, [r0,:128], r1
420 function x264_pixel_avg2_w20_neon
427 vld1.64 {d0-d2}, [r2], r3
428 vld1.64 {d4-d6}, [lr], r3
431 vld1.64 {d4-d6}, [r2], r3
432 vld1.64 {d16-d18},[lr], r3
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
444 .macro weight_prologue type
446 ldr r4, [sp, #4*3] // weight_t
447 ldr ip, [sp, #4*3+4] // h
449 ldr lr, [r4, #32] // denom
451 ldrd r4, r5, [r4, #32+4] // scale, offset
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
467 vld1.8 {d17-d19}, [r2], r3
468 vmull.u8 q10, d17, d0
469 vmull.u8 q11, d18, d0
470 vld1.8 {d16-d18}, [r2], r3
471 vmull.u8 q12, d16, d0
472 vmull.u8 q13, d17, d0
474 vmull.u8 q14, d19, d0
475 vrshl.s16 q10, q10, q2
476 vrshl.s16 q11, q11, q2
477 vrshl.s16 q12, q12, q2
478 vrshl.s16 q13, q13, q2
479 vrshl.s16 q14, q14, q2
480 vadd.s16 q10, q10, q1
481 vadd.s16 q11, q11, q1
482 vadd.s16 q12, q12, q1
483 vadd.s16 q13, q13, q1
484 vadd.s16 q14, q14, q1
490 vst1.8 {d16-d17}, [r0,:128]!
491 vst1.32 {d20[0]}, [r0,:32], r1
492 vst1.8 {d18-d19}, [r0,:128]!
493 vst1.32 {d20[1]}, [r0,:32], r1
498 function x264_mc_weight_w16_neon
502 vld1.8 {d16-d17}, [r2], r3
503 vld1.8 {d18-d19}, [r2], r3
504 vmull.u8 q10, d16, d0
505 vmull.u8 q11, d17, d0
506 vmull.u8 q12, d18, d0
507 vmull.u8 q13, d19, d0
508 vrshl.s16 q10, q10, q2
509 vrshl.s16 q11, q11, q2
510 vrshl.s16 q12, q12, q2
511 vrshl.s16 q13, q13, q2
512 vadd.s16 q10, q10, q1
513 vadd.s16 q11, q11, q1
514 vadd.s16 q12, q12, q1
515 vadd.s16 q13, q13, q1
520 vst1.8 {d16-d17}, [r0,:128], r1
521 vst1.8 {d18-d19}, [r0,:128], r1
526 function x264_mc_weight_w8_neon
530 vld1.8 {d16}, [r2], r3
531 vld1.8 {d18}, [r2], r3
540 vst1.8 {d16}, [r0,:64], r1
541 vst1.8 {d18}, [r0,:64], r1
546 function x264_mc_weight_w4_neon
550 vld1.32 {d16[0]}, [r2], r3
551 vld1.32 {d16[1]}, [r2], r3
556 vst1.32 {d16[0]}, [r0], r1
557 vst1.32 {d16[1]}, [r0], r1
562 function x264_mc_weight_w20_nodenom_neon
563 weight_prologue nodenom
565 weight20_nodenom_loop:
567 vld1.8 {d26-d28}, [r2], r3
570 vld1.8 {d29-d31}, [r2], r3
577 vmlal.u8 q10, d29, d0
578 vmlal.u8 q11, d30, d0
579 vmlal.u8 q12, d28, d0
585 vst1.8 {d16-d17}, [r0,:128]!
586 vst1.32 {d20[0]}, [r0,:32], r1
587 vst1.8 {d18-d19}, [r0,:128]!
588 vst1.32 {d20[1]}, [r0,:32], r1
589 bgt weight20_nodenom_loop
593 function x264_mc_weight_w16_nodenom_neon
594 weight_prologue nodenom
595 weight16_nodenom_loop:
597 vld1.8 {d16-d17}, [r2], r3
598 vld1.8 {d18-d19}, [r2], r3
603 vmlal.u8 q12, d16, d0
604 vmlal.u8 q13, d17, d0
605 vmlal.u8 q14, d18, d0
606 vmlal.u8 q15, d19, d0
611 vst1.8 {d16-d17}, [r0,:128], r1
612 vst1.8 {d18-d19}, [r0,:128], r1
613 bgt weight16_nodenom_loop
617 function x264_mc_weight_w8_nodenom_neon
618 weight_prologue nodenom
619 weight8_nodenom_loop:
621 vld1.8 {d16}, [r2], r3
622 vld1.8 {d18}, [r2], r3
625 vmlal.u8 q10, d16, d0
626 vmlal.u8 q11, d18, d0
629 vst1.8 {d16}, [r0,:64], r1
630 vst1.8 {d17}, [r0,:64], r1
631 bgt weight8_nodenom_loop
635 function x264_mc_weight_w4_nodenom_neon
636 weight_prologue nodenom
637 weight4_nodenom_loop:
639 vld1.32 {d16[0]}, [r2], r3
640 vld1.32 {d16[1]}, [r2], r3
642 vmlal.u8 q10, d16, d0
644 vst1.32 {d16[0]}, [r0], r1
645 vst1.32 {d16[1]}, [r0], r1
646 bgt weight4_nodenom_loop
650 .macro weight_simple_prologue
652 ldr lr, [sp, #4] // weight_t
653 ldr ip, [sp, #8] // h
654 ldr lr, [lr] // offset
658 .macro weight_simple name op
659 function x264_mc_weight_w20_\name\()_neon
660 weight_simple_prologue
661 weight20_\name\()_loop:
663 vld1.8 {d16-d18}, [r2], r3
664 vld1.8 {d19-d21}, [r2], r3
668 vst1.8 {d16-d18}, [r0,:64], r1
669 vst1.8 {d19-d21}, [r0,:64], r1
670 bgt weight20_\name\()_loop
674 function x264_mc_weight_w16_\name\()_neon
675 weight_simple_prologue
676 weight16_\name\()_loop:
678 vld1.8 {d16-d17}, [r2], r3
679 vld1.8 {d18-d19}, [r2], r3
682 vst1.8 {d16-d17}, [r0,:128], r1
683 vst1.8 {d18-d19}, [r0,:128], r1
684 bgt weight16_\name\()_loop
688 function x264_mc_weight_w8_\name\()_neon
689 weight_simple_prologue
690 weight8_\name\()_loop:
692 vld1.8 {d16}, [r2], r3
693 vld1.8 {d17}, [r2], r3
695 vst1.8 {d16}, [r0,:64], r1
696 vst1.8 {d17}, [r0,:64], r1
697 bgt weight8_\name\()_loop
701 function x264_mc_weight_w4_\name\()_neon
702 weight_simple_prologue
703 weight4_\name\()_loop:
705 vld1.32 {d16[]}, [r2], r3
706 vld1.32 {d17[]}, [r2], r3
708 vst1.32 {d16[0]}, [r0], r1
709 vst1.32 {d17[0]}, [r0], r1
710 bgt weight4_\name\()_loop
715 weight_simple offsetadd, vqadd.u8
716 weight_simple offsetsub, vqsub.u8
719 // void mc_copy( uint8_t *dst, intptr_t dst_stride, uint8_t *src, intptr_t src_stride, int height )
720 function x264_mc_copy_w4_neon
724 vld1.32 {d0[]}, [r2], r3
725 vld1.32 {d1[]}, [r2], r3
726 vld1.32 {d2[]}, [r2], r3
727 vld1.32 {d3[]}, [r2], r3
728 vst1.32 {d0[0]}, [r0,:32], r1
729 vst1.32 {d1[0]}, [r0,:32], r1
730 vst1.32 {d2[0]}, [r0,:32], r1
731 vst1.32 {d3[0]}, [r0,:32], r1
736 function x264_mc_copy_w8_neon
740 vld1.32 {d0}, [r2], r3
741 vld1.32 {d1}, [r2], r3
742 vld1.32 {d2}, [r2], r3
743 vld1.32 {d3}, [r2], r3
744 vst1.32 {d0}, [r0,:64], r1
745 vst1.32 {d1}, [r0,:64], r1
746 vst1.32 {d2}, [r0,:64], r1
747 vst1.32 {d3}, [r0,:64], r1
752 function x264_mc_copy_w16_neon
756 vld1.32 {d0-d1}, [r2], r3
757 vld1.32 {d2-d3}, [r2], r3
758 vld1.32 {d4-d5}, [r2], r3
759 vld1.32 {d6-d7}, [r2], r3
760 vst1.32 {d0-d1}, [r0,:128], r1
761 vst1.32 {d2-d3}, [r0,:128], r1
762 vst1.32 {d4-d5}, [r0,:128], r1
763 vst1.32 {d6-d7}, [r0,:128], r1
768 function x264_mc_copy_w16_aligned_neon
770 copy_w16_aligned_loop:
772 vld1.32 {d0-d1}, [r2,:128], r3
773 vld1.32 {d2-d3}, [r2,:128], r3
774 vld1.32 {d4-d5}, [r2,:128], r3
775 vld1.32 {d6-d7}, [r2,:128], r3
776 vst1.32 {d0-d1}, [r0,:128], r1
777 vst1.32 {d2-d3}, [r0,:128], r1
778 vst1.32 {d4-d5}, [r0,:128], r1
779 vst1.32 {d6-d7}, [r0,:128], r1
780 bgt copy_w16_aligned_loop
785 // void x264_mc_chroma_neon( uint8_t *dst, intptr_t i_dst_stride,
786 // uint8_t *src, intptr_t i_src_stride,
787 // int dx, int dy, int i_width, int i_height );
789 function x264_mc_chroma_neon
792 ldrd r4, r5, [sp, #56]
793 ldrd r6, r7, [sp, #64]
797 add r3, r3, r5, asr #2
812 .macro CHROMA_MC_START r00, r01, r10, r11
814 rsb r7, lr, r6, lsl #3
815 rsb ip, lr, r5, lsl #3
816 sub r5, lr, r5, lsl #3
817 sub r5, r5, r6, lsl #3
821 vld2.8 {\r00-\r01}, [r3], r4
827 vld2.8 {\r10-\r11}, [r3], r4
832 .macro CHROMA_MC width, align
834 CHROMA_MC_START d4, d5, d8, d9
835 vext.8 d6, d4, d6, #1
836 vext.8 d7, d5, d7, #1
837 vext.8 d10, d8, d10, #1
838 vext.8 d11, d9, d11, #1
839 // since the element size varies, there's a different index for the 2nd store
854 1: // height loop, interpolate xy
861 vld2.8 {d4-d5}, [r3], r4
863 vext.8 d6, d4, d6, #1
864 vext.8 d7, d5, d7, #1
866 vadd.i16 d16, d16, d17
867 vadd.i16 d17, d18, d19
877 vld2.8 {d8-d9}, [r3], r4
879 vrshrn.u16 d16, q8, #6
881 vext.8 d10, d8, d10, #1
882 vext.8 d11, d9, d11, #1
884 vadd.i16 d18, d20, d21
885 vadd.i16 d19, d22, d23
890 vrshrn.u16 d18, q9, #6
897 vst1.\align {d16[0]}, [r0,:\align], r2
898 vst1.\align {d16[st2]}, [r1,:\align], r2
899 vst1.\align {d18[0]}, [r0,:\align], r2
900 vst1.\align {d18[st2]}, [r1,:\align], r2
915 vld1.64 {d4}, [r3], r4
916 vld1.64 {d6}, [r3], r4
918 3: // vertical interpolation loop
923 vld1.64 {d4}, [r3], r4
925 vld1.64 {d6}, [r3], r4
927 vrshrn.u16 d16, q8, #6 // uvuvuvuv
928 vrshrn.u16 d17, q9, #6 // uvuvuvuv
930 vuzp.8 d16, d17 // d16=uuuu|uuuu, d17=vvvv|vvvv
935 vst1.\align {d16[0]}, [r0,:\align], r2
936 vst1.\align {d16[st2]}, [r0,:\align], r2
937 vst1.\align {d17[0]}, [r1,:\align], r2
938 vst1.\align {d17[st2]}, [r1,:\align], r2
946 vld1.64 {d4-d5}, [r3], r4
947 vld1.64 {d6-d7}, [r3], r4
949 vext.8 d5, d4, d5, #2
950 vext.8 d7, d6, d7, #2
952 5: // horizontal interpolation loop
960 vld1.64 {d4-d5}, [r3], r4
961 vld1.64 {d6-d7}, [r3], r4
962 vext.8 d5, d4, d5, #2
963 vrshrn.u16 d16, q8, #6
964 vrshrn.u16 d17, q9, #6
965 vext.8 d7, d6, d7, #2
971 vst1.\align {d16[0]}, [r0,:\align], r2
972 vst1.\align {d16[st2]}, [r0,:\align], r2
973 vst1.\align {d17[0]}, [r1,:\align], r2
974 vst1.\align {d17[st2]}, [r1,:\align], r2
985 CHROMA_MC_START d4, d7, d8, d11
986 vext.8 d5, d4, d5, #1
987 vext.8 d9, d8, d9, #1
988 vext.8 d7, d6, d7, #1
989 vext.8 d11, d10, d11, #1
991 1: // height loop, interpolate xy
1000 vmlal.u8 q9, d11, d3
1002 vld2.8 {d4-d7}, [r3], r4
1004 vext.8 d5, d4, d5, #1
1005 vext.8 d7, d6, d7, #1
1007 vmull.u8 q10, d8, d0
1008 vmlal.u8 q10, d9, d1
1009 vmlal.u8 q10, d4, d2
1010 vmlal.u8 q10, d5, d3
1012 vmull.u8 q11, d10, d0
1013 vmlal.u8 q11, d11, d1
1014 vmlal.u8 q11, d6, d2
1015 vmlal.u8 q11, d7, d3
1018 vld2.8 {d8-d11}, [r3], r4
1020 vrshrn.u16 d16, q8, #6
1021 vrshrn.u16 d17, q9, #6
1022 vrshrn.u16 d18, q10, #6
1023 vext.8 d9, d8, d9, #1
1024 vrshrn.u16 d19, q11, #6
1025 vext.8 d11, d10, d11, #1
1030 vst1.64 {d16}, [r0,:64], r2
1031 vst1.64 {d17}, [r1,:64], r2
1032 vst1.64 {d18}, [r0,:64], r2
1033 vst1.64 {d19}, [r1,:64], r2
1040 2: // dx or dy are 0
1049 vld2.8 {d4-d5}, [r3], r4
1050 vld2.8 {d6-d7}, [r3], r4
1052 3: // vertical interpolation loop
1053 vmull.u8 q8, d4, d0 //U
1055 vmull.u8 q9, d5, d0 //V
1058 vld2.8 {d4-d5}, [r3], r4
1060 vmull.u8 q10, d6, d0
1061 vmlal.u8 q10, d4, d1
1062 vmull.u8 q11, d7, d0
1063 vmlal.u8 q11, d5, d1
1065 vld2.8 {d6-d7}, [r3], r4
1067 vrshrn.u16 d16, q8, #6
1068 vrshrn.u16 d17, q9, #6
1069 vrshrn.u16 d18, q10, #6
1070 vrshrn.u16 d19, q11, #6
1076 vst1.64 {d16}, [r0,:64], r2
1077 vst1.64 {d17}, [r1,:64], r2
1078 vst1.64 {d18}, [r0,:64], r2
1079 vst1.64 {d19}, [r1,:64], r2
1088 vld2.8 {d4-d7}, [r3], r4
1089 vld2.8 {d8-d11}, [r3], r4
1090 vext.8 d5, d4, d5, #1
1091 vext.8 d7, d6, d7, #1
1092 vext.8 d9, d8, d9, #1
1093 vext.8 d11, d10, d11, #1
1095 5: // horizontal interpolation loop
1097 vmull.u8 q8, d4, d0 //U
1099 vmull.u8 q9, d6, d0 //V
1102 vld2.8 {d4-d7}, [r3], r4
1104 vmull.u8 q10, d8, d0
1105 vmlal.u8 q10, d9, d1
1106 vmull.u8 q11, d10, d0
1107 vmlal.u8 q11, d11, d1
1109 vld2.8 {d8-d11}, [r3], r4
1111 vext.8 d5, d4, d5, #1
1112 vrshrn.u16 d16, q8, #6
1113 vext.8 d7, d6, d7, #1
1114 vrshrn.u16 d17, q9, #6
1115 vext.8 d9, d8, d9, #1
1116 vrshrn.u16 d18, q10, #6
1117 vext.8 d11, d10, d11, #1
1118 vrshrn.u16 d19, q11, #6
1123 vst1.64 {d16}, [r0,:64], r2
1124 vst1.64 {d17}, [r1,:64], r2
1125 vst1.64 {d18}, [r0,:64], r2
1126 vst1.64 {d19}, [r1,:64], r2
1135 // hpel_filter_v( uint8_t *dst, uint8_t *src, int16_t *buf, intptr_t stride, int width )
1136 function x264_hpel_filter_v_neon
1138 sub r1, r1, r3, lsl #1
1146 vld1.64 {d0-d1}, [r1,:128], r3
1147 vld1.64 {d2-d3}, [r1,:128], r3
1148 vld1.64 {d4-d5}, [r1,:128], r3
1149 vld1.64 {d6-d7}, [r1,:128], r3
1150 vld1.64 {d16-d17}, [r1,:128], r3
1151 vld1.64 {d18-d19}, [r1,:128], r3
1154 vaddl.u8 q10, d0, d18
1155 vmlsl.u8 q10, d2, d30
1156 vmlal.u8 q10, d4, d31
1157 vmlal.u8 q10, d6, d31
1158 vmlsl.u8 q10, d16, d30
1160 vaddl.u8 q11, d1, d19
1161 vmlsl.u8 q11, d3, d30
1162 vmlal.u8 q11, d5, d31
1163 vmlal.u8 q11, d7, d31
1164 vmlsl.u8 q11, d17, d30
1166 vqrshrun.s16 d0, q10, #5
1167 vst1.64 {d20-d21}, [r2,:128]!
1168 vqrshrun.s16 d1, q11, #5
1169 vst1.64 {d22-d23}, [r2,:128]!
1170 vst1.64 {d0-d1}, [r0,:128]!
1175 // hpel_filter_c( uint8_t *dst, int16_t *buf, int width );
1176 function x264_hpel_filter_c_neon
1178 vld1.64 {d0-d3}, [r1,:128]!
1180 // unrolled 2x: 4% faster
1183 vld1.64 {d4-d7}, [r1,:128]!
1184 vext.16 q8, q0, q1, #6
1185 vext.16 q12, q1, q2, #3
1186 vadd.s16 q8, q8, q12
1187 vext.16 q9, q0, q1, #7
1188 vext.16 q11, q1, q2, #2
1189 vadd.s16 q9, q9, q11
1190 vext.16 q10, q1, q2, #1
1191 vext.16 q11, q1, q2, #6
1192 vadd.s16 q10, q1, q10
1193 vsub.s16 q8, q8, q9 // a-b
1194 vext.16 q15, q2, q3, #3
1195 vsub.s16 q9, q9, q10 // b-c
1197 vext.16 q12, q1, q2, #7
1198 vshr.s16 q8, q8, #2 // (a-b)/4
1199 vadd.s16 q11, q11, q15
1200 vext.16 q14, q2, q3, #2
1201 vsub.s16 q8, q8, q9 // (a-b)/4-b+c
1202 vadd.s16 q12, q12, q14
1203 vext.16 q13, q2, q3, #1
1205 vshr.s16 q8, q8, #2 // ((a-b)/4-b+c)/4
1206 vadd.s16 q13, q2, q13
1207 vadd.s16 q8, q8, q10 // ((a-b)/4-b+c)/4+c = (a-5*b+20*c)/16
1208 vsub.s16 q11, q11, q12 // a-b
1209 vsub.s16 q12, q12, q13 // b-c
1210 vshr.s16 q11, q11, #2 // (a-b)/4
1211 vqrshrun.s16 d30, q8, #6
1212 vsub.s16 q11, q11, q12 // (a-b)/4-b+c
1213 vshr.s16 q11, q11, #2 // ((a-b)/4-b+c)/4
1214 vld1.64 {d0-d3}, [r1,:128]!
1215 vadd.s16 q11, q11, q13 // ((a-b)/4-b+c)/4+c = (a-5*b+20*c)/16
1217 vext.16 q8, q2, q3, #6
1218 vqrshrun.s16 d31, q11, #6
1219 vext.16 q12, q3, q0, #3
1220 vadd.s16 q8, q8, q12
1221 vext.16 q9, q2, q3, #7
1222 vst1.64 {d30-d31}, [r0,:128]!
1226 vext.16 q11, q3, q0, #2
1227 vadd.s16 q9, q9, q11
1228 vext.16 q10, q3, q0, #1
1229 vext.16 q11, q3, q0, #6
1230 vadd.s16 q10, q3, q10
1231 vsub.s16 q8, q8, q9 // a-b
1232 vext.16 q15, q0, q1, #3
1233 vsub.s16 q9, q9, q10 // b-c
1235 vext.16 q12, q3, q0, #7
1236 vshr.s16 q8, q8, #2 // (a-b)/4
1237 vadd.s16 q11, q11, q15
1238 vext.16 q14, q0, q1, #2
1239 vsub.s16 q8, q8, q9 // (a-b)/4-b+c
1240 vadd.s16 q12, q12, q14
1241 vext.16 q13, q0, q1, #1
1243 vshr.s16 q8, q8, #2 // ((a-b)/4-b+c)/4
1244 vadd.s16 q13, q0, q13
1245 vadd.s16 q8, q8, q10 // ((a-b)/4-b+c)/4+c = (a-5*b+20*c)/16
1246 vsub.s16 q11, q11, q12 // a-b
1247 vsub.s16 q12, q12, q13 // b-c
1248 vshr.s16 q11, q11, #2 // (a-b)/4
1249 vqrshrun.s16 d30, q8, #6
1250 vsub.s16 q11, q11, q12 // (a-b)/4-b+c
1251 vshr.s16 q11, q11, #2 // ((a-b)/4-b+c)/4
1252 vadd.s16 q11, q11, q13 // ((a-b)/4-b+c)/4+c = (a-5*b+20*c)/16
1254 vqrshrun.s16 d31, q11, #6
1255 vst1.64 {d30-d31}, [r0,:128]!
1260 // hpel_filter_h( uint8_t *dst, uint8_t *src, int width );
1261 function x264_hpel_filter_h_neon
1264 vld1.64 {d0-d3}, [r1,:128]!
1267 // unrolled 3x because it's 5% faster, due to mitigating
1268 // the high latency of multiplication and vqrshrun
1271 vld1.64 {d4-d5}, [r1,:128]!
1272 vext.8 q8, q0, q1, #14
1273 vext.8 q12, q1, q2, #3
1274 vaddl.u8 q13, d16, d24
1275 vext.8 q9, q0, q1, #15
1276 vaddl.u8 q14, d17, d25
1278 vext.8 q10, q1, q2, #1
1279 vmlal.u8 q13, d2, d31
1280 vmlsl.u8 q13, d18, d30
1281 vext.8 q11, q1, q2, #2
1282 vmlal.u8 q13, d20, d31
1283 vmlsl.u8 q13, d22, d30
1285 vmlsl.u8 q14, d19, d30
1286 vmlal.u8 q14, d3, d31
1287 vmlal.u8 q14, d21, d31
1288 vmlsl.u8 q14, d23, d30
1289 vqrshrun.s16 d6, q13, #5
1291 vld1.64 {d0-d1}, [r1,:128]!
1292 vext.8 q8, q1, q2, #14
1293 vext.8 q12, q2, q0, #3
1294 vaddl.u8 q13, d16, d24
1295 vqrshrun.s16 d7, q14, #5
1296 vext.8 q9, q1, q2, #15
1297 vaddl.u8 q14, d17, d25
1299 vst1.64 {d6-d7}, [r0,:128]!
1303 vext.8 q10, q2, q0, #1
1304 vmlal.u8 q13, d4, d31
1305 vmlsl.u8 q13, d18, d30
1306 vext.8 q11, q2, q0, #2
1307 vmlal.u8 q13, d20, d31
1308 vmlsl.u8 q13, d22, d30
1310 vmlsl.u8 q14, d19, d30
1311 vmlal.u8 q14, d5, d31
1312 vmlal.u8 q14, d21, d31
1313 vmlsl.u8 q14, d23, d30
1314 vqrshrun.s16 d6, q13, #5
1316 vld1.64 {d2-d3}, [r1,:128]!
1317 vext.8 q8, q2, q0, #14
1318 vext.8 q12, q0, q1, #3
1319 vaddl.u8 q13, d16, d24
1320 vqrshrun.s16 d7, q14, #5
1321 vext.8 q9, q2, q0, #15
1322 vaddl.u8 q14, d17, d25
1324 vst1.64 {d6-d7}, [r0,:128]!
1328 vext.8 q10, q0, q1, #1
1329 vmlal.u8 q13, d0, d31
1330 vmlsl.u8 q13, d18, d30
1331 vext.8 q11, q0, q1, #2
1332 vmlal.u8 q13, d20, d31
1333 vmlsl.u8 q13, d22, d30
1335 vmlsl.u8 q14, d19, d30
1336 vmlal.u8 q14, d1, d31
1337 vmlal.u8 q14, d21, d31
1338 vmlsl.u8 q14, d23, d30
1340 vqrshrun.s16 d6, q13, #5
1341 vqrshrun.s16 d7, q14, #5
1342 vst1.64 {d6-d7}, [r0,:128]!
1348 // frame_init_lowres_core( uint8_t *src0, uint8_t *dst0, uint8_t *dsth, uint8_t *dstv,
1349 // uint8_t *dstc, intptr_t src_stride, intptr_t dst_stride, int width,
1351 function x264_frame_init_lowres_core_neon
1354 ldrd r4, r5, [sp, #96]
1355 ldrd r6, r7, [sp, #104]
1357 sub r10, r6, r7 // dst_stride - width
1363 add r8, r0, r5 // src1 = src0 + src_stride
1364 add r9, r0, r5, lsl #1 // src2 = src1 + src_stride
1366 vld2.8 {d8, d10}, [r6,:128]!
1367 vld2.8 {d12,d14}, [r8,:128]!
1368 vld2.8 {d16,d18}, [r9,:128]!
1373 vld2.8 {d9, d11}, [r6,:128]!
1374 vld2.8 {d13,d15}, [r8,:128]!
1375 vrhadd.u8 q0, q4, q6
1376 vld2.8 {d17,d19}, [r9,:128]!
1377 vrhadd.u8 q5, q5, q7
1378 vld2.8 {d20,d22}, [r6,:128]!
1379 vrhadd.u8 q1, q6, q8
1380 vld2.8 {d24,d26}, [r8,:128]!
1381 vrhadd.u8 q7, q7, q9
1382 vext.8 q4, q4, q10, #1
1383 vrhadd.u8 q0, q0, q5
1384 vext.8 q6, q6, q12, #1
1385 vrhadd.u8 q1, q1, q7
1386 vld2.8 {d28,d30}, [r9,:128]!
1387 vrhadd.u8 q4, q4, q6
1388 vext.8 q8, q8, q14, #1
1389 vrhadd.u8 q6, q6, q8
1390 vst1.64 {d0-d1}, [r1,:128]!
1391 vrhadd.u8 q2, q4, q5
1392 vst1.64 {d2-d3}, [r3,:128]!
1393 vrhadd.u8 q3, q6, q7
1394 vst1.64 {d4-d5}, [r2,:128]!
1395 vst1.64 {d6-d7}, [r4,:128]!
1397 ble lowres_xloop_end
1400 vld2.8 {d21,d23}, [r6,:128]!
1401 vld2.8 {d25,d27}, [r8,:128]!
1402 vrhadd.u8 q0, q10, q12
1403 vld2.8 {d29,d31}, [r9,:128]!
1404 vrhadd.u8 q11, q11, q13
1405 vld2.8 {d8, d10}, [r6,:128]!
1406 vrhadd.u8 q1, q12, q14
1407 vld2.8 {d12,d14}, [r8,:128]!
1408 vrhadd.u8 q13, q13, q15
1409 vext.8 q10, q10, q4, #1
1410 vrhadd.u8 q0, q0, q11
1411 vext.8 q12, q12, q6, #1
1412 vrhadd.u8 q1, q1, q13
1413 vld2.8 {d16,d18}, [r9,:128]!
1414 vrhadd.u8 q10, q10, q12
1415 vext.8 q14, q14, q8, #1
1416 vrhadd.u8 q12, q12, q14
1417 vst1.64 {d0-d1}, [r1,:128]!
1418 vrhadd.u8 q2, q10, q11
1419 vst1.64 {d2-d3}, [r3,:128]!
1420 vrhadd.u8 q3, q12, q13
1421 vst1.64 {d4-d5}, [r2,:128]!
1422 vst1.64 {d6-d7}, [r4,:128]!
1428 add r0, r0, r5, lsl #1
1439 function x264_load_deinterleave_chroma_fdec_neon
1440 mov ip, #FDEC_STRIDE/2
1442 vld2.8 {d0-d1}, [r1,:128], r2
1445 vst1.8 {d0}, [r0,:64], ip
1446 vst1.8 {d1}, [r0,:64], ip
1452 function x264_load_deinterleave_chroma_fenc_neon
1453 mov ip, #FENC_STRIDE/2
1455 vld2.8 {d0-d1}, [r1,:128], r2
1458 vst1.8 {d0}, [r0,:64], ip
1459 vst1.8 {d1}, [r0,:64], ip
1465 function x264_plane_copy_neon
1484 vld1.8 {q0, q1}, [r2]!
1485 vst1.8 {q0, q1}, [r0]!
1496 function x264_plane_copy_deinterleave_neon
1498 ldrd r6, r7, [sp, #28]
1499 ldrd r4, r5, [sp, #20]
1504 sub r5, r5, lr, lsl #1
1506 vld2.8 {d0-d3}, [r4,:128]!
1522 function x264_plane_copy_deinterleave_rgb_neon
1523 push {r4-r8, r10, r11, lr}
1524 ldrd r4, r5, [sp, #32]
1525 ldrd r6, r7, [sp, #40]
1527 ldrd r10, r11, [sp, #52]
1531 sub r7, r7, lr, lsl #1
1535 subne r7, r7, lr, lsl #1
1539 vld3.8 {d0,d1,d2}, [r6]!
1554 pop {r4-r8, r10, r11, pc}
1556 vld4.8 {d0,d1,d2,d3}, [r6]!
1571 pop {r4-r8, r10, r11, pc}
1574 function x264_plane_copy_interleave_neon
1576 ldrd r6, r7, [sp, #28]
1577 ldrd r4, r5, [sp, #20]
1580 sub r1, r1, lr, lsl #1
1587 vst2.8 {d0,d2}, [r0]!
1588 vst2.8 {d1,d3}, [r0]!
1601 function x264_plane_copy_swap_neon
1603 ldrd r4, r5, [sp, #12]
1606 sub r1, r1, lr, lsl #1
1607 sub r3, r3, lr, lsl #1
1609 vld1.8 {q0, q1}, [r2]!
1613 vst1.8 {q0, q1}, [r0]!
1625 function x264_store_interleave_chroma_neon
1628 mov ip, #FDEC_STRIDE
1630 vld1.8 {d0}, [r2], ip
1631 vld1.8 {d1}, [r3], ip
1633 vst2.8 {d0,d1}, [r0,:128], r1
1639 .macro integral4h p1, p2
1640 vext.8 d1, \p1, \p2, #1
1641 vext.8 d2, \p1, \p2, #2
1642 vext.8 d3, \p1, \p2, #3
1643 vaddl.u8 q0, \p1, d1
1649 function integral_init4h_neon
1650 sub r3, r0, r2, lsl #1
1651 vld1.8 {d6, d7}, [r1, :128]!
1654 vld1.16 {q2}, [r3, :128]!
1656 vld1.8 {d6}, [r1, :64]!
1657 vld1.16 {q2}, [r3, :128]!
1658 vst1.16 {q0}, [r0, :128]!
1660 vld1.8 {d7}, [r1, :64]!
1661 vst1.16 {q0}, [r0, :128]!
1666 .macro integral8h p1, p2, s
1667 vext.8 d1, \p1, \p2, #1
1668 vext.8 d2, \p1, \p2, #2
1669 vext.8 d3, \p1, \p2, #3
1670 vext.8 d4, \p1, \p2, #4
1671 vext.8 d5, \p1, \p2, #5
1672 vext.8 d6, \p1, \p2, #6
1673 vext.8 d7, \p1, \p2, #7
1674 vaddl.u8 q0, \p1, d1
1684 function integral_init8h_neon
1685 sub r3, r0, r2, lsl #1
1686 vld1.8 {d16, d17}, [r1, :128]!
1689 vld1.16 {q9}, [r3, :128]!
1690 integral8h d16, d17, q9
1691 vld1.8 {d16}, [r1, :64]!
1692 vld1.16 {q9}, [r3, :128]!
1693 vst1.16 {q0}, [r0, :128]!
1694 integral8h d17, d16, q9
1695 vld1.8 {d17}, [r1, :64]!
1696 vst1.16 {q0}, [r0, :128]!
1701 function integral_init4v_neon
1704 add r4, r0, r2, lsl #3
1705 add r5, r0, r2, lsl #4
1707 vld1.16 {q11, q12}, [r3]!
1708 vld1.16 {q8, q9}, [r5]!
1709 vld1.16 {q13}, [r3]!
1710 vld1.16 {q10}, [r5]!
1713 vld1.16 {q14, q15}, [r4]!
1714 vext.8 q0, q11, q12, #8
1715 vext.8 q1, q12, q13, #8
1716 vext.8 q2, q8, q9, #8
1717 vext.8 q3, q9, q10, #8
1718 vsub.u16 q14, q14, q11
1719 vsub.u16 q15, q15, q12
1720 vadd.u16 q0, q0, q11
1721 vadd.u16 q1, q1, q12
1724 vst1.16 {q14}, [r1]!
1725 vst1.16 {q15}, [r1]!
1730 vld1.16 {q12, q13}, [r3]!
1731 vld1.16 {q9, q10}, [r5]!
1740 function integral_init8v_neon
1741 add r2, r0, r1, lsl #4
1743 ands r3, r1, #16 - 1
1753 vld1.16 {q0, q1}, [r0]
1754 vld1.16 {q2, q3}, [r2]!