1 /*****************************************************************************
2 * mc.S: arm motion compensation
3 *****************************************************************************
4 * Copyright (C) 2009-2011 x264 project
6 * Authors: David Conrad <lessen42@gmail.com>
7 * Mans Rullgard <mans@mansr.com>
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.
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.
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.
23 * This program is also available under a commercial proprietary license.
24 * For more information, contact us at licensing@x264.com.
25 *****************************************************************************/
32 // note: prefetch stuff assumes 64-byte cacheline, true for the Cortex-A8
33 // They also use nothing above armv5te, but we don't care about pre-armv6
35 // void prefetch_ref( uint8_t *pix, int stride, int parity )
36 function x264_prefetch_ref_arm
40 add r0, r0, r2, lsl #3
41 add r2, r1, r1, lsl #1
45 add r3, r0, r1, lsl #2
54 // void prefetch_fenc( uint8_t *pix_y, int stride_y,
55 // uint8_t *pix_uv, int stride_uv, int mb_x )
56 function x264_prefetch_fenc_arm
60 smulbb lr, lr, r1 // note: this assumes stride_y is <= 16 bits signed
65 add r0, r0, lr, lsl #2
67 add lr, r0, r1, lsl #1
70 add r2, r2, ip, lsl #2
73 add ip, r2, r3, lsl #1
81 // void *x264_memcpy_aligned( void * dst, const void * src, size_t n )
82 function x264_memcpy_aligned_neon
83 orr r3, r0, r1, lsr #1
84 movrel ip, memcpy_table
89 .macro MEMCPY_ALIGNED srcalign dstalign
90 function memcpy_aligned_\dstalign\()_\srcalign\()_neon
92 .if \srcalign == 8 && \dstalign == 8
94 vld1.64 {d0}, [r1,:64]!
95 vst1.64 {d0}, [r3,:64]!
99 .set r1align, \srcalign * 8
100 .set r3align, \dstalign * 8
105 vld1.64 {d0-d1}, [r1,:r1align]!
106 vst1.64 {d0-d1}, [r3,:r3align]!
107 32: // n is a multiple of 32
111 vld1.64 {d0-d3}, [r1,:r1align]!
112 vst1.64 {d0-d3}, [r3,:r3align]!
113 640: // n is a multiple of 64
118 vld1.64 {d0-d3}, [r1,:r1align]!
119 vld1.64 {d4-d7}, [r1,:r1align]!
120 vst1.64 {d0-d3}, [r3,:r3align]!
121 vst1.64 {d4-d7}, [r3,:r3align]!
124 .if \srcalign == 8 && \dstalign == 8
125 vld1.64 {d0}, [r1,:64]!
126 vst1.64 {d0}, [r3,:64]!
132 MEMCPY_ALIGNED 16, 16
139 .word memcpy_aligned_16_16_neon
140 .word memcpy_aligned_16_8_neon
141 .word memcpy_aligned_8_16_neon
142 .word memcpy_aligned_8_8_neon
147 // void x264_memzero_aligned( void *dst, size_t n )
148 function x264_memzero_aligned_neon
154 vst1.64 {d0-d3}, [r0,:128]!
161 // void pixel_avg( uint8_t *dst, int dst_stride,
162 // uint8_t *src1, int src1_stride,
163 // uint8_t *src2, int src2_stride, int weight );
165 function x264_pixel_avg_\w\()x\h\()_neon
171 beq x264_pixel_avg_w\w\()_neon
173 blt x264_pixel_avg_weight_w\w\()_add_sub_neon // weight > 64
175 bge x264_pixel_avg_weight_w\w\()_add_add_neon
176 b x264_pixel_avg_weight_w\w\()_sub_add_neon // weight < 0
190 .macro load_weights_add_add
195 .macro load_add_add d1 d2
196 vld1.32 {\d1}, [r2], r3
197 vld1.32 {\d2}, [r4], r5
200 .macro weight_add_add dst s1 s2
201 vmull.u8 \dst, \s1, d30
202 vmlal.u8 \dst, \s2, d31
206 .macro load_weights_add_sub
212 .macro load_add_sub d1 d2
213 vld1.32 {\d1}, [r2], r3
214 vld1.32 {\d2}, [r4], r5
217 .macro weight_add_sub dst s1 s2
218 vmull.u8 \dst, \s1, d30
219 vmlsl.u8 \dst, \s2, d31
223 .macro load_weights_sub_add
229 .macro load_sub_add d1 d2
230 vld1.32 {\d2}, [r4], r5
231 vld1.32 {\d1}, [r2], r3
234 .macro weight_sub_add dst s1 s2
235 vmull.u8 \dst, \s2, d31
236 vmlsl.u8 \dst, \s1, d30
239 .macro AVG_WEIGHT ext
240 function x264_pixel_avg_weight_w4_\ext\()_neon
245 weight_\ext q8, d0, d1
247 vqrshrun.s16 d0, q8, #6
248 weight_\ext q9, d2, d3
249 vst1.32 {d0[0]}, [r0,:32], r1
250 vqrshrun.s16 d1, q9, #6
251 vst1.32 {d1[0]}, [r0,:32], r1
256 function x264_pixel_avg_weight_w8_\ext\()_neon
261 weight_\ext q8, d0, d1
263 weight_\ext q9, d2, d3
265 weight_\ext q10, d4, d5
267 weight_\ext q11, d6, d7
268 vqrshrun.s16 d0, q8, #6
269 vqrshrun.s16 d1, q9, #6
270 vqrshrun.s16 d2, q10, #6
271 vqrshrun.s16 d3, q11, #6
272 vst1.64 {d0}, [r0,:64], r1
273 vst1.64 {d1}, [r0,:64], r1
274 vst1.64 {d2}, [r0,:64], r1
275 vst1.64 {d3}, [r0,:64], r1
280 function x264_pixel_avg_weight_w16_\ext\()_neon
284 load_\ext d0-d1, d2-d3
285 weight_\ext q8, d0, d2
286 weight_\ext q9, d1, d3
287 load_\ext d4-d5, d6-d7
288 weight_\ext q10, d4, d6
289 weight_\ext q11, d5, d7
290 vqrshrun.s16 d0, q8, #6
291 vqrshrun.s16 d1, q9, #6
292 vqrshrun.s16 d2, q10, #6
293 vqrshrun.s16 d3, q11, #6
294 vst1.64 {d0-d1}, [r0,:128], r1
295 vst1.64 {d2-d3}, [r0,:128], r1
305 function x264_pixel_avg_w4_neon
307 vld1.32 {d0[]}, [r2], r3
308 vld1.32 {d2[]}, [r4], r5
310 vld1.32 {d1[]}, [r2], r3
311 vld1.32 {d3[]}, [r4], r5
313 vst1.32 {d0[0]}, [r0,:32], r1
314 vst1.32 {d1[0]}, [r0,:32], r1
315 bgt x264_pixel_avg_w4_neon
319 function x264_pixel_avg_w8_neon
321 vld1.64 {d0}, [r2], r3
322 vld1.64 {d2}, [r4], r5
324 vld1.64 {d1}, [r2], r3
325 vld1.64 {d3}, [r4], r5
327 vst1.64 {d0}, [r0,:64], r1
328 vld1.64 {d2}, [r2], r3
329 vld1.64 {d4}, [r4], r5
331 vst1.64 {d1}, [r0,:64], r1
332 vld1.64 {d3}, [r2], r3
333 vld1.64 {d5}, [r4], r5
335 vst1.64 {d2}, [r0,:64], r1
336 vst1.64 {d3}, [r0,:64], r1
337 bgt x264_pixel_avg_w8_neon
341 function x264_pixel_avg_w16_neon
343 vld1.64 {d0-d1}, [r2], r3
344 vld1.64 {d2-d3}, [r4], r5
346 vld1.64 {d2-d3}, [r2], r3
347 vld1.64 {d4-d5}, [r4], r5
349 vst1.64 {d0-d1}, [r0,:128], r1
350 vld1.64 {d4-d5}, [r2], r3
351 vld1.64 {d6-d7}, [r4], r5
353 vst1.64 {d2-d3}, [r0,:128], r1
354 vld1.64 {d6-d7}, [r2], r3
355 vld1.64 {d0-d1}, [r4], r5
357 vst1.64 {d4-d5}, [r0,:128], r1
358 vst1.64 {d6-d7}, [r0,:128], r1
359 bgt x264_pixel_avg_w16_neon
364 function x264_pixel_avg2_w4_neon
370 vld1.32 {d0[]}, [r2], r3
371 vld1.32 {d2[]}, [lr], r3
373 vld1.32 {d1[]}, [r2], r3
374 vld1.32 {d3[]}, [lr], r3
376 vst1.32 {d0[0]}, [r0,:32], r1
377 vst1.32 {d1[0]}, [r0,:32], r1
382 function x264_pixel_avg2_w8_neon
388 vld1.64 {d0}, [r2], r3
389 vld1.64 {d2}, [lr], r3
391 vld1.64 {d1}, [r2], r3
392 vld1.64 {d3}, [lr], r3
394 vst1.64 {d0}, [r0,:64], r1
395 vst1.64 {d1}, [r0,:64], r1
400 function x264_pixel_avg2_w16_neon
406 vld1.64 {d0-d1}, [r2], r3
407 vld1.64 {d2-d3}, [lr], r3
409 vld1.64 {d4-d5}, [r2], r3
410 vld1.64 {d6-d7}, [lr], r3
412 vst1.64 {d0-d1}, [r0,:128], r1
413 vst1.64 {d4-d5}, [r0,:128], r1
418 function x264_pixel_avg2_w20_neon
425 vld1.64 {d0-d2}, [r2], r3
426 vld1.64 {d4-d6}, [lr], r3
429 vld1.64 {d4-d6}, [r2], r3
430 vld1.64 {d16-d18},[lr], r3
432 vst1.64 {d0-d1}, [r0,:128]!
433 vrhadd.u8 d6, d6, d18
434 vst1.32 {d2[0]}, [r0,:32], r1
435 vst1.64 {d4-d5}, [r0,:128]!
436 vst1.32 {d6[0]}, [r0,:32], r1
442 .macro weight_prologue type
444 ldr r4, [sp, #4*3] // weight_t
445 ldr ip, [sp, #4*3+4] // h
447 ldr lr, [r4, #32] // denom
449 ldrd r4, [r4, #32+4] // scale, offset
458 // void mc_weight( uint8_t *src, int src_stride, uint8_t *dst, int dst_stride,
459 // const x264_weight_t *weight, int height )
460 function x264_mc_weight_w20_neon
465 vld1.8 {d17-d19}, [r2], r3
469 vld1.8 {d16-d18}, [r2], r3
473 vmul.s16 q10, q10, q0
474 vmul.s16 q11, q11, q0
475 vmul.s16 q12, q12, q0
476 vmul.s16 q13, q13, q0
477 vmul.s16 d28, d28, d0
478 vmul.s16 d29, d30, d0
479 vrshl.s16 q10, q10, q2
480 vrshl.s16 q11, q11, q2
481 vrshl.s16 q12, q12, q2
482 vrshl.s16 q13, q13, q2
483 vrshl.s16 q14, q14, q2
484 vadd.s16 q10, q10, q1
485 vadd.s16 q11, q11, q1
486 vadd.s16 q12, q12, q1
487 vadd.s16 q13, q13, q1
488 vadd.s16 q14, q14, q1
494 vst1.8 {d16-d17}, [r0,:128]!
495 vst1.32 {d20[0]}, [r0,:32], r1
496 vst1.8 {d18-d19}, [r0,:128]!
497 vst1.32 {d20[1]}, [r0,:32], r1
502 function x264_mc_weight_w16_neon
506 vld1.8 {d16-d17}, [r2], r3
507 vld1.8 {d18-d19}, [r2], r3
512 vmul.s16 q10, q10, q0
513 vmul.s16 q11, q11, q0
514 vmul.s16 q12, q12, q0
515 vmul.s16 q13, q13, q0
516 vrshl.s16 q10, q10, q2
517 vrshl.s16 q11, q11, q2
518 vrshl.s16 q12, q12, q2
519 vrshl.s16 q13, q13, q2
520 vadd.s16 q10, q10, q1
521 vadd.s16 q11, q11, q1
522 vadd.s16 q12, q12, q1
523 vadd.s16 q13, q13, q1
528 vst1.8 {d16-d17}, [r0,:128], r1
529 vst1.8 {d18-d19}, [r0,:128], r1
534 function x264_mc_weight_w8_neon
538 vld1.8 {d16}, [r2], r3
539 vld1.8 {d18}, [r2], r3
550 vst1.8 {d16}, [r0,:64], r1
551 vst1.8 {d18}, [r0,:64], r1
556 function x264_mc_weight_w4_neon
560 vld1.32 {d16[]}, [r2], r3
561 vld1.32 {d18[]}, [r2], r3
564 vmul.s16 d16, d16, d0
565 vmul.s16 d17, d18, d0
569 vst1.32 {d16[0]}, [r0,:32], r1
570 vst1.32 {d16[1]}, [r0,:32], r1
575 function x264_mc_weight_w20_nodenom_neon
576 weight_prologue nodenom
578 weight20_nodenom_loop:
580 vld1.8 {d17-d19}, [r2], r3
584 vld1.8 {d16-d18}, [r2], r3
594 vmla.s16 q10, q12, q0
595 vmla.s16 q11, q13, q0
597 vmla.s16 d24, d28, d0
598 vmla.s16 d25, d30, d0
604 vst1.8 {d16-d17}, [r0,:128]!
605 vst1.32 {d20[0]}, [r0,:32], r1
606 vst1.8 {d18-d19}, [r0,:128]!
607 vst1.32 {d20[1]}, [r0,:32], r1
608 bgt weight20_nodenom_loop
612 function x264_mc_weight_w16_nodenom_neon
613 weight_prologue nodenom
614 weight16_nodenom_loop:
616 vld1.8 {d16-d17}, [r2], r3
617 vld1.8 {d18-d19}, [r2], r3
628 vmla.s16 q10, q14, q0
629 vmla.s16 q11, q15, q0
634 vst1.8 {d16-d17}, [r0,:128], r1
635 vst1.8 {d18-d19}, [r0,:128], r1
636 bgt weight16_nodenom_loop
640 function x264_mc_weight_w8_nodenom_neon
641 weight_prologue nodenom
642 weight8_nodenom_loop:
644 vld1.8 {d16}, [r2], r3
645 vld1.8 {d18}, [r2], r3
654 vst1.8 {d16}, [r0,:64], r1
655 vst1.8 {d17}, [r0,:64], r1
656 bgt weight8_nodenom_loop
660 function x264_mc_weight_w4_nodenom_neon
661 weight_prologue nodenom
662 weight4_nodenom_loop:
664 vld1.32 {d16[]}, [r2], r3
665 vld1.32 {d18[]}, [r2], r3
669 vmla.s16 d20, d16, d0
670 vmla.s16 d21, d18, d0
672 vst1.32 {d16[0]}, [r0,:32], r1
673 vst1.32 {d16[1]}, [r0,:32], r1
674 bgt weight4_nodenom_loop
678 .macro weight_simple_prologue
680 ldr lr, [sp, #4] // weight_t
681 ldr ip, [sp, #8] // h
682 ldr lr, [lr] // offset
686 .macro weight_simple name op
687 function x264_mc_weight_w20_\name\()_neon
688 weight_simple_prologue
689 weight20_\name\()_loop:
691 vld1.8 {d16-d18}, [r2], r3
692 vld1.8 {d19-d21}, [r2], r3
696 vst1.8 {d16-d18}, [r0,:64], r1
697 vst1.8 {d19-d21}, [r0,:64], r1
698 bgt weight20_\name\()_loop
702 function x264_mc_weight_w16_\name\()_neon
703 weight_simple_prologue
704 weight16_\name\()_loop:
706 vld1.8 {d16-d17}, [r2], r3
707 vld1.8 {d18-d19}, [r2], r3
710 vst1.8 {d16-d17}, [r0,:128], r1
711 vst1.8 {d18-d19}, [r0,:128], r1
712 bgt weight16_\name\()_loop
716 function x264_mc_weight_w8_\name\()_neon
717 weight_simple_prologue
718 weight8_\name\()_loop:
720 vld1.8 {d16}, [r2], r3
721 vld1.8 {d17}, [r2], r3
723 vst1.8 {d16}, [r0,:64], r1
724 vst1.8 {d17}, [r0,:64], r1
725 bgt weight8_\name\()_loop
729 function x264_mc_weight_w4_\name\()_neon
730 weight_simple_prologue
731 weight4_\name\()_loop:
733 vld1.32 {d16[]}, [r2], r3
734 vld1.32 {d17[]}, [r2], r3
736 vst1.32 {d16[0]}, [r0,:32], r1
737 vst1.32 {d17[0]}, [r0,:32], r1
738 bgt weight4_\name\()_loop
743 weight_simple offsetadd, vqadd.u8
744 weight_simple offsetsub, vqsub.u8
747 // void mc_copy( uint8_t *dst, int dst_stride, uint8_t *src, int src_stride, int height )
748 function x264_mc_copy_w4_neon
752 vld1.32 {d0[]}, [r2], r3
753 vld1.32 {d1[]}, [r2], r3
754 vld1.32 {d2[]}, [r2], r3
755 vld1.32 {d3[]}, [r2], r3
756 vst1.32 {d0[0]}, [r0,:32], r1
757 vst1.32 {d1[0]}, [r0,:32], r1
758 vst1.32 {d2[0]}, [r0,:32], r1
759 vst1.32 {d3[0]}, [r0,:32], r1
764 function x264_mc_copy_w8_neon
768 vld1.32 {d0}, [r2], r3
769 vld1.32 {d1}, [r2], r3
770 vld1.32 {d2}, [r2], r3
771 vld1.32 {d3}, [r2], r3
772 vst1.32 {d0}, [r0,:64], r1
773 vst1.32 {d1}, [r0,:64], r1
774 vst1.32 {d2}, [r0,:64], r1
775 vst1.32 {d3}, [r0,:64], r1
780 function x264_mc_copy_w16_neon
784 vld1.32 {d0-d1}, [r2], r3
785 vld1.32 {d2-d3}, [r2], r3
786 vld1.32 {d4-d5}, [r2], r3
787 vld1.32 {d6-d7}, [r2], r3
788 vst1.32 {d0-d1}, [r0,:128], r1
789 vst1.32 {d2-d3}, [r0,:128], r1
790 vst1.32 {d4-d5}, [r0,:128], r1
791 vst1.32 {d6-d7}, [r0,:128], r1
796 function x264_mc_copy_w16_aligned_neon
798 copy_w16_aligned_loop:
800 vld1.32 {d0-d1}, [r2,:128], r3
801 vld1.32 {d2-d3}, [r2,:128], r3
802 vld1.32 {d4-d5}, [r2,:128], r3
803 vld1.32 {d6-d7}, [r2,:128], r3
804 vst1.32 {d0-d1}, [r0,:128], r1
805 vst1.32 {d2-d3}, [r0,:128], r1
806 vst1.32 {d4-d5}, [r0,:128], r1
807 vst1.32 {d6-d7}, [r0,:128], r1
808 bgt copy_w16_aligned_loop
813 // void x264_mc_chroma_neon( uint8_t *dst, int i_dst_stride,
814 // uint8_t *src, int i_src_stride,
815 // int dx, int dy, int i_width, int i_height );
816 function x264_mc_chroma_neon
823 add r2, r2, r4, asr #3
835 // calculate cA cB cC cD
836 .macro CHROMA_MC_START r0 r1
838 rsb r6, lr, r5, lsl #3
839 rsb ip, lr, r4, lsl #3
840 sub r4, lr, r4, lsl #3
841 sub r4, r4, r5, lsl #3
851 vld1.64 {\r0}, [r2], r3
853 vld1.64 {\r1}, [r5], r3
857 vext.8 d5, d4, d5, #1
858 vext.8 d7, d6, d7, #1
861 .macro CHROMA_MC width, align
863 CHROMA_MC_START d4, d6
864 // since the element size varies, there's a different index for the 2nd store
877 1: // height loop, interpolate xy
881 vld1.64 {d4}, [r2], r3
882 vext.8 d5, d4, d5, #1
886 vld1.64 {d6}, [r5], r3
887 vadd.i16 d16, d16, d17
888 vadd.i16 d17, d18, d19
889 vrshrn.u16 d16, q8, #6
892 vext.8 d7, d6, d7, #1
894 vst1.\align {d16[0]}, [r0,:\align], r1
895 vst1.\align {d16[st2]}, [r0,:\align], r1
910 vext.32 d1, d0, d1, #1
913 vld1.32 {d4[0]}, [r2], r3
914 vld1.32 {d4[1]}, [r5], r3
916 3: // vertical interpolation loop
919 vld1.32 {d4[0]}, [r2], r3
921 vld1.32 {d4[1]}, [r5], r3
922 vadd.i16 d16, d16, d17
923 vadd.i16 d17, d18, d19
924 vrshrn.u16 d16, q8, #6
927 vst1.\align {d16[0]}, [r0,:\align], r1
928 vst1.\align {d16[st2]}, [r0,:\align], r1
934 vld1.64 {d4}, [r2], r3
935 vld1.64 {d6}, [r2], r3
936 vext.8 d5, d4, d5, #1
937 vext.8 d7, d6, d7, #1
941 5: // horizontal interpolation loop
945 vld1.64 {d4}, [r2], r3
946 vext.8 d5, d4, d5, #1
948 vadd.i16 d16, d16, d17
949 vadd.i16 d17, d18, d19
951 vrshrn.u16 d16, q8, #6
952 vld1.64 {d6}, [r2], r3
953 vext.8 d7, d6, d7, #1
956 vst1.\align {d16[0]}, [r0,:\align], r1
957 vst1.\align {d16[st2]}, [r0,:\align], r1
966 // the optimial timing for width 8 is different enough that it's not
967 // readable to put it in the same macro as width 2/4
969 CHROMA_MC_START d4-d5, d6-d7
971 1: // height loop, interpolate xy
975 vld1.64 {d4, d5}, [r2], r3
977 vext.8 d5, d4, d5, #1
984 vrshrn.u16 d16, q8, #6
985 vld1.64 {d6, d7}, [r5], r3
987 vrshrn.u16 d17, q9, #6
988 vext.8 d7, d6, d7, #1
989 vst1.64 {d16}, [r0,:64], r1
990 vst1.64 {d17}, [r0,:64], r1
1006 vld1.64 {d4}, [r2], r3
1007 vld1.64 {d6}, [r5], r3
1009 3: // vertical interpolation loop
1013 vld1.64 {d4}, [r2], r3
1016 vld1.64 {d6}, [r5], r3
1017 vrshrn.u16 d16, q8, #6
1018 vrshrn.u16 d17, q9, #6
1021 vst1.64 {d16}, [r0,:64], r1
1022 vst1.64 {d17}, [r0,:64], r1
1028 vld1.64 {d4, d5}, [r2], r3
1029 vld1.64 {d6, d7}, [r2], r3
1030 vext.8 d5, d4, d5, #1
1031 vext.8 d7, d6, d7, #1
1033 5: // horizontal interpolation loop
1038 vld1.64 {d4, d5}, [r2], r3
1042 vext.8 d5, d4, d5, #1
1043 vrshrn.u16 d16, q8, #6
1044 vrshrn.u16 d17, q9, #6
1045 vld1.64 {d6, d7}, [r2], r3
1046 vext.8 d7, d6, d7, #1
1047 vst1.64 {d16}, [r0,:64], r1
1048 vst1.64 {d17}, [r0,:64], r1
1055 // hpel_filter_v( uint8_t *dst, uint8_t *src, int16_t *buf, int stride, int width)
1056 function x264_hpel_filter_v_neon
1058 sub r1, r1, r3, lsl #1
1066 vld1.64 {d0-d1}, [r1,:128], r3
1067 vld1.64 {d2-d3}, [r1,:128], r3
1068 vld1.64 {d4-d5}, [r1,:128], r3
1069 vld1.64 {d6-d7}, [r1,:128], r3
1070 vld1.64 {d16-d17}, [r1,:128], r3
1071 vld1.64 {d18-d19}, [r1,:128], r3
1074 vaddl.u8 q10, d0, d18
1075 vmlsl.u8 q10, d2, d30
1076 vmlal.u8 q10, d4, d31
1077 vmlal.u8 q10, d6, d31
1078 vmlsl.u8 q10, d16, d30
1080 vaddl.u8 q11, d1, d19
1081 vmlsl.u8 q11, d3, d30
1082 vmlal.u8 q11, d5, d31
1083 vmlal.u8 q11, d7, d31
1084 vmlsl.u8 q11, d17, d30
1086 vqrshrun.s16 d0, q10, #5
1087 vst1.64 {d20-d21}, [r2,:128]!
1088 vqrshrun.s16 d1, q11, #5
1089 vst1.64 {d22-d23}, [r2,:128]!
1090 vst1.64 {d0-d1}, [r0,:128]!
1095 // hpel_filter_c( uint8_t *dst, int16_t *buf, int width );
1096 function x264_hpel_filter_c_neon
1098 vld1.64 {d0-d3}, [r1,:128]!
1100 // unrolled 2x: 4% faster
1103 vld1.64 {d4-d7}, [r1,:128]!
1104 vext.16 q8, q0, q1, #6
1105 vext.16 q12, q1, q2, #3
1106 vadd.s16 q8, q8, q12
1107 vext.16 q9, q0, q1, #7
1108 vext.16 q11, q1, q2, #2
1109 vadd.s16 q9, q9, q11
1110 vext.16 q10, q1, q2, #1
1111 vext.16 q11, q1, q2, #6
1112 vadd.s16 q10, q1, q10
1113 vsub.s16 q8, q8, q9 // a-b
1114 vext.16 q15, q2, q3, #3
1115 vsub.s16 q9, q9, q10 // b-c
1117 vext.16 q12, q1, q2, #7
1118 vshr.s16 q8, q8, #2 // (a-b)/4
1119 vadd.s16 q11, q11, q15
1120 vext.16 q14, q2, q3, #2
1121 vsub.s16 q8, q8, q9 // (a-b)/4-b+c
1122 vadd.s16 q12, q12, q14
1123 vext.16 q13, q2, q3, #1
1125 vshr.s16 q8, q8, #2 // ((a-b)/4-b+c)/4
1126 vadd.s16 q13, q2, q13
1127 vadd.s16 q8, q8, q10 // ((a-b)/4-b+c)/4+c = (a-5*b+20*c)/16
1128 vsub.s16 q11, q11, q12 // a-b
1129 vsub.s16 q12, q12, q13 // b-c
1130 vshr.s16 q11, q11, #2 // (a-b)/4
1131 vqrshrun.s16 d30, q8, #6
1132 vsub.s16 q11, q11, q12 // (a-b)/4-b+c
1133 vshr.s16 q11, q11, #2 // ((a-b)/4-b+c)/4
1134 vld1.64 {d0-d3}, [r1,:128]!
1135 vadd.s16 q11, q11, q13 // ((a-b)/4-b+c)/4+c = (a-5*b+20*c)/16
1137 vext.16 q8, q2, q3, #6
1138 vqrshrun.s16 d31, q11, #6
1139 vext.16 q12, q3, q0, #3
1140 vadd.s16 q8, q8, q12
1141 vext.16 q9, q2, q3, #7
1142 vst1.64 {d30-d31}, [r0,:128]!
1146 vext.16 q11, q3, q0, #2
1147 vadd.s16 q9, q9, q11
1148 vext.16 q10, q3, q0, #1
1149 vext.16 q11, q3, q0, #6
1150 vadd.s16 q10, q3, q10
1151 vsub.s16 q8, q8, q9 // a-b
1152 vext.16 q15, q0, q1, #3
1153 vsub.s16 q9, q9, q10 // b-c
1155 vext.16 q12, q3, q0, #7
1156 vshr.s16 q8, q8, #2 // (a-b)/4
1157 vadd.s16 q11, q11, q15
1158 vext.16 q14, q0, q1, #2
1159 vsub.s16 q8, q8, q9 // (a-b)/4-b+c
1160 vadd.s16 q12, q12, q14
1161 vext.16 q13, q0, q1, #1
1163 vshr.s16 q8, q8, #2 // ((a-b)/4-b+c)/4
1164 vadd.s16 q13, q0, q13
1165 vadd.s16 q8, q8, q10 // ((a-b)/4-b+c)/4+c = (a-5*b+20*c)/16
1166 vsub.s16 q11, q11, q12 // a-b
1167 vsub.s16 q12, q12, q13 // b-c
1168 vshr.s16 q11, q11, #2 // (a-b)/4
1169 vqrshrun.s16 d30, q8, #6
1170 vsub.s16 q11, q11, q12 // (a-b)/4-b+c
1171 vshr.s16 q11, q11, #2 // ((a-b)/4-b+c)/4
1172 vadd.s16 q11, q11, q13 // ((a-b)/4-b+c)/4+c = (a-5*b+20*c)/16
1174 vqrshrun.s16 d31, q11, #6
1175 vst1.64 {d30-d31}, [r0,:128]!
1180 // hpel_filter_h( uint8_t *dst, uint8_t *src, int width );
1181 function x264_hpel_filter_h_neon
1184 vld1.64 {d0-d3}, [r1,:128]!
1187 // unrolled 3x because it's 5% faster, due to mitigating
1188 // the high latency of multiplication and vqrshrun
1191 vld1.64 {d4-d5}, [r1,:128]!
1192 vext.8 q8, q0, q1, #14
1193 vext.8 q12, q1, q2, #3
1194 vaddl.u8 q13, d16, d24
1195 vext.8 q9, q0, q1, #15
1196 vaddl.u8 q14, d17, d25
1198 vext.8 q10, q1, q2, #1
1199 vmlal.u8 q13, d2, d31
1200 vmlsl.u8 q13, d18, d30
1201 vext.8 q11, q1, q2, #2
1202 vmlal.u8 q13, d20, d31
1203 vmlsl.u8 q13, d22, d30
1205 vmlsl.u8 q14, d19, d30
1206 vmlal.u8 q14, d3, d31
1207 vmlal.u8 q14, d21, d31
1208 vmlsl.u8 q14, d23, d30
1209 vqrshrun.s16 d6, q13, #5
1211 vld1.64 {d0-d1}, [r1,:128]!
1212 vext.8 q8, q1, q2, #14
1213 vext.8 q12, q2, q0, #3
1214 vaddl.u8 q13, d16, d24
1215 vqrshrun.s16 d7, q14, #5
1216 vext.8 q9, q1, q2, #15
1217 vaddl.u8 q14, d17, d25
1219 vst1.64 {d6-d7}, [r0,:128]!
1223 vext.8 q10, q2, q0, #1
1224 vmlal.u8 q13, d4, d31
1225 vmlsl.u8 q13, d18, d30
1226 vext.8 q11, q2, q0, #2
1227 vmlal.u8 q13, d20, d31
1228 vmlsl.u8 q13, d22, d30
1230 vmlsl.u8 q14, d19, d30
1231 vmlal.u8 q14, d5, d31
1232 vmlal.u8 q14, d21, d31
1233 vmlsl.u8 q14, d23, d30
1234 vqrshrun.s16 d6, q13, #5
1236 vld1.64 {d2-d3}, [r1,:128]!
1237 vext.8 q8, q2, q0, #14
1238 vext.8 q12, q0, q1, #3
1239 vaddl.u8 q13, d16, d24
1240 vqrshrun.s16 d7, q14, #5
1241 vext.8 q9, q2, q0, #15
1242 vaddl.u8 q14, d17, d25
1244 vst1.64 {d6-d7}, [r0,:128]!
1248 vext.8 q10, q0, q1, #1
1249 vmlal.u8 q13, d0, d31
1250 vmlsl.u8 q13, d18, d30
1251 vext.8 q11, q0, q1, #2
1252 vmlal.u8 q13, d20, d31
1253 vmlsl.u8 q13, d22, d30
1255 vmlsl.u8 q14, d19, d30
1256 vmlal.u8 q14, d1, d31
1257 vmlal.u8 q14, d21, d31
1258 vmlsl.u8 q14, d23, d30
1260 vqrshrun.s16 d6, q13, #5
1261 vqrshrun.s16 d7, q14, #5
1262 vst1.64 {d6-d7}, [r0,:128]!
1268 // frame_init_lowres_core( uint8_t *src0, uint8_t *dst0, uint8_t *dsth, uint8_t *dstv,
1269 // uint8_t *dstc, int src_stride, int dst_stride, int width,
1271 function x264_frame_init_lowres_core_neon
1277 sub r10, r6, r7 // dst_stride - width
1283 add r8, r0, r5 // src1 = src0 + src_stride
1284 add r9, r0, r5, lsl #1 // src2 = src1 + src_stride
1286 vld2.8 {d8, d10}, [r6,:128]!
1287 vld2.8 {d12,d14}, [r8,:128]!
1288 vld2.8 {d16,d18}, [r9,:128]!
1293 vld2.8 {d9, d11}, [r6,:128]!
1294 vld2.8 {d13,d15}, [r8,:128]!
1295 vrhadd.u8 q0, q4, q6
1296 vld2.8 {d17,d19}, [r9,:128]!
1297 vrhadd.u8 q5, q5, q7
1298 vld2.8 {d20,d22}, [r6,:128]!
1299 vrhadd.u8 q1, q6, q8
1300 vld2.8 {d24,d26}, [r8,:128]!
1301 vrhadd.u8 q7, q7, q9
1302 vext.8 q4, q4, q10, #1
1303 vrhadd.u8 q0, q0, q5
1304 vext.8 q6, q6, q12, #1
1305 vrhadd.u8 q1, q1, q7
1306 vld2.8 {d28,d30}, [r9,:128]!
1307 vrhadd.u8 q4, q4, q6
1308 vext.8 q8, q8, q14, #1
1309 vrhadd.u8 q6, q6, q8
1310 vst1.64 {d0-d1}, [r1,:128]!
1311 vrhadd.u8 q2, q4, q5
1312 vst1.64 {d2-d3}, [r3,:128]!
1313 vrhadd.u8 q3, q6, q7
1314 vst1.64 {d4-d5}, [r2,:128]!
1315 vst1.64 {d6-d7}, [r4,:128]!
1317 ble lowres_xloop_end
1320 vld2.8 {d21,d23}, [r6,:128]!
1321 vld2.8 {d25,d27}, [r8,:128]!
1322 vrhadd.u8 q0, q10, q12
1323 vld2.8 {d29,d31}, [r9,:128]!
1324 vrhadd.u8 q11, q11, q13
1325 vld2.8 {d8, d10}, [r6,:128]!
1326 vrhadd.u8 q1, q12, q14
1327 vld2.8 {d12,d14}, [r8,:128]!
1328 vrhadd.u8 q13, q13, q15
1329 vext.8 q10, q10, q4, #1
1330 vrhadd.u8 q0, q0, q11
1331 vext.8 q12, q12, q6, #1
1332 vrhadd.u8 q1, q1, q13
1333 vld2.8 {d16,d18}, [r9,:128]!
1334 vrhadd.u8 q10, q10, q12
1335 vext.8 q14, q14, q8, #1
1336 vrhadd.u8 q12, q12, q14
1337 vst1.64 {d0-d1}, [r1,:128]!
1338 vrhadd.u8 q2, q10, q11
1339 vst1.64 {d2-d3}, [r3,:128]!
1340 vrhadd.u8 q3, q12, q13
1341 vst1.64 {d4-d5}, [r2,:128]!
1342 vst1.64 {d6-d7}, [r4,:128]!
1348 add r0, r0, r5, lsl #1