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 *****************************************************************************/
34 .short 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
38 // note: prefetch stuff assumes 64-byte cacheline, true for the Cortex-A8
39 // They also use nothing above armv5te, but we don't care about pre-armv6
41 // void prefetch_ref( uint8_t *pix, intptr_t stride, int parity )
42 function x264_prefetch_ref_arm
46 add r0, r0, r2, lsl #3
47 add r2, r1, r1, lsl #1
51 add r3, r0, r1, lsl #2
60 // void prefetch_fenc( uint8_t *pix_y, intptr_t stride_y,
61 // uint8_t *pix_uv, intptr_t stride_uv, int mb_x )
62 function x264_prefetch_fenc_arm
66 smulbb lr, lr, r1 // note: this assumes stride_y is <= 16 bits signed
71 add r0, r0, lr, lsl #2
73 add lr, r0, r1, lsl #1
76 add r2, r2, ip, lsl #2
79 add ip, r2, r3, lsl #1
87 // void *x264_memcpy_aligned( void *dst, const void *src, size_t n )
88 function x264_memcpy_aligned_neon
89 orr r3, r0, r1, lsr #1
90 movrel ip, memcpy_table
95 .macro MEMCPY_ALIGNED srcalign dstalign
96 function memcpy_aligned_\dstalign\()_\srcalign\()_neon, export=0
98 .if \srcalign == 8 && \dstalign == 8
100 vld1.64 {d0}, [r1,:64]!
101 vst1.64 {d0}, [r3,:64]!
105 .set r1align, \srcalign * 8
106 .set r3align, \dstalign * 8
111 vld1.64 {d0-d1}, [r1,:r1align]!
112 vst1.64 {d0-d1}, [r3,:r3align]!
113 32: // n is a multiple of 32
117 vld1.64 {d0-d3}, [r1,:r1align]!
118 vst1.64 {d0-d3}, [r3,:r3align]!
119 640: // n is a multiple of 64
124 vld1.64 {d0-d3}, [r1,:r1align]!
125 vld1.64 {d4-d7}, [r1,:r1align]!
126 vst1.64 {d0-d3}, [r3,:r3align]!
127 vst1.64 {d4-d7}, [r3,:r3align]!
130 .if \srcalign == 8 && \dstalign == 8
131 vld1.64 {d0}, [r1,:64]!
132 vst1.64 {d0}, [r3,:64]!
138 MEMCPY_ALIGNED 16, 16
143 const memcpy_table align=2, relocate=1
144 .word memcpy_aligned_16_16_neon
145 .word memcpy_aligned_16_8_neon
146 .word memcpy_aligned_8_16_neon
147 .word memcpy_aligned_8_8_neon
154 // void x264_memzero_aligned( void *dst, size_t n )
155 function x264_memzero_aligned_neon
161 vst1.64 {d0-d3}, [r0,:128]!
168 // void pixel_avg( uint8_t *dst, intptr_t dst_stride,
169 // uint8_t *src1, intptr_t src1_stride,
170 // uint8_t *src2, intptr_t src2_stride, int weight );
172 function x264_pixel_avg_\w\()x\h\()_neon
176 ldrd r4, r5, [sp, #16]
178 beq x264_pixel_avg_w\w\()_neon
180 blt x264_pixel_avg_weight_w\w\()_add_sub_neon // weight > 64
182 bge x264_pixel_avg_weight_w\w\()_add_add_neon
183 b x264_pixel_avg_weight_w\w\()_sub_add_neon // weight < 0
198 .macro load_weights_add_add
203 .macro load_add_add d1 d2
204 vld1.32 {\d1}, [r2], r3
205 vld1.32 {\d2}, [r4], r5
208 .macro weight_add_add dst s1 s2
209 vmull.u8 \dst, \s1, d30
210 vmlal.u8 \dst, \s2, d31
214 .macro load_weights_add_sub
220 .macro load_add_sub d1 d2
221 vld1.32 {\d1}, [r2], r3
222 vld1.32 {\d2}, [r4], r5
225 .macro weight_add_sub dst s1 s2
226 vmull.u8 \dst, \s1, d30
227 vmlsl.u8 \dst, \s2, d31
231 .macro load_weights_sub_add
237 .macro load_sub_add d1 d2
238 vld1.32 {\d2}, [r4], r5
239 vld1.32 {\d1}, [r2], r3
242 .macro weight_sub_add dst s1 s2
243 vmull.u8 \dst, \s2, d31
244 vmlsl.u8 \dst, \s1, d30
247 .macro AVG_WEIGHT ext
248 function x264_pixel_avg_weight_w4_\ext\()_neon, export=0
253 weight_\ext q8, d0, d1
255 vqrshrun.s16 d0, q8, #6
256 weight_\ext q9, d2, d3
257 vst1.32 {d0[0]}, [r0,:32], r1
258 vqrshrun.s16 d1, q9, #6
259 vst1.32 {d1[0]}, [r0,:32], r1
264 function x264_pixel_avg_weight_w8_\ext\()_neon, export=0
269 weight_\ext q8, d0, d1
271 weight_\ext q9, d2, d3
273 weight_\ext q10, d4, d5
275 weight_\ext q11, d6, d7
276 vqrshrun.s16 d0, q8, #6
277 vqrshrun.s16 d1, q9, #6
278 vqrshrun.s16 d2, q10, #6
279 vqrshrun.s16 d3, q11, #6
280 vst1.64 {d0}, [r0,:64], r1
281 vst1.64 {d1}, [r0,:64], r1
282 vst1.64 {d2}, [r0,:64], r1
283 vst1.64 {d3}, [r0,:64], r1
288 function x264_pixel_avg_weight_w16_\ext\()_neon, export=0
292 load_\ext d0-d1, d2-d3
293 weight_\ext q8, d0, d2
294 weight_\ext q9, d1, d3
295 load_\ext d4-d5, d6-d7
296 weight_\ext q10, d4, d6
297 weight_\ext q11, d5, d7
298 vqrshrun.s16 d0, q8, #6
299 vqrshrun.s16 d1, q9, #6
300 vqrshrun.s16 d2, q10, #6
301 vqrshrun.s16 d3, q11, #6
302 vst1.64 {d0-d1}, [r0,:128], r1
303 vst1.64 {d2-d3}, [r0,:128], r1
313 function x264_pixel_avg_w4_neon, export=0
315 vld1.32 {d0[]}, [r2], r3
316 vld1.32 {d2[]}, [r4], r5
318 vld1.32 {d1[]}, [r2], r3
319 vld1.32 {d3[]}, [r4], r5
321 vst1.32 {d0[0]}, [r0,:32], r1
322 vst1.32 {d1[0]}, [r0,:32], r1
323 bgt x264_pixel_avg_w4_neon
327 function x264_pixel_avg_w8_neon, export=0
329 vld1.64 {d0}, [r2], r3
330 vld1.64 {d2}, [r4], r5
332 vld1.64 {d1}, [r2], r3
333 vld1.64 {d3}, [r4], r5
335 vst1.64 {d0}, [r0,:64], r1
336 vld1.64 {d2}, [r2], r3
337 vld1.64 {d4}, [r4], r5
339 vst1.64 {d1}, [r0,:64], r1
340 vld1.64 {d3}, [r2], r3
341 vld1.64 {d5}, [r4], r5
343 vst1.64 {d2}, [r0,:64], r1
344 vst1.64 {d3}, [r0,:64], r1
345 bgt x264_pixel_avg_w8_neon
349 function x264_pixel_avg_w16_neon, export=0
351 vld1.64 {d0-d1}, [r2], r3
352 vld1.64 {d2-d3}, [r4], r5
354 vld1.64 {d2-d3}, [r2], r3
355 vld1.64 {d4-d5}, [r4], r5
357 vst1.64 {d0-d1}, [r0,:128], r1
358 vld1.64 {d4-d5}, [r2], r3
359 vld1.64 {d6-d7}, [r4], r5
361 vst1.64 {d2-d3}, [r0,:128], r1
362 vld1.64 {d6-d7}, [r2], r3
363 vld1.64 {d0-d1}, [r4], r5
365 vst1.64 {d4-d5}, [r0,:128], r1
366 vst1.64 {d6-d7}, [r0,:128], r1
367 bgt x264_pixel_avg_w16_neon
372 function x264_pixel_avg2_w4_neon
378 vld1.32 {d0[]}, [r2], r3
379 vld1.32 {d2[]}, [lr], r3
381 vld1.32 {d1[]}, [r2], r3
382 vld1.32 {d3[]}, [lr], r3
384 vst1.32 {d0[0]}, [r0,:32], r1
385 vst1.32 {d1[0]}, [r0,:32], r1
390 function x264_pixel_avg2_w8_neon
396 vld1.64 {d0}, [r2], r3
397 vld1.64 {d2}, [lr], r3
399 vld1.64 {d1}, [r2], r3
400 vld1.64 {d3}, [lr], r3
402 vst1.64 {d0}, [r0,:64], r1
403 vst1.64 {d1}, [r0,:64], r1
408 function x264_pixel_avg2_w16_neon
414 vld1.64 {d0-d1}, [r2], r3
415 vld1.64 {d2-d3}, [lr], r3
417 vld1.64 {d4-d5}, [r2], r3
418 vld1.64 {d6-d7}, [lr], r3
420 vst1.64 {d0-d1}, [r0,:128], r1
421 vst1.64 {d4-d5}, [r0,:128], r1
426 function x264_pixel_avg2_w20_neon
433 vld1.64 {d0-d2}, [r2], r3
434 vld1.64 {d4-d6}, [lr], r3
437 vld1.64 {d4-d6}, [r2], r3
438 vld1.64 {d16-d18},[lr], r3
440 vst1.64 {d0-d1}, [r0,:128]!
441 vrhadd.u8 d6, d6, d18
442 vst1.32 {d2[0]}, [r0,:32], r1
443 vst1.64 {d4-d5}, [r0,:128]!
444 vst1.32 {d6[0]}, [r0,:32], r1
450 .macro weight_prologue type
452 ldr r4, [sp, #4*3] // weight_t
453 ldr ip, [sp, #4*3+4] // h
455 ldr lr, [r4, #32] // denom
457 ldrd r4, r5, [r4, #32+4] // scale, offset
466 // void mc_weight( uint8_t *src, intptr_t src_stride, uint8_t *dst, intptr_t dst_stride,
467 // const x264_weight_t *weight, int height )
468 function x264_mc_weight_w20_neon
473 vld1.8 {d17-d19}, [r2], r3
474 vmull.u8 q10, d17, d0
475 vmull.u8 q11, d18, d0
476 vld1.8 {d16-d18}, [r2], r3
477 vmull.u8 q12, d16, d0
478 vmull.u8 q13, d17, d0
480 vmull.u8 q14, d19, 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
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
504 function x264_mc_weight_w16_neon
508 vld1.8 {d16-d17}, [r2], r3
509 vld1.8 {d18-d19}, [r2], r3
510 vmull.u8 q10, d16, d0
511 vmull.u8 q11, d17, d0
512 vmull.u8 q12, d18, d0
513 vmull.u8 q13, d19, d0
514 vrshl.s16 q10, q10, q2
515 vrshl.s16 q11, q11, q2
516 vrshl.s16 q12, q12, q2
517 vrshl.s16 q13, q13, q2
518 vadd.s16 q10, q10, q1
519 vadd.s16 q11, q11, q1
520 vadd.s16 q12, q12, q1
521 vadd.s16 q13, q13, q1
526 vst1.8 {d16-d17}, [r0,:128], r1
527 vst1.8 {d18-d19}, [r0,:128], r1
532 function x264_mc_weight_w8_neon
536 vld1.8 {d16}, [r2], r3
537 vld1.8 {d18}, [r2], r3
546 vst1.8 {d16}, [r0,:64], r1
547 vst1.8 {d18}, [r0,:64], r1
552 function x264_mc_weight_w4_neon
556 vld1.32 {d16[0]}, [r2], r3
557 vld1.32 {d16[1]}, [r2], r3
562 vst1.32 {d16[0]}, [r0], r1
563 vst1.32 {d16[1]}, [r0], r1
568 function x264_mc_weight_w20_nodenom_neon
569 weight_prologue nodenom
571 weight20_nodenom_loop:
573 vld1.8 {d26-d28}, [r2], r3
576 vld1.8 {d29-d31}, [r2], r3
583 vmlal.u8 q10, d29, d0
584 vmlal.u8 q11, d30, d0
585 vmlal.u8 q12, d28, d0
591 vst1.8 {d16-d17}, [r0,:128]!
592 vst1.32 {d20[0]}, [r0,:32], r1
593 vst1.8 {d18-d19}, [r0,:128]!
594 vst1.32 {d20[1]}, [r0,:32], r1
595 bgt weight20_nodenom_loop
599 function x264_mc_weight_w16_nodenom_neon
600 weight_prologue nodenom
601 weight16_nodenom_loop:
603 vld1.8 {d16-d17}, [r2], r3
604 vld1.8 {d18-d19}, [r2], r3
609 vmlal.u8 q12, d16, d0
610 vmlal.u8 q13, d17, d0
611 vmlal.u8 q14, d18, d0
612 vmlal.u8 q15, d19, d0
617 vst1.8 {d16-d17}, [r0,:128], r1
618 vst1.8 {d18-d19}, [r0,:128], r1
619 bgt weight16_nodenom_loop
623 function x264_mc_weight_w8_nodenom_neon
624 weight_prologue nodenom
625 weight8_nodenom_loop:
627 vld1.8 {d16}, [r2], r3
628 vld1.8 {d18}, [r2], r3
631 vmlal.u8 q10, d16, d0
632 vmlal.u8 q11, d18, d0
635 vst1.8 {d16}, [r0,:64], r1
636 vst1.8 {d17}, [r0,:64], r1
637 bgt weight8_nodenom_loop
641 function x264_mc_weight_w4_nodenom_neon
642 weight_prologue nodenom
643 weight4_nodenom_loop:
645 vld1.32 {d16[0]}, [r2], r3
646 vld1.32 {d16[1]}, [r2], r3
648 vmlal.u8 q10, d16, d0
650 vst1.32 {d16[0]}, [r0], r1
651 vst1.32 {d16[1]}, [r0], r1
652 bgt weight4_nodenom_loop
656 .macro weight_simple_prologue
658 ldr lr, [sp, #4] // weight_t
659 ldr ip, [sp, #8] // h
660 ldr lr, [lr] // offset
664 .macro weight_simple name op
665 function x264_mc_weight_w20_\name\()_neon
666 weight_simple_prologue
667 weight20_\name\()_loop:
669 vld1.8 {d16-d18}, [r2], r3
670 vld1.8 {d19-d21}, [r2], r3
674 vst1.8 {d16-d18}, [r0,:64], r1
675 vst1.8 {d19-d21}, [r0,:64], r1
676 bgt weight20_\name\()_loop
680 function x264_mc_weight_w16_\name\()_neon
681 weight_simple_prologue
682 weight16_\name\()_loop:
684 vld1.8 {d16-d17}, [r2], r3
685 vld1.8 {d18-d19}, [r2], r3
688 vst1.8 {d16-d17}, [r0,:128], r1
689 vst1.8 {d18-d19}, [r0,:128], r1
690 bgt weight16_\name\()_loop
694 function x264_mc_weight_w8_\name\()_neon
695 weight_simple_prologue
696 weight8_\name\()_loop:
698 vld1.8 {d16}, [r2], r3
699 vld1.8 {d17}, [r2], r3
701 vst1.8 {d16}, [r0,:64], r1
702 vst1.8 {d17}, [r0,:64], r1
703 bgt weight8_\name\()_loop
707 function x264_mc_weight_w4_\name\()_neon
708 weight_simple_prologue
709 weight4_\name\()_loop:
711 vld1.32 {d16[]}, [r2], r3
712 vld1.32 {d17[]}, [r2], r3
714 vst1.32 {d16[0]}, [r0], r1
715 vst1.32 {d17[0]}, [r0], r1
716 bgt weight4_\name\()_loop
721 weight_simple offsetadd, vqadd.u8
722 weight_simple offsetsub, vqsub.u8
725 // void mc_copy( uint8_t *dst, intptr_t dst_stride, uint8_t *src, intptr_t src_stride, int height )
726 function x264_mc_copy_w4_neon
730 vld1.32 {d0[]}, [r2], r3
731 vld1.32 {d1[]}, [r2], r3
732 vld1.32 {d2[]}, [r2], r3
733 vld1.32 {d3[]}, [r2], r3
734 vst1.32 {d0[0]}, [r0,:32], r1
735 vst1.32 {d1[0]}, [r0,:32], r1
736 vst1.32 {d2[0]}, [r0,:32], r1
737 vst1.32 {d3[0]}, [r0,:32], r1
742 function x264_mc_copy_w8_neon
746 vld1.32 {d0}, [r2], r3
747 vld1.32 {d1}, [r2], r3
748 vld1.32 {d2}, [r2], r3
749 vld1.32 {d3}, [r2], r3
750 vst1.32 {d0}, [r0,:64], r1
751 vst1.32 {d1}, [r0,:64], r1
752 vst1.32 {d2}, [r0,:64], r1
753 vst1.32 {d3}, [r0,:64], r1
758 function x264_mc_copy_w16_neon
762 vld1.32 {d0-d1}, [r2], r3
763 vld1.32 {d2-d3}, [r2], r3
764 vld1.32 {d4-d5}, [r2], r3
765 vld1.32 {d6-d7}, [r2], r3
766 vst1.32 {d0-d1}, [r0,:128], r1
767 vst1.32 {d2-d3}, [r0,:128], r1
768 vst1.32 {d4-d5}, [r0,:128], r1
769 vst1.32 {d6-d7}, [r0,:128], r1
774 function x264_mc_copy_w16_aligned_neon
776 copy_w16_aligned_loop:
778 vld1.32 {d0-d1}, [r2,:128], r3
779 vld1.32 {d2-d3}, [r2,:128], r3
780 vld1.32 {d4-d5}, [r2,:128], r3
781 vld1.32 {d6-d7}, [r2,:128], r3
782 vst1.32 {d0-d1}, [r0,:128], r1
783 vst1.32 {d2-d3}, [r0,:128], r1
784 vst1.32 {d4-d5}, [r0,:128], r1
785 vst1.32 {d6-d7}, [r0,:128], r1
786 bgt copy_w16_aligned_loop
791 // void x264_mc_chroma_neon( uint8_t *dst, intptr_t i_dst_stride,
792 // uint8_t *src, intptr_t i_src_stride,
793 // int dx, int dy, int i_width, int i_height );
795 function x264_mc_chroma_neon
798 ldrd r4, r5, [sp, #56]
799 ldrd r6, r7, [sp, #64]
803 add r3, r3, r5, asr #2
818 .macro CHROMA_MC_START r00, r01, r10, r11
820 rsb r7, lr, r6, lsl #3
821 rsb ip, lr, r5, lsl #3
822 sub r5, lr, r5, lsl #3
823 sub r5, r5, r6, lsl #3
827 vld2.8 {\r00-\r01}, [r3], r4
833 vld2.8 {\r10-\r11}, [r3], r4
838 .macro CHROMA_MC width, align
840 CHROMA_MC_START d4, d5, d8, d9
841 vext.8 d6, d4, d6, #1
842 vext.8 d7, d5, d7, #1
843 vext.8 d10, d8, d10, #1
844 vext.8 d11, d9, d11, #1
845 // since the element size varies, there's a different index for the 2nd store
860 1: // height loop, interpolate xy
867 vld2.8 {d4-d5}, [r3], r4
869 vext.8 d6, d4, d6, #1
870 vext.8 d7, d5, d7, #1
872 vadd.i16 d16, d16, d17
873 vadd.i16 d17, d18, d19
883 vld2.8 {d8-d9}, [r3], r4
885 vrshrn.u16 d16, q8, #6
887 vext.8 d10, d8, d10, #1
888 vext.8 d11, d9, d11, #1
890 vadd.i16 d18, d20, d21
891 vadd.i16 d19, d22, d23
896 vrshrn.u16 d18, q9, #6
903 vst1.\align {d16[0]}, [r0,:\align], r2
904 vst1.\align {d16[st2]}, [r1,:\align], r2
905 vst1.\align {d18[0]}, [r0,:\align], r2
906 vst1.\align {d18[st2]}, [r1,:\align], r2
921 vld1.64 {d4}, [r3], r4
922 vld1.64 {d6}, [r3], r4
924 3: // vertical interpolation loop
929 vld1.64 {d4}, [r3], r4
931 vld1.64 {d6}, [r3], r4
933 vrshrn.u16 d16, q8, #6 // uvuvuvuv
934 vrshrn.u16 d17, q9, #6 // uvuvuvuv
936 vuzp.8 d16, d17 // d16=uuuu|uuuu, d17=vvvv|vvvv
941 vst1.\align {d16[0]}, [r0,:\align], r2
942 vst1.\align {d16[st2]}, [r0,:\align], r2
943 vst1.\align {d17[0]}, [r1,:\align], r2
944 vst1.\align {d17[st2]}, [r1,:\align], r2
952 vld1.64 {d4-d5}, [r3], r4
953 vld1.64 {d6-d7}, [r3], r4
955 vext.8 d5, d4, d5, #2
956 vext.8 d7, d6, d7, #2
958 5: // horizontal interpolation loop
966 vld1.64 {d4-d5}, [r3], r4
967 vld1.64 {d6-d7}, [r3], r4
968 vext.8 d5, d4, d5, #2
969 vrshrn.u16 d16, q8, #6
970 vrshrn.u16 d17, q9, #6
971 vext.8 d7, d6, d7, #2
977 vst1.\align {d16[0]}, [r0,:\align], r2
978 vst1.\align {d16[st2]}, [r0,:\align], r2
979 vst1.\align {d17[0]}, [r1,:\align], r2
980 vst1.\align {d17[st2]}, [r1,:\align], r2
991 CHROMA_MC_START d4, d7, d8, d11
992 vext.8 d5, d4, d5, #1
993 vext.8 d9, d8, d9, #1
994 vext.8 d7, d6, d7, #1
995 vext.8 d11, d10, d11, #1
997 1: // height loop, interpolate xy
1005 vmlal.u8 q9, d10, d2
1006 vmlal.u8 q9, d11, d3
1008 vld2.8 {d4-d7}, [r3], r4
1010 vext.8 d5, d4, d5, #1
1011 vext.8 d7, d6, d7, #1
1013 vmull.u8 q10, d8, d0
1014 vmlal.u8 q10, d9, d1
1015 vmlal.u8 q10, d4, d2
1016 vmlal.u8 q10, d5, d3
1018 vmull.u8 q11, d10, d0
1019 vmlal.u8 q11, d11, d1
1020 vmlal.u8 q11, d6, d2
1021 vmlal.u8 q11, d7, d3
1024 vld2.8 {d8-d11}, [r3], r4
1026 vrshrn.u16 d16, q8, #6
1027 vrshrn.u16 d17, q9, #6
1028 vrshrn.u16 d18, q10, #6
1029 vext.8 d9, d8, d9, #1
1030 vrshrn.u16 d19, q11, #6
1031 vext.8 d11, d10, d11, #1
1036 vst1.64 {d16}, [r0,:64], r2
1037 vst1.64 {d17}, [r1,:64], r2
1038 vst1.64 {d18}, [r0,:64], r2
1039 vst1.64 {d19}, [r1,:64], r2
1046 2: // dx or dy are 0
1055 vld2.8 {d4-d5}, [r3], r4
1056 vld2.8 {d6-d7}, [r3], r4
1058 3: // vertical interpolation loop
1059 vmull.u8 q8, d4, d0 //U
1061 vmull.u8 q9, d5, d0 //V
1064 vld2.8 {d4-d5}, [r3], r4
1066 vmull.u8 q10, d6, d0
1067 vmlal.u8 q10, d4, d1
1068 vmull.u8 q11, d7, d0
1069 vmlal.u8 q11, d5, d1
1071 vld2.8 {d6-d7}, [r3], r4
1073 vrshrn.u16 d16, q8, #6
1074 vrshrn.u16 d17, q9, #6
1075 vrshrn.u16 d18, q10, #6
1076 vrshrn.u16 d19, q11, #6
1082 vst1.64 {d16}, [r0,:64], r2
1083 vst1.64 {d17}, [r1,:64], r2
1084 vst1.64 {d18}, [r0,:64], r2
1085 vst1.64 {d19}, [r1,:64], r2
1094 vld2.8 {d4-d7}, [r3], r4
1095 vld2.8 {d8-d11}, [r3], r4
1096 vext.8 d5, d4, d5, #1
1097 vext.8 d7, d6, d7, #1
1098 vext.8 d9, d8, d9, #1
1099 vext.8 d11, d10, d11, #1
1101 5: // horizontal interpolation loop
1103 vmull.u8 q8, d4, d0 //U
1105 vmull.u8 q9, d6, d0 //V
1108 vld2.8 {d4-d7}, [r3], r4
1110 vmull.u8 q10, d8, d0
1111 vmlal.u8 q10, d9, d1
1112 vmull.u8 q11, d10, d0
1113 vmlal.u8 q11, d11, d1
1115 vld2.8 {d8-d11}, [r3], r4
1117 vext.8 d5, d4, d5, #1
1118 vrshrn.u16 d16, q8, #6
1119 vext.8 d7, d6, d7, #1
1120 vrshrn.u16 d17, q9, #6
1121 vext.8 d9, d8, d9, #1
1122 vrshrn.u16 d18, q10, #6
1123 vext.8 d11, d10, d11, #1
1124 vrshrn.u16 d19, q11, #6
1129 vst1.64 {d16}, [r0,:64], r2
1130 vst1.64 {d17}, [r1,:64], r2
1131 vst1.64 {d18}, [r0,:64], r2
1132 vst1.64 {d19}, [r1,:64], r2
1141 // hpel_filter_v( uint8_t *dst, uint8_t *src, int16_t *buf, intptr_t stride, int width )
1142 function x264_hpel_filter_v_neon
1144 sub r1, r1, r3, lsl #1
1152 vld1.64 {d0-d1}, [r1,:128], r3
1153 vld1.64 {d2-d3}, [r1,:128], r3
1154 vld1.64 {d4-d5}, [r1,:128], r3
1155 vld1.64 {d6-d7}, [r1,:128], r3
1156 vld1.64 {d16-d17}, [r1,:128], r3
1157 vld1.64 {d18-d19}, [r1,:128], r3
1160 vaddl.u8 q10, d0, d18
1161 vmlsl.u8 q10, d2, d30
1162 vmlal.u8 q10, d4, d31
1163 vmlal.u8 q10, d6, d31
1164 vmlsl.u8 q10, d16, d30
1166 vaddl.u8 q11, d1, d19
1167 vmlsl.u8 q11, d3, d30
1168 vmlal.u8 q11, d5, d31
1169 vmlal.u8 q11, d7, d31
1170 vmlsl.u8 q11, d17, d30
1172 vqrshrun.s16 d0, q10, #5
1173 vst1.64 {d20-d21}, [r2,:128]!
1174 vqrshrun.s16 d1, q11, #5
1175 vst1.64 {d22-d23}, [r2,:128]!
1176 vst1.64 {d0-d1}, [r0,:128]!
1181 // hpel_filter_c( uint8_t *dst, int16_t *buf, int width );
1182 function x264_hpel_filter_c_neon
1184 vld1.64 {d0-d3}, [r1,:128]!
1186 // unrolled 2x: 4% faster
1189 vld1.64 {d4-d7}, [r1,:128]!
1190 vext.16 q8, q0, q1, #6
1191 vext.16 q12, q1, q2, #3
1192 vadd.s16 q8, q8, q12
1193 vext.16 q9, q0, q1, #7
1194 vext.16 q11, q1, q2, #2
1195 vadd.s16 q9, q9, q11
1196 vext.16 q10, q1, q2, #1
1197 vext.16 q11, q1, q2, #6
1198 vadd.s16 q10, q1, q10
1199 vsub.s16 q8, q8, q9 // a-b
1200 vext.16 q15, q2, q3, #3
1201 vsub.s16 q9, q9, q10 // b-c
1203 vext.16 q12, q1, q2, #7
1204 vshr.s16 q8, q8, #2 // (a-b)/4
1205 vadd.s16 q11, q11, q15
1206 vext.16 q14, q2, q3, #2
1207 vsub.s16 q8, q8, q9 // (a-b)/4-b+c
1208 vadd.s16 q12, q12, q14
1209 vext.16 q13, q2, q3, #1
1211 vshr.s16 q8, q8, #2 // ((a-b)/4-b+c)/4
1212 vadd.s16 q13, q2, q13
1213 vadd.s16 q8, q8, q10 // ((a-b)/4-b+c)/4+c = (a-5*b+20*c)/16
1214 vsub.s16 q11, q11, q12 // a-b
1215 vsub.s16 q12, q12, q13 // b-c
1216 vshr.s16 q11, q11, #2 // (a-b)/4
1217 vqrshrun.s16 d30, q8, #6
1218 vsub.s16 q11, q11, q12 // (a-b)/4-b+c
1219 vshr.s16 q11, q11, #2 // ((a-b)/4-b+c)/4
1220 vld1.64 {d0-d3}, [r1,:128]!
1221 vadd.s16 q11, q11, q13 // ((a-b)/4-b+c)/4+c = (a-5*b+20*c)/16
1223 vext.16 q8, q2, q3, #6
1224 vqrshrun.s16 d31, q11, #6
1225 vext.16 q12, q3, q0, #3
1226 vadd.s16 q8, q8, q12
1227 vext.16 q9, q2, q3, #7
1228 vst1.64 {d30-d31}, [r0,:128]!
1232 vext.16 q11, q3, q0, #2
1233 vadd.s16 q9, q9, q11
1234 vext.16 q10, q3, q0, #1
1235 vext.16 q11, q3, q0, #6
1236 vadd.s16 q10, q3, q10
1237 vsub.s16 q8, q8, q9 // a-b
1238 vext.16 q15, q0, q1, #3
1239 vsub.s16 q9, q9, q10 // b-c
1241 vext.16 q12, q3, q0, #7
1242 vshr.s16 q8, q8, #2 // (a-b)/4
1243 vadd.s16 q11, q11, q15
1244 vext.16 q14, q0, q1, #2
1245 vsub.s16 q8, q8, q9 // (a-b)/4-b+c
1246 vadd.s16 q12, q12, q14
1247 vext.16 q13, q0, q1, #1
1249 vshr.s16 q8, q8, #2 // ((a-b)/4-b+c)/4
1250 vadd.s16 q13, q0, q13
1251 vadd.s16 q8, q8, q10 // ((a-b)/4-b+c)/4+c = (a-5*b+20*c)/16
1252 vsub.s16 q11, q11, q12 // a-b
1253 vsub.s16 q12, q12, q13 // b-c
1254 vshr.s16 q11, q11, #2 // (a-b)/4
1255 vqrshrun.s16 d30, q8, #6
1256 vsub.s16 q11, q11, q12 // (a-b)/4-b+c
1257 vshr.s16 q11, q11, #2 // ((a-b)/4-b+c)/4
1258 vadd.s16 q11, q11, q13 // ((a-b)/4-b+c)/4+c = (a-5*b+20*c)/16
1260 vqrshrun.s16 d31, q11, #6
1261 vst1.64 {d30-d31}, [r0,:128]!
1266 // hpel_filter_h( uint8_t *dst, uint8_t *src, int width );
1267 function x264_hpel_filter_h_neon
1270 vld1.64 {d0-d3}, [r1,:128]!
1273 // unrolled 3x because it's 5% faster, due to mitigating
1274 // the high latency of multiplication and vqrshrun
1277 vld1.64 {d4-d5}, [r1,:128]!
1278 vext.8 q8, q0, q1, #14
1279 vext.8 q12, q1, q2, #3
1280 vaddl.u8 q13, d16, d24
1281 vext.8 q9, q0, q1, #15
1282 vaddl.u8 q14, d17, d25
1284 vext.8 q10, q1, q2, #1
1285 vmlal.u8 q13, d2, d31
1286 vmlsl.u8 q13, d18, d30
1287 vext.8 q11, q1, q2, #2
1288 vmlal.u8 q13, d20, d31
1289 vmlsl.u8 q13, d22, d30
1291 vmlsl.u8 q14, d19, d30
1292 vmlal.u8 q14, d3, d31
1293 vmlal.u8 q14, d21, d31
1294 vmlsl.u8 q14, d23, d30
1295 vqrshrun.s16 d6, q13, #5
1297 vld1.64 {d0-d1}, [r1,:128]!
1298 vext.8 q8, q1, q2, #14
1299 vext.8 q12, q2, q0, #3
1300 vaddl.u8 q13, d16, d24
1301 vqrshrun.s16 d7, q14, #5
1302 vext.8 q9, q1, q2, #15
1303 vaddl.u8 q14, d17, d25
1305 vst1.64 {d6-d7}, [r0,:128]!
1309 vext.8 q10, q2, q0, #1
1310 vmlal.u8 q13, d4, d31
1311 vmlsl.u8 q13, d18, d30
1312 vext.8 q11, q2, q0, #2
1313 vmlal.u8 q13, d20, d31
1314 vmlsl.u8 q13, d22, d30
1316 vmlsl.u8 q14, d19, d30
1317 vmlal.u8 q14, d5, d31
1318 vmlal.u8 q14, d21, d31
1319 vmlsl.u8 q14, d23, d30
1320 vqrshrun.s16 d6, q13, #5
1322 vld1.64 {d2-d3}, [r1,:128]!
1323 vext.8 q8, q2, q0, #14
1324 vext.8 q12, q0, q1, #3
1325 vaddl.u8 q13, d16, d24
1326 vqrshrun.s16 d7, q14, #5
1327 vext.8 q9, q2, q0, #15
1328 vaddl.u8 q14, d17, d25
1330 vst1.64 {d6-d7}, [r0,:128]!
1334 vext.8 q10, q0, q1, #1
1335 vmlal.u8 q13, d0, d31
1336 vmlsl.u8 q13, d18, d30
1337 vext.8 q11, q0, q1, #2
1338 vmlal.u8 q13, d20, d31
1339 vmlsl.u8 q13, d22, d30
1341 vmlsl.u8 q14, d19, d30
1342 vmlal.u8 q14, d1, d31
1343 vmlal.u8 q14, d21, d31
1344 vmlsl.u8 q14, d23, d30
1346 vqrshrun.s16 d6, q13, #5
1347 vqrshrun.s16 d7, q14, #5
1348 vst1.64 {d6-d7}, [r0,:128]!
1354 // frame_init_lowres_core( uint8_t *src0, uint8_t *dst0, uint8_t *dsth, uint8_t *dstv,
1355 // uint8_t *dstc, intptr_t src_stride, intptr_t dst_stride, int width,
1357 function x264_frame_init_lowres_core_neon
1360 ldrd r4, r5, [sp, #96]
1361 ldrd r6, r7, [sp, #104]
1363 sub r10, r6, r7 // dst_stride - width
1369 add r8, r0, r5 // src1 = src0 + src_stride
1370 add r9, r0, r5, lsl #1 // src2 = src1 + src_stride
1372 vld2.8 {d8, d10}, [r6,:128]!
1373 vld2.8 {d12,d14}, [r8,:128]!
1374 vld2.8 {d16,d18}, [r9,:128]!
1379 vld2.8 {d9, d11}, [r6,:128]!
1380 vld2.8 {d13,d15}, [r8,:128]!
1381 vrhadd.u8 q0, q4, q6
1382 vld2.8 {d17,d19}, [r9,:128]!
1383 vrhadd.u8 q5, q5, q7
1384 vld2.8 {d20,d22}, [r6,:128]!
1385 vrhadd.u8 q1, q6, q8
1386 vld2.8 {d24,d26}, [r8,:128]!
1387 vrhadd.u8 q7, q7, q9
1388 vext.8 q4, q4, q10, #1
1389 vrhadd.u8 q0, q0, q5
1390 vext.8 q6, q6, q12, #1
1391 vrhadd.u8 q1, q1, q7
1392 vld2.8 {d28,d30}, [r9,:128]!
1393 vrhadd.u8 q4, q4, q6
1394 vext.8 q8, q8, q14, #1
1395 vrhadd.u8 q6, q6, q8
1396 vst1.64 {d0-d1}, [r1,:128]!
1397 vrhadd.u8 q2, q4, q5
1398 vst1.64 {d2-d3}, [r3,:128]!
1399 vrhadd.u8 q3, q6, q7
1400 vst1.64 {d4-d5}, [r2,:128]!
1401 vst1.64 {d6-d7}, [r4,:128]!
1403 ble lowres_xloop_end
1406 vld2.8 {d21,d23}, [r6,:128]!
1407 vld2.8 {d25,d27}, [r8,:128]!
1408 vrhadd.u8 q0, q10, q12
1409 vld2.8 {d29,d31}, [r9,:128]!
1410 vrhadd.u8 q11, q11, q13
1411 vld2.8 {d8, d10}, [r6,:128]!
1412 vrhadd.u8 q1, q12, q14
1413 vld2.8 {d12,d14}, [r8,:128]!
1414 vrhadd.u8 q13, q13, q15
1415 vext.8 q10, q10, q4, #1
1416 vrhadd.u8 q0, q0, q11
1417 vext.8 q12, q12, q6, #1
1418 vrhadd.u8 q1, q1, q13
1419 vld2.8 {d16,d18}, [r9,:128]!
1420 vrhadd.u8 q10, q10, q12
1421 vext.8 q14, q14, q8, #1
1422 vrhadd.u8 q12, q12, q14
1423 vst1.64 {d0-d1}, [r1,:128]!
1424 vrhadd.u8 q2, q10, q11
1425 vst1.64 {d2-d3}, [r3,:128]!
1426 vrhadd.u8 q3, q12, q13
1427 vst1.64 {d4-d5}, [r2,:128]!
1428 vst1.64 {d6-d7}, [r4,:128]!
1434 add r0, r0, r5, lsl #1
1445 function x264_load_deinterleave_chroma_fdec_neon
1446 mov ip, #FDEC_STRIDE/2
1448 vld2.8 {d0-d1}, [r1,:128], r2
1451 vst1.8 {d0}, [r0,:64], ip
1452 vst1.8 {d1}, [r0,:64], ip
1458 function x264_load_deinterleave_chroma_fenc_neon
1459 mov ip, #FENC_STRIDE/2
1461 vld2.8 {d0-d1}, [r1,:128], r2
1464 vst1.8 {d0}, [r0,:64], ip
1465 vst1.8 {d1}, [r0,:64], ip
1471 function x264_plane_copy_neon
1490 vld1.8 {q0, q1}, [r2]!
1491 vst1.8 {q0, q1}, [r0]!
1502 function x264_plane_copy_deinterleave_neon
1504 ldrd r6, r7, [sp, #28]
1505 ldrd r4, r5, [sp, #20]
1510 sub r5, r5, lr, lsl #1
1512 vld2.8 {d0-d3}, [r4,:128]!
1528 function x264_plane_copy_deinterleave_rgb_neon
1529 push {r4-r8, r10, r11, lr}
1530 ldrd r4, r5, [sp, #32]
1531 ldrd r6, r7, [sp, #40]
1533 ldrd r10, r11, [sp, #52]
1537 sub r7, r7, lr, lsl #1
1541 subne r7, r7, lr, lsl #1
1545 vld3.8 {d0,d1,d2}, [r6]!
1560 pop {r4-r8, r10, r11, pc}
1562 vld4.8 {d0,d1,d2,d3}, [r6]!
1577 pop {r4-r8, r10, r11, pc}
1580 function x264_plane_copy_interleave_neon
1582 ldrd r6, r7, [sp, #28]
1583 ldrd r4, r5, [sp, #20]
1586 sub r1, r1, lr, lsl #1
1593 vst2.8 {d0,d2}, [r0]!
1594 vst2.8 {d1,d3}, [r0]!
1607 function x264_plane_copy_swap_neon
1609 ldrd r4, r5, [sp, #12]
1612 sub r1, r1, lr, lsl #1
1613 sub r3, r3, lr, lsl #1
1615 vld1.8 {q0, q1}, [r2]!
1619 vst1.8 {q0, q1}, [r0]!
1631 function x264_store_interleave_chroma_neon
1634 mov ip, #FDEC_STRIDE
1636 vld1.8 {d0}, [r2], ip
1637 vld1.8 {d1}, [r3], ip
1639 vst2.8 {d0,d1}, [r0,:128], r1
1645 .macro integral4h p1, p2
1646 vext.8 d1, \p1, \p2, #1
1647 vext.8 d2, \p1, \p2, #2
1648 vext.8 d3, \p1, \p2, #3
1649 vaddl.u8 q0, \p1, d1
1655 function integral_init4h_neon
1656 sub r3, r0, r2, lsl #1
1657 vld1.8 {d6, d7}, [r1, :128]!
1660 vld1.16 {q2}, [r3, :128]!
1662 vld1.8 {d6}, [r1, :64]!
1663 vld1.16 {q2}, [r3, :128]!
1664 vst1.16 {q0}, [r0, :128]!
1666 vld1.8 {d7}, [r1, :64]!
1667 vst1.16 {q0}, [r0, :128]!
1672 .macro integral8h p1, p2, s
1673 vext.8 d1, \p1, \p2, #1
1674 vext.8 d2, \p1, \p2, #2
1675 vext.8 d3, \p1, \p2, #3
1676 vext.8 d4, \p1, \p2, #4
1677 vext.8 d5, \p1, \p2, #5
1678 vext.8 d6, \p1, \p2, #6
1679 vext.8 d7, \p1, \p2, #7
1680 vaddl.u8 q0, \p1, d1
1690 function integral_init8h_neon
1691 sub r3, r0, r2, lsl #1
1692 vld1.8 {d16, d17}, [r1, :128]!
1695 vld1.16 {q9}, [r3, :128]!
1696 integral8h d16, d17, q9
1697 vld1.8 {d16}, [r1, :64]!
1698 vld1.16 {q9}, [r3, :128]!
1699 vst1.16 {q0}, [r0, :128]!
1700 integral8h d17, d16, q9
1701 vld1.8 {d17}, [r1, :64]!
1702 vst1.16 {q0}, [r0, :128]!
1707 function integral_init4v_neon
1710 add r4, r0, r2, lsl #3
1711 add r5, r0, r2, lsl #4
1713 vld1.16 {q11, q12}, [r3]!
1714 vld1.16 {q8, q9}, [r5]!
1715 vld1.16 {q13}, [r3]!
1716 vld1.16 {q10}, [r5]!
1719 vld1.16 {q14, q15}, [r4]!
1720 vext.8 q0, q11, q12, #8
1721 vext.8 q1, q12, q13, #8
1722 vext.8 q2, q8, q9, #8
1723 vext.8 q3, q9, q10, #8
1724 vsub.u16 q14, q14, q11
1725 vsub.u16 q15, q15, q12
1726 vadd.u16 q0, q0, q11
1727 vadd.u16 q1, q1, q12
1730 vst1.16 {q14}, [r1]!
1731 vst1.16 {q15}, [r1]!
1736 vld1.16 {q12, q13}, [r3]!
1737 vld1.16 {q9, q10}, [r5]!
1746 function integral_init8v_neon
1747 add r2, r0, r1, lsl #4
1749 ands r3, r1, #16 - 1
1759 vld1.16 {q0, q1}, [r0]
1760 vld1.16 {q2, q3}, [r2]!
1770 function x264_mbtree_propagate_cost_neon
1772 ldrd r4, r5, [sp, #12]
1774 vld1.32 {d6[], d7[]}, [r5]
1779 vld1.16 {q10}, [r3]!
1780 vld1.16 {q11}, [r4]!
1781 vbic.u16 q10, #0xc000
1782 vmin.u16 q10, q9, q10
1783 vmull.u16 q12, d18, d22 @ propagate_intra
1784 vmull.u16 q13, d19, d23 @ propagate_intra
1785 vsubl.u16 q14, d18, d20 @ propagate_num
1786 vsubl.u16 q15, d19, d21 @ propagate_num
1787 vmovl.u16 q10, d18 @ propagate_denom
1788 vmovl.u16 q11, d19 @ propagate_denom
1791 vcvt.f32.s32 q12, q12
1792 vcvt.f32.s32 q13, q13
1793 vcvt.f32.s32 q14, q14
1794 vcvt.f32.s32 q15, q15
1795 vcvt.f32.s32 q10, q10
1796 vcvt.f32.s32 q11, q11
1801 vrecps.f32 q10, q0, q10
1802 vrecps.f32 q11, q1, q11
1803 vmla.f32 q8, q12, q3 @ propagate_amount
1804 vmla.f32 q9, q13, q3 @ propagate_amount
1805 vmul.f32 q0, q0, q10
1806 vmul.f32 q1, q1, q11
1807 vmul.f32 q8, q8, q14
1808 vmul.f32 q9, q9, q15
1820 function x264_mbtree_propagate_list_internal_neon
1821 vld2.16 {d4[], d5[]}, [sp] @ bipred_weight, mb_y
1822 movrel r12, pw_0to15
1823 vmov.u16 q10, #0xc000
1824 vld1.16 {q0}, [r12, :128] @h->mb.i_mb_x,h->mb.i_mb_y
1827 vdup.u16 q8, d5[0] @ mb_y
1832 vld1.16 {q14}, [r1, :128]! @ propagate_amount
1833 vld1.16 {q15}, [r2]! @ lowres_cost
1834 vld1.16 {q8, q9}, [r0]!
1836 vceq.u16 q1, q15, q10
1837 vmull.u16 q12, d28, d4
1838 vmull.u16 q13, d29, d4
1839 vrshrn.u32 d30, q12, #6
1840 vrshrn.u32 d31, q13, #6
1841 vbsl q1, q15, q14 @ if( lists_used == 3 )
1842 @ propagate_amount = (propagate_amount * bipred_weight + 32) >> 6
1843 vshr.s16 q12, q8, #5
1844 vshr.s16 q13, q9, #5
1845 vuzp.16 q8, q9 @ x & 31, y & 31
1846 vadd.s16 q12, q12, q0
1847 vadd.s16 q0, q0, q11
1850 vadd.s16 q13, q13, q0
1851 vbic.i16 q8, #128+64+32
1852 vadd.s16 q0, q0, q11
1853 vbic.i16 q8, #(128+64+32)<<8
1854 vst1.16 {q12, q13}, [r3, :128]!
1856 vmull.u8 q12, d17, d16 @ idx3weight = y*x
1857 vmull.u8 q14, d19, d16 @ idx1weight = (32-y)*x
1858 vmull.u8 q15, d19, d18 @ idx0weight = (32-y)*(32-x)
1859 vmull.u8 q13, d17, d18 @ idx2weight = y*(32-x)
1860 vmull.u16 q9, d28, d2 @ idx1weight
1861 vmull.u16 q8, d29, d3
1862 vmull.u16 q14, d30, d2 @ idx0weight
1863 vmull.u16 q15, d31, d3
1864 vrshrn.u32 d18, q9, #10 @ idx1weight
1865 vrshrn.u32 d19, q8, #10
1866 vrshrn.u32 d16, q14, #10 @ idx0weight
1867 vrshrn.u32 d17, q15, #10
1868 vmull.u16 q14, d24, d2 @ idx3weight
1869 vmull.u16 q15, d25, d3
1871 vmull.u16 q12, d26, d2 @ idx2weight
1872 vmull.u16 q13, d27, d3
1873 vst1.16 {q8, q9}, [r3, :128]!
1874 vrshrn.u32 d19, q15, #10 @ idx3weight
1875 vrshrn.u32 d18, q14, #10
1876 vrshrn.u32 d16, q12, #10 @ idx2weight
1877 vrshrn.u32 d17, q13, #10
1879 vst1.16 {q8, q9}, [r3, :128]!