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
145 .word memcpy_aligned_16_16_neon
146 .word memcpy_aligned_16_8_neon
147 .word memcpy_aligned_8_16_neon
148 .word memcpy_aligned_8_8_neon
153 // void x264_memzero_aligned( void *dst, size_t n )
154 function x264_memzero_aligned_neon
160 vst1.64 {d0-d3}, [r0,:128]!
167 // void pixel_avg( uint8_t *dst, intptr_t dst_stride,
168 // uint8_t *src1, intptr_t src1_stride,
169 // uint8_t *src2, intptr_t src2_stride, int weight );
171 function x264_pixel_avg_\w\()x\h\()_neon
175 ldrd r4, r5, [sp, #16]
177 beq x264_pixel_avg_w\w\()_neon
179 blt x264_pixel_avg_weight_w\w\()_add_sub_neon // weight > 64
181 bge x264_pixel_avg_weight_w\w\()_add_add_neon
182 b x264_pixel_avg_weight_w\w\()_sub_add_neon // weight < 0
197 .macro load_weights_add_add
202 .macro load_add_add d1 d2
203 vld1.32 {\d1}, [r2], r3
204 vld1.32 {\d2}, [r4], r5
207 .macro weight_add_add dst s1 s2
208 vmull.u8 \dst, \s1, d30
209 vmlal.u8 \dst, \s2, d31
213 .macro load_weights_add_sub
219 .macro load_add_sub d1 d2
220 vld1.32 {\d1}, [r2], r3
221 vld1.32 {\d2}, [r4], r5
224 .macro weight_add_sub dst s1 s2
225 vmull.u8 \dst, \s1, d30
226 vmlsl.u8 \dst, \s2, d31
230 .macro load_weights_sub_add
236 .macro load_sub_add d1 d2
237 vld1.32 {\d2}, [r4], r5
238 vld1.32 {\d1}, [r2], r3
241 .macro weight_sub_add dst s1 s2
242 vmull.u8 \dst, \s2, d31
243 vmlsl.u8 \dst, \s1, d30
246 .macro AVG_WEIGHT ext
247 function x264_pixel_avg_weight_w4_\ext\()_neon, export=0
252 weight_\ext q8, d0, d1
254 vqrshrun.s16 d0, q8, #6
255 weight_\ext q9, d2, d3
256 vst1.32 {d0[0]}, [r0,:32], r1
257 vqrshrun.s16 d1, q9, #6
258 vst1.32 {d1[0]}, [r0,:32], r1
263 function x264_pixel_avg_weight_w8_\ext\()_neon, export=0
268 weight_\ext q8, d0, d1
270 weight_\ext q9, d2, d3
272 weight_\ext q10, d4, d5
274 weight_\ext q11, d6, d7
275 vqrshrun.s16 d0, q8, #6
276 vqrshrun.s16 d1, q9, #6
277 vqrshrun.s16 d2, q10, #6
278 vqrshrun.s16 d3, q11, #6
279 vst1.64 {d0}, [r0,:64], r1
280 vst1.64 {d1}, [r0,:64], r1
281 vst1.64 {d2}, [r0,:64], r1
282 vst1.64 {d3}, [r0,:64], r1
287 function x264_pixel_avg_weight_w16_\ext\()_neon, export=0
291 load_\ext d0-d1, d2-d3
292 weight_\ext q8, d0, d2
293 weight_\ext q9, d1, d3
294 load_\ext d4-d5, d6-d7
295 weight_\ext q10, d4, d6
296 weight_\ext q11, d5, d7
297 vqrshrun.s16 d0, q8, #6
298 vqrshrun.s16 d1, q9, #6
299 vqrshrun.s16 d2, q10, #6
300 vqrshrun.s16 d3, q11, #6
301 vst1.64 {d0-d1}, [r0,:128], r1
302 vst1.64 {d2-d3}, [r0,:128], r1
312 function x264_pixel_avg_w4_neon, export=0
314 vld1.32 {d0[]}, [r2], r3
315 vld1.32 {d2[]}, [r4], r5
317 vld1.32 {d1[]}, [r2], r3
318 vld1.32 {d3[]}, [r4], r5
320 vst1.32 {d0[0]}, [r0,:32], r1
321 vst1.32 {d1[0]}, [r0,:32], r1
322 bgt x264_pixel_avg_w4_neon
326 function x264_pixel_avg_w8_neon, export=0
328 vld1.64 {d0}, [r2], r3
329 vld1.64 {d2}, [r4], r5
331 vld1.64 {d1}, [r2], r3
332 vld1.64 {d3}, [r4], r5
334 vst1.64 {d0}, [r0,:64], r1
335 vld1.64 {d2}, [r2], r3
336 vld1.64 {d4}, [r4], r5
338 vst1.64 {d1}, [r0,:64], r1
339 vld1.64 {d3}, [r2], r3
340 vld1.64 {d5}, [r4], r5
342 vst1.64 {d2}, [r0,:64], r1
343 vst1.64 {d3}, [r0,:64], r1
344 bgt x264_pixel_avg_w8_neon
348 function x264_pixel_avg_w16_neon, export=0
350 vld1.64 {d0-d1}, [r2], r3
351 vld1.64 {d2-d3}, [r4], r5
353 vld1.64 {d2-d3}, [r2], r3
354 vld1.64 {d4-d5}, [r4], r5
356 vst1.64 {d0-d1}, [r0,:128], r1
357 vld1.64 {d4-d5}, [r2], r3
358 vld1.64 {d6-d7}, [r4], r5
360 vst1.64 {d2-d3}, [r0,:128], r1
361 vld1.64 {d6-d7}, [r2], r3
362 vld1.64 {d0-d1}, [r4], r5
364 vst1.64 {d4-d5}, [r0,:128], r1
365 vst1.64 {d6-d7}, [r0,:128], r1
366 bgt x264_pixel_avg_w16_neon
371 function x264_pixel_avg2_w4_neon
377 vld1.32 {d0[]}, [r2], r3
378 vld1.32 {d2[]}, [lr], r3
380 vld1.32 {d1[]}, [r2], r3
381 vld1.32 {d3[]}, [lr], r3
383 vst1.32 {d0[0]}, [r0,:32], r1
384 vst1.32 {d1[0]}, [r0,:32], r1
389 function x264_pixel_avg2_w8_neon
395 vld1.64 {d0}, [r2], r3
396 vld1.64 {d2}, [lr], r3
398 vld1.64 {d1}, [r2], r3
399 vld1.64 {d3}, [lr], r3
401 vst1.64 {d0}, [r0,:64], r1
402 vst1.64 {d1}, [r0,:64], r1
407 function x264_pixel_avg2_w16_neon
413 vld1.64 {d0-d1}, [r2], r3
414 vld1.64 {d2-d3}, [lr], r3
416 vld1.64 {d4-d5}, [r2], r3
417 vld1.64 {d6-d7}, [lr], r3
419 vst1.64 {d0-d1}, [r0,:128], r1
420 vst1.64 {d4-d5}, [r0,:128], r1
425 function x264_pixel_avg2_w20_neon
432 vld1.64 {d0-d2}, [r2], r3
433 vld1.64 {d4-d6}, [lr], r3
436 vld1.64 {d4-d6}, [r2], r3
437 vld1.64 {d16-d18},[lr], r3
439 vst1.64 {d0-d1}, [r0,:128]!
440 vrhadd.u8 d6, d6, d18
441 vst1.32 {d2[0]}, [r0,:32], r1
442 vst1.64 {d4-d5}, [r0,:128]!
443 vst1.32 {d6[0]}, [r0,:32], r1
449 .macro weight_prologue type
451 ldr r4, [sp, #4*3] // weight_t
452 ldr ip, [sp, #4*3+4] // h
454 ldr lr, [r4, #32] // denom
456 ldrd r4, r5, [r4, #32+4] // scale, offset
465 // void mc_weight( uint8_t *src, intptr_t src_stride, uint8_t *dst, intptr_t dst_stride,
466 // const x264_weight_t *weight, int height )
467 function x264_mc_weight_w20_neon
472 vld1.8 {d17-d19}, [r2], r3
473 vmull.u8 q10, d17, d0
474 vmull.u8 q11, d18, d0
475 vld1.8 {d16-d18}, [r2], r3
476 vmull.u8 q12, d16, d0
477 vmull.u8 q13, d17, d0
479 vmull.u8 q14, d19, d0
480 vrshl.s16 q10, q10, q2
481 vrshl.s16 q11, q11, q2
482 vrshl.s16 q12, q12, q2
483 vrshl.s16 q13, q13, q2
484 vrshl.s16 q14, q14, q2
485 vadd.s16 q10, q10, q1
486 vadd.s16 q11, q11, q1
487 vadd.s16 q12, q12, q1
488 vadd.s16 q13, q13, q1
489 vadd.s16 q14, q14, q1
495 vst1.8 {d16-d17}, [r0,:128]!
496 vst1.32 {d20[0]}, [r0,:32], r1
497 vst1.8 {d18-d19}, [r0,:128]!
498 vst1.32 {d20[1]}, [r0,:32], r1
503 function x264_mc_weight_w16_neon
507 vld1.8 {d16-d17}, [r2], r3
508 vld1.8 {d18-d19}, [r2], r3
509 vmull.u8 q10, d16, d0
510 vmull.u8 q11, d17, d0
511 vmull.u8 q12, d18, d0
512 vmull.u8 q13, d19, d0
513 vrshl.s16 q10, q10, q2
514 vrshl.s16 q11, q11, q2
515 vrshl.s16 q12, q12, q2
516 vrshl.s16 q13, q13, q2
517 vadd.s16 q10, q10, q1
518 vadd.s16 q11, q11, q1
519 vadd.s16 q12, q12, q1
520 vadd.s16 q13, q13, q1
525 vst1.8 {d16-d17}, [r0,:128], r1
526 vst1.8 {d18-d19}, [r0,:128], r1
531 function x264_mc_weight_w8_neon
535 vld1.8 {d16}, [r2], r3
536 vld1.8 {d18}, [r2], r3
545 vst1.8 {d16}, [r0,:64], r1
546 vst1.8 {d18}, [r0,:64], r1
551 function x264_mc_weight_w4_neon
555 vld1.32 {d16[0]}, [r2], r3
556 vld1.32 {d16[1]}, [r2], r3
561 vst1.32 {d16[0]}, [r0], r1
562 vst1.32 {d16[1]}, [r0], r1
567 function x264_mc_weight_w20_nodenom_neon
568 weight_prologue nodenom
570 weight20_nodenom_loop:
572 vld1.8 {d26-d28}, [r2], r3
575 vld1.8 {d29-d31}, [r2], r3
582 vmlal.u8 q10, d29, d0
583 vmlal.u8 q11, d30, d0
584 vmlal.u8 q12, d28, d0
590 vst1.8 {d16-d17}, [r0,:128]!
591 vst1.32 {d20[0]}, [r0,:32], r1
592 vst1.8 {d18-d19}, [r0,:128]!
593 vst1.32 {d20[1]}, [r0,:32], r1
594 bgt weight20_nodenom_loop
598 function x264_mc_weight_w16_nodenom_neon
599 weight_prologue nodenom
600 weight16_nodenom_loop:
602 vld1.8 {d16-d17}, [r2], r3
603 vld1.8 {d18-d19}, [r2], r3
608 vmlal.u8 q12, d16, d0
609 vmlal.u8 q13, d17, d0
610 vmlal.u8 q14, d18, d0
611 vmlal.u8 q15, d19, d0
616 vst1.8 {d16-d17}, [r0,:128], r1
617 vst1.8 {d18-d19}, [r0,:128], r1
618 bgt weight16_nodenom_loop
622 function x264_mc_weight_w8_nodenom_neon
623 weight_prologue nodenom
624 weight8_nodenom_loop:
626 vld1.8 {d16}, [r2], r3
627 vld1.8 {d18}, [r2], r3
630 vmlal.u8 q10, d16, d0
631 vmlal.u8 q11, d18, d0
634 vst1.8 {d16}, [r0,:64], r1
635 vst1.8 {d17}, [r0,:64], r1
636 bgt weight8_nodenom_loop
640 function x264_mc_weight_w4_nodenom_neon
641 weight_prologue nodenom
642 weight4_nodenom_loop:
644 vld1.32 {d16[0]}, [r2], r3
645 vld1.32 {d16[1]}, [r2], r3
647 vmlal.u8 q10, d16, d0
649 vst1.32 {d16[0]}, [r0], r1
650 vst1.32 {d16[1]}, [r0], r1
651 bgt weight4_nodenom_loop
655 .macro weight_simple_prologue
657 ldr lr, [sp, #4] // weight_t
658 ldr ip, [sp, #8] // h
659 ldr lr, [lr] // offset
663 .macro weight_simple name op
664 function x264_mc_weight_w20_\name\()_neon
665 weight_simple_prologue
666 weight20_\name\()_loop:
668 vld1.8 {d16-d18}, [r2], r3
669 vld1.8 {d19-d21}, [r2], r3
673 vst1.8 {d16-d18}, [r0,:64], r1
674 vst1.8 {d19-d21}, [r0,:64], r1
675 bgt weight20_\name\()_loop
679 function x264_mc_weight_w16_\name\()_neon
680 weight_simple_prologue
681 weight16_\name\()_loop:
683 vld1.8 {d16-d17}, [r2], r3
684 vld1.8 {d18-d19}, [r2], r3
687 vst1.8 {d16-d17}, [r0,:128], r1
688 vst1.8 {d18-d19}, [r0,:128], r1
689 bgt weight16_\name\()_loop
693 function x264_mc_weight_w8_\name\()_neon
694 weight_simple_prologue
695 weight8_\name\()_loop:
697 vld1.8 {d16}, [r2], r3
698 vld1.8 {d17}, [r2], r3
700 vst1.8 {d16}, [r0,:64], r1
701 vst1.8 {d17}, [r0,:64], r1
702 bgt weight8_\name\()_loop
706 function x264_mc_weight_w4_\name\()_neon
707 weight_simple_prologue
708 weight4_\name\()_loop:
710 vld1.32 {d16[]}, [r2], r3
711 vld1.32 {d17[]}, [r2], r3
713 vst1.32 {d16[0]}, [r0], r1
714 vst1.32 {d17[0]}, [r0], r1
715 bgt weight4_\name\()_loop
720 weight_simple offsetadd, vqadd.u8
721 weight_simple offsetsub, vqsub.u8
724 // void mc_copy( uint8_t *dst, intptr_t dst_stride, uint8_t *src, intptr_t src_stride, int height )
725 function x264_mc_copy_w4_neon
729 vld1.32 {d0[]}, [r2], r3
730 vld1.32 {d1[]}, [r2], r3
731 vld1.32 {d2[]}, [r2], r3
732 vld1.32 {d3[]}, [r2], r3
733 vst1.32 {d0[0]}, [r0,:32], r1
734 vst1.32 {d1[0]}, [r0,:32], r1
735 vst1.32 {d2[0]}, [r0,:32], r1
736 vst1.32 {d3[0]}, [r0,:32], r1
741 function x264_mc_copy_w8_neon
745 vld1.32 {d0}, [r2], r3
746 vld1.32 {d1}, [r2], r3
747 vld1.32 {d2}, [r2], r3
748 vld1.32 {d3}, [r2], r3
749 vst1.32 {d0}, [r0,:64], r1
750 vst1.32 {d1}, [r0,:64], r1
751 vst1.32 {d2}, [r0,:64], r1
752 vst1.32 {d3}, [r0,:64], r1
757 function x264_mc_copy_w16_neon
761 vld1.32 {d0-d1}, [r2], r3
762 vld1.32 {d2-d3}, [r2], r3
763 vld1.32 {d4-d5}, [r2], r3
764 vld1.32 {d6-d7}, [r2], r3
765 vst1.32 {d0-d1}, [r0,:128], r1
766 vst1.32 {d2-d3}, [r0,:128], r1
767 vst1.32 {d4-d5}, [r0,:128], r1
768 vst1.32 {d6-d7}, [r0,:128], r1
773 function x264_mc_copy_w16_aligned_neon
775 copy_w16_aligned_loop:
777 vld1.32 {d0-d1}, [r2,:128], r3
778 vld1.32 {d2-d3}, [r2,:128], r3
779 vld1.32 {d4-d5}, [r2,:128], r3
780 vld1.32 {d6-d7}, [r2,:128], r3
781 vst1.32 {d0-d1}, [r0,:128], r1
782 vst1.32 {d2-d3}, [r0,:128], r1
783 vst1.32 {d4-d5}, [r0,:128], r1
784 vst1.32 {d6-d7}, [r0,:128], r1
785 bgt copy_w16_aligned_loop
790 // void x264_mc_chroma_neon( uint8_t *dst, intptr_t i_dst_stride,
791 // uint8_t *src, intptr_t i_src_stride,
792 // int dx, int dy, int i_width, int i_height );
794 function x264_mc_chroma_neon
797 ldrd r4, r5, [sp, #56]
798 ldrd r6, r7, [sp, #64]
802 add r3, r3, r5, asr #2
817 .macro CHROMA_MC_START r00, r01, r10, r11
819 rsb r7, lr, r6, lsl #3
820 rsb ip, lr, r5, lsl #3
821 sub r5, lr, r5, lsl #3
822 sub r5, r5, r6, lsl #3
826 vld2.8 {\r00-\r01}, [r3], r4
832 vld2.8 {\r10-\r11}, [r3], r4
837 .macro CHROMA_MC width, align
839 CHROMA_MC_START d4, d5, d8, d9
840 vext.8 d6, d4, d6, #1
841 vext.8 d7, d5, d7, #1
842 vext.8 d10, d8, d10, #1
843 vext.8 d11, d9, d11, #1
844 // since the element size varies, there's a different index for the 2nd store
859 1: // height loop, interpolate xy
866 vld2.8 {d4-d5}, [r3], r4
868 vext.8 d6, d4, d6, #1
869 vext.8 d7, d5, d7, #1
871 vadd.i16 d16, d16, d17
872 vadd.i16 d17, d18, d19
882 vld2.8 {d8-d9}, [r3], r4
884 vrshrn.u16 d16, q8, #6
886 vext.8 d10, d8, d10, #1
887 vext.8 d11, d9, d11, #1
889 vadd.i16 d18, d20, d21
890 vadd.i16 d19, d22, d23
895 vrshrn.u16 d18, q9, #6
902 vst1.\align {d16[0]}, [r0,:\align], r2
903 vst1.\align {d16[st2]}, [r1,:\align], r2
904 vst1.\align {d18[0]}, [r0,:\align], r2
905 vst1.\align {d18[st2]}, [r1,:\align], r2
920 vld1.64 {d4}, [r3], r4
921 vld1.64 {d6}, [r3], r4
923 3: // vertical interpolation loop
928 vld1.64 {d4}, [r3], r4
930 vld1.64 {d6}, [r3], r4
932 vrshrn.u16 d16, q8, #6 // uvuvuvuv
933 vrshrn.u16 d17, q9, #6 // uvuvuvuv
935 vuzp.8 d16, d17 // d16=uuuu|uuuu, d17=vvvv|vvvv
940 vst1.\align {d16[0]}, [r0,:\align], r2
941 vst1.\align {d16[st2]}, [r0,:\align], r2
942 vst1.\align {d17[0]}, [r1,:\align], r2
943 vst1.\align {d17[st2]}, [r1,:\align], r2
951 vld1.64 {d4-d5}, [r3], r4
952 vld1.64 {d6-d7}, [r3], r4
954 vext.8 d5, d4, d5, #2
955 vext.8 d7, d6, d7, #2
957 5: // horizontal interpolation loop
965 vld1.64 {d4-d5}, [r3], r4
966 vld1.64 {d6-d7}, [r3], r4
967 vext.8 d5, d4, d5, #2
968 vrshrn.u16 d16, q8, #6
969 vrshrn.u16 d17, q9, #6
970 vext.8 d7, d6, d7, #2
976 vst1.\align {d16[0]}, [r0,:\align], r2
977 vst1.\align {d16[st2]}, [r0,:\align], r2
978 vst1.\align {d17[0]}, [r1,:\align], r2
979 vst1.\align {d17[st2]}, [r1,:\align], r2
990 CHROMA_MC_START d4, d7, d8, d11
991 vext.8 d5, d4, d5, #1
992 vext.8 d9, d8, d9, #1
993 vext.8 d7, d6, d7, #1
994 vext.8 d11, d10, d11, #1
996 1: // height loop, interpolate xy
1004 vmlal.u8 q9, d10, d2
1005 vmlal.u8 q9, d11, d3
1007 vld2.8 {d4-d7}, [r3], r4
1009 vext.8 d5, d4, d5, #1
1010 vext.8 d7, d6, d7, #1
1012 vmull.u8 q10, d8, d0
1013 vmlal.u8 q10, d9, d1
1014 vmlal.u8 q10, d4, d2
1015 vmlal.u8 q10, d5, d3
1017 vmull.u8 q11, d10, d0
1018 vmlal.u8 q11, d11, d1
1019 vmlal.u8 q11, d6, d2
1020 vmlal.u8 q11, d7, d3
1023 vld2.8 {d8-d11}, [r3], r4
1025 vrshrn.u16 d16, q8, #6
1026 vrshrn.u16 d17, q9, #6
1027 vrshrn.u16 d18, q10, #6
1028 vext.8 d9, d8, d9, #1
1029 vrshrn.u16 d19, q11, #6
1030 vext.8 d11, d10, d11, #1
1035 vst1.64 {d16}, [r0,:64], r2
1036 vst1.64 {d17}, [r1,:64], r2
1037 vst1.64 {d18}, [r0,:64], r2
1038 vst1.64 {d19}, [r1,:64], r2
1045 2: // dx or dy are 0
1054 vld2.8 {d4-d5}, [r3], r4
1055 vld2.8 {d6-d7}, [r3], r4
1057 3: // vertical interpolation loop
1058 vmull.u8 q8, d4, d0 //U
1060 vmull.u8 q9, d5, d0 //V
1063 vld2.8 {d4-d5}, [r3], r4
1065 vmull.u8 q10, d6, d0
1066 vmlal.u8 q10, d4, d1
1067 vmull.u8 q11, d7, d0
1068 vmlal.u8 q11, d5, d1
1070 vld2.8 {d6-d7}, [r3], r4
1072 vrshrn.u16 d16, q8, #6
1073 vrshrn.u16 d17, q9, #6
1074 vrshrn.u16 d18, q10, #6
1075 vrshrn.u16 d19, q11, #6
1081 vst1.64 {d16}, [r0,:64], r2
1082 vst1.64 {d17}, [r1,:64], r2
1083 vst1.64 {d18}, [r0,:64], r2
1084 vst1.64 {d19}, [r1,:64], r2
1093 vld2.8 {d4-d7}, [r3], r4
1094 vld2.8 {d8-d11}, [r3], r4
1095 vext.8 d5, d4, d5, #1
1096 vext.8 d7, d6, d7, #1
1097 vext.8 d9, d8, d9, #1
1098 vext.8 d11, d10, d11, #1
1100 5: // horizontal interpolation loop
1102 vmull.u8 q8, d4, d0 //U
1104 vmull.u8 q9, d6, d0 //V
1107 vld2.8 {d4-d7}, [r3], r4
1109 vmull.u8 q10, d8, d0
1110 vmlal.u8 q10, d9, d1
1111 vmull.u8 q11, d10, d0
1112 vmlal.u8 q11, d11, d1
1114 vld2.8 {d8-d11}, [r3], r4
1116 vext.8 d5, d4, d5, #1
1117 vrshrn.u16 d16, q8, #6
1118 vext.8 d7, d6, d7, #1
1119 vrshrn.u16 d17, q9, #6
1120 vext.8 d9, d8, d9, #1
1121 vrshrn.u16 d18, q10, #6
1122 vext.8 d11, d10, d11, #1
1123 vrshrn.u16 d19, q11, #6
1128 vst1.64 {d16}, [r0,:64], r2
1129 vst1.64 {d17}, [r1,:64], r2
1130 vst1.64 {d18}, [r0,:64], r2
1131 vst1.64 {d19}, [r1,:64], r2
1140 // hpel_filter_v( uint8_t *dst, uint8_t *src, int16_t *buf, intptr_t stride, int width )
1141 function x264_hpel_filter_v_neon
1143 sub r1, r1, r3, lsl #1
1151 vld1.64 {d0-d1}, [r1,:128], r3
1152 vld1.64 {d2-d3}, [r1,:128], r3
1153 vld1.64 {d4-d5}, [r1,:128], r3
1154 vld1.64 {d6-d7}, [r1,:128], r3
1155 vld1.64 {d16-d17}, [r1,:128], r3
1156 vld1.64 {d18-d19}, [r1,:128], r3
1159 vaddl.u8 q10, d0, d18
1160 vmlsl.u8 q10, d2, d30
1161 vmlal.u8 q10, d4, d31
1162 vmlal.u8 q10, d6, d31
1163 vmlsl.u8 q10, d16, d30
1165 vaddl.u8 q11, d1, d19
1166 vmlsl.u8 q11, d3, d30
1167 vmlal.u8 q11, d5, d31
1168 vmlal.u8 q11, d7, d31
1169 vmlsl.u8 q11, d17, d30
1171 vqrshrun.s16 d0, q10, #5
1172 vst1.64 {d20-d21}, [r2,:128]!
1173 vqrshrun.s16 d1, q11, #5
1174 vst1.64 {d22-d23}, [r2,:128]!
1175 vst1.64 {d0-d1}, [r0,:128]!
1180 // hpel_filter_c( uint8_t *dst, int16_t *buf, int width );
1181 function x264_hpel_filter_c_neon
1183 vld1.64 {d0-d3}, [r1,:128]!
1185 // unrolled 2x: 4% faster
1188 vld1.64 {d4-d7}, [r1,:128]!
1189 vext.16 q8, q0, q1, #6
1190 vext.16 q12, q1, q2, #3
1191 vadd.s16 q8, q8, q12
1192 vext.16 q9, q0, q1, #7
1193 vext.16 q11, q1, q2, #2
1194 vadd.s16 q9, q9, q11
1195 vext.16 q10, q1, q2, #1
1196 vext.16 q11, q1, q2, #6
1197 vadd.s16 q10, q1, q10
1198 vsub.s16 q8, q8, q9 // a-b
1199 vext.16 q15, q2, q3, #3
1200 vsub.s16 q9, q9, q10 // b-c
1202 vext.16 q12, q1, q2, #7
1203 vshr.s16 q8, q8, #2 // (a-b)/4
1204 vadd.s16 q11, q11, q15
1205 vext.16 q14, q2, q3, #2
1206 vsub.s16 q8, q8, q9 // (a-b)/4-b+c
1207 vadd.s16 q12, q12, q14
1208 vext.16 q13, q2, q3, #1
1210 vshr.s16 q8, q8, #2 // ((a-b)/4-b+c)/4
1211 vadd.s16 q13, q2, q13
1212 vadd.s16 q8, q8, q10 // ((a-b)/4-b+c)/4+c = (a-5*b+20*c)/16
1213 vsub.s16 q11, q11, q12 // a-b
1214 vsub.s16 q12, q12, q13 // b-c
1215 vshr.s16 q11, q11, #2 // (a-b)/4
1216 vqrshrun.s16 d30, q8, #6
1217 vsub.s16 q11, q11, q12 // (a-b)/4-b+c
1218 vshr.s16 q11, q11, #2 // ((a-b)/4-b+c)/4
1219 vld1.64 {d0-d3}, [r1,:128]!
1220 vadd.s16 q11, q11, q13 // ((a-b)/4-b+c)/4+c = (a-5*b+20*c)/16
1222 vext.16 q8, q2, q3, #6
1223 vqrshrun.s16 d31, q11, #6
1224 vext.16 q12, q3, q0, #3
1225 vadd.s16 q8, q8, q12
1226 vext.16 q9, q2, q3, #7
1227 vst1.64 {d30-d31}, [r0,:128]!
1231 vext.16 q11, q3, q0, #2
1232 vadd.s16 q9, q9, q11
1233 vext.16 q10, q3, q0, #1
1234 vext.16 q11, q3, q0, #6
1235 vadd.s16 q10, q3, q10
1236 vsub.s16 q8, q8, q9 // a-b
1237 vext.16 q15, q0, q1, #3
1238 vsub.s16 q9, q9, q10 // b-c
1240 vext.16 q12, q3, q0, #7
1241 vshr.s16 q8, q8, #2 // (a-b)/4
1242 vadd.s16 q11, q11, q15
1243 vext.16 q14, q0, q1, #2
1244 vsub.s16 q8, q8, q9 // (a-b)/4-b+c
1245 vadd.s16 q12, q12, q14
1246 vext.16 q13, q0, q1, #1
1248 vshr.s16 q8, q8, #2 // ((a-b)/4-b+c)/4
1249 vadd.s16 q13, q0, q13
1250 vadd.s16 q8, q8, q10 // ((a-b)/4-b+c)/4+c = (a-5*b+20*c)/16
1251 vsub.s16 q11, q11, q12 // a-b
1252 vsub.s16 q12, q12, q13 // b-c
1253 vshr.s16 q11, q11, #2 // (a-b)/4
1254 vqrshrun.s16 d30, q8, #6
1255 vsub.s16 q11, q11, q12 // (a-b)/4-b+c
1256 vshr.s16 q11, q11, #2 // ((a-b)/4-b+c)/4
1257 vadd.s16 q11, q11, q13 // ((a-b)/4-b+c)/4+c = (a-5*b+20*c)/16
1259 vqrshrun.s16 d31, q11, #6
1260 vst1.64 {d30-d31}, [r0,:128]!
1265 // hpel_filter_h( uint8_t *dst, uint8_t *src, int width );
1266 function x264_hpel_filter_h_neon
1269 vld1.64 {d0-d3}, [r1,:128]!
1272 // unrolled 3x because it's 5% faster, due to mitigating
1273 // the high latency of multiplication and vqrshrun
1276 vld1.64 {d4-d5}, [r1,:128]!
1277 vext.8 q8, q0, q1, #14
1278 vext.8 q12, q1, q2, #3
1279 vaddl.u8 q13, d16, d24
1280 vext.8 q9, q0, q1, #15
1281 vaddl.u8 q14, d17, d25
1283 vext.8 q10, q1, q2, #1
1284 vmlal.u8 q13, d2, d31
1285 vmlsl.u8 q13, d18, d30
1286 vext.8 q11, q1, q2, #2
1287 vmlal.u8 q13, d20, d31
1288 vmlsl.u8 q13, d22, d30
1290 vmlsl.u8 q14, d19, d30
1291 vmlal.u8 q14, d3, d31
1292 vmlal.u8 q14, d21, d31
1293 vmlsl.u8 q14, d23, d30
1294 vqrshrun.s16 d6, q13, #5
1296 vld1.64 {d0-d1}, [r1,:128]!
1297 vext.8 q8, q1, q2, #14
1298 vext.8 q12, q2, q0, #3
1299 vaddl.u8 q13, d16, d24
1300 vqrshrun.s16 d7, q14, #5
1301 vext.8 q9, q1, q2, #15
1302 vaddl.u8 q14, d17, d25
1304 vst1.64 {d6-d7}, [r0,:128]!
1308 vext.8 q10, q2, q0, #1
1309 vmlal.u8 q13, d4, d31
1310 vmlsl.u8 q13, d18, d30
1311 vext.8 q11, q2, q0, #2
1312 vmlal.u8 q13, d20, d31
1313 vmlsl.u8 q13, d22, d30
1315 vmlsl.u8 q14, d19, d30
1316 vmlal.u8 q14, d5, d31
1317 vmlal.u8 q14, d21, d31
1318 vmlsl.u8 q14, d23, d30
1319 vqrshrun.s16 d6, q13, #5
1321 vld1.64 {d2-d3}, [r1,:128]!
1322 vext.8 q8, q2, q0, #14
1323 vext.8 q12, q0, q1, #3
1324 vaddl.u8 q13, d16, d24
1325 vqrshrun.s16 d7, q14, #5
1326 vext.8 q9, q2, q0, #15
1327 vaddl.u8 q14, d17, d25
1329 vst1.64 {d6-d7}, [r0,:128]!
1333 vext.8 q10, q0, q1, #1
1334 vmlal.u8 q13, d0, d31
1335 vmlsl.u8 q13, d18, d30
1336 vext.8 q11, q0, q1, #2
1337 vmlal.u8 q13, d20, d31
1338 vmlsl.u8 q13, d22, d30
1340 vmlsl.u8 q14, d19, d30
1341 vmlal.u8 q14, d1, d31
1342 vmlal.u8 q14, d21, d31
1343 vmlsl.u8 q14, d23, d30
1345 vqrshrun.s16 d6, q13, #5
1346 vqrshrun.s16 d7, q14, #5
1347 vst1.64 {d6-d7}, [r0,:128]!
1353 // frame_init_lowres_core( uint8_t *src0, uint8_t *dst0, uint8_t *dsth, uint8_t *dstv,
1354 // uint8_t *dstc, intptr_t src_stride, intptr_t dst_stride, int width,
1356 function x264_frame_init_lowres_core_neon
1359 ldrd r4, r5, [sp, #96]
1360 ldrd r6, r7, [sp, #104]
1362 sub r10, r6, r7 // dst_stride - width
1368 add r8, r0, r5 // src1 = src0 + src_stride
1369 add r9, r0, r5, lsl #1 // src2 = src1 + src_stride
1371 vld2.8 {d8, d10}, [r6,:128]!
1372 vld2.8 {d12,d14}, [r8,:128]!
1373 vld2.8 {d16,d18}, [r9,:128]!
1378 vld2.8 {d9, d11}, [r6,:128]!
1379 vld2.8 {d13,d15}, [r8,:128]!
1380 vrhadd.u8 q0, q4, q6
1381 vld2.8 {d17,d19}, [r9,:128]!
1382 vrhadd.u8 q5, q5, q7
1383 vld2.8 {d20,d22}, [r6,:128]!
1384 vrhadd.u8 q1, q6, q8
1385 vld2.8 {d24,d26}, [r8,:128]!
1386 vrhadd.u8 q7, q7, q9
1387 vext.8 q4, q4, q10, #1
1388 vrhadd.u8 q0, q0, q5
1389 vext.8 q6, q6, q12, #1
1390 vrhadd.u8 q1, q1, q7
1391 vld2.8 {d28,d30}, [r9,:128]!
1392 vrhadd.u8 q4, q4, q6
1393 vext.8 q8, q8, q14, #1
1394 vrhadd.u8 q6, q6, q8
1395 vst1.64 {d0-d1}, [r1,:128]!
1396 vrhadd.u8 q2, q4, q5
1397 vst1.64 {d2-d3}, [r3,:128]!
1398 vrhadd.u8 q3, q6, q7
1399 vst1.64 {d4-d5}, [r2,:128]!
1400 vst1.64 {d6-d7}, [r4,:128]!
1402 ble lowres_xloop_end
1405 vld2.8 {d21,d23}, [r6,:128]!
1406 vld2.8 {d25,d27}, [r8,:128]!
1407 vrhadd.u8 q0, q10, q12
1408 vld2.8 {d29,d31}, [r9,:128]!
1409 vrhadd.u8 q11, q11, q13
1410 vld2.8 {d8, d10}, [r6,:128]!
1411 vrhadd.u8 q1, q12, q14
1412 vld2.8 {d12,d14}, [r8,:128]!
1413 vrhadd.u8 q13, q13, q15
1414 vext.8 q10, q10, q4, #1
1415 vrhadd.u8 q0, q0, q11
1416 vext.8 q12, q12, q6, #1
1417 vrhadd.u8 q1, q1, q13
1418 vld2.8 {d16,d18}, [r9,:128]!
1419 vrhadd.u8 q10, q10, q12
1420 vext.8 q14, q14, q8, #1
1421 vrhadd.u8 q12, q12, q14
1422 vst1.64 {d0-d1}, [r1,:128]!
1423 vrhadd.u8 q2, q10, q11
1424 vst1.64 {d2-d3}, [r3,:128]!
1425 vrhadd.u8 q3, q12, q13
1426 vst1.64 {d4-d5}, [r2,:128]!
1427 vst1.64 {d6-d7}, [r4,:128]!
1433 add r0, r0, r5, lsl #1
1444 function x264_load_deinterleave_chroma_fdec_neon
1445 mov ip, #FDEC_STRIDE/2
1447 vld2.8 {d0-d1}, [r1,:128], r2
1450 vst1.8 {d0}, [r0,:64], ip
1451 vst1.8 {d1}, [r0,:64], ip
1457 function x264_load_deinterleave_chroma_fenc_neon
1458 mov ip, #FENC_STRIDE/2
1460 vld2.8 {d0-d1}, [r1,:128], r2
1463 vst1.8 {d0}, [r0,:64], ip
1464 vst1.8 {d1}, [r0,:64], ip
1470 function x264_plane_copy_neon
1489 vld1.8 {q0, q1}, [r2]!
1490 vst1.8 {q0, q1}, [r0]!
1501 function x264_plane_copy_deinterleave_neon
1503 ldrd r6, r7, [sp, #28]
1504 ldrd r4, r5, [sp, #20]
1509 sub r5, r5, lr, lsl #1
1511 vld2.8 {d0-d3}, [r4,:128]!
1527 function x264_plane_copy_deinterleave_rgb_neon
1528 push {r4-r8, r10, r11, lr}
1529 ldrd r4, r5, [sp, #32]
1530 ldrd r6, r7, [sp, #40]
1532 ldrd r10, r11, [sp, #52]
1536 sub r7, r7, lr, lsl #1
1540 subne r7, r7, lr, lsl #1
1544 vld3.8 {d0,d1,d2}, [r6]!
1559 pop {r4-r8, r10, r11, pc}
1561 vld4.8 {d0,d1,d2,d3}, [r6]!
1576 pop {r4-r8, r10, r11, pc}
1579 function x264_plane_copy_interleave_neon
1581 ldrd r6, r7, [sp, #28]
1582 ldrd r4, r5, [sp, #20]
1585 sub r1, r1, lr, lsl #1
1592 vst2.8 {d0,d2}, [r0]!
1593 vst2.8 {d1,d3}, [r0]!
1606 function x264_plane_copy_swap_neon
1608 ldrd r4, r5, [sp, #12]
1611 sub r1, r1, lr, lsl #1
1612 sub r3, r3, lr, lsl #1
1614 vld1.8 {q0, q1}, [r2]!
1618 vst1.8 {q0, q1}, [r0]!
1630 function x264_store_interleave_chroma_neon
1633 mov ip, #FDEC_STRIDE
1635 vld1.8 {d0}, [r2], ip
1636 vld1.8 {d1}, [r3], ip
1638 vst2.8 {d0,d1}, [r0,:128], r1
1644 .macro integral4h p1, p2
1645 vext.8 d1, \p1, \p2, #1
1646 vext.8 d2, \p1, \p2, #2
1647 vext.8 d3, \p1, \p2, #3
1648 vaddl.u8 q0, \p1, d1
1654 function integral_init4h_neon
1655 sub r3, r0, r2, lsl #1
1656 vld1.8 {d6, d7}, [r1, :128]!
1659 vld1.16 {q2}, [r3, :128]!
1661 vld1.8 {d6}, [r1, :64]!
1662 vld1.16 {q2}, [r3, :128]!
1663 vst1.16 {q0}, [r0, :128]!
1665 vld1.8 {d7}, [r1, :64]!
1666 vst1.16 {q0}, [r0, :128]!
1671 .macro integral8h p1, p2, s
1672 vext.8 d1, \p1, \p2, #1
1673 vext.8 d2, \p1, \p2, #2
1674 vext.8 d3, \p1, \p2, #3
1675 vext.8 d4, \p1, \p2, #4
1676 vext.8 d5, \p1, \p2, #5
1677 vext.8 d6, \p1, \p2, #6
1678 vext.8 d7, \p1, \p2, #7
1679 vaddl.u8 q0, \p1, d1
1689 function integral_init8h_neon
1690 sub r3, r0, r2, lsl #1
1691 vld1.8 {d16, d17}, [r1, :128]!
1694 vld1.16 {q9}, [r3, :128]!
1695 integral8h d16, d17, q9
1696 vld1.8 {d16}, [r1, :64]!
1697 vld1.16 {q9}, [r3, :128]!
1698 vst1.16 {q0}, [r0, :128]!
1699 integral8h d17, d16, q9
1700 vld1.8 {d17}, [r1, :64]!
1701 vst1.16 {q0}, [r0, :128]!
1706 function integral_init4v_neon
1709 add r4, r0, r2, lsl #3
1710 add r5, r0, r2, lsl #4
1712 vld1.16 {q11, q12}, [r3]!
1713 vld1.16 {q8, q9}, [r5]!
1714 vld1.16 {q13}, [r3]!
1715 vld1.16 {q10}, [r5]!
1718 vld1.16 {q14, q15}, [r4]!
1719 vext.8 q0, q11, q12, #8
1720 vext.8 q1, q12, q13, #8
1721 vext.8 q2, q8, q9, #8
1722 vext.8 q3, q9, q10, #8
1723 vsub.u16 q14, q14, q11
1724 vsub.u16 q15, q15, q12
1725 vadd.u16 q0, q0, q11
1726 vadd.u16 q1, q1, q12
1729 vst1.16 {q14}, [r1]!
1730 vst1.16 {q15}, [r1]!
1735 vld1.16 {q12, q13}, [r3]!
1736 vld1.16 {q9, q10}, [r5]!
1745 function integral_init8v_neon
1746 add r2, r0, r1, lsl #4
1748 ands r3, r1, #16 - 1
1758 vld1.16 {q0, q1}, [r0]
1759 vld1.16 {q2, q3}, [r2]!
1769 function x264_mbtree_propagate_cost_neon
1771 ldrd r4, r5, [sp, #12]
1773 vld1.32 {d6[], d7[]}, [r5]
1778 vld1.16 {q10}, [r3]!
1779 vld1.16 {q11}, [r4]!
1780 vbic.u16 q10, #0xc000
1781 vmin.u16 q10, q9, q10
1782 vmull.u16 q12, d18, d22 @ propagate_intra
1783 vmull.u16 q13, d19, d23 @ propagate_intra
1784 vsubl.u16 q14, d18, d20 @ propagate_num
1785 vsubl.u16 q15, d19, d21 @ propagate_num
1786 vmovl.u16 q10, d18 @ propagate_denom
1787 vmovl.u16 q11, d19 @ propagate_denom
1790 vcvt.f32.s32 q12, q12
1791 vcvt.f32.s32 q13, q13
1792 vcvt.f32.s32 q14, q14
1793 vcvt.f32.s32 q15, q15
1794 vcvt.f32.s32 q10, q10
1795 vcvt.f32.s32 q11, q11
1800 vrecps.f32 q10, q0, q10
1801 vrecps.f32 q11, q1, q11
1802 vmla.f32 q8, q12, q3 @ propagate_amount
1803 vmla.f32 q9, q13, q3 @ propagate_amount
1804 vmul.f32 q0, q0, q10
1805 vmul.f32 q1, q1, q11
1806 vmul.f32 q8, q8, q14
1807 vmul.f32 q9, q9, q15
1819 function x264_mbtree_propagate_list_internal_neon
1820 vld2.16 {d4[], d5[]}, [sp] @ bipred_weight, mb_y
1821 movrel r12, pw_0to15
1822 vmov.u16 q10, #0xc000
1823 vld1.16 {q0}, [r12, :128] @h->mb.i_mb_x,h->mb.i_mb_y
1826 vdup.u16 q8, d5[0] @ mb_y
1831 vld1.16 {q14}, [r1, :128]! @ propagate_amount
1832 vld1.16 {q15}, [r2, :128]! @ lowres_cost
1833 vld1.16 {q8, q9}, [r0, :128]!
1835 vceq.u16 q1, q15, q10
1836 vmull.u16 q12, d28, d4
1837 vmull.u16 q13, d29, d4
1838 vrshrn.u32 d30, q12, #6
1839 vrshrn.u32 d31, q13, #6
1840 vbsl q1, q15, q14 @ if( lists_used == 3 )
1841 @ propagate_amount = (propagate_amount * bipred_weight + 32) >> 6
1842 vshr.s16 q12, q8, #5
1843 vshr.s16 q13, q9, #5
1844 vuzp.16 q8, q9 @ x & 31, y & 31
1845 vadd.s16 q12, q12, q0
1846 vadd.s16 q0, q0, q11
1849 vadd.s16 q13, q13, q0
1850 vbic.i16 q8, #128+64+32
1851 vadd.s16 q0, q0, q11
1852 vbic.i16 q8, #(128+64+32)<<8
1853 vst1.16 {q12, q13}, [r3, :128]!
1855 vmull.u8 q12, d17, d16 @ idx3weight = y*x
1856 vmull.u8 q14, d19, d16 @ idx1weight = (32-y)*x
1857 vmull.u8 q15, d19, d18 @ idx0weight = (32-y)*(32-x)
1858 vmull.u8 q13, d17, d18 @ idx2weight = y*(32-x)
1859 vmull.u16 q9, d28, d2 @ idx1weight
1860 vmull.u16 q8, d29, d3
1861 vmull.u16 q14, d30, d2 @ idx0weight
1862 vmull.u16 q15, d31, d3
1863 vrshrn.u32 d18, q9, #10 @ idx1weight
1864 vrshrn.u32 d19, q8, #10
1865 vrshrn.u32 d16, q14, #10 @ idx0weight
1866 vrshrn.u32 d17, q15, #10
1867 vmull.u16 q14, d24, d2 @ idx3weight
1868 vmull.u16 q15, d25, d3
1870 vmull.u16 q12, d26, d2 @ idx2weight
1871 vmull.u16 q13, d27, d3
1872 vst1.16 {q8, q9}, [r3, :128]!
1873 vrshrn.u32 d19, q15, #10 @ idx3weight
1874 vrshrn.u32 d18, q14, #10
1875 vrshrn.u32 d16, q12, #10 @ idx2weight
1876 vrshrn.u32 d17, q13, #10
1878 vst1.16 {q8, q9}, [r3, :128]!