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>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
24 * This program is also available under a commercial proprietary license.
25 * For more information, contact us at licensing@x264.com.
26 *****************************************************************************/
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, intptr_t 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, intptr_t stride_y,
55 // uint8_t *pix_uv, intptr_t 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, export=0
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, intptr_t dst_stride,
162 // uint8_t *src1, intptr_t src1_stride,
163 // uint8_t *src2, intptr_t src2_stride, int weight );
165 function x264_pixel_avg_\w\()x\h\()_neon
169 ldrd r4, r5, [sp, #16]
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
191 .macro load_weights_add_add
196 .macro load_add_add d1 d2
197 vld1.32 {\d1}, [r2], r3
198 vld1.32 {\d2}, [r4], r5
201 .macro weight_add_add dst s1 s2
202 vmull.u8 \dst, \s1, d30
203 vmlal.u8 \dst, \s2, d31
207 .macro load_weights_add_sub
213 .macro load_add_sub d1 d2
214 vld1.32 {\d1}, [r2], r3
215 vld1.32 {\d2}, [r4], r5
218 .macro weight_add_sub dst s1 s2
219 vmull.u8 \dst, \s1, d30
220 vmlsl.u8 \dst, \s2, d31
224 .macro load_weights_sub_add
230 .macro load_sub_add d1 d2
231 vld1.32 {\d2}, [r4], r5
232 vld1.32 {\d1}, [r2], r3
235 .macro weight_sub_add dst s1 s2
236 vmull.u8 \dst, \s2, d31
237 vmlsl.u8 \dst, \s1, d30
240 .macro AVG_WEIGHT ext
241 function x264_pixel_avg_weight_w4_\ext\()_neon, export=0
246 weight_\ext q8, d0, d1
248 vqrshrun.s16 d0, q8, #6
249 weight_\ext q9, d2, d3
250 vst1.32 {d0[0]}, [r0,:32], r1
251 vqrshrun.s16 d1, q9, #6
252 vst1.32 {d1[0]}, [r0,:32], r1
257 function x264_pixel_avg_weight_w8_\ext\()_neon, export=0
262 weight_\ext q8, d0, d1
264 weight_\ext q9, d2, d3
266 weight_\ext q10, d4, d5
268 weight_\ext q11, d6, d7
269 vqrshrun.s16 d0, q8, #6
270 vqrshrun.s16 d1, q9, #6
271 vqrshrun.s16 d2, q10, #6
272 vqrshrun.s16 d3, q11, #6
273 vst1.64 {d0}, [r0,:64], r1
274 vst1.64 {d1}, [r0,:64], r1
275 vst1.64 {d2}, [r0,:64], r1
276 vst1.64 {d3}, [r0,:64], r1
281 function x264_pixel_avg_weight_w16_\ext\()_neon, export=0
285 load_\ext d0-d1, d2-d3
286 weight_\ext q8, d0, d2
287 weight_\ext q9, d1, d3
288 load_\ext d4-d5, d6-d7
289 weight_\ext q10, d4, d6
290 weight_\ext q11, d5, d7
291 vqrshrun.s16 d0, q8, #6
292 vqrshrun.s16 d1, q9, #6
293 vqrshrun.s16 d2, q10, #6
294 vqrshrun.s16 d3, q11, #6
295 vst1.64 {d0-d1}, [r0,:128], r1
296 vst1.64 {d2-d3}, [r0,:128], r1
306 function x264_pixel_avg_w4_neon, export=0
308 vld1.32 {d0[]}, [r2], r3
309 vld1.32 {d2[]}, [r4], r5
311 vld1.32 {d1[]}, [r2], r3
312 vld1.32 {d3[]}, [r4], r5
314 vst1.32 {d0[0]}, [r0,:32], r1
315 vst1.32 {d1[0]}, [r0,:32], r1
316 bgt x264_pixel_avg_w4_neon
320 function x264_pixel_avg_w8_neon, export=0
322 vld1.64 {d0}, [r2], r3
323 vld1.64 {d2}, [r4], r5
325 vld1.64 {d1}, [r2], r3
326 vld1.64 {d3}, [r4], r5
328 vst1.64 {d0}, [r0,:64], r1
329 vld1.64 {d2}, [r2], r3
330 vld1.64 {d4}, [r4], r5
332 vst1.64 {d1}, [r0,:64], r1
333 vld1.64 {d3}, [r2], r3
334 vld1.64 {d5}, [r4], r5
336 vst1.64 {d2}, [r0,:64], r1
337 vst1.64 {d3}, [r0,:64], r1
338 bgt x264_pixel_avg_w8_neon
342 function x264_pixel_avg_w16_neon, export=0
344 vld1.64 {d0-d1}, [r2], r3
345 vld1.64 {d2-d3}, [r4], r5
347 vld1.64 {d2-d3}, [r2], r3
348 vld1.64 {d4-d5}, [r4], r5
350 vst1.64 {d0-d1}, [r0,:128], r1
351 vld1.64 {d4-d5}, [r2], r3
352 vld1.64 {d6-d7}, [r4], r5
354 vst1.64 {d2-d3}, [r0,:128], r1
355 vld1.64 {d6-d7}, [r2], r3
356 vld1.64 {d0-d1}, [r4], r5
358 vst1.64 {d4-d5}, [r0,:128], r1
359 vst1.64 {d6-d7}, [r0,:128], r1
360 bgt x264_pixel_avg_w16_neon
365 function x264_pixel_avg2_w4_neon
371 vld1.32 {d0[]}, [r2], r3
372 vld1.32 {d2[]}, [lr], r3
374 vld1.32 {d1[]}, [r2], r3
375 vld1.32 {d3[]}, [lr], r3
377 vst1.32 {d0[0]}, [r0,:32], r1
378 vst1.32 {d1[0]}, [r0,:32], r1
383 function x264_pixel_avg2_w8_neon
389 vld1.64 {d0}, [r2], r3
390 vld1.64 {d2}, [lr], r3
392 vld1.64 {d1}, [r2], r3
393 vld1.64 {d3}, [lr], r3
395 vst1.64 {d0}, [r0,:64], r1
396 vst1.64 {d1}, [r0,:64], r1
401 function x264_pixel_avg2_w16_neon
407 vld1.64 {d0-d1}, [r2], r3
408 vld1.64 {d2-d3}, [lr], r3
410 vld1.64 {d4-d5}, [r2], r3
411 vld1.64 {d6-d7}, [lr], r3
413 vst1.64 {d0-d1}, [r0,:128], r1
414 vst1.64 {d4-d5}, [r0,:128], r1
419 function x264_pixel_avg2_w20_neon
426 vld1.64 {d0-d2}, [r2], r3
427 vld1.64 {d4-d6}, [lr], r3
430 vld1.64 {d4-d6}, [r2], r3
431 vld1.64 {d16-d18},[lr], r3
433 vst1.64 {d0-d1}, [r0,:128]!
434 vrhadd.u8 d6, d6, d18
435 vst1.32 {d2[0]}, [r0,:32], r1
436 vst1.64 {d4-d5}, [r0,:128]!
437 vst1.32 {d6[0]}, [r0,:32], r1
443 .macro weight_prologue type
445 ldr r4, [sp, #4*3] // weight_t
446 ldr ip, [sp, #4*3+4] // h
448 ldr lr, [r4, #32] // denom
450 ldrd r4, r5, [r4, #32+4] // scale, offset
459 // void mc_weight( uint8_t *src, intptr_t src_stride, uint8_t *dst, intptr_t dst_stride,
460 // const x264_weight_t *weight, int height )
461 function x264_mc_weight_w20_neon
466 vld1.8 {d17-d19}, [r2], r3
467 vmull.u8 q10, d17, d0
468 vmull.u8 q11, d18, d0
469 vld1.8 {d16-d18}, [r2], r3
470 vmull.u8 q12, d16, d0
471 vmull.u8 q13, d17, d0
473 vmull.u8 q14, d19, d0
474 vrshl.s16 q10, q10, q2
475 vrshl.s16 q11, q11, q2
476 vrshl.s16 q12, q12, q2
477 vrshl.s16 q13, q13, q2
478 vrshl.s16 q14, q14, q2
479 vadd.s16 q10, q10, q1
480 vadd.s16 q11, q11, q1
481 vadd.s16 q12, q12, q1
482 vadd.s16 q13, q13, q1
483 vadd.s16 q14, q14, q1
489 vst1.8 {d16-d17}, [r0,:128]!
490 vst1.32 {d20[0]}, [r0,:32], r1
491 vst1.8 {d18-d19}, [r0,:128]!
492 vst1.32 {d20[1]}, [r0,:32], r1
497 function x264_mc_weight_w16_neon
501 vld1.8 {d16-d17}, [r2], r3
502 vld1.8 {d18-d19}, [r2], r3
503 vmull.u8 q10, d16, d0
504 vmull.u8 q11, d17, d0
505 vmull.u8 q12, d18, d0
506 vmull.u8 q13, d19, d0
507 vrshl.s16 q10, q10, q2
508 vrshl.s16 q11, q11, q2
509 vrshl.s16 q12, q12, q2
510 vrshl.s16 q13, q13, q2
511 vadd.s16 q10, q10, q1
512 vadd.s16 q11, q11, q1
513 vadd.s16 q12, q12, q1
514 vadd.s16 q13, q13, q1
519 vst1.8 {d16-d17}, [r0,:128], r1
520 vst1.8 {d18-d19}, [r0,:128], r1
525 function x264_mc_weight_w8_neon
529 vld1.8 {d16}, [r2], r3
530 vld1.8 {d18}, [r2], r3
539 vst1.8 {d16}, [r0,:64], r1
540 vst1.8 {d18}, [r0,:64], r1
545 function x264_mc_weight_w4_neon
549 vld1.32 {d16[0]}, [r2], r3
550 vld1.32 {d16[1]}, [r2], r3
555 vst1.32 {d16[0]}, [r0], r1
556 vst1.32 {d16[1]}, [r0], r1
561 function x264_mc_weight_w20_nodenom_neon
562 weight_prologue nodenom
564 weight20_nodenom_loop:
566 vld1.8 {d26-d28}, [r2], r3
569 vld1.8 {d29-d31}, [r2], r3
576 vmlal.u8 q10, d29, d0
577 vmlal.u8 q11, d30, d0
578 vmlal.u8 q12, d28, d0
584 vst1.8 {d16-d17}, [r0,:128]!
585 vst1.32 {d20[0]}, [r0,:32], r1
586 vst1.8 {d18-d19}, [r0,:128]!
587 vst1.32 {d20[1]}, [r0,:32], r1
588 bgt weight20_nodenom_loop
592 function x264_mc_weight_w16_nodenom_neon
593 weight_prologue nodenom
594 weight16_nodenom_loop:
596 vld1.8 {d16-d17}, [r2], r3
597 vld1.8 {d18-d19}, [r2], r3
602 vmlal.u8 q12, d16, d0
603 vmlal.u8 q13, d17, d0
604 vmlal.u8 q14, d18, d0
605 vmlal.u8 q15, d19, d0
610 vst1.8 {d16-d17}, [r0,:128], r1
611 vst1.8 {d18-d19}, [r0,:128], r1
612 bgt weight16_nodenom_loop
616 function x264_mc_weight_w8_nodenom_neon
617 weight_prologue nodenom
618 weight8_nodenom_loop:
620 vld1.8 {d16}, [r2], r3
621 vld1.8 {d18}, [r2], r3
624 vmlal.u8 q10, d16, d0
625 vmlal.u8 q11, d18, d0
628 vst1.8 {d16}, [r0,:64], r1
629 vst1.8 {d17}, [r0,:64], r1
630 bgt weight8_nodenom_loop
634 function x264_mc_weight_w4_nodenom_neon
635 weight_prologue nodenom
636 weight4_nodenom_loop:
638 vld1.32 {d16[0]}, [r2], r3
639 vld1.32 {d16[1]}, [r2], r3
641 vmlal.u8 q10, d16, d0
643 vst1.32 {d16[0]}, [r0], r1
644 vst1.32 {d16[1]}, [r0], r1
645 bgt weight4_nodenom_loop
649 .macro weight_simple_prologue
651 ldr lr, [sp, #4] // weight_t
652 ldr ip, [sp, #8] // h
653 ldr lr, [lr] // offset
657 .macro weight_simple name op
658 function x264_mc_weight_w20_\name\()_neon
659 weight_simple_prologue
660 weight20_\name\()_loop:
662 vld1.8 {d16-d18}, [r2], r3
663 vld1.8 {d19-d21}, [r2], r3
667 vst1.8 {d16-d18}, [r0,:64], r1
668 vst1.8 {d19-d21}, [r0,:64], r1
669 bgt weight20_\name\()_loop
673 function x264_mc_weight_w16_\name\()_neon
674 weight_simple_prologue
675 weight16_\name\()_loop:
677 vld1.8 {d16-d17}, [r2], r3
678 vld1.8 {d18-d19}, [r2], r3
681 vst1.8 {d16-d17}, [r0,:128], r1
682 vst1.8 {d18-d19}, [r0,:128], r1
683 bgt weight16_\name\()_loop
687 function x264_mc_weight_w8_\name\()_neon
688 weight_simple_prologue
689 weight8_\name\()_loop:
691 vld1.8 {d16}, [r2], r3
692 vld1.8 {d17}, [r2], r3
694 vst1.8 {d16}, [r0,:64], r1
695 vst1.8 {d17}, [r0,:64], r1
696 bgt weight8_\name\()_loop
700 function x264_mc_weight_w4_\name\()_neon
701 weight_simple_prologue
702 weight4_\name\()_loop:
704 vld1.32 {d16[]}, [r2], r3
705 vld1.32 {d17[]}, [r2], r3
707 vst1.32 {d16[0]}, [r0], r1
708 vst1.32 {d17[0]}, [r0], r1
709 bgt weight4_\name\()_loop
714 weight_simple offsetadd, vqadd.u8
715 weight_simple offsetsub, vqsub.u8
718 // void mc_copy( uint8_t *dst, intptr_t dst_stride, uint8_t *src, intptr_t src_stride, int height )
719 function x264_mc_copy_w4_neon
723 vld1.32 {d0[]}, [r2], r3
724 vld1.32 {d1[]}, [r2], r3
725 vld1.32 {d2[]}, [r2], r3
726 vld1.32 {d3[]}, [r2], r3
727 vst1.32 {d0[0]}, [r0,:32], r1
728 vst1.32 {d1[0]}, [r0,:32], r1
729 vst1.32 {d2[0]}, [r0,:32], r1
730 vst1.32 {d3[0]}, [r0,:32], r1
735 function x264_mc_copy_w8_neon
739 vld1.32 {d0}, [r2], r3
740 vld1.32 {d1}, [r2], r3
741 vld1.32 {d2}, [r2], r3
742 vld1.32 {d3}, [r2], r3
743 vst1.32 {d0}, [r0,:64], r1
744 vst1.32 {d1}, [r0,:64], r1
745 vst1.32 {d2}, [r0,:64], r1
746 vst1.32 {d3}, [r0,:64], r1
751 function x264_mc_copy_w16_neon
755 vld1.32 {d0-d1}, [r2], r3
756 vld1.32 {d2-d3}, [r2], r3
757 vld1.32 {d4-d5}, [r2], r3
758 vld1.32 {d6-d7}, [r2], r3
759 vst1.32 {d0-d1}, [r0,:128], r1
760 vst1.32 {d2-d3}, [r0,:128], r1
761 vst1.32 {d4-d5}, [r0,:128], r1
762 vst1.32 {d6-d7}, [r0,:128], r1
767 function x264_mc_copy_w16_aligned_neon
769 copy_w16_aligned_loop:
771 vld1.32 {d0-d1}, [r2,:128], r3
772 vld1.32 {d2-d3}, [r2,:128], r3
773 vld1.32 {d4-d5}, [r2,:128], r3
774 vld1.32 {d6-d7}, [r2,:128], r3
775 vst1.32 {d0-d1}, [r0,:128], r1
776 vst1.32 {d2-d3}, [r0,:128], r1
777 vst1.32 {d4-d5}, [r0,:128], r1
778 vst1.32 {d6-d7}, [r0,:128], r1
779 bgt copy_w16_aligned_loop
784 // void x264_mc_chroma_neon( uint8_t *dst, intptr_t i_dst_stride,
785 // uint8_t *src, intptr_t i_src_stride,
786 // int dx, int dy, int i_width, int i_height );
788 function x264_mc_chroma_neon
791 ldrd r4, r5, [sp, #56]
792 ldrd r6, r7, [sp, #64]
796 add r3, r3, r5, asr #2
811 .macro CHROMA_MC_START r00, r01, r10, r11
813 rsb r7, lr, r6, lsl #3
814 rsb ip, lr, r5, lsl #3
815 sub r5, lr, r5, lsl #3
816 sub r5, r5, r6, lsl #3
820 vld2.8 {\r00-\r01}, [r3], r4
826 vld2.8 {\r10-\r11}, [r3], r4
831 .macro CHROMA_MC width, align
833 CHROMA_MC_START d4, d5, d8, d9
834 vext.8 d6, d4, d6, #1
835 vext.8 d7, d5, d7, #1
836 vext.8 d10, d8, d10, #1
837 vext.8 d11, d9, d11, #1
838 // since the element size varies, there's a different index for the 2nd store
853 1: // height loop, interpolate xy
860 vld2.8 {d4-d5}, [r3], r4
862 vext.8 d6, d4, d6, #1
863 vext.8 d7, d5, d7, #1
865 vadd.i16 d16, d16, d17
866 vadd.i16 d17, d18, d19
876 vld2.8 {d8-d9}, [r3], r4
878 vrshrn.u16 d16, q8, #6
880 vext.8 d10, d8, d10, #1
881 vext.8 d11, d9, d11, #1
883 vadd.i16 d18, d20, d21
884 vadd.i16 d19, d22, d23
889 vrshrn.u16 d18, q9, #6
896 vst1.\align {d16[0]}, [r0,:\align], r2
897 vst1.\align {d16[st2]}, [r1,:\align], r2
898 vst1.\align {d18[0]}, [r0,:\align], r2
899 vst1.\align {d18[st2]}, [r1,:\align], r2
914 vld1.64 {d4}, [r3], r4
915 vld1.64 {d6}, [r3], r4
917 3: // vertical interpolation loop
922 vld1.64 {d4}, [r3], r4
924 vld1.64 {d6}, [r3], r4
926 vrshrn.u16 d16, q8, #6 // uvuvuvuv
927 vrshrn.u16 d17, q9, #6 // uvuvuvuv
929 vuzp.8 d16, d17 // d16=uuuu|uuuu, d17=vvvv|vvvv
934 vst1.\align {d16[0]}, [r0,:\align], r2
935 vst1.\align {d16[st2]}, [r0,:\align], r2
936 vst1.\align {d17[0]}, [r1,:\align], r2
937 vst1.\align {d17[st2]}, [r1,:\align], r2
945 vld1.64 {d4-d5}, [r3], r4
946 vld1.64 {d6-d7}, [r3], r4
948 vext.8 d5, d4, d5, #2
949 vext.8 d7, d6, d7, #2
951 5: // horizontal interpolation loop
959 vld1.64 {d4-d5}, [r3], r4
960 vld1.64 {d6-d7}, [r3], r4
961 vext.8 d5, d4, d5, #2
962 vrshrn.u16 d16, q8, #6
963 vrshrn.u16 d17, q9, #6
964 vext.8 d7, d6, d7, #2
970 vst1.\align {d16[0]}, [r0,:\align], r2
971 vst1.\align {d16[st2]}, [r0,:\align], r2
972 vst1.\align {d17[0]}, [r1,:\align], r2
973 vst1.\align {d17[st2]}, [r1,:\align], r2
984 CHROMA_MC_START d4, d7, d8, d11
985 vext.8 d5, d4, d5, #1
986 vext.8 d9, d8, d9, #1
987 vext.8 d7, d6, d7, #1
988 vext.8 d11, d10, d11, #1
990 1: // height loop, interpolate xy
1001 vld2.8 {d4-d7}, [r3], r4
1003 vext.8 d5, d4, d5, #1
1004 vext.8 d7, d6, d7, #1
1006 vmull.u8 q10, d8, d0
1007 vmlal.u8 q10, d9, d1
1008 vmlal.u8 q10, d4, d2
1009 vmlal.u8 q10, d5, d3
1011 vmull.u8 q11, d10, d0
1012 vmlal.u8 q11, d11, d1
1013 vmlal.u8 q11, d6, d2
1014 vmlal.u8 q11, d7, d3
1017 vld2.8 {d8-d11}, [r3], r4
1019 vrshrn.u16 d16, q8, #6
1020 vrshrn.u16 d17, q9, #6
1021 vrshrn.u16 d18, q10, #6
1022 vext.8 d9, d8, d9, #1
1023 vrshrn.u16 d19, q11, #6
1024 vext.8 d11, d10, d11, #1
1029 vst1.64 {d16}, [r0,:64], r2
1030 vst1.64 {d17}, [r1,:64], r2
1031 vst1.64 {d18}, [r0,:64], r2
1032 vst1.64 {d19}, [r1,:64], r2
1039 2: // dx or dy are 0
1048 vld2.8 {d4-d5}, [r3], r4
1049 vld2.8 {d6-d7}, [r3], r4
1051 3: // vertical interpolation loop
1052 vmull.u8 q8, d4, d0 //U
1054 vmull.u8 q9, d5, d0 //V
1057 vld2.8 {d4-d5}, [r3], r4
1059 vmull.u8 q10, d6, d0
1060 vmlal.u8 q10, d4, d1
1061 vmull.u8 q11, d7, d0
1062 vmlal.u8 q11, d5, d1
1064 vld2.8 {d6-d7}, [r3], r4
1066 vrshrn.u16 d16, q8, #6
1067 vrshrn.u16 d17, q9, #6
1068 vrshrn.u16 d18, q10, #6
1069 vrshrn.u16 d19, q11, #6
1075 vst1.64 {d16}, [r0,:64], r2
1076 vst1.64 {d17}, [r1,:64], r2
1077 vst1.64 {d18}, [r0,:64], r2
1078 vst1.64 {d19}, [r1,:64], r2
1087 vld2.8 {d4-d7}, [r3], r4
1088 vld2.8 {d8-d11}, [r3], r4
1089 vext.8 d5, d4, d5, #1
1090 vext.8 d7, d6, d7, #1
1091 vext.8 d9, d8, d9, #1
1092 vext.8 d11, d10, d11, #1
1094 5: // horizontal interpolation loop
1096 vmull.u8 q8, d4, d0 //U
1098 vmull.u8 q9, d6, d0 //V
1101 vld2.8 {d4-d7}, [r3], r4
1103 vmull.u8 q10, d8, d0
1104 vmlal.u8 q10, d9, d1
1105 vmull.u8 q11, d10, d0
1106 vmlal.u8 q11, d11, d1
1108 vld2.8 {d8-d11}, [r3], r4
1110 vext.8 d5, d4, d5, #1
1111 vrshrn.u16 d16, q8, #6
1112 vext.8 d7, d6, d7, #1
1113 vrshrn.u16 d17, q9, #6
1114 vext.8 d9, d8, d9, #1
1115 vrshrn.u16 d18, q10, #6
1116 vext.8 d11, d10, d11, #1
1117 vrshrn.u16 d19, q11, #6
1122 vst1.64 {d16}, [r0,:64], r2
1123 vst1.64 {d17}, [r1,:64], r2
1124 vst1.64 {d18}, [r0,:64], r2
1125 vst1.64 {d19}, [r1,:64], r2
1134 // hpel_filter_v( uint8_t *dst, uint8_t *src, int16_t *buf, intptr_t stride, int width )
1135 function x264_hpel_filter_v_neon
1137 sub r1, r1, r3, lsl #1
1145 vld1.64 {d0-d1}, [r1,:128], r3
1146 vld1.64 {d2-d3}, [r1,:128], r3
1147 vld1.64 {d4-d5}, [r1,:128], r3
1148 vld1.64 {d6-d7}, [r1,:128], r3
1149 vld1.64 {d16-d17}, [r1,:128], r3
1150 vld1.64 {d18-d19}, [r1,:128], r3
1153 vaddl.u8 q10, d0, d18
1154 vmlsl.u8 q10, d2, d30
1155 vmlal.u8 q10, d4, d31
1156 vmlal.u8 q10, d6, d31
1157 vmlsl.u8 q10, d16, d30
1159 vaddl.u8 q11, d1, d19
1160 vmlsl.u8 q11, d3, d30
1161 vmlal.u8 q11, d5, d31
1162 vmlal.u8 q11, d7, d31
1163 vmlsl.u8 q11, d17, d30
1165 vqrshrun.s16 d0, q10, #5
1166 vst1.64 {d20-d21}, [r2,:128]!
1167 vqrshrun.s16 d1, q11, #5
1168 vst1.64 {d22-d23}, [r2,:128]!
1169 vst1.64 {d0-d1}, [r0,:128]!
1174 // hpel_filter_c( uint8_t *dst, int16_t *buf, int width );
1175 function x264_hpel_filter_c_neon
1177 vld1.64 {d0-d3}, [r1,:128]!
1179 // unrolled 2x: 4% faster
1182 vld1.64 {d4-d7}, [r1,:128]!
1183 vext.16 q8, q0, q1, #6
1184 vext.16 q12, q1, q2, #3
1185 vadd.s16 q8, q8, q12
1186 vext.16 q9, q0, q1, #7
1187 vext.16 q11, q1, q2, #2
1188 vadd.s16 q9, q9, q11
1189 vext.16 q10, q1, q2, #1
1190 vext.16 q11, q1, q2, #6
1191 vadd.s16 q10, q1, q10
1192 vsub.s16 q8, q8, q9 // a-b
1193 vext.16 q15, q2, q3, #3
1194 vsub.s16 q9, q9, q10 // b-c
1196 vext.16 q12, q1, q2, #7
1197 vshr.s16 q8, q8, #2 // (a-b)/4
1198 vadd.s16 q11, q11, q15
1199 vext.16 q14, q2, q3, #2
1200 vsub.s16 q8, q8, q9 // (a-b)/4-b+c
1201 vadd.s16 q12, q12, q14
1202 vext.16 q13, q2, q3, #1
1204 vshr.s16 q8, q8, #2 // ((a-b)/4-b+c)/4
1205 vadd.s16 q13, q2, q13
1206 vadd.s16 q8, q8, q10 // ((a-b)/4-b+c)/4+c = (a-5*b+20*c)/16
1207 vsub.s16 q11, q11, q12 // a-b
1208 vsub.s16 q12, q12, q13 // b-c
1209 vshr.s16 q11, q11, #2 // (a-b)/4
1210 vqrshrun.s16 d30, q8, #6
1211 vsub.s16 q11, q11, q12 // (a-b)/4-b+c
1212 vshr.s16 q11, q11, #2 // ((a-b)/4-b+c)/4
1213 vld1.64 {d0-d3}, [r1,:128]!
1214 vadd.s16 q11, q11, q13 // ((a-b)/4-b+c)/4+c = (a-5*b+20*c)/16
1216 vext.16 q8, q2, q3, #6
1217 vqrshrun.s16 d31, q11, #6
1218 vext.16 q12, q3, q0, #3
1219 vadd.s16 q8, q8, q12
1220 vext.16 q9, q2, q3, #7
1221 vst1.64 {d30-d31}, [r0,:128]!
1225 vext.16 q11, q3, q0, #2
1226 vadd.s16 q9, q9, q11
1227 vext.16 q10, q3, q0, #1
1228 vext.16 q11, q3, q0, #6
1229 vadd.s16 q10, q3, q10
1230 vsub.s16 q8, q8, q9 // a-b
1231 vext.16 q15, q0, q1, #3
1232 vsub.s16 q9, q9, q10 // b-c
1234 vext.16 q12, q3, q0, #7
1235 vshr.s16 q8, q8, #2 // (a-b)/4
1236 vadd.s16 q11, q11, q15
1237 vext.16 q14, q0, q1, #2
1238 vsub.s16 q8, q8, q9 // (a-b)/4-b+c
1239 vadd.s16 q12, q12, q14
1240 vext.16 q13, q0, q1, #1
1242 vshr.s16 q8, q8, #2 // ((a-b)/4-b+c)/4
1243 vadd.s16 q13, q0, q13
1244 vadd.s16 q8, q8, q10 // ((a-b)/4-b+c)/4+c = (a-5*b+20*c)/16
1245 vsub.s16 q11, q11, q12 // a-b
1246 vsub.s16 q12, q12, q13 // b-c
1247 vshr.s16 q11, q11, #2 // (a-b)/4
1248 vqrshrun.s16 d30, q8, #6
1249 vsub.s16 q11, q11, q12 // (a-b)/4-b+c
1250 vshr.s16 q11, q11, #2 // ((a-b)/4-b+c)/4
1251 vadd.s16 q11, q11, q13 // ((a-b)/4-b+c)/4+c = (a-5*b+20*c)/16
1253 vqrshrun.s16 d31, q11, #6
1254 vst1.64 {d30-d31}, [r0,:128]!
1259 // hpel_filter_h( uint8_t *dst, uint8_t *src, int width );
1260 function x264_hpel_filter_h_neon
1263 vld1.64 {d0-d3}, [r1,:128]!
1266 // unrolled 3x because it's 5% faster, due to mitigating
1267 // the high latency of multiplication and vqrshrun
1270 vld1.64 {d4-d5}, [r1,:128]!
1271 vext.8 q8, q0, q1, #14
1272 vext.8 q12, q1, q2, #3
1273 vaddl.u8 q13, d16, d24
1274 vext.8 q9, q0, q1, #15
1275 vaddl.u8 q14, d17, d25
1277 vext.8 q10, q1, q2, #1
1278 vmlal.u8 q13, d2, d31
1279 vmlsl.u8 q13, d18, d30
1280 vext.8 q11, q1, q2, #2
1281 vmlal.u8 q13, d20, d31
1282 vmlsl.u8 q13, d22, d30
1284 vmlsl.u8 q14, d19, d30
1285 vmlal.u8 q14, d3, d31
1286 vmlal.u8 q14, d21, d31
1287 vmlsl.u8 q14, d23, d30
1288 vqrshrun.s16 d6, q13, #5
1290 vld1.64 {d0-d1}, [r1,:128]!
1291 vext.8 q8, q1, q2, #14
1292 vext.8 q12, q2, q0, #3
1293 vaddl.u8 q13, d16, d24
1294 vqrshrun.s16 d7, q14, #5
1295 vext.8 q9, q1, q2, #15
1296 vaddl.u8 q14, d17, d25
1298 vst1.64 {d6-d7}, [r0,:128]!
1302 vext.8 q10, q2, q0, #1
1303 vmlal.u8 q13, d4, d31
1304 vmlsl.u8 q13, d18, d30
1305 vext.8 q11, q2, q0, #2
1306 vmlal.u8 q13, d20, d31
1307 vmlsl.u8 q13, d22, d30
1309 vmlsl.u8 q14, d19, d30
1310 vmlal.u8 q14, d5, d31
1311 vmlal.u8 q14, d21, d31
1312 vmlsl.u8 q14, d23, d30
1313 vqrshrun.s16 d6, q13, #5
1315 vld1.64 {d2-d3}, [r1,:128]!
1316 vext.8 q8, q2, q0, #14
1317 vext.8 q12, q0, q1, #3
1318 vaddl.u8 q13, d16, d24
1319 vqrshrun.s16 d7, q14, #5
1320 vext.8 q9, q2, q0, #15
1321 vaddl.u8 q14, d17, d25
1323 vst1.64 {d6-d7}, [r0,:128]!
1327 vext.8 q10, q0, q1, #1
1328 vmlal.u8 q13, d0, d31
1329 vmlsl.u8 q13, d18, d30
1330 vext.8 q11, q0, q1, #2
1331 vmlal.u8 q13, d20, d31
1332 vmlsl.u8 q13, d22, d30
1334 vmlsl.u8 q14, d19, d30
1335 vmlal.u8 q14, d1, d31
1336 vmlal.u8 q14, d21, d31
1337 vmlsl.u8 q14, d23, d30
1339 vqrshrun.s16 d6, q13, #5
1340 vqrshrun.s16 d7, q14, #5
1341 vst1.64 {d6-d7}, [r0,:128]!
1347 // frame_init_lowres_core( uint8_t *src0, uint8_t *dst0, uint8_t *dsth, uint8_t *dstv,
1348 // uint8_t *dstc, intptr_t src_stride, intptr_t dst_stride, int width,
1350 function x264_frame_init_lowres_core_neon
1353 ldrd r4, r5, [sp, #96]
1354 ldrd r6, r7, [sp, #104]
1356 sub r10, r6, r7 // dst_stride - width
1362 add r8, r0, r5 // src1 = src0 + src_stride
1363 add r9, r0, r5, lsl #1 // src2 = src1 + src_stride
1365 vld2.8 {d8, d10}, [r6,:128]!
1366 vld2.8 {d12,d14}, [r8,:128]!
1367 vld2.8 {d16,d18}, [r9,:128]!
1372 vld2.8 {d9, d11}, [r6,:128]!
1373 vld2.8 {d13,d15}, [r8,:128]!
1374 vrhadd.u8 q0, q4, q6
1375 vld2.8 {d17,d19}, [r9,:128]!
1376 vrhadd.u8 q5, q5, q7
1377 vld2.8 {d20,d22}, [r6,:128]!
1378 vrhadd.u8 q1, q6, q8
1379 vld2.8 {d24,d26}, [r8,:128]!
1380 vrhadd.u8 q7, q7, q9
1381 vext.8 q4, q4, q10, #1
1382 vrhadd.u8 q0, q0, q5
1383 vext.8 q6, q6, q12, #1
1384 vrhadd.u8 q1, q1, q7
1385 vld2.8 {d28,d30}, [r9,:128]!
1386 vrhadd.u8 q4, q4, q6
1387 vext.8 q8, q8, q14, #1
1388 vrhadd.u8 q6, q6, q8
1389 vst1.64 {d0-d1}, [r1,:128]!
1390 vrhadd.u8 q2, q4, q5
1391 vst1.64 {d2-d3}, [r3,:128]!
1392 vrhadd.u8 q3, q6, q7
1393 vst1.64 {d4-d5}, [r2,:128]!
1394 vst1.64 {d6-d7}, [r4,:128]!
1396 ble lowres_xloop_end
1399 vld2.8 {d21,d23}, [r6,:128]!
1400 vld2.8 {d25,d27}, [r8,:128]!
1401 vrhadd.u8 q0, q10, q12
1402 vld2.8 {d29,d31}, [r9,:128]!
1403 vrhadd.u8 q11, q11, q13
1404 vld2.8 {d8, d10}, [r6,:128]!
1405 vrhadd.u8 q1, q12, q14
1406 vld2.8 {d12,d14}, [r8,:128]!
1407 vrhadd.u8 q13, q13, q15
1408 vext.8 q10, q10, q4, #1
1409 vrhadd.u8 q0, q0, q11
1410 vext.8 q12, q12, q6, #1
1411 vrhadd.u8 q1, q1, q13
1412 vld2.8 {d16,d18}, [r9,:128]!
1413 vrhadd.u8 q10, q10, q12
1414 vext.8 q14, q14, q8, #1
1415 vrhadd.u8 q12, q12, q14
1416 vst1.64 {d0-d1}, [r1,:128]!
1417 vrhadd.u8 q2, q10, q11
1418 vst1.64 {d2-d3}, [r3,:128]!
1419 vrhadd.u8 q3, q12, q13
1420 vst1.64 {d4-d5}, [r2,:128]!
1421 vst1.64 {d6-d7}, [r4,:128]!
1427 add r0, r0, r5, lsl #1
1438 function x264_load_deinterleave_chroma_fdec_neon
1439 mov ip, #FDEC_STRIDE/2
1441 vld2.8 {d0-d1}, [r1,:128], r2
1444 vst1.8 {d0}, [r0,:64], ip
1445 vst1.8 {d1}, [r0,:64], ip
1451 function x264_load_deinterleave_chroma_fenc_neon
1452 mov ip, #FENC_STRIDE/2
1454 vld2.8 {d0-d1}, [r1,:128], r2
1457 vst1.8 {d0}, [r0,:64], ip
1458 vst1.8 {d1}, [r0,:64], ip
1464 function x264_plane_copy_deinterleave_neon
1466 ldrd r6, r7, [sp, #28]
1467 ldrd r4, r5, [sp, #20]
1472 sub r5, r5, lr, lsl #1
1474 vld2.8 {d0-d3}, [r4,:128]!
1490 function x264_plane_copy_deinterleave_rgb_neon
1491 push {r4-r8, r10, r11, lr}
1492 ldrd r4, r5, [sp, #32]
1493 ldrd r6, r7, [sp, #40]
1495 ldrd r10, r11, [sp, #52]
1499 sub r7, r7, lr, lsl #1
1503 subne r7, r7, lr, lsl #1
1507 vld3.8 {d0,d1,d2}, [r6]!
1522 pop {r4-r8, r10, r11, pc}
1524 vld4.8 {d0,d1,d2,d3}, [r6]!
1539 pop {r4-r8, r10, r11, pc}
1542 function x264_plane_copy_interleave_neon
1544 ldrd r6, r7, [sp, #28]
1545 ldrd r4, r5, [sp, #20]
1548 sub r1, r1, lr, lsl #1
1555 vst2.8 {d0,d2}, [r0]!
1556 vst2.8 {d1,d3}, [r0]!
1569 function x264_plane_copy_swap_neon
1571 ldrd r4, r5, [sp, #12]
1574 sub r1, r1, lr, lsl #1
1575 sub r3, r3, lr, lsl #1
1577 vld1.8 {q0, q1}, [r2]!
1581 vst1.8 {q0, q1}, [r0]!
1593 function x264_store_interleave_chroma_neon
1596 mov ip, #FDEC_STRIDE
1598 vld1.8 {d0}, [r2], ip
1599 vld1.8 {d1}, [r3], ip
1601 vst2.8 {d0,d1}, [r0,:128], r1
1607 .macro integral4h p1, p2
1608 vext.8 d1, \p1, \p2, #1
1609 vext.8 d2, \p1, \p2, #2
1610 vext.8 d3, \p1, \p2, #3
1611 vaddl.u8 q0, \p1, d1
1617 function integral_init4h_neon
1618 sub r3, r0, r2, lsl #1
1619 vld1.8 {d6, d7}, [r1, :128]!
1622 vld1.16 {q2}, [r3, :128]!
1624 vld1.8 {d6}, [r1, :64]!
1625 vld1.16 {q2}, [r3, :128]!
1626 vst1.16 {q0}, [r0, :128]!
1628 vld1.8 {d7}, [r1, :64]!
1629 vst1.16 {q0}, [r0, :128]!
1634 .macro integral8h p1, p2, s
1635 vext.8 d1, \p1, \p2, #1
1636 vext.8 d2, \p1, \p2, #2
1637 vext.8 d3, \p1, \p2, #3
1638 vext.8 d4, \p1, \p2, #4
1639 vext.8 d5, \p1, \p2, #5
1640 vext.8 d6, \p1, \p2, #6
1641 vext.8 d7, \p1, \p2, #7
1642 vaddl.u8 q0, \p1, d1
1652 function integral_init8h_neon
1653 sub r3, r0, r2, lsl #1
1654 vld1.8 {d16, d17}, [r1, :128]!
1657 vld1.16 {q9}, [r3, :128]!
1658 integral8h d16, d17, q9
1659 vld1.8 {d16}, [r1, :64]!
1660 vld1.16 {q9}, [r3, :128]!
1661 vst1.16 {q0}, [r0, :128]!
1662 integral8h d17, d16, q9
1663 vld1.8 {d17}, [r1, :64]!
1664 vst1.16 {q0}, [r0, :128]!
1669 function integral_init4v_neon
1672 add r4, r0, r2, lsl #3
1673 add r5, r0, r2, lsl #4
1675 vld1.16 {q11, q12}, [r3]!
1676 vld1.16 {q8, q9}, [r5]!
1677 vld1.16 {q13}, [r3]!
1678 vld1.16 {q10}, [r5]!
1681 vld1.16 {q14, q15}, [r4]!
1682 vext.8 q0, q11, q12, #8
1683 vext.8 q1, q12, q13, #8
1684 vext.8 q2, q8, q9, #8
1685 vext.8 q3, q9, q10, #8
1686 vsub.u16 q14, q14, q11
1687 vsub.u16 q15, q15, q12
1688 vadd.u16 q0, q0, q11
1689 vadd.u16 q1, q1, q12
1692 vst1.16 {q14}, [r1]!
1693 vst1.16 {q15}, [r1]!
1698 vld1.16 {q12, q13}, [r3]!
1699 vld1.16 {q9, q10}, [r5]!
1708 function integral_init8v_neon
1709 add r2, r0, r1, lsl #4
1711 ands r3, r1, #16 - 1
1721 vld1.16 {q0, q1}, [r0]
1722 vld1.16 {q2, q3}, [r2]!