]> git.sesse.net Git - x264/blob - common/arm/mc-a.S
Add Windows resource file
[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         640f
110     sub         r2, #32
111     vld1.64     {d0-d3}, [r1,:r1align]!
112     vst1.64     {d0-d3}, [r3,:r3align]!
113 640: // n is a multiple of 64
114     cmp         r2, #0
115     beq         1f
116 64:
117     subs        r2, #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]!
122     bgt         64b
123 1:   // end
124 .if \srcalign == 8 && \dstalign == 8
125     vld1.64     {d0}, [r1,:64]!
126     vst1.64     {d0}, [r3,:64]!
127 .endif
128     bx          lr
129 .endfunc
130 .endm
131
132 MEMCPY_ALIGNED 16, 16
133 MEMCPY_ALIGNED 16, 8
134 MEMCPY_ALIGNED  8, 16
135 MEMCPY_ALIGNED  8, 8
136
137 .section .rodata
138 memcpy_table:
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
143 .text
144
145 .ltorg
146
147 // void x264_memzero_aligned( void *dst, size_t n )
148 function x264_memzero_aligned_neon
149     vmov.i8     q0, #0
150     vmov.i8     q1, #0
151 memzero_loop:
152     subs        r1, #128
153 .rept 4
154     vst1.64     {d0-d3}, [r0,:128]!
155 .endr
156     bgt         memzero_loop
157     bx          lr
158 .endfunc
159
160
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 );
164 .macro AVGH w h
165 function x264_pixel_avg_\w\()x\h\()_neon
166     ldr         ip, [sp, #8]
167     push        {r4-r6,lr}
168     cmp         ip, #32
169     ldrd        r4, [sp, #16]
170     mov         lr, #\h
171     beq         x264_pixel_avg_w\w\()_neon
172     rsbs        r6,  ip,  #64
173     blt         x264_pixel_avg_weight_w\w\()_add_sub_neon     // weight > 64
174     cmp         ip,  #0
175     bge         x264_pixel_avg_weight_w\w\()_add_add_neon
176     b           x264_pixel_avg_weight_w\w\()_sub_add_neon     // weight < 0
177 .endfunc
178 .endm
179
180 AVGH  4, 2
181 AVGH  4, 4
182 AVGH  4, 8
183 AVGH  8, 4
184 AVGH  8, 8
185 AVGH  8, 16
186 AVGH 16, 8
187 AVGH 16, 16
188
189 // 0 < weight < 64
190 .macro load_weights_add_add
191     vdup.8      d30, ip
192     vdup.8      d31, r6
193 .endm
194
195 .macro load_add_add d1 d2
196     vld1.32     {\d1}, [r2], r3
197     vld1.32     {\d2}, [r4], r5
198 .endm
199
200 .macro weight_add_add dst s1 s2
201     vmull.u8    \dst, \s1, d30
202     vmlal.u8    \dst, \s2, d31
203 .endm
204
205 // weight > 64
206 .macro load_weights_add_sub
207     rsb         r6,  #0
208     vdup.8      d30, ip
209     vdup.8      d31, r6
210 .endm
211
212 .macro load_add_sub d1 d2
213     vld1.32     {\d1}, [r2], r3
214     vld1.32     {\d2}, [r4], r5
215 .endm
216
217 .macro weight_add_sub dst s1 s2
218     vmull.u8    \dst, \s1, d30
219     vmlsl.u8    \dst, \s2, d31
220 .endm
221
222 // weight < 0
223 .macro load_weights_sub_add
224     rsb         ip,  #0
225     vdup.8      d31, r6
226     vdup.8      d30, ip
227 .endm
228
229 .macro load_sub_add d1 d2
230     vld1.32     {\d2}, [r4], r5
231     vld1.32     {\d1}, [r2], r3
232 .endm
233
234 .macro weight_sub_add dst s1 s2
235     vmull.u8    \dst, \s2, d31
236     vmlsl.u8    \dst, \s1, d30
237 .endm
238
239 .macro AVG_WEIGHT ext
240 function x264_pixel_avg_weight_w4_\ext\()_neon
241     load_weights_\ext
242 1:  // height loop
243     subs            lr,  lr,  #2
244     load_\ext       d0[], d1[]
245     weight_\ext     q8,  d0,  d1
246     load_\ext       d2[], d3[]
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
252     bgt             1b
253     pop             {r4-r6,pc}
254 .endfunc
255
256 function x264_pixel_avg_weight_w8_\ext\()_neon
257     load_weights_\ext
258 1:  // height loop
259     subs            lr,  lr,  #4
260     load_\ext       d0,  d1
261     weight_\ext     q8,  d0,  d1
262     load_\ext       d2,  d3
263     weight_\ext     q9,  d2,  d3
264     load_\ext       d4,  d5
265     weight_\ext     q10, d4,  d5
266     load_\ext       d6,  d7
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
276     bgt             1b
277     pop             {r4-r6,pc}
278 .endfunc
279
280 function x264_pixel_avg_weight_w16_\ext\()_neon
281     load_weights_\ext
282 1:  // height loop
283     subs            lr,  lr,  #2
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
296     bgt             1b
297     pop             {r4-r6,pc}
298 .endfunc
299 .endm
300
301 AVG_WEIGHT add_add
302 AVG_WEIGHT add_sub
303 AVG_WEIGHT sub_add
304
305 function x264_pixel_avg_w4_neon
306     subs        lr,  lr,  #2
307     vld1.32     {d0[]}, [r2], r3
308     vld1.32     {d2[]}, [r4], r5
309     vrhadd.u8   d0,  d0,  d2
310     vld1.32     {d1[]}, [r2], r3
311     vld1.32     {d3[]}, [r4], r5
312     vrhadd.u8   d1,  d1,  d3
313     vst1.32     {d0[0]}, [r0,:32], r1
314     vst1.32     {d1[0]}, [r0,:32], r1
315     bgt         x264_pixel_avg_w4_neon
316     pop         {r4-r6,pc}
317 .endfunc
318
319 function x264_pixel_avg_w8_neon
320     subs        lr,  lr,  #4
321     vld1.64     {d0}, [r2], r3
322     vld1.64     {d2}, [r4], r5
323     vrhadd.u8   d0,  d0,  d2
324     vld1.64     {d1}, [r2], r3
325     vld1.64     {d3}, [r4], r5
326     vrhadd.u8   d1,  d1,  d3
327     vst1.64     {d0}, [r0,:64], r1
328     vld1.64     {d2}, [r2], r3
329     vld1.64     {d4}, [r4], r5
330     vrhadd.u8   d2,  d2,  d4
331     vst1.64     {d1}, [r0,:64], r1
332     vld1.64     {d3}, [r2], r3
333     vld1.64     {d5}, [r4], r5
334     vrhadd.u8   d3,  d3,  d5
335     vst1.64     {d2}, [r0,:64], r1
336     vst1.64     {d3}, [r0,:64], r1
337     bgt         x264_pixel_avg_w8_neon
338     pop         {r4-r6,pc}
339 .endfunc
340
341 function x264_pixel_avg_w16_neon
342     subs        lr,  lr,  #4
343     vld1.64     {d0-d1}, [r2], r3
344     vld1.64     {d2-d3}, [r4], r5
345     vrhadd.u8   q0,  q0,  q1
346     vld1.64     {d2-d3}, [r2], r3
347     vld1.64     {d4-d5}, [r4], r5
348     vrhadd.u8   q1,  q1,  q2
349     vst1.64     {d0-d1}, [r0,:128], r1
350     vld1.64     {d4-d5}, [r2], r3
351     vld1.64     {d6-d7}, [r4], r5
352     vrhadd.u8   q2,  q2,  q3
353     vst1.64     {d2-d3}, [r0,:128], r1
354     vld1.64     {d6-d7}, [r2], r3
355     vld1.64     {d0-d1}, [r4], r5
356     vrhadd.u8   q3,  q3,  q0
357     vst1.64     {d4-d5}, [r0,:128], r1
358     vst1.64     {d6-d7}, [r0,:128], r1
359     bgt         x264_pixel_avg_w16_neon
360     pop         {r4-r6,pc}
361 .endfunc
362
363
364 function x264_pixel_avg2_w4_neon
365     ldr         ip,  [sp, #4]
366     push        {lr}
367     ldr         lr,  [sp, #4]
368 avg2_w4_loop:
369     subs        ip,  ip,  #2
370     vld1.32     {d0[]},  [r2], r3
371     vld1.32     {d2[]},  [lr], r3
372     vrhadd.u8   d0,  d0,  d2
373     vld1.32     {d1[]},  [r2], r3
374     vld1.32     {d3[]},  [lr], r3
375     vrhadd.u8   d1,  d1,  d3
376     vst1.32     {d0[0]}, [r0,:32], r1
377     vst1.32     {d1[0]}, [r0,:32], r1
378     bgt         avg2_w4_loop
379     pop         {pc}
380 .endfunc
381
382 function x264_pixel_avg2_w8_neon
383     ldr         ip,  [sp, #4]
384     push        {lr}
385     ldr         lr,  [sp, #4]
386 avg2_w8_loop:
387     subs        ip,  ip,  #2
388     vld1.64     {d0}, [r2], r3
389     vld1.64     {d2}, [lr], r3
390     vrhadd.u8   d0,  d0,  d2
391     vld1.64     {d1}, [r2], r3
392     vld1.64     {d3}, [lr], r3
393     vrhadd.u8   d1,  d1,  d3
394     vst1.64     {d0}, [r0,:64], r1
395     vst1.64     {d1}, [r0,:64], r1
396     bgt         avg2_w8_loop
397     pop         {pc}
398 .endfunc
399
400 function x264_pixel_avg2_w16_neon
401     ldr         ip,  [sp, #4]
402     push        {lr}
403     ldr         lr,  [sp, #4]
404 avg2_w16_loop:
405     subs        ip,  ip,  #2
406     vld1.64     {d0-d1}, [r2], r3
407     vld1.64     {d2-d3}, [lr], r3
408     vrhadd.u8   q0,  q0,  q1
409     vld1.64     {d4-d5}, [r2], r3
410     vld1.64     {d6-d7}, [lr], r3
411     vrhadd.u8   q2,  q2,  q3
412     vst1.64     {d0-d1}, [r0,:128], r1
413     vst1.64     {d4-d5}, [r0,:128], r1
414     bgt         avg2_w16_loop
415     pop         {pc}
416 .endfunc
417
418 function x264_pixel_avg2_w20_neon
419     ldr         ip,  [sp, #4]
420     push        {lr}
421     sub         r1,  r1,  #16
422     ldr         lr,  [sp, #4]
423 avg2_w20_loop:
424     subs        ip,  ip,  #2
425     vld1.64     {d0-d2},  [r2], r3
426     vld1.64     {d4-d6},  [lr], r3
427     vrhadd.u8   q0,  q0,  q2
428     vrhadd.u8   d2,  d2,  d6
429     vld1.64     {d4-d6},  [r2], r3
430     vld1.64     {d16-d18},[lr], r3
431     vrhadd.u8   q2,  q2,  q8
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
437     bgt         avg2_w20_loop
438     pop         {pc}
439 .endfunc
440
441
442 .macro weight_prologue type
443     push        {r4-r5,lr}
444     ldr         r4,  [sp, #4*3]     // weight_t
445     ldr         ip,  [sp, #4*3+4]   // h
446 .ifc \type, full
447     ldr         lr,  [r4, #32]      // denom
448 .endif
449     ldrd        r4,  [r4, #32+4]    // scale, offset
450     vdup.16     q0,  r4
451     vdup.16     q1,  r5
452 .ifc \type, full
453     rsb         lr,  lr,  #0
454     vdup.16     q2,  lr
455 .endif
456 .endm
457
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
461     weight_prologue full
462     sub         r1, #16
463 weight20_loop:
464     subs        ip,  #2
465     vld1.8      {d17-d19}, [r2], r3
466     vmovl.u8    q10, d17
467     vmovl.u8    q11, d18
468     vmovl.u8    q14, d19
469     vld1.8      {d16-d18}, [r2], r3
470     vmovl.u8    q12, d16
471     vmovl.u8    q13, d17
472     vmovl.u8    q15, d18
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
489     vqmovun.s16 d16, q10
490     vqmovun.s16 d17, q11
491     vqmovun.s16 d18, q12
492     vqmovun.s16 d19, q13
493     vqmovun.s16 d20, q14
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
498     bgt         weight20_loop
499     pop         {r4-r5,pc}
500 .endfunc
501
502 function x264_mc_weight_w16_neon
503     weight_prologue full
504 weight16_loop:
505     subs        ip,  #2
506     vld1.8      {d16-d17}, [r2], r3
507     vld1.8      {d18-d19}, [r2], r3
508     vmovl.u8    q10, d16
509     vmovl.u8    q11, d17
510     vmovl.u8    q12, d18
511     vmovl.u8    q13, d19
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
524     vqmovun.s16 d16, q10
525     vqmovun.s16 d17, q11
526     vqmovun.s16 d18, q12
527     vqmovun.s16 d19, q13
528     vst1.8      {d16-d17}, [r0,:128], r1
529     vst1.8      {d18-d19}, [r0,:128], r1
530     bgt         weight16_loop
531     pop         {r4-r5,pc}
532 .endfunc
533
534 function x264_mc_weight_w8_neon
535     weight_prologue full
536 weight8_loop:
537     subs        ip,  #2
538     vld1.8      {d16}, [r2], r3
539     vld1.8      {d18}, [r2], r3
540     vmovl.u8    q8,  d16
541     vmovl.u8    q9,  d18
542     vmul.s16    q8,  q8,  q0
543     vmul.s16    q9,  q9,  q0
544     vrshl.s16   q8,  q8,  q2
545     vrshl.s16   q9,  q9,  q2
546     vadd.s16    q8,  q8,  q1
547     vadd.s16    q9,  q9,  q1
548     vqmovun.s16 d16, q8
549     vqmovun.s16 d18, q9
550     vst1.8      {d16}, [r0,:64], r1
551     vst1.8      {d18}, [r0,:64], r1
552     bgt         weight8_loop
553     pop         {r4-r5,pc}
554 .endfunc
555
556 function x264_mc_weight_w4_neon
557     weight_prologue full
558 weight4_loop:
559     subs        ip,  #2
560     vld1.32     {d16[]}, [r2], r3
561     vld1.32     {d18[]}, [r2], r3
562     vmovl.u8    q8,  d16
563     vmovl.u8    q9,  d18
564     vmul.s16    d16, d16, d0
565     vmul.s16    d17, d18, d0
566     vrshl.s16   q8,  q8,  q2
567     vadd.s16    q8,  q8,  q1
568     vqmovun.s16 d16, q8
569     vst1.32     {d16[0]}, [r0,:32], r1
570     vst1.32     {d16[1]}, [r0,:32], r1
571     bgt         weight4_loop
572     pop         {r4-r5,pc}
573 .endfunc
574
575 function x264_mc_weight_w20_nodenom_neon
576     weight_prologue nodenom
577     sub         r1, #16
578 weight20_nodenom_loop:
579     subs        ip,  #2
580     vld1.8      {d17-d19}, [r2], r3
581     vmovl.u8    q10, d17
582     vmovl.u8    q11, d18
583     vmovl.u8    q14, d19
584     vld1.8      {d16-d18}, [r2], r3
585     vmovl.u8    q12, d16
586     vmovl.u8    q13, d17
587     vmovl.u8    q15, d18
588     vmov        q8,  q1
589     vmov        q9,  q1
590     vmla.s16    q8,  q10, q0
591     vmla.s16    q9,  q11, q0
592     vmov        q10, q1
593     vmov        q11, q1
594     vmla.s16    q10, q12, q0
595     vmla.s16    q11, q13, q0
596     vmov        q12, q1
597     vmla.s16    d24, d28, d0
598     vmla.s16    d25, d30, d0
599     vqmovun.s16 d16, q8
600     vqmovun.s16 d17, q9
601     vqmovun.s16 d18, q10
602     vqmovun.s16 d19, q11
603     vqmovun.s16 d20, q12
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
609     pop         {r4-r5,pc}
610 .endfunc
611
612 function x264_mc_weight_w16_nodenom_neon
613     weight_prologue nodenom
614 weight16_nodenom_loop:
615     subs        ip,  #2
616     vld1.8      {d16-d17}, [r2], r3
617     vld1.8      {d18-d19}, [r2], r3
618     vmovl.u8    q12, d16
619     vmovl.u8    q13, d17
620     vmovl.u8    q14, d18
621     vmovl.u8    q15, d19
622     vmov        q8,  q1
623     vmov        q9,  q1
624     vmov        q10, q1
625     vmov        q11, q1
626     vmla.s16    q8,  q12, q0
627     vmla.s16    q9,  q13, q0
628     vmla.s16    q10, q14, q0
629     vmla.s16    q11, q15, q0
630     vqmovun.s16 d16, q8
631     vqmovun.s16 d17, q9
632     vqmovun.s16 d18, q10
633     vqmovun.s16 d19, q11
634     vst1.8      {d16-d17}, [r0,:128], r1
635     vst1.8      {d18-d19}, [r0,:128], r1
636     bgt         weight16_nodenom_loop
637     pop         {r4-r5,pc}
638 .endfunc
639
640 function x264_mc_weight_w8_nodenom_neon
641     weight_prologue nodenom
642 weight8_nodenom_loop:
643     subs        ip,  #2
644     vld1.8      {d16}, [r2], r3
645     vld1.8      {d18}, [r2], r3
646     vmovl.u8    q8,  d16
647     vmovl.u8    q9,  d18
648     vmov        q10, q1
649     vmov        q11, q1
650     vmla.s16    q10, q8,  q0
651     vmla.s16    q11, q9,  q0
652     vqmovun.s16 d16, q10
653     vqmovun.s16 d17, q11
654     vst1.8      {d16}, [r0,:64], r1
655     vst1.8      {d17}, [r0,:64], r1
656     bgt         weight8_nodenom_loop
657     pop         {r4-r5,pc}
658 .endfunc
659
660 function x264_mc_weight_w4_nodenom_neon
661     weight_prologue nodenom
662 weight4_nodenom_loop:
663     subs        ip,  #2
664     vld1.32     {d16[]}, [r2], r3
665     vld1.32     {d18[]}, [r2], r3
666     vmovl.u8    q8,  d16
667     vmovl.u8    q9,  d18
668     vmov        q10, q1
669     vmla.s16    d20, d16, d0
670     vmla.s16    d21, d18, d0
671     vqmovun.s16 d16, q10
672     vst1.32     {d16[0]}, [r0,:32], r1
673     vst1.32     {d16[1]}, [r0,:32], r1
674     bgt         weight4_nodenom_loop
675     pop         {r4-r5,pc}
676 .endfunc
677
678 .macro weight_simple_prologue
679     push        {lr}
680     ldr         lr,  [sp, #4]       // weight_t
681     ldr         ip,  [sp, #8]       // h
682     ldr         lr,  [lr]           // offset
683     vdup.8      q1,  lr
684 .endm
685
686 .macro weight_simple name op
687 function x264_mc_weight_w20_\name\()_neon
688     weight_simple_prologue
689 weight20_\name\()_loop:
690     subs        ip,  #2
691     vld1.8      {d16-d18}, [r2], r3
692     vld1.8      {d19-d21}, [r2], r3
693     \op         q8,  q8,  q1
694     \op         q9,  q9,  q1
695     \op         q10, q10, q1
696     vst1.8      {d16-d18}, [r0,:64], r1
697     vst1.8      {d19-d21}, [r0,:64], r1
698     bgt         weight20_\name\()_loop
699     pop         {pc}
700 .endfunc
701
702 function x264_mc_weight_w16_\name\()_neon
703     weight_simple_prologue
704 weight16_\name\()_loop:
705     subs        ip,  #2
706     vld1.8      {d16-d17}, [r2], r3
707     vld1.8      {d18-d19}, [r2], r3
708     \op         q8,  q8,  q1
709     \op         q9,  q9,  q1
710     vst1.8      {d16-d17}, [r0,:128], r1
711     vst1.8      {d18-d19}, [r0,:128], r1
712     bgt         weight16_\name\()_loop
713     pop         {pc}
714 .endfunc
715
716 function x264_mc_weight_w8_\name\()_neon
717     weight_simple_prologue
718 weight8_\name\()_loop:
719     subs        ip,  #2
720     vld1.8      {d16}, [r2], r3
721     vld1.8      {d17}, [r2], r3
722     \op         q8,  q8,  q1
723     vst1.8      {d16}, [r0,:64], r1
724     vst1.8      {d17}, [r0,:64], r1
725     bgt         weight8_\name\()_loop
726     pop         {pc}
727 .endfunc
728
729 function x264_mc_weight_w4_\name\()_neon
730     weight_simple_prologue
731 weight4_\name\()_loop:
732     subs        ip,  #2
733     vld1.32     {d16[]}, [r2], r3
734     vld1.32     {d17[]}, [r2], r3
735     \op         q8,  q8,  q1
736     vst1.32     {d16[0]}, [r0,:32], r1
737     vst1.32     {d17[0]}, [r0,:32], r1
738     bgt         weight4_\name\()_loop
739     pop         {pc}
740 .endfunc
741 .endm
742
743 weight_simple offsetadd, vqadd.u8
744 weight_simple offsetsub, vqsub.u8
745
746
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
749     ldr         ip,  [sp]
750 copy_w4_loop:
751     subs        ip,  ip,  #4
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
760     bgt         copy_w4_loop
761     bx          lr
762 .endfunc
763
764 function x264_mc_copy_w8_neon
765     ldr         ip,  [sp]
766 copy_w8_loop:
767     subs        ip,  ip,  #4
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
776     bgt         copy_w8_loop
777     bx          lr
778 .endfunc
779
780 function x264_mc_copy_w16_neon
781     ldr         ip,  [sp]
782 copy_w16_loop:
783     subs        ip,  ip,  #4
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
792     bgt         copy_w16_loop
793     bx          lr
794 .endfunc
795
796 function x264_mc_copy_w16_aligned_neon
797     ldr         ip,  [sp]
798 copy_w16_aligned_loop:
799     subs        ip,  ip,  #4
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
809     bx          lr
810 .endfunc
811
812
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
817     push            {r4-r6, lr}
818     ldrd            r4,  [sp, #16]
819     ldr             r6,  [sp, #24]
820
821     asr             lr,  r5,  #3
822     mul             lr,  r3,  lr
823     add             r2,  r2,  r4,  asr #3
824     cmp             r6, #4
825     add             r2,  r2,  lr
826
827     and             r4, r4, #7
828     and             r5, r5, #7
829     pld             [r2]
830     pld             [r2, r3]
831
832     bgt             mc_chroma_w8
833     beq             mc_chroma_w4
834
835 // calculate cA cB cC cD
836 .macro CHROMA_MC_START r0 r1
837     muls            lr,  r4,  r5
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
842     add             r4,  r4,  #64
843
844     beq             2f
845
846     add             r5,  r2,  r3
847
848     vdup.8          d0,  r4
849     lsl             r3,  r3,  #1
850     vdup.8          d1,  ip
851     vld1.64         {\r0}, [r2], r3
852     vdup.8          d2,  r6
853     vld1.64         {\r1}, [r5], r3
854     vdup.8          d3,  lr
855     ldr             r4,  [sp, #28]
856
857     vext.8          d5,  d4,  d5,  #1
858     vext.8          d7,  d6,  d7,  #1
859 .endm
860
861 .macro CHROMA_MC width, align
862 mc_chroma_w\width:
863     CHROMA_MC_START d4,  d6
864 // since the element size varies, there's a different index for the 2nd store
865 .if \width == 4
866     .set st2, 1
867 .else
868     .set st2, 2
869 .endif
870
871     vtrn.32         d4,  d5
872     vtrn.32         d6,  d7
873
874     vtrn.32         d0,  d1
875     vtrn.32         d2,  d3
876
877 1:  // height loop, interpolate xy
878     pld             [r5]
879     vmull.u8        q8,  d4,  d0
880     vmlal.u8        q8,  d6,  d2
881     vld1.64         {d4},     [r2], r3
882     vext.8          d5,  d4,  d5,  #1
883     vtrn.32         d4,  d5
884     vmull.u8        q9,  d6,  d0
885     vmlal.u8        q9,  d4,  d2
886     vld1.64         {d6},     [r5], r3
887     vadd.i16        d16, d16, d17
888     vadd.i16        d17, d18, d19
889     vrshrn.u16      d16, q8,  #6
890     subs            r4,  r4,  #2
891     pld             [r2]
892     vext.8          d7,  d6,  d7,  #1
893     vtrn.32         d6,  d7
894     vst1.\align     {d16[0]},   [r0,:\align], r1
895     vst1.\align     {d16[st2]}, [r0,:\align], r1
896     bgt             1b
897
898     pop             {r4-r6, pc}
899
900 2:  // dx or dy are 0
901     tst             r6,  r6
902     add             ip,  ip,  r6
903     vdup.8          d0,  r4
904     vdup.8          d1,  ip
905     vtrn.32         d0,  d1
906     ldr             r4,  [sp, #28]
907
908     beq             4f
909
910     vext.32         d1,  d0,  d1,  #1
911     add             r5,  r2,  r3
912     lsl             r3,  r3,  #1
913     vld1.32         {d4[0]},  [r2], r3
914     vld1.32         {d4[1]},  [r5], r3
915
916 3:  // vertical interpolation loop
917     pld             [r5]
918     vmull.u8        q8,  d4,  d0
919     vld1.32         {d4[0]},  [r2], r3
920     vmull.u8        q9,  d4,  d1
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
925     subs            r4,  r4,  #2
926     pld             [r2]
927     vst1.\align     {d16[0]},   [r0,:\align], r1
928     vst1.\align     {d16[st2]}, [r0,:\align], r1
929     bgt             3b
930
931     pop             {r4-r6, pc}
932
933 4:  // dy is 0
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
938     vtrn.32         d4,  d5
939     vtrn.32         d6,  d7
940
941 5:  // horizontal interpolation loop
942     vmull.u8        q8,  d4,  d0
943     vmull.u8        q9,  d6,  d0
944     subs            r4,  r4,  #2
945     vld1.64         {d4},     [r2], r3
946     vext.8          d5,  d4,  d5,  #1
947     vtrn.32         d4,  d5
948     vadd.i16        d16, d16, d17
949     vadd.i16        d17, d18, d19
950     pld             [r2]
951     vrshrn.u16      d16, q8,  #6
952     vld1.64         {d6},     [r2], r3
953     vext.8          d7,  d6,  d7,  #1
954     vtrn.32         d6,  d7
955     pld             [r2]
956     vst1.\align     {d16[0]},   [r0,:\align], r1
957     vst1.\align     {d16[st2]}, [r0,:\align], r1
958     bgt             5b
959
960     pop             {r4-r6, pc}
961 .endm
962
963     CHROMA_MC 2, 16
964     CHROMA_MC 4, 32
965
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
968 mc_chroma_w8:
969     CHROMA_MC_START d4-d5, d6-d7
970
971 1:  // height loop, interpolate xy
972     pld             [r5]
973     vmull.u8        q8,  d4,  d0
974     vmlal.u8        q8,  d5,  d1
975     vld1.64         {d4, d5}, [r2], r3
976     vmlal.u8        q8,  d6,  d2
977     vext.8          d5,  d4,  d5,  #1
978     vmlal.u8        q8,  d7,  d3
979     vmull.u8        q9,  d6,  d0
980     subs            r4,  r4,  #2
981     vmlal.u8        q9,  d7,  d1
982     vmlal.u8        q9,  d4,  d2
983     vmlal.u8        q9,  d5,  d3
984     vrshrn.u16      d16, q8,  #6
985     vld1.64         {d6, d7}, [r5], r3
986     pld             [r2]
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
991     bgt             1b
992
993     pop             {r4-r6, pc}
994
995 2:  // dx or dy are 0
996     tst             r6,  r6
997     add             ip,  ip,  r6
998     vdup.8          d0,  r4
999     vdup.8          d1,  ip
1000     ldr             r4,  [sp, #28]
1001
1002     beq             4f
1003
1004     add             r5,  r2,  r3
1005     lsl             r3,  r3,  #1
1006     vld1.64         {d4}, [r2], r3
1007     vld1.64         {d6}, [r5], r3
1008
1009 3:  // vertical interpolation loop
1010     pld             [r5]
1011     vmull.u8        q8,  d4,  d0
1012     vmlal.u8        q8,  d6,  d1
1013     vld1.64         {d4}, [r2], r3
1014     vmull.u8        q9,  d6,  d0
1015     vmlal.u8        q9,  d4,  d1
1016     vld1.64         {d6}, [r5], r3
1017     vrshrn.u16      d16, q8,  #6
1018     vrshrn.u16      d17, q9,  #6
1019     subs            r4,  r4,  #2
1020     pld             [r2]
1021     vst1.64         {d16}, [r0,:64], r1
1022     vst1.64         {d17}, [r0,:64], r1
1023     bgt             3b
1024
1025     pop             {r4-r6, pc}
1026
1027 4:  // dy is 0
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
1032
1033 5:  // horizontal interpolation loop
1034     pld             [r2]
1035     subs            r4,  r4,  #2
1036     vmull.u8        q8,  d4,  d0
1037     vmlal.u8        q8,  d5,  d1
1038     vld1.64         {d4,  d5}, [r2], r3
1039     vmull.u8        q9,  d6,  d0
1040     vmlal.u8        q9,  d7,  d1
1041     pld             [r2]
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
1049     bgt             5b
1050
1051     pop             {r4-r6, pc}
1052 .endfunc
1053
1054
1055 // hpel_filter_v( uint8_t *dst, uint8_t *src, int16_t *buf, int stride, int width)
1056 function x264_hpel_filter_v_neon
1057     ldr             ip,  [sp]
1058     sub             r1,  r1,  r3,  lsl #1
1059     push            {lr}
1060     add             lr,  r1,  ip
1061     vmov.u8         d30, #5
1062     vmov.u8         d31, #20
1063
1064 filter_v_loop:
1065     subs            ip,  ip,  #16
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
1072     sub             r1,  lr,  ip
1073
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
1079
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
1085
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]!
1091     bgt             filter_v_loop
1092     pop             {pc}
1093 .endfunc
1094
1095 // hpel_filter_c( uint8_t *dst, int16_t *buf, int width );
1096 function x264_hpel_filter_c_neon
1097     sub             r1,  #16
1098     vld1.64         {d0-d3}, [r1,:128]!
1099
1100     // unrolled 2x: 4% faster
1101 filter_c_loop:
1102     subs            r2,  r2,  #16
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
1116
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
1124
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
1136
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]!
1143     bxle            lr
1144     subs            r2,  r2,  #16
1145
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
1154
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
1162
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
1173
1174     vqrshrun.s16    d31, q11,  #6
1175     vst1.64         {d30-d31}, [r0,:128]!
1176     bgt             filter_c_loop
1177     bx              lr
1178 .endfunc
1179
1180 // hpel_filter_h( uint8_t *dst, uint8_t *src, int width );
1181 function x264_hpel_filter_h_neon
1182     sub             r1,  #16
1183     vmov.u8         d30, #5
1184     vld1.64         {d0-d3}, [r1,:128]!
1185     vmov.u8         d31, #20
1186
1187     // unrolled 3x because it's 5% faster, due to mitigating
1188     // the high latency of multiplication and vqrshrun
1189 filter_h_loop:
1190     subs            r2,  r2,  #16
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
1197
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
1204
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
1210
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
1218
1219     vst1.64         {d6-d7}, [r0,:128]!
1220     bxle            lr
1221     subs            r2,  r2,  #16
1222
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
1229
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
1235
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
1243
1244     vst1.64         {d6-d7}, [r0,:128]!
1245     bxle            lr
1246     subs            r2,  r2,  #16
1247
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
1254
1255     vmlsl.u8        q14, d19, d30
1256     vmlal.u8        q14, d1,  d31
1257     vmlal.u8        q14, d21, d31
1258     vmlsl.u8        q14, d23, d30
1259
1260     vqrshrun.s16    d6, q13, #5
1261     vqrshrun.s16    d7, q14, #5
1262     vst1.64         {d6-d7}, [r0,:128]!
1263     bgt             filter_h_loop
1264     bx              lr
1265 .endfunc
1266
1267
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,
1270 //                         int height )
1271 function x264_frame_init_lowres_core_neon
1272     push            {r4-r10,lr}
1273     vpush           {d8-d15}
1274     ldrd            r4,  [sp, #96]
1275     ldrd            r6,  [sp, #104]
1276     ldr             lr,  [sp, #112]
1277     sub             r10, r6,  r7            // dst_stride - width
1278     and             r10, r10, #~15
1279
1280 lowres_yloop:
1281     mov             ip,  r7                 // width
1282     mov             r6,  r0                 // src0
1283     add             r8,  r0,  r5            // src1 = src0 + src_stride
1284     add             r9,  r0,  r5,  lsl #1   // src2 = src1 + src_stride
1285
1286     vld2.8          {d8, d10}, [r6,:128]!
1287     vld2.8          {d12,d14}, [r8,:128]!
1288     vld2.8          {d16,d18}, [r9,:128]!
1289
1290 lowres_xloop:
1291     subs            ip,  ip,  #16
1292
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]!
1316
1317     ble             lowres_xloop_end
1318     subs            ip,  ip,  #16
1319
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]!
1343
1344     bgt             lowres_xloop
1345
1346 lowres_xloop_end:
1347     subs            lr,  lr,  #1
1348     add             r0,  r0,  r5,  lsl #1
1349     add             r1,  r1,  r10
1350     add             r2,  r2,  r10
1351     add             r3,  r3,  r10
1352     add             r4,  r4,  r10
1353     bgt             lowres_yloop
1354
1355     vpop            {d8-d15}
1356     pop             {r4-r10,pc}
1357 .endfunc