]> git.sesse.net Git - x264/blob - common/arm/mc-a.S
MBAFF: Add extra data to the deblock strength structure
[x264] / common / arm / mc-a.S
1 /*****************************************************************************
2  * mc.S: arm motion compensation
3  *****************************************************************************
4  * Copyright (C) 2009-2011 x264 project
5  *
6  * Authors: David Conrad <lessen42@gmail.com>
7  *          Mans Rullgard <mans@mansr.com>
8  *
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.
13  *
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.
18  *
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.
22  *
23  * This program is also available under a commercial proprietary license.
24  * For more information, contact us at licensing@x264.com.
25  *****************************************************************************/
26
27 #include "asm.S"
28
29 .fpu neon
30 .text
31
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
34
35 // void prefetch_ref( uint8_t *pix, int stride, int parity )
36 function x264_prefetch_ref_arm
37     sub         r2, r2, #1
38     add         r0, r0, #64
39     and         r2, r2, r1
40     add         r0, r0, r2, lsl #3
41     add         r2, r1, r1, lsl #1
42     pld         [r0]
43     pld         [r0, r1]
44     pld         [r0, r1, lsl #1]
45     add         r3, r0, r1, lsl #2
46     pld         [r0, r2]
47     pld         [r3]
48     pld         [r3, r1]
49     pld         [r3, r1, lsl #1]
50     pld         [r3, r2]
51     bx          lr
52 .endfunc
53
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
57     ldr         ip, [sp]
58     push        {lr}
59     and         lr, ip, #3
60     smulbb      lr, lr, r1      // note: this assumes stride_y is <= 16 bits signed
61     and         ip, ip, #6
62     smulbb      ip, ip, r3
63     add         r0, r0, #64
64     add         r2, r2, #64
65     add         r0, r0, lr, lsl #2
66     pld         [r0]
67     add         lr, r0, r1, lsl #1
68     pld         [r0, r1]
69     pld         [lr]
70     add         r2, r2, ip, lsl #2
71     pld         [lr, r1]
72     pld         [r2]
73     add         ip, r2, r3, lsl #1
74     pld         [r2, r3]
75     pld         [ip]
76     pld         [ip, r3]
77     pop         {pc}
78 .endfunc
79
80
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
85     and         r3,  r3,  #0xc
86     ldr         pc,  [ip, r3]
87 .endfunc
88
89 .macro MEMCPY_ALIGNED srcalign dstalign
90 function memcpy_aligned_\dstalign\()_\srcalign\()_neon
91     mov         r3, r0
92 .if \srcalign == 8 && \dstalign == 8
93     sub         r2, #16
94     vld1.64     {d0}, [r1,:64]!
95     vst1.64     {d0}, [r3,:64]!
96     .set r1align, 128
97     .set r3align, 128
98 .else
99     .set r1align, \srcalign * 8
100     .set r3align, \dstalign * 8
101 .endif
102     tst         r2, #16
103     beq         32f
104     sub         r2, #16
105     vld1.64     {d0-d1}, [r1,:r1align]!
106     vst1.64     {d0-d1}, [r3,:r3align]!
107 32: // n is a multiple of 32
108     tst         r2, #32
109     beq         64f
110     sub         r2, #32
111     vld1.64     {d0-d3}, [r1,:r1align]!
112     vst1.64     {d0-d3}, [r3,:r3align]!
113 64: // n is a multiple of 64
114     subs        r2, #64
115     vld1.64     {d0-d3}, [r1,:r1align]!
116     vld1.64     {d4-d7}, [r1,:r1align]!
117     vst1.64     {d0-d3}, [r3,:r3align]!
118     vst1.64     {d4-d7}, [r3,:r3align]!
119     bgt         64b
120 .if \srcalign == 8 && \dstalign == 8
121     vld1.64     {d0}, [r1,:64]!
122     vst1.64     {d0}, [r3,:64]!
123 .endif
124     bx          lr
125 .endfunc
126 .endm
127
128 MEMCPY_ALIGNED 16, 16
129 MEMCPY_ALIGNED 16, 8
130 MEMCPY_ALIGNED  8, 16
131 MEMCPY_ALIGNED  8, 8
132
133 .section .rodata
134 memcpy_table:
135 .word memcpy_aligned_16_16_neon
136 .word memcpy_aligned_16_8_neon
137 .word memcpy_aligned_8_16_neon
138 .word memcpy_aligned_8_8_neon
139 .text
140
141 .ltorg
142
143 // void x264_memzero_aligned( void *dst, size_t n )
144 function x264_memzero_aligned_neon
145     vmov.i8     q0, #0
146     vmov.i8     q1, #0
147 memzero_loop:
148     subs        r1, #128
149 .rept 4
150     vst1.64     {d0-d3}, [r0,:128]!
151 .endr
152     bgt         memzero_loop
153     bx          lr
154 .endfunc
155
156
157 // void pixel_avg( uint8_t *dst, int dst_stride,
158 //                 uint8_t *src1, int src1_stride,
159 //                 uint8_t *src2, int src2_stride, int weight );
160 .macro AVGH w h
161 function x264_pixel_avg_\w\()x\h\()_neon
162     ldr         ip, [sp, #8]
163     push        {r4-r6,lr}
164     cmp         ip, #32
165     ldrd        r4, [sp, #16]
166     mov         lr, #\h
167     beq         x264_pixel_avg_w\w\()_neon
168     rsbs        r6,  ip,  #64
169     blt         x264_pixel_avg_weight_w\w\()_add_sub_neon     // weight > 64
170     cmp         ip,  #0
171     bge         x264_pixel_avg_weight_w\w\()_add_add_neon
172     b           x264_pixel_avg_weight_w\w\()_sub_add_neon     // weight < 0
173 .endfunc
174 .endm
175
176 AVGH  4, 2
177 AVGH  4, 4
178 AVGH  4, 8
179 AVGH  8, 4
180 AVGH  8, 8
181 AVGH  8, 16
182 AVGH 16, 8
183 AVGH 16, 16
184
185 // 0 < weight < 64
186 .macro load_weights_add_add
187     vdup.8      d30, ip
188     vdup.8      d31, r6
189 .endm
190
191 .macro load_add_add d1 d2
192     vld1.32     {\d1}, [r2], r3
193     vld1.32     {\d2}, [r4], r5
194 .endm
195
196 .macro weight_add_add dst s1 s2
197     vmull.u8    \dst, \s1, d30
198     vmlal.u8    \dst, \s2, d31
199 .endm
200
201 // weight > 64
202 .macro load_weights_add_sub
203     rsb         r6,  #0
204     vdup.8      d30, ip
205     vdup.8      d31, r6
206 .endm
207
208 .macro load_add_sub d1 d2
209     vld1.32     {\d1}, [r2], r3
210     vld1.32     {\d2}, [r4], r5
211 .endm
212
213 .macro weight_add_sub dst s1 s2
214     vmull.u8    \dst, \s1, d30
215     vmlsl.u8    \dst, \s2, d31
216 .endm
217
218 // weight < 0
219 .macro load_weights_sub_add
220     rsb         ip,  #0
221     vdup.8      d31, r6
222     vdup.8      d30, ip
223 .endm
224
225 .macro load_sub_add d1 d2
226     vld1.32     {\d2}, [r4], r5
227     vld1.32     {\d1}, [r2], r3
228 .endm
229
230 .macro weight_sub_add dst s1 s2
231     vmull.u8    \dst, \s2, d31
232     vmlsl.u8    \dst, \s1, d30
233 .endm
234
235 .macro AVG_WEIGHT ext
236 function x264_pixel_avg_weight_w4_\ext\()_neon
237     load_weights_\ext
238 1:  // height loop
239     subs            lr,  lr,  #2
240     load_\ext       d0[], d1[]
241     weight_\ext     q8,  d0,  d1
242     load_\ext       d2[], d3[]
243     vqrshrun.s16    d0,  q8,  #6
244     weight_\ext     q9,  d2,  d3
245     vst1.32         {d0[0]}, [r0,:32], r1
246     vqrshrun.s16    d1,  q9,  #6
247     vst1.32         {d1[0]}, [r0,:32], r1
248     bgt             1b
249     pop             {r4-r6,pc}
250 .endfunc
251
252 function x264_pixel_avg_weight_w8_\ext\()_neon
253     load_weights_\ext
254 1:  // height loop
255     subs            lr,  lr,  #4
256     load_\ext       d0,  d1
257     weight_\ext     q8,  d0,  d1
258     load_\ext       d2,  d3
259     weight_\ext     q9,  d2,  d3
260     load_\ext       d4,  d5
261     weight_\ext     q10, d4,  d5
262     load_\ext       d6,  d7
263     weight_\ext     q11, d6,  d7
264     vqrshrun.s16    d0,  q8,  #6
265     vqrshrun.s16    d1,  q9,  #6
266     vqrshrun.s16    d2,  q10, #6
267     vqrshrun.s16    d3,  q11, #6
268     vst1.64         {d0}, [r0,:64], r1
269     vst1.64         {d1}, [r0,:64], r1
270     vst1.64         {d2}, [r0,:64], r1
271     vst1.64         {d3}, [r0,:64], r1
272     bgt             1b
273     pop             {r4-r6,pc}
274 .endfunc
275
276 function x264_pixel_avg_weight_w16_\ext\()_neon
277     load_weights_\ext
278 1:  // height loop
279     subs            lr,  lr,  #2
280     load_\ext       d0-d1, d2-d3
281     weight_\ext     q8,  d0,  d2
282     weight_\ext     q9,  d1,  d3
283     load_\ext       d4-d5, d6-d7
284     weight_\ext     q10, d4,  d6
285     weight_\ext     q11, d5,  d7
286     vqrshrun.s16    d0,  q8,  #6
287     vqrshrun.s16    d1,  q9,  #6
288     vqrshrun.s16    d2,  q10, #6
289     vqrshrun.s16    d3,  q11, #6
290     vst1.64         {d0-d1}, [r0,:128], r1
291     vst1.64         {d2-d3}, [r0,:128], r1
292     bgt             1b
293     pop             {r4-r6,pc}
294 .endfunc
295 .endm
296
297 AVG_WEIGHT add_add
298 AVG_WEIGHT add_sub
299 AVG_WEIGHT sub_add
300
301 function x264_pixel_avg_w4_neon
302     subs        lr,  lr,  #2
303     vld1.32     {d0[]}, [r2], r3
304     vld1.32     {d2[]}, [r4], r5
305     vrhadd.u8   d0,  d0,  d2
306     vld1.32     {d1[]}, [r2], r3
307     vld1.32     {d3[]}, [r4], r5
308     vrhadd.u8   d1,  d1,  d3
309     vst1.32     {d0[0]}, [r0,:32], r1
310     vst1.32     {d1[0]}, [r0,:32], r1
311     bgt         x264_pixel_avg_w4_neon
312     pop         {r4-r6,pc}
313 .endfunc
314
315 function x264_pixel_avg_w8_neon
316     subs        lr,  lr,  #4
317     vld1.64     {d0}, [r2], r3
318     vld1.64     {d2}, [r4], r5
319     vrhadd.u8   d0,  d0,  d2
320     vld1.64     {d1}, [r2], r3
321     vld1.64     {d3}, [r4], r5
322     vrhadd.u8   d1,  d1,  d3
323     vst1.64     {d0}, [r0,:64], r1
324     vld1.64     {d2}, [r2], r3
325     vld1.64     {d4}, [r4], r5
326     vrhadd.u8   d2,  d2,  d4
327     vst1.64     {d1}, [r0,:64], r1
328     vld1.64     {d3}, [r2], r3
329     vld1.64     {d5}, [r4], r5
330     vrhadd.u8   d3,  d3,  d5
331     vst1.64     {d2}, [r0,:64], r1
332     vst1.64     {d3}, [r0,:64], r1
333     bgt         x264_pixel_avg_w8_neon
334     pop         {r4-r6,pc}
335 .endfunc
336
337 function x264_pixel_avg_w16_neon
338     subs        lr,  lr,  #4
339     vld1.64     {d0-d1}, [r2], r3
340     vld1.64     {d2-d3}, [r4], r5
341     vrhadd.u8   q0,  q0,  q1
342     vld1.64     {d2-d3}, [r2], r3
343     vld1.64     {d4-d5}, [r4], r5
344     vrhadd.u8   q1,  q1,  q2
345     vst1.64     {d0-d1}, [r0,:128], r1
346     vld1.64     {d4-d5}, [r2], r3
347     vld1.64     {d6-d7}, [r4], r5
348     vrhadd.u8   q2,  q2,  q3
349     vst1.64     {d2-d3}, [r0,:128], r1
350     vld1.64     {d6-d7}, [r2], r3
351     vld1.64     {d0-d1}, [r4], r5
352     vrhadd.u8   q3,  q3,  q0
353     vst1.64     {d4-d5}, [r0,:128], r1
354     vst1.64     {d6-d7}, [r0,:128], r1
355     bgt         x264_pixel_avg_w16_neon
356     pop         {r4-r6,pc}
357 .endfunc
358
359
360 function x264_pixel_avg2_w4_neon
361     ldr         ip,  [sp, #4]
362     push        {lr}
363     ldr         lr,  [sp, #4]
364 avg2_w4_loop:
365     subs        ip,  ip,  #2
366     vld1.32     {d0[]},  [r2], r3
367     vld1.32     {d2[]},  [lr], r3
368     vrhadd.u8   d0,  d0,  d2
369     vld1.32     {d1[]},  [r2], r3
370     vld1.32     {d3[]},  [lr], r3
371     vrhadd.u8   d1,  d1,  d3
372     vst1.32     {d0[0]}, [r0,:32], r1
373     vst1.32     {d1[0]}, [r0,:32], r1
374     bgt         avg2_w4_loop
375     pop         {pc}
376 .endfunc
377
378 function x264_pixel_avg2_w8_neon
379     ldr         ip,  [sp, #4]
380     push        {lr}
381     ldr         lr,  [sp, #4]
382 avg2_w8_loop:
383     subs        ip,  ip,  #2
384     vld1.64     {d0}, [r2], r3
385     vld1.64     {d2}, [lr], r3
386     vrhadd.u8   d0,  d0,  d2
387     vld1.64     {d1}, [r2], r3
388     vld1.64     {d3}, [lr], r3
389     vrhadd.u8   d1,  d1,  d3
390     vst1.64     {d0}, [r0,:64], r1
391     vst1.64     {d1}, [r0,:64], r1
392     bgt         avg2_w8_loop
393     pop         {pc}
394 .endfunc
395
396 function x264_pixel_avg2_w16_neon
397     ldr         ip,  [sp, #4]
398     push        {lr}
399     ldr         lr,  [sp, #4]
400 avg2_w16_loop:
401     subs        ip,  ip,  #2
402     vld1.64     {d0-d1}, [r2], r3
403     vld1.64     {d2-d3}, [lr], r3
404     vrhadd.u8   q0,  q0,  q1
405     vld1.64     {d4-d5}, [r2], r3
406     vld1.64     {d6-d7}, [lr], r3
407     vrhadd.u8   q2,  q2,  q3
408     vst1.64     {d0-d1}, [r0,:128], r1
409     vst1.64     {d4-d5}, [r0,:128], r1
410     bgt         avg2_w16_loop
411     pop         {pc}
412 .endfunc
413
414 function x264_pixel_avg2_w20_neon
415     ldr         ip,  [sp, #4]
416     push        {lr}
417     sub         r1,  r1,  #16
418     ldr         lr,  [sp, #4]
419 avg2_w20_loop:
420     subs        ip,  ip,  #2
421     vld1.64     {d0-d2},  [r2], r3
422     vld1.64     {d4-d6},  [lr], r3
423     vrhadd.u8   q0,  q0,  q2
424     vrhadd.u8   d2,  d2,  d6
425     vld1.64     {d4-d6},  [r2], r3
426     vld1.64     {d16-d18},[lr], r3
427     vrhadd.u8   q2,  q2,  q8
428     vst1.64     {d0-d1},  [r0,:128]!
429     vrhadd.u8   d6,  d6,  d18
430     vst1.32     {d2[0]},  [r0,:32], r1
431     vst1.64     {d4-d5},  [r0,:128]!
432     vst1.32     {d6[0]},  [r0,:32], r1
433     bgt         avg2_w20_loop
434     pop         {pc}
435 .endfunc
436
437
438 .macro weight_prologue type
439     push        {r4-r5,lr}
440     ldr         r4,  [sp, #4*3]     // weight_t
441     ldr         ip,  [sp, #4*3+4]   // h
442 .ifc \type, full
443     ldr         lr,  [r4, #32]      // denom
444 .endif
445     ldrd        r4,  [r4, #32+4]    // scale, offset
446     vdup.16     q0,  r4
447     vdup.16     q1,  r5
448 .ifc \type, full
449     rsb         lr,  lr,  #0
450     vdup.16     q2,  lr
451 .endif
452 .endm
453
454 // void mc_weight( uint8_t *src, int src_stride, uint8_t *dst, int dst_stride,
455 //                 const x264_weight_t *weight, int height )
456 function x264_mc_weight_w20_neon
457     weight_prologue full
458     sub         r1, #16
459 weight20_loop:
460     subs        ip,  #2
461     vld1.8      {d17-d19}, [r2], r3
462     vmovl.u8    q10, d17
463     vmovl.u8    q11, d18
464     vmovl.u8    q14, d19
465     vld1.8      {d16-d18}, [r2], r3
466     vmovl.u8    q12, d16
467     vmovl.u8    q13, d17
468     vmovl.u8    q15, d18
469     vmul.s16    q10, q10, q0
470     vmul.s16    q11, q11, q0
471     vmul.s16    q12, q12, q0
472     vmul.s16    q13, q13, q0
473     vmul.s16    d28, d28, d0
474     vmul.s16    d29, d30, d0
475     vrshl.s16   q10, q10, q2
476     vrshl.s16   q11, q11, q2
477     vrshl.s16   q12, q12, q2
478     vrshl.s16   q13, q13, q2
479     vrshl.s16   q14, q14, q2
480     vadd.s16    q10, q10, q1
481     vadd.s16    q11, q11, q1
482     vadd.s16    q12, q12, q1
483     vadd.s16    q13, q13, q1
484     vadd.s16    q14, q14, q1
485     vqmovun.s16 d16, q10
486     vqmovun.s16 d17, q11
487     vqmovun.s16 d18, q12
488     vqmovun.s16 d19, q13
489     vqmovun.s16 d20, q14
490     vst1.8      {d16-d17}, [r0,:128]!
491     vst1.32     {d20[0]},  [r0,:32], r1
492     vst1.8      {d18-d19}, [r0,:128]!
493     vst1.32     {d20[1]},  [r0,:32], r1
494     bgt         weight20_loop
495     pop         {r4-r5,pc}
496 .endfunc
497
498 function x264_mc_weight_w16_neon
499     weight_prologue full
500 weight16_loop:
501     subs        ip,  #2
502     vld1.8      {d16-d17}, [r2], r3
503     vld1.8      {d18-d19}, [r2], r3
504     vmovl.u8    q10, d16
505     vmovl.u8    q11, d17
506     vmovl.u8    q12, d18
507     vmovl.u8    q13, d19
508     vmul.s16    q10, q10, q0
509     vmul.s16    q11, q11, q0
510     vmul.s16    q12, q12, q0
511     vmul.s16    q13, q13, q0
512     vrshl.s16   q10, q10, q2
513     vrshl.s16   q11, q11, q2
514     vrshl.s16   q12, q12, q2
515     vrshl.s16   q13, q13, q2
516     vadd.s16    q10, q10, q1
517     vadd.s16    q11, q11, q1
518     vadd.s16    q12, q12, q1
519     vadd.s16    q13, q13, q1
520     vqmovun.s16 d16, q10
521     vqmovun.s16 d17, q11
522     vqmovun.s16 d18, q12
523     vqmovun.s16 d19, q13
524     vst1.8      {d16-d17}, [r0,:128], r1
525     vst1.8      {d18-d19}, [r0,:128], r1
526     bgt         weight16_loop
527     pop         {r4-r5,pc}
528 .endfunc
529
530 function x264_mc_weight_w8_neon
531     weight_prologue full
532 weight8_loop:
533     subs        ip,  #2
534     vld1.8      {d16}, [r2], r3
535     vld1.8      {d18}, [r2], r3
536     vmovl.u8    q8,  d16
537     vmovl.u8    q9,  d18
538     vmul.s16    q8,  q8,  q0
539     vmul.s16    q9,  q9,  q0
540     vrshl.s16   q8,  q8,  q2
541     vrshl.s16   q9,  q9,  q2
542     vadd.s16    q8,  q8,  q1
543     vadd.s16    q9,  q9,  q1
544     vqmovun.s16 d16, q8
545     vqmovun.s16 d18, q9
546     vst1.8      {d16}, [r0,:64], r1
547     vst1.8      {d18}, [r0,:64], r1
548     bgt         weight8_loop
549     pop         {r4-r5,pc}
550 .endfunc
551
552 function x264_mc_weight_w4_neon
553     weight_prologue full
554 weight4_loop:
555     subs        ip,  #2
556     vld1.32     {d16[]}, [r2], r3
557     vld1.32     {d18[]}, [r2], r3
558     vmovl.u8    q8,  d16
559     vmovl.u8    q9,  d18
560     vmul.s16    d16, d16, d0
561     vmul.s16    d17, d18, d0
562     vrshl.s16   q8,  q8,  q2
563     vadd.s16    q8,  q8,  q1
564     vqmovun.s16 d16, q8
565     vst1.32     {d16[0]}, [r0,:32], r1
566     vst1.32     {d16[1]}, [r0,:32], r1
567     bgt         weight4_loop
568     pop         {r4-r5,pc}
569 .endfunc
570
571 function x264_mc_weight_w20_nodenom_neon
572     weight_prologue nodenom
573     sub         r1, #16
574 weight20_nodenom_loop:
575     subs        ip,  #2
576     vld1.8      {d17-d19}, [r2], r3
577     vmovl.u8    q10, d17
578     vmovl.u8    q11, d18
579     vmovl.u8    q14, d19
580     vld1.8      {d16-d18}, [r2], r3
581     vmovl.u8    q12, d16
582     vmovl.u8    q13, d17
583     vmovl.u8    q15, d18
584     vmov        q8,  q1
585     vmov        q9,  q1
586     vmla.s16    q8,  q10, q0
587     vmla.s16    q9,  q11, q0
588     vmov        q10, q1
589     vmov        q11, q1
590     vmla.s16    q10, q12, q0
591     vmla.s16    q11, q13, q0
592     vmov        q12, q1
593     vmla.s16    d24, d28, d0
594     vmla.s16    d25, d30, d0
595     vqmovun.s16 d16, q8
596     vqmovun.s16 d17, q9
597     vqmovun.s16 d18, q10
598     vqmovun.s16 d19, q11
599     vqmovun.s16 d20, q12
600     vst1.8      {d16-d17}, [r0,:128]!
601     vst1.32     {d20[0]},  [r0,:32], r1
602     vst1.8      {d18-d19}, [r0,:128]!
603     vst1.32     {d20[1]},  [r0,:32], r1
604     bgt         weight20_nodenom_loop
605     pop         {r4-r5,pc}
606 .endfunc
607
608 function x264_mc_weight_w16_nodenom_neon
609     weight_prologue nodenom
610 weight16_nodenom_loop:
611     subs        ip,  #2
612     vld1.8      {d16-d17}, [r2], r3
613     vld1.8      {d18-d19}, [r2], r3
614     vmovl.u8    q12, d16
615     vmovl.u8    q13, d17
616     vmovl.u8    q14, d18
617     vmovl.u8    q15, d19
618     vmov        q8,  q1
619     vmov        q9,  q1
620     vmov        q10, q1
621     vmov        q11, q1
622     vmla.s16    q8,  q12, q0
623     vmla.s16    q9,  q13, q0
624     vmla.s16    q10, q14, q0
625     vmla.s16    q11, q15, q0
626     vqmovun.s16 d16, q8
627     vqmovun.s16 d17, q9
628     vqmovun.s16 d18, q10
629     vqmovun.s16 d19, q11
630     vst1.8      {d16-d17}, [r0,:128], r1
631     vst1.8      {d18-d19}, [r0,:128], r1
632     bgt         weight16_nodenom_loop
633     pop         {r4-r5,pc}
634 .endfunc
635
636 function x264_mc_weight_w8_nodenom_neon
637     weight_prologue nodenom
638 weight8_nodenom_loop:
639     subs        ip,  #2
640     vld1.8      {d16}, [r2], r3
641     vld1.8      {d18}, [r2], r3
642     vmovl.u8    q8,  d16
643     vmovl.u8    q9,  d18
644     vmov        q10, q1
645     vmov        q11, q1
646     vmla.s16    q10, q8,  q0
647     vmla.s16    q11, q9,  q0
648     vqmovun.s16 d16, q10
649     vqmovun.s16 d17, q11
650     vst1.8      {d16}, [r0,:64], r1
651     vst1.8      {d17}, [r0,:64], r1
652     bgt         weight8_nodenom_loop
653     pop         {r4-r5,pc}
654 .endfunc
655
656 function x264_mc_weight_w4_nodenom_neon
657     weight_prologue nodenom
658 weight4_nodenom_loop:
659     subs        ip,  #2
660     vld1.32     {d16[]}, [r2], r3
661     vld1.32     {d18[]}, [r2], r3
662     vmovl.u8    q8,  d16
663     vmovl.u8    q9,  d18
664     vmov        q10, q1
665     vmla.s16    d20, d16, d0
666     vmla.s16    d21, d18, d0
667     vqmovun.s16 d16, q10
668     vst1.32     {d16[0]}, [r0,:32], r1
669     vst1.32     {d16[1]}, [r0,:32], r1
670     bgt         weight4_nodenom_loop
671     pop         {r4-r5,pc}
672 .endfunc
673
674 .macro weight_simple_prologue
675     push        {lr}
676     ldr         lr,  [sp, #4]       // weight_t
677     ldr         ip,  [sp, #8]       // h
678     ldr         lr,  [lr]           // offset
679     vdup.8      q1,  lr
680 .endm
681
682 .macro weight_simple name op
683 function x264_mc_weight_w20_\name\()_neon
684     weight_simple_prologue
685 weight20_\name\()_loop:
686     subs        ip,  #2
687     vld1.8      {d16-d18}, [r2], r3
688     vld1.8      {d19-d21}, [r2], r3
689     \op         q8,  q8,  q1
690     \op         q9,  q9,  q1
691     \op         q10, q10, q1
692     vst1.8      {d16-d18}, [r0,:64], r1
693     vst1.8      {d19-d21}, [r0,:64], r1
694     bgt         weight20_\name\()_loop
695     pop         {pc}
696 .endfunc
697
698 function x264_mc_weight_w16_\name\()_neon
699     weight_simple_prologue
700 weight16_\name\()_loop:
701     subs        ip,  #2
702     vld1.8      {d16-d17}, [r2], r3
703     vld1.8      {d18-d19}, [r2], r3
704     \op         q8,  q8,  q1
705     \op         q9,  q9,  q1
706     vst1.8      {d16-d17}, [r0,:128], r1
707     vst1.8      {d18-d19}, [r0,:128], r1
708     bgt         weight16_\name\()_loop
709     pop         {pc}
710 .endfunc
711
712 function x264_mc_weight_w8_\name\()_neon
713     weight_simple_prologue
714 weight8_\name\()_loop:
715     subs        ip,  #2
716     vld1.8      {d16}, [r2], r3
717     vld1.8      {d17}, [r2], r3
718     \op         q8,  q8,  q1
719     vst1.8      {d16}, [r0,:64], r1
720     vst1.8      {d17}, [r0,:64], r1
721     bgt         weight8_\name\()_loop
722     pop         {pc}
723 .endfunc
724
725 function x264_mc_weight_w4_\name\()_neon
726     weight_simple_prologue
727 weight4_\name\()_loop:
728     subs        ip,  #2
729     vld1.32     {d16[]}, [r2], r3
730     vld1.32     {d17[]}, [r2], r3
731     \op         q8,  q8,  q1
732     vst1.32     {d16[0]}, [r0,:32], r1
733     vst1.32     {d17[0]}, [r0,:32], r1
734     bgt         weight4_\name\()_loop
735     pop         {pc}
736 .endfunc
737 .endm
738
739 weight_simple offsetadd, vqadd.u8
740 weight_simple offsetsub, vqsub.u8
741
742
743 // void mc_copy( uint8_t *dst, int dst_stride, uint8_t *src, int src_stride, int height )
744 function x264_mc_copy_w4_neon
745     ldr         ip,  [sp]
746 copy_w4_loop:
747     subs        ip,  ip,  #4
748     vld1.32     {d0[]},  [r2], r3
749     vld1.32     {d1[]},  [r2], r3
750     vld1.32     {d2[]},  [r2], r3
751     vld1.32     {d3[]},  [r2], r3
752     vst1.32     {d0[0]}, [r0,:32], r1
753     vst1.32     {d1[0]}, [r0,:32], r1
754     vst1.32     {d2[0]}, [r0,:32], r1
755     vst1.32     {d3[0]}, [r0,:32], r1
756     bgt         copy_w4_loop
757     bx          lr
758 .endfunc
759
760 function x264_mc_copy_w8_neon
761     ldr         ip,  [sp]
762 copy_w8_loop:
763     subs        ip,  ip,  #4
764     vld1.32     {d0}, [r2], r3
765     vld1.32     {d1}, [r2], r3
766     vld1.32     {d2}, [r2], r3
767     vld1.32     {d3}, [r2], r3
768     vst1.32     {d0}, [r0,:64], r1
769     vst1.32     {d1}, [r0,:64], r1
770     vst1.32     {d2}, [r0,:64], r1
771     vst1.32     {d3}, [r0,:64], r1
772     bgt         copy_w8_loop
773     bx          lr
774 .endfunc
775
776 function x264_mc_copy_w16_neon
777     ldr         ip,  [sp]
778 copy_w16_loop:
779     subs        ip,  ip,  #4
780     vld1.32     {d0-d1}, [r2], r3
781     vld1.32     {d2-d3}, [r2], r3
782     vld1.32     {d4-d5}, [r2], r3
783     vld1.32     {d6-d7}, [r2], r3
784     vst1.32     {d0-d1}, [r0,:128], r1
785     vst1.32     {d2-d3}, [r0,:128], r1
786     vst1.32     {d4-d5}, [r0,:128], r1
787     vst1.32     {d6-d7}, [r0,:128], r1
788     bgt         copy_w16_loop
789     bx          lr
790 .endfunc
791
792 function x264_mc_copy_w16_aligned_neon
793     ldr         ip,  [sp]
794 copy_w16_aligned_loop:
795     subs        ip,  ip,  #4
796     vld1.32     {d0-d1}, [r2,:128], r3
797     vld1.32     {d2-d3}, [r2,:128], r3
798     vld1.32     {d4-d5}, [r2,:128], r3
799     vld1.32     {d6-d7}, [r2,:128], r3
800     vst1.32     {d0-d1}, [r0,:128], r1
801     vst1.32     {d2-d3}, [r0,:128], r1
802     vst1.32     {d4-d5}, [r0,:128], r1
803     vst1.32     {d6-d7}, [r0,:128], r1
804     bgt         copy_w16_aligned_loop
805     bx          lr
806 .endfunc
807
808
809 // void x264_mc_chroma_neon( uint8_t *dst, int i_dst_stride,
810 //                           uint8_t *src, int i_src_stride,
811 //                           int dx, int dy, int i_width, int i_height );
812 function x264_mc_chroma_neon
813     push            {r4-r6, lr}
814     ldrd            r4,  [sp, #16]
815     ldr             r6,  [sp, #24]
816
817     asr             lr,  r5,  #3
818     mul             lr,  r3,  lr
819     add             r2,  r2,  r4,  asr #3
820     cmp             r6, #4
821     add             r2,  r2,  lr
822
823     and             r4, r4, #7
824     and             r5, r5, #7
825     pld             [r2]
826     pld             [r2, r3]
827
828     bgt             mc_chroma_w8
829     beq             mc_chroma_w4
830
831 // calculate cA cB cC cD
832 .macro CHROMA_MC_START r0 r1
833     muls            lr,  r4,  r5
834     rsb             r6,  lr,  r5,  lsl #3
835     rsb             ip,  lr,  r4,  lsl #3
836     sub             r4,  lr,  r4,  lsl #3
837     sub             r4,  r4,  r5,  lsl #3
838     add             r4,  r4,  #64
839
840     beq             2f
841
842     add             r5,  r2,  r3
843
844     vdup.8          d0,  r4
845     lsl             r3,  r3,  #1
846     vdup.8          d1,  ip
847     vld1.64         {\r0}, [r2], r3
848     vdup.8          d2,  r6
849     vld1.64         {\r1}, [r5], r3
850     vdup.8          d3,  lr
851     ldr             r4,  [sp, #28]
852
853     vext.8          d5,  d4,  d5,  #1
854     vext.8          d7,  d6,  d7,  #1
855 .endm
856
857 .macro CHROMA_MC width, align
858 mc_chroma_w\width:
859     CHROMA_MC_START d4,  d6
860 // since the element size varies, there's a different index for the 2nd store
861 .if \width == 4
862     .set st2, 1
863 .else
864     .set st2, 2
865 .endif
866
867     vtrn.32         d4,  d5
868     vtrn.32         d6,  d7
869
870     vtrn.32         d0,  d1
871     vtrn.32         d2,  d3
872
873 1:  // height loop, interpolate xy
874     pld             [r5]
875     vmull.u8        q8,  d4,  d0
876     vmlal.u8        q8,  d6,  d2
877     vld1.64         {d4},     [r2], r3
878     vext.8          d5,  d4,  d5,  #1
879     vtrn.32         d4,  d5
880     vmull.u8        q9,  d6,  d0
881     vmlal.u8        q9,  d4,  d2
882     vld1.64         {d6},     [r5], r3
883     vadd.i16        d16, d16, d17
884     vadd.i16        d17, d18, d19
885     vrshrn.u16      d16, q8,  #6
886     subs            r4,  r4,  #2
887     pld             [r2]
888     vext.8          d7,  d6,  d7,  #1
889     vtrn.32         d6,  d7
890     vst1.\align     {d16[0]},   [r0,:\align], r1
891     vst1.\align     {d16[st2]}, [r0,:\align], r1
892     bgt             1b
893
894     pop             {r4-r6, pc}
895
896 2:  // dx or dy are 0
897     tst             r6,  r6
898     add             ip,  ip,  r6
899     vdup.8          d0,  r4
900     vdup.8          d1,  ip
901     vtrn.32         d0,  d1
902     ldr             r4,  [sp, #28]
903
904     beq             4f
905
906     vext.32         d1,  d0,  d1,  #1
907     add             r5,  r2,  r3
908     lsl             r3,  r3,  #1
909     vld1.32         {d4[0]},  [r2], r3
910     vld1.32         {d4[1]},  [r5], r3
911
912 3:  // vertical interpolation loop
913     pld             [r5]
914     vmull.u8        q8,  d4,  d0
915     vld1.32         {d4[0]},  [r2], r3
916     vmull.u8        q9,  d4,  d1
917     vld1.32         {d4[1]},  [r5], r3
918     vadd.i16        d16, d16, d17
919     vadd.i16        d17, d18, d19
920     vrshrn.u16      d16, q8,  #6
921     subs            r4,  r4,  #2
922     pld             [r2]
923     vst1.\align     {d16[0]},   [r0,:\align], r1
924     vst1.\align     {d16[st2]}, [r0,:\align], r1
925     bgt             3b
926
927     pop             {r4-r6, pc}
928
929 4:  // dy is 0
930     vld1.64         {d4},     [r2], r3
931     vld1.64         {d6},     [r2], r3
932     vext.8          d5,  d4,  d5,  #1
933     vext.8          d7,  d6,  d7,  #1
934     vtrn.32         d4,  d5
935     vtrn.32         d6,  d7
936
937 5:  // horizontal interpolation loop
938     vmull.u8        q8,  d4,  d0
939     vmull.u8        q9,  d6,  d0
940     subs            r4,  r4,  #2
941     vld1.64         {d4},     [r2], r3
942     vext.8          d5,  d4,  d5,  #1
943     vtrn.32         d4,  d5
944     vadd.i16        d16, d16, d17
945     vadd.i16        d17, d18, d19
946     pld             [r2]
947     vrshrn.u16      d16, q8,  #6
948     vld1.64         {d6},     [r2], r3
949     vext.8          d7,  d6,  d7,  #1
950     vtrn.32         d6,  d7
951     pld             [r2]
952     vst1.\align     {d16[0]},   [r0,:\align], r1
953     vst1.\align     {d16[st2]}, [r0,:\align], r1
954     bgt             5b
955
956     pop             {r4-r6, pc}
957 .endm
958
959     CHROMA_MC 2, 16
960     CHROMA_MC 4, 32
961
962 // the optimial timing for width 8 is different enough that it's not
963 // readable to put it in the same macro as width 2/4
964 mc_chroma_w8:
965     CHROMA_MC_START d4-d5, d6-d7
966
967 1:  // height loop, interpolate xy
968     pld             [r5]
969     vmull.u8        q8,  d4,  d0
970     vmlal.u8        q8,  d5,  d1
971     vld1.64         {d4, d5}, [r2], r3
972     vmlal.u8        q8,  d6,  d2
973     vext.8          d5,  d4,  d5,  #1
974     vmlal.u8        q8,  d7,  d3
975     vmull.u8        q9,  d6,  d0
976     subs            r4,  r4,  #2
977     vmlal.u8        q9,  d7,  d1
978     vmlal.u8        q9,  d4,  d2
979     vmlal.u8        q9,  d5,  d3
980     vrshrn.u16      d16, q8,  #6
981     vld1.64         {d6, d7}, [r5], r3
982     pld             [r2]
983     vrshrn.u16      d17, q9,  #6
984     vext.8          d7,  d6,  d7,  #1
985     vst1.64         {d16}, [r0,:64], r1
986     vst1.64         {d17}, [r0,:64], r1
987     bgt             1b
988
989     pop             {r4-r6, pc}
990
991 2:  // dx or dy are 0
992     tst             r6,  r6
993     add             ip,  ip,  r6
994     vdup.8          d0,  r4
995     vdup.8          d1,  ip
996     ldr             r4,  [sp, #28]
997
998     beq             4f
999
1000     add             r5,  r2,  r3
1001     lsl             r3,  r3,  #1
1002     vld1.64         {d4}, [r2], r3
1003     vld1.64         {d6}, [r5], r3
1004
1005 3:  // vertical interpolation loop
1006     pld             [r5]
1007     vmull.u8        q8,  d4,  d0
1008     vmlal.u8        q8,  d6,  d1
1009     vld1.64         {d4}, [r2], r3
1010     vmull.u8        q9,  d6,  d0
1011     vmlal.u8        q9,  d4,  d1
1012     vld1.64         {d6}, [r5], r3
1013     vrshrn.u16      d16, q8,  #6
1014     vrshrn.u16      d17, q9,  #6
1015     subs            r4,  r4,  #2
1016     pld             [r2]
1017     vst1.64         {d16}, [r0,:64], r1
1018     vst1.64         {d17}, [r0,:64], r1
1019     bgt             3b
1020
1021     pop             {r4-r6, pc}
1022
1023 4:  // dy is 0
1024     vld1.64         {d4, d5}, [r2], r3
1025     vld1.64         {d6, d7}, [r2], r3
1026     vext.8          d5,  d4,  d5,  #1
1027     vext.8          d7,  d6,  d7,  #1
1028
1029 5:  // horizontal interpolation loop
1030     pld             [r2]
1031     subs            r4,  r4,  #2
1032     vmull.u8        q8,  d4,  d0
1033     vmlal.u8        q8,  d5,  d1
1034     vld1.64         {d4,  d5}, [r2], r3
1035     vmull.u8        q9,  d6,  d0
1036     vmlal.u8        q9,  d7,  d1
1037     pld             [r2]
1038     vext.8          d5,  d4,  d5,  #1
1039     vrshrn.u16      d16, q8,  #6
1040     vrshrn.u16      d17, q9,  #6
1041     vld1.64         {d6, d7}, [r2], r3
1042     vext.8          d7,  d6,  d7,  #1
1043     vst1.64         {d16}, [r0,:64], r1
1044     vst1.64         {d17}, [r0,:64], r1
1045     bgt             5b
1046
1047     pop             {r4-r6, pc}
1048 .endfunc
1049
1050
1051 // hpel_filter_v( uint8_t *dst, uint8_t *src, int16_t *buf, int stride, int width)
1052 function x264_hpel_filter_v_neon
1053     ldr             ip,  [sp]
1054     sub             r1,  r1,  r3,  lsl #1
1055     push            {lr}
1056     add             lr,  r1,  ip
1057     vmov.u8         d30, #5
1058     vmov.u8         d31, #20
1059
1060 filter_v_loop:
1061     subs            ip,  ip,  #16
1062     vld1.64         {d0-d1},   [r1,:128], r3
1063     vld1.64         {d2-d3},   [r1,:128], r3
1064     vld1.64         {d4-d5},   [r1,:128], r3
1065     vld1.64         {d6-d7},   [r1,:128], r3
1066     vld1.64         {d16-d17}, [r1,:128], r3
1067     vld1.64         {d18-d19}, [r1,:128], r3
1068     sub             r1,  lr,  ip
1069
1070     vaddl.u8        q10, d0,  d18
1071     vmlsl.u8        q10, d2,  d30
1072     vmlal.u8        q10, d4,  d31
1073     vmlal.u8        q10, d6,  d31
1074     vmlsl.u8        q10, d16, d30
1075
1076     vaddl.u8        q11, d1,  d19
1077     vmlsl.u8        q11, d3,  d30
1078     vmlal.u8        q11, d5,  d31
1079     vmlal.u8        q11, d7,  d31
1080     vmlsl.u8        q11, d17, d30
1081
1082     vqrshrun.s16    d0,  q10, #5
1083     vst1.64         {d20-d21}, [r2,:128]!
1084     vqrshrun.s16    d1,  q11, #5
1085     vst1.64         {d22-d23}, [r2,:128]!
1086     vst1.64         {d0-d1},   [r0,:128]!
1087     bgt             filter_v_loop
1088     pop             {pc}
1089 .endfunc
1090
1091 // hpel_filter_c( uint8_t *dst, int16_t *buf, int width );
1092 function x264_hpel_filter_c_neon
1093     sub             r1,  #16
1094     vld1.64         {d0-d3}, [r1,:128]!
1095
1096     // unrolled 2x: 4% faster
1097 filter_c_loop:
1098     subs            r2,  r2,  #16
1099     vld1.64         {d4-d7}, [r1,:128]!
1100     vext.16         q8,  q0,  q1,  #6
1101     vext.16         q12, q1,  q2,  #3
1102     vadd.s16        q8,  q8,  q12
1103     vext.16         q9,  q0,  q1,  #7
1104     vext.16         q11, q1,  q2,  #2
1105     vadd.s16        q9,  q9,  q11
1106     vext.16         q10, q1,  q2,  #1
1107     vext.16         q11, q1,  q2,  #6
1108     vadd.s16        q10, q1,  q10
1109     vsub.s16        q8,  q8,  q9    // a-b
1110     vext.16         q15, q2,  q3,  #3
1111     vsub.s16        q9,  q9,  q10   // b-c
1112
1113     vext.16         q12, q1,  q2,  #7
1114     vshr.s16        q8,  q8,  #2    // (a-b)/4
1115     vadd.s16        q11, q11, q15
1116     vext.16         q14, q2,  q3,  #2
1117     vsub.s16        q8,  q8,  q9    // (a-b)/4-b+c
1118     vadd.s16        q12, q12, q14
1119     vext.16         q13, q2,  q3,  #1
1120
1121     vshr.s16        q8,  q8,  #2    // ((a-b)/4-b+c)/4
1122     vadd.s16        q13, q2,  q13
1123     vadd.s16        q8,  q8,  q10   // ((a-b)/4-b+c)/4+c = (a-5*b+20*c)/16
1124     vsub.s16        q11, q11, q12   // a-b
1125     vsub.s16        q12, q12, q13   // b-c
1126     vshr.s16        q11, q11, #2    // (a-b)/4
1127     vqrshrun.s16    d30, q8,  #6
1128     vsub.s16        q11, q11, q12   // (a-b)/4-b+c
1129     vshr.s16        q11, q11, #2    // ((a-b)/4-b+c)/4
1130     vld1.64         {d0-d3}, [r1,:128]!
1131     vadd.s16        q11, q11, q13   // ((a-b)/4-b+c)/4+c = (a-5*b+20*c)/16
1132
1133     vext.16         q8,  q2,  q3,  #6
1134     vqrshrun.s16    d31, q11,  #6
1135     vext.16         q12, q3,  q0,  #3
1136     vadd.s16        q8,  q8,  q12
1137     vext.16         q9,  q2,  q3,  #7
1138     vst1.64         {d30-d31}, [r0,:128]!
1139     bxle            lr
1140     subs            r2,  r2,  #16
1141
1142     vext.16         q11, q3,  q0,  #2
1143     vadd.s16        q9,  q9,  q11
1144     vext.16         q10, q3,  q0,  #1
1145     vext.16         q11, q3,  q0,  #6
1146     vadd.s16        q10, q3,  q10
1147     vsub.s16        q8,  q8,  q9    // a-b
1148     vext.16         q15, q0,  q1,  #3
1149     vsub.s16        q9,  q9,  q10   // b-c
1150
1151     vext.16         q12, q3,  q0,  #7
1152     vshr.s16        q8,  q8,  #2    // (a-b)/4
1153     vadd.s16        q11, q11, q15
1154     vext.16         q14, q0,  q1,  #2
1155     vsub.s16        q8,  q8,  q9    // (a-b)/4-b+c
1156     vadd.s16        q12, q12, q14
1157     vext.16         q13, q0,  q1,  #1
1158
1159     vshr.s16        q8,  q8,  #2    // ((a-b)/4-b+c)/4
1160     vadd.s16        q13, q0,  q13
1161     vadd.s16        q8,  q8,  q10   // ((a-b)/4-b+c)/4+c = (a-5*b+20*c)/16
1162     vsub.s16        q11, q11, q12   // a-b
1163     vsub.s16        q12, q12, q13   // b-c
1164     vshr.s16        q11, q11, #2    // (a-b)/4
1165     vqrshrun.s16    d30, q8,  #6
1166     vsub.s16        q11, q11, q12   // (a-b)/4-b+c
1167     vshr.s16        q11, q11, #2    // ((a-b)/4-b+c)/4
1168     vadd.s16        q11, q11, q13   // ((a-b)/4-b+c)/4+c = (a-5*b+20*c)/16
1169
1170     vqrshrun.s16    d31, q11,  #6
1171     vst1.64         {d30-d31}, [r0,:128]!
1172     bgt             filter_c_loop
1173     bx              lr
1174 .endfunc
1175
1176 // hpel_filter_h( uint8_t *dst, uint8_t *src, int width );
1177 function x264_hpel_filter_h_neon
1178     sub             r1,  #16
1179     vmov.u8         d30, #5
1180     vld1.64         {d0-d3}, [r1,:128]!
1181     vmov.u8         d31, #20
1182
1183     // unrolled 3x because it's 5% faster, due to mitigating
1184     // the high latency of multiplication and vqrshrun
1185 filter_h_loop:
1186     subs            r2,  r2,  #16
1187     vld1.64         {d4-d5}, [r1,:128]!
1188     vext.8          q8,  q0,  q1,  #14
1189     vext.8          q12, q1,  q2,  #3
1190     vaddl.u8        q13, d16, d24
1191     vext.8          q9,  q0,  q1,  #15
1192     vaddl.u8        q14, d17, d25
1193
1194     vext.8          q10, q1,  q2,  #1
1195     vmlal.u8        q13, d2,  d31
1196     vmlsl.u8        q13, d18, d30
1197     vext.8          q11, q1,  q2,  #2
1198     vmlal.u8        q13, d20, d31
1199     vmlsl.u8        q13, d22, d30
1200
1201     vmlsl.u8        q14, d19, d30
1202     vmlal.u8        q14, d3,  d31
1203     vmlal.u8        q14, d21, d31
1204     vmlsl.u8        q14, d23, d30
1205     vqrshrun.s16    d6,  q13, #5
1206
1207     vld1.64         {d0-d1}, [r1,:128]!
1208     vext.8          q8,  q1,  q2,  #14
1209     vext.8          q12, q2,  q0,  #3
1210     vaddl.u8        q13, d16, d24
1211     vqrshrun.s16    d7,  q14, #5
1212     vext.8          q9,  q1,  q2,  #15
1213     vaddl.u8        q14, d17, d25
1214
1215     vst1.64         {d6-d7}, [r0,:128]!
1216     bxle            lr
1217     subs            r2,  r2,  #16
1218
1219     vext.8          q10, q2,  q0,  #1
1220     vmlal.u8        q13, d4,  d31
1221     vmlsl.u8        q13, d18, d30
1222     vext.8          q11, q2,  q0,  #2
1223     vmlal.u8        q13, d20, d31
1224     vmlsl.u8        q13, d22, d30
1225
1226     vmlsl.u8        q14, d19, d30
1227     vmlal.u8        q14, d5,  d31
1228     vmlal.u8        q14, d21, d31
1229     vmlsl.u8        q14, d23, d30
1230     vqrshrun.s16    d6,  q13, #5
1231
1232     vld1.64         {d2-d3}, [r1,:128]!
1233     vext.8          q8,  q2,  q0,  #14
1234     vext.8          q12, q0,  q1,  #3
1235     vaddl.u8        q13, d16, d24
1236     vqrshrun.s16    d7,  q14, #5
1237     vext.8          q9,  q2,  q0,  #15
1238     vaddl.u8        q14, d17, d25
1239
1240     vst1.64         {d6-d7}, [r0,:128]!
1241     bxle            lr
1242     subs            r2,  r2,  #16
1243
1244     vext.8          q10, q0,  q1,  #1
1245     vmlal.u8        q13, d0,  d31
1246     vmlsl.u8        q13, d18, d30
1247     vext.8          q11, q0,  q1,  #2
1248     vmlal.u8        q13, d20, d31
1249     vmlsl.u8        q13, d22, d30
1250
1251     vmlsl.u8        q14, d19, d30
1252     vmlal.u8        q14, d1,  d31
1253     vmlal.u8        q14, d21, d31
1254     vmlsl.u8        q14, d23, d30
1255
1256     vqrshrun.s16    d6, q13, #5
1257     vqrshrun.s16    d7, q14, #5
1258     vst1.64         {d6-d7}, [r0,:128]!
1259     bgt             filter_h_loop
1260     bx              lr
1261 .endfunc
1262
1263
1264 // frame_init_lowres_core( uint8_t *src0, uint8_t *dst0, uint8_t *dsth, uint8_t *dstv,
1265 //                         uint8_t *dstc, int src_stride, int dst_stride, int width,
1266 //                         int height )
1267 function x264_frame_init_lowres_core_neon
1268     push            {r4-r10,lr}
1269     vpush           {d8-d15}
1270     ldrd            r4,  [sp, #96]
1271     ldrd            r6,  [sp, #104]
1272     ldr             lr,  [sp, #112]
1273     sub             r10, r6,  r7            // dst_stride - width
1274     and             r10, r10, #~15
1275
1276 lowres_yloop:
1277     mov             ip,  r7                 // width
1278     mov             r6,  r0                 // src0
1279     add             r8,  r0,  r5            // src1 = src0 + src_stride
1280     add             r9,  r0,  r5,  lsl #1   // src2 = src1 + src_stride
1281
1282     vld2.8          {d8, d10}, [r6,:128]!
1283     vld2.8          {d12,d14}, [r8,:128]!
1284     vld2.8          {d16,d18}, [r9,:128]!
1285
1286 lowres_xloop:
1287     subs            ip,  ip,  #16
1288
1289     vld2.8          {d9, d11}, [r6,:128]!
1290     vld2.8          {d13,d15}, [r8,:128]!
1291     vrhadd.u8       q0,  q4,  q6
1292     vld2.8          {d17,d19}, [r9,:128]!
1293     vrhadd.u8       q5,  q5,  q7
1294     vld2.8          {d20,d22}, [r6,:128]!
1295     vrhadd.u8       q1,  q6,  q8
1296     vld2.8          {d24,d26}, [r8,:128]!
1297     vrhadd.u8       q7,  q7,  q9
1298     vext.8          q4,  q4,  q10, #1
1299     vrhadd.u8       q0,  q0,  q5
1300     vext.8          q6,  q6,  q12, #1
1301     vrhadd.u8       q1,  q1,  q7
1302     vld2.8          {d28,d30}, [r9,:128]!
1303     vrhadd.u8       q4,  q4,  q6
1304     vext.8          q8,  q8,  q14, #1
1305     vrhadd.u8       q6,  q6,  q8
1306     vst1.64         {d0-d1},   [r1,:128]!
1307     vrhadd.u8       q2,  q4,  q5
1308     vst1.64         {d2-d3},   [r3,:128]!
1309     vrhadd.u8       q3,  q6,  q7
1310     vst1.64         {d4-d5},   [r2,:128]!
1311     vst1.64         {d6-d7},   [r4,:128]!
1312
1313     ble             lowres_xloop_end
1314     subs            ip,  ip,  #16
1315
1316     vld2.8          {d21,d23}, [r6,:128]!
1317     vld2.8          {d25,d27}, [r8,:128]!
1318     vrhadd.u8       q0,  q10, q12
1319     vld2.8          {d29,d31}, [r9,:128]!
1320     vrhadd.u8       q11, q11, q13
1321     vld2.8          {d8, d10}, [r6,:128]!
1322     vrhadd.u8       q1,  q12, q14
1323     vld2.8          {d12,d14}, [r8,:128]!
1324     vrhadd.u8       q13, q13, q15
1325     vext.8          q10, q10, q4,  #1
1326     vrhadd.u8       q0,  q0,  q11
1327     vext.8          q12, q12, q6,  #1
1328     vrhadd.u8       q1,  q1,  q13
1329     vld2.8          {d16,d18}, [r9,:128]!
1330     vrhadd.u8       q10, q10, q12
1331     vext.8          q14, q14, q8,  #1
1332     vrhadd.u8       q12, q12, q14
1333     vst1.64         {d0-d1},   [r1,:128]!
1334     vrhadd.u8       q2,  q10, q11
1335     vst1.64         {d2-d3},   [r3,:128]!
1336     vrhadd.u8       q3,  q12, q13
1337     vst1.64         {d4-d5},   [r2,:128]!
1338     vst1.64         {d6-d7},   [r4,:128]!
1339
1340     bgt             lowres_xloop
1341
1342 lowres_xloop_end:
1343     subs            lr,  lr,  #1
1344     add             r0,  r0,  r5,  lsl #1
1345     add             r1,  r1,  r10
1346     add             r2,  r2,  r10
1347     add             r3,  r3,  r10
1348     add             r4,  r4,  r10
1349     bgt             lowres_yloop
1350
1351     vpop            {d8-d15}
1352     pop             {r4-r10,pc}
1353 .endfunc