1/*****************************************************************************
2 * pixel.S: arm pixel metrics
3 *****************************************************************************
4 * Copyright (C) 2009-2021 x264 project
5 *
6 * Authors: David Conrad <lessen42@gmail.com>
7 *          Janne Grunau <janne-x264@jannau.net>
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
29const mask_array, align=4
30.rept 16
31        .byte 0xff
32.endr
33mask_ff:
34.rept 16
35        .byte 0
36.endr
37endconst
38
39const mask_ac4, align=4
40.short 0, -1, -1, -1,  0, -1, -1, -1
41endconst
42const mask_ac8, align=4
43.short 0, -1, -1, -1, -1, -1, -1, -1
44endconst
45
46.text
47
48.macro SAD4_ARMV6 h
49function pixel_sad_4x\h\()_armv6
50    push        {r4-r6,lr}
51    ldr         r4, [r2], r3
52    ldr         r5, [r0], r1
53    ldr         r6, [r2], r3
54    ldr         lr, [r0], r1
55    usad8       ip, r4, r5
56.rept (\h - 2)/2
57    ldr         r4, [r2], r3
58    ldr         r5, [r0], r1
59    usada8      ip, r6, lr, ip
60    ldr         r6, [r2], r3
61    ldr         lr, [r0], r1
62    usada8      ip, r4, r5, ip
63.endr
64    usada8      r0, r6, lr, ip
65    pop         {r4-r6,pc}
66endfunc
67.endm
68
69SAD4_ARMV6 4
70SAD4_ARMV6 8
71
72
73.macro SAD_START_4 align:vararg
74    vld1.32     {d1[]}, [r2\align], r3
75    vld1.32     {d0[]}, [r0,:32], r1
76    vabdl.u8    q8,  d0,  d1
77.endm
78
79.macro SAD_4 align:vararg
80    vld1.32     {d1[]}, [r2\align], r3
81    vld1.32     {d0[]}, [r0,:32], r1
82    vabal.u8    q8,  d0,  d1
83.endm
84
85.macro SAD_START_8 align:vararg
86    vld1.64     {d1}, [r2\align], r3
87    vld1.64     {d0}, [r0,:64], r1
88    vabdl.u8    q8,  d0,  d1
89.endm
90
91.macro SAD_8 align:vararg
92    vld1.64     {d1}, [r2\align], r3
93    vld1.64     {d0}, [r0,:64], r1
94    vabal.u8    q8,  d0,  d1
95.endm
96
97.macro SAD_START_16 align:vararg
98    vld1.64     {d2-d3}, [r2\align], r3
99    vld1.64     {d0-d1}, [r0,:128], r1
100    vabdl.u8    q8,  d0,  d2
101    vld1.64     {d6-d7}, [r2\align], r3
102    vabdl.u8    q9,  d1,  d3
103    vld1.64     {d4-d5}, [r0,:128], r1
104.endm
105
106.macro SAD_16 align:vararg
107    vabal.u8    q8,  d4,  d6
108    vld1.64     {d2-d3}, [r2\align], r3
109    vabal.u8    q9,  d5,  d7
110    vld1.64     {d0-d1}, [r0,:128], r1
111    vabal.u8    q8,  d0,  d2
112    vld1.64     {d6-d7}, [r2\align], r3
113    vabal.u8    q9,  d1,  d3
114    vld1.64     {d4-d5}, [r0,:128], r1
115.endm
116
117.macro SAD_FUNC w, h, name, align:vararg
118function pixel_sad\name\()_\w\()x\h\()_neon
119    SAD_START_\w \align
120
121.if \w == 16
122.rept \h / 2 - 1
123    SAD_\w \align
124.endr
125.else
126.rept \h - 1
127    SAD_\w \align
128.endr
129.endif
130
131.if \w > 8
132    vabal.u8    q8,  d4,  d6
133    vabal.u8    q9,  d5,  d7
134    vadd.u16    q8,  q8,  q9
135.endif
136.if \w > 4
137    vadd.u16    d16, d16, d17
138.endif
139    vpadd.u16   d0,  d16, d16
140    vpaddl.u16  d0,  d0
141    vmov.u32    r0,  d0[0]
142    bx          lr
143endfunc
144.endm
145
146SAD_FUNC  4,  4
147SAD_FUNC  4,  8
148SAD_FUNC  8,  4
149SAD_FUNC  8,  8
150SAD_FUNC  8,  16
151SAD_FUNC  16, 8
152SAD_FUNC  16, 16
153
154SAD_FUNC  4,  4,  _aligned, ,:32
155SAD_FUNC  4,  8,  _aligned, ,:32
156SAD_FUNC  8,  4,  _aligned, ,:64
157SAD_FUNC  8,  8,  _aligned, ,:64
158SAD_FUNC  8,  16, _aligned, ,:64
159SAD_FUNC  16, 8,  _aligned, ,:128
160SAD_FUNC  16, 16, _aligned, ,:128
161
162// If dual issue is possible, use additional accumulators to avoid
163// stalls from vadal's latency. This only matters for aligned.
164.macro SAD_DUAL_START_8
165    SAD_START_8 ,:64
166    vld1.64     {d3}, [r2,:64], r3
167    vld1.64     {d2}, [r0,:64], r1
168    vabdl.u8    q9,  d2,  d3
169.endm
170
171.macro SAD_DUAL_8 align:vararg
172    vld1.64     {d1}, [r2,:64], r3
173    vld1.64     {d0}, [r0,:64], r1
174    vabal.u8    q8,  d0,  d1
175    vld1.64     {d3}, [r2,:64], r3
176    vld1.64     {d2}, [r0,:64], r1
177    vabal.u8    q9,  d2,  d3
178.endm
179
180.macro SAD_DUAL_START_16
181    SAD_START_16 ,:128
182    vabdl.u8    q10, d4,  d6
183    vld1.64     {d2-d3}, [r2,:128], r3
184    vabdl.u8    q11, d5,  d7
185    vld1.64     {d0-d1}, [r0,:128], r1
186.endm
187
188.macro SAD_DUAL_16
189    vabal.u8    q8,  d0,  d2
190    vld1.64     {d6-d7}, [r2,:128], r3
191    vabal.u8    q9,  d1,  d3
192    vld1.64     {d4-d5}, [r0,:128], r1
193    vabal.u8    q10, d4,  d6
194    vld1.64     {d2-d3}, [r2,:128], r3
195    vabal.u8    q11, d5,  d7
196    vld1.64     {d0-d1}, [r0,:128], r1
197.endm
198
199.macro SAD_DUAL_END_16
200    vabal.u8    q8,  d0,  d2
201    vld1.64     {d6-d7}, [r2,:128], r3
202    vabal.u8    q9,  d1,  d3
203    vld1.64     {d4-d5}, [r0,:128], r1
204    vabal.u8    q10, d4,  d6
205    vabal.u8    q11, d5,  d7
206.endm
207
208.macro SAD_FUNC_DUAL w, h
209function pixel_sad_aligned_\w\()x\h\()_neon_dual
210    SAD_DUAL_START_\w
211.rept \h / 2 - \w / 8
212    SAD_DUAL_\w
213.endr
214
215.if \w > 8
216    SAD_DUAL_END_16
217    vadd.u16    q8,  q8,  q9
218    vadd.u16    q9,  q10, q11
219.endif
220.if \w > 4
221    vadd.u16    q8,  q8,  q9
222    vadd.u16    d16, d16, d17
223.endif
224    vpadd.u16   d0,  d16, d16
225    vpaddl.u16  d0,  d0
226    vmov.u32    r0,  d0[0]
227    bx          lr
228endfunc
229.endm
230
231SAD_FUNC_DUAL  8,  4
232SAD_FUNC_DUAL  8,  8
233SAD_FUNC_DUAL  8,  16
234SAD_FUNC_DUAL  16, 8
235SAD_FUNC_DUAL  16, 16
236
237
238.macro SAD_X_START_4 x
239    vld1.32     {d0[]}, [r0,:32], lr
240    vld1.32     {d1[]}, [r1], r6
241    vabdl.u8    q8,  d1,  d0
242    vld1.32     {d2[]}, [r2], r6
243    vabdl.u8    q9,  d2,  d0
244    vld1.32     {d3[]}, [r3], r6
245    vabdl.u8    q10, d3,  d0
246.if \x == 4
247    vld1.32     {d4[]}, [r12], r6
248    vabdl.u8    q11, d4,  d0
249.endif
250.endm
251
252.macro SAD_X_4 x
253    vld1.32     {d0[]}, [r0,:32], lr
254    vld1.32     {d1[]}, [r1], r6
255    vabal.u8    q8,  d1,  d0
256    vld1.32     {d2[]}, [r2], r6
257    vabal.u8    q9,  d2,  d0
258    vld1.32     {d3[]}, [r3], r6
259    vabal.u8    q10, d3,  d0
260.if \x == 4
261    vld1.32     {d4[]}, [r12], r6
262    vabal.u8    q11, d4,  d0
263.endif
264.endm
265
266.macro SAD_X_START_8 x
267    vld1.64     {d0}, [r0,:64], lr
268    vld1.64     {d1}, [r1], r6
269    vabdl.u8    q8,  d1,  d0
270    vld1.64     {d2}, [r2], r6
271    vabdl.u8    q9,  d2,  d0
272    vld1.64     {d3}, [r3], r6
273    vabdl.u8    q10, d3,  d0
274.if \x == 4
275    vld1.64     {d4}, [r12], r6
276    vabdl.u8    q11, d4,  d0
277.endif
278.endm
279
280.macro SAD_X_8 x
281    vld1.64     {d0}, [r0,:64], lr
282    vld1.64     {d1}, [r1], r6
283    vabal.u8    q8,  d1,  d0
284    vld1.64     {d2}, [r2], r6
285    vabal.u8    q9,  d2,  d0
286    vld1.64     {d3}, [r3], r6
287    vabal.u8    q10, d3,  d0
288.if \x == 4
289    vld1.64     {d4}, [r12], r6
290    vabal.u8    q11, d4,  d0
291.endif
292.endm
293
294.macro SAD_X_START_16 x
295    vld1.64     {d0-d1}, [r0,:128], lr
296    vld1.64     {d2-d3}, [r1], r6
297    vabdl.u8    q8,  d2,  d0
298    vabdl.u8    q12, d3,  d1
299    vld1.64     {d4-d5}, [r2], r6
300    vabdl.u8    q9,  d4,  d0
301    vabdl.u8    q13, d5,  d1
302    vld1.64     {d6-d7}, [r3], r6
303    vabdl.u8    q10, d6,  d0
304    vabdl.u8    q14, d7,  d1
305.if \x == 4
306    vld1.64     {d2-d3}, [r12], r6
307    vabdl.u8    q11, d2,  d0
308    vabdl.u8    q15, d3,  d1
309.endif
310.endm
311
312.macro SAD_X_16 x
313    vld1.64     {d0-d1}, [r0,:128], lr
314    vld1.64     {d2-d3}, [r1], r6
315    vabal.u8    q8,  d2,  d0
316    vabal.u8    q12, d3,  d1
317    vld1.64     {d4-d5}, [r2], r6
318    vabal.u8    q9,  d4,  d0
319    vabal.u8    q13, d5,  d1
320    vld1.64     {d6-d7}, [r3], r6
321    vabal.u8    q10, d6,  d0
322    vabal.u8    q14, d7,  d1
323.if \x == 4
324    vld1.64     {d2-d3}, [r12], r6
325    vabal.u8    q11, d2,  d0
326    vabal.u8    q15, d3,  d1
327.endif
328.endm
329
330.macro SAD_X_FUNC x, w, h
331function pixel_sad_x\x\()_\w\()x\h\()_neon
332    push        {r6-r7,lr}
333.if \x == 3
334    ldrd        r6,  r7,  [sp, #12]
335.else
336    ldrd        r6,  r7,  [sp, #16]
337    ldr         r12, [sp, #12]
338.endif
339    mov         lr,  #FENC_STRIDE
340
341    SAD_X_START_\w \x
342.rept \h - 1
343    SAD_X_\w \x
344.endr
345
346// add up the sads
347.if \w > 8
348    vadd.u16    q8,  q8,  q12
349    vadd.u16    q9,  q9,  q13
350    vadd.u16    q10, q10, q14
351.if \x == 4
352    vadd.u16    q11, q11, q15
353.endif
354.endif
355.if \w > 4
356    vadd.u16    d16, d16, d17
357    vadd.u16    d18, d18, d19
358    vadd.u16    d20, d20, d21
359.if \x == 4
360    vadd.u16    d22, d22, d23
361.endif
362.endif
363    vpadd.u16   d0,  d16, d18
364    vpadd.u16   d1,  d20, d22
365    vpaddl.u16  q0,  q0
366
367.if \x == 3
368    vst1.32     {d0},    [r7]!
369    vst1.32     {d1[0]}, [r7,:32]
370.else
371    vst1.32     {d0-d1}, [r7]
372.endif
373    pop         {r6-r7,pc}
374endfunc
375.endm
376
377SAD_X_FUNC  3, 4,  4
378SAD_X_FUNC  3, 4,  8
379SAD_X_FUNC  3, 8,  4
380SAD_X_FUNC  3, 8,  8
381SAD_X_FUNC  3, 8,  16
382SAD_X_FUNC  3, 16, 8
383SAD_X_FUNC  3, 16, 16
384
385SAD_X_FUNC  4, 4,  4
386SAD_X_FUNC  4, 4,  8
387SAD_X_FUNC  4, 8,  4
388SAD_X_FUNC  4, 8,  8
389SAD_X_FUNC  4, 8,  16
390SAD_X_FUNC  4, 16, 8
391SAD_X_FUNC  4, 16, 16
392
393function pixel_vsad_neon
394    subs        r2,  r2,    #2
395    vld1.8     {q0}, [r0],  r1
396    vld1.8     {q1}, [r0],  r1
397    vabdl.u8    q2,  d0,    d2
398    vabdl.u8    q3,  d1,    d3
399    ble         2f
4001:
401    subs        r2,  r2,    #2
402    vld1.8     {q0}, [r0],  r1
403    vabal.u8    q2,  d2,    d0
404    vabal.u8    q3,  d3,    d1
405    vld1.8     {q1}, [r0],  r1
406    blt         2f
407    vabal.u8    q2,  d0,    d2
408    vabal.u8    q3,  d1,    d3
409    bgt         1b
4102:
411    vadd.u16    q0,  q2,    q3
412    HORIZ_ADD   d0,  d0,    d1
413    vmov.32     r0,  d0[0]
414    bx          lr
415endfunc
416
417function pixel_asd8_neon
418    ldr         r12, [sp,  #0]
419    sub         r12,  r12, #2
420    vld1.8     {d0}, [r0], r1
421    vld1.8     {d1}, [r2], r3
422    vld1.8     {d2}, [r0], r1
423    vld1.8     {d3}, [r2], r3
424    vsubl.u8    q8,   d0,  d1
4251:
426    subs        r12,  r12,  #2
427    vld1.8     {d4}, [r0], r1
428    vld1.8     {d5}, [r2], r3
429    vsubl.u8    q9,   d2,  d3
430    vsubl.u8    q10,  d4,  d5
431    vadd.s16    q8,   q9
432    vld1.8     {d2}, [r0], r1
433    vld1.8     {d3}, [r2], r3
434    vadd.s16    q8,   q10
435    bgt         1b
436    vsubl.u8    q9,   d2,  d3
437    vadd.s16    q8,   q9
438    vpaddl.s16  q8,   q8
439    vpadd.s32   d16,  d16, d17
440    vpadd.s32   d16,  d16, d17
441    vabs.s32    d16,  d16
442    vmov.32     r0,   d16[0]
443    bx          lr
444endfunc
445
446
447.macro SSD_START_4
448    vld1.32     {d16[]}, [r0,:32], r1
449    vld1.32     {d17[]}, [r2,:32], r3
450    vsubl.u8    q2, d16, d17
451    vld1.32     {d16[]}, [r0,:32], r1
452    vmull.s16   q0, d4, d4
453    vld1.32     {d17[]}, [r2,:32], r3
454.endm
455
456.macro SSD_4
457    vsubl.u8    q2, d16, d17
458    vld1.32     {d16[]}, [r0,:32], r1
459    vmlal.s16   q0, d4, d4
460    vld1.32     {d17[]}, [r2,:32], r3
461.endm
462
463.macro SSD_END_4
464    vsubl.u8    q2, d16, d17
465    vmlal.s16   q0, d4, d4
466.endm
467
468.macro SSD_START_8
469    vld1.64     {d16}, [r0,:64], r1
470    vld1.64     {d17}, [r2,:64], r3
471    vsubl.u8    q2, d16, d17
472    vld1.64     {d16}, [r0,:64], r1
473    vmull.s16   q0, d4, d4
474    vmlal.s16   q0, d5, d5
475    vld1.64     {d17}, [r2,:64], r3
476.endm
477
478.macro SSD_8
479    vsubl.u8    q2, d16, d17
480    vld1.64     {d16}, [r0,:64], r1
481    vmlal.s16   q0, d4, d4
482    vmlal.s16   q0, d5, d5
483    vld1.64     {d17}, [r2,:64], r3
484.endm
485
486.macro SSD_END_8
487    vsubl.u8    q2, d16, d17
488    vmlal.s16   q0, d4, d4
489    vmlal.s16   q0, d5, d5
490.endm
491
492.macro SSD_START_16
493    vld1.64     {d16-d17}, [r0,:128], r1
494    vld1.64     {d18-d19}, [r2,:128], r3
495    vsubl.u8    q2, d16, d18
496    vsubl.u8    q3, d17, d19
497    vld1.64     {d16-d17}, [r0,:128], r1
498    vmull.s16   q0, d4, d4
499    vmlal.s16   q0, d5, d5
500    vld1.64     {d18-d19}, [r2,:128], r3
501    vmlal.s16   q0, d6, d6
502    vmlal.s16   q0, d7, d7
503.endm
504
505.macro SSD_16
506    vsubl.u8    q2, d16, d18
507    vsubl.u8    q3, d17, d19
508    vld1.64     {d16-d17}, [r0,:128], r1
509    vmlal.s16   q0, d4, d4
510    vmlal.s16   q0, d5, d5
511    vld1.64     {d18-d19}, [r2,:128], r3
512    vmlal.s16   q0, d6, d6
513    vmlal.s16   q0, d7, d7
514.endm
515
516.macro SSD_END_16
517    vsubl.u8    q2, d16, d18
518    vsubl.u8    q3, d17, d19
519    vmlal.s16   q0, d4, d4
520    vmlal.s16   q0, d5, d5
521    vmlal.s16   q0, d6, d6
522    vmlal.s16   q0, d7, d7
523.endm
524
525.macro SSD_FUNC w h
526function pixel_ssd_\w\()x\h\()_neon
527    SSD_START_\w
528.rept \h-2
529    SSD_\w
530.endr
531    SSD_END_\w
532    vadd.s32    d0, d0, d1
533    vpadd.s32   d0, d0, d0
534    vmov.32     r0, d0[0]
535    bx          lr
536endfunc
537.endm
538
539SSD_FUNC   4, 4
540SSD_FUNC   4, 8
541SSD_FUNC   8, 4
542SSD_FUNC   8, 8
543SSD_FUNC   8, 16
544SSD_FUNC  16, 8
545SSD_FUNC  16, 16
546
547function pixel_ssd_nv12_core_neon
548    push       {r4-r5}
549    ldrd        r4,  r5,  [sp, #8]
550    add         r12, r4,  #8
551    bic         r12, r12, #15
552    vmov.u64    q8,  #0
553    vmov.u64    q9,  #0
554    sub         r1,  r1,  r12, lsl #1
555    sub         r3,  r3,  r12, lsl #1
5561:
557    subs        r12, r4,  #16
558    vld2.8     {d0,d1},   [r0]!
559    vld2.8     {d2,d3},   [r2]!
560    vld2.8     {d4,d5},   [r0]!
561    vld2.8     {d6,d7},   [r2]!
562
563    vsubl.u8    q10, d0,  d2
564    vsubl.u8    q11, d1,  d3
565    vmull.s16   q14, d20, d20
566    vmull.s16   q15, d22, d22
567    vsubl.u8    q12, d4,  d6
568    vsubl.u8    q13, d5,  d7
569    vmlal.s16   q14, d21, d21
570    vmlal.s16   q15, d23, d23
571
572    blt         4f
573    beq         3f
5742:
575    vmlal.s16   q14, d24, d24
576    vmlal.s16   q15, d26, d26
577    vld2.8     {d0,d1},   [r0]!
578    vld2.8     {d2,d3},   [r2]!
579    vmlal.s16   q14, d25, d25
580    vmlal.s16   q15, d27, d27
581
582    subs        r12, r12, #16
583    vsubl.u8    q10, d0,  d2
584    vsubl.u8    q11, d1,  d3
585    vmlal.s16   q14, d20, d20
586    vmlal.s16   q15, d22, d22
587    vld2.8     {d4,d5},   [r0]!
588    vld2.8     {d6,d7},   [r2]!
589    vmlal.s16   q14, d21, d21
590    vmlal.s16   q15, d23, d23
591    blt         4f
592
593    vsubl.u8    q12, d4,  d6
594    vsubl.u8    q13, d5,  d7
595    bgt         2b
5963:
597    vmlal.s16   q14, d24, d24
598    vmlal.s16   q15, d26, d26
599    vmlal.s16   q14, d25, d25
600    vmlal.s16   q15, d27, d27
6014:
602    subs        r5,  r5,  #1
603    vaddw.s32   q8,  q8,  d28
604    vaddw.s32   q9,  q9,  d30
605    add         r0,  r0,  r1
606    add         r2,  r2,  r3
607    vaddw.s32   q8,  q8,  d29
608    vaddw.s32   q9,  q9,  d31
609    bgt         1b
610
611    vadd.u64    d16, d16, d17
612    vadd.u64    d18, d18, d19
613    ldrd        r4,  r5, [sp, #16]
614    vst1.64    {d16}, [r4]
615    vst1.64    {d18}, [r5]
616
617    pop        {r4-r5}
618    bx          lr
619endfunc
620
621.macro VAR_SQR_SUM qsqr_sum qsqr_last qsqr dsrc vpadal=vpadal.u16
622    vmull.u8        \qsqr, \dsrc, \dsrc
623    vaddw.u8        q0, q0, \dsrc
624    \vpadal         \qsqr_sum, \qsqr_last
625.endm
626
627function pixel_var_8x8_neon
628    vld1.64         {d16}, [r0,:64], r1
629    vmull.u8        q1,  d16, d16
630    vmovl.u8        q0,  d16
631    vld1.64         {d18}, [r0,:64], r1
632    vmull.u8        q2,  d18, d18
633    vaddw.u8        q0,  q0,  d18
634
635    vld1.64         {d20}, [r0,:64], r1
636    VAR_SQR_SUM     q1,  q1,   q3,  d20, vpaddl.u16
637    vld1.64         {d22}, [r0,:64], r1
638    VAR_SQR_SUM     q2,  q2,   q8,  d22, vpaddl.u16
639
640    vld1.64         {d24}, [r0,:64], r1
641    VAR_SQR_SUM     q1,  q3,   q9,  d24
642    vld1.64         {d26}, [r0,:64], r1
643    VAR_SQR_SUM     q2,  q8,   q10, d26
644    vld1.64         {d24}, [r0,:64], r1
645    VAR_SQR_SUM     q1,  q9,   q14, d24
646    vld1.64         {d26}, [r0,:64], r1
647    VAR_SQR_SUM     q2,  q10,  q15, d26
648    b               var_end
649endfunc
650
651function pixel_var_8x16_neon
652    vld1.64         {d16}, [r0,:64], r1
653    vld1.64         {d18}, [r0,:64], r1
654    vmull.u8        q1,  d16, d16
655    vmovl.u8        q0,  d16
656    vld1.64         {d20}, [r0,:64], r1
657    vmull.u8        q2,  d18, d18
658    vaddw.u8        q0,  q0,  d18
659
660    mov             ip,  #12
661
662    vld1.64         {d22}, [r0,:64], r1
663    VAR_SQR_SUM     q1,  q1,   q14,  d20, vpaddl.u16
664    vld1.64         {d16}, [r0,:64], r1
665    VAR_SQR_SUM     q2,  q2,   q15,  d22, vpaddl.u16
666
6671:  subs            ip,  ip,  #4
668    vld1.64         {d18}, [r0,:64], r1
669    VAR_SQR_SUM     q1,  q14,  q12, d16
670    vld1.64         {d20}, [r0,:64], r1
671    VAR_SQR_SUM     q2,  q15,  q13, d18
672    vld1.64         {d22}, [r0,:64], r1
673    VAR_SQR_SUM     q1,  q12,  q14, d20
674    beq             2f
675    vld1.64         {d16}, [r0,:64], r1
676    VAR_SQR_SUM     q2,  q13,  q15, d22
677    b               1b
6782:
679    VAR_SQR_SUM     q2,  q13,  q15, d22
680    b               var_end
681endfunc
682
683function pixel_var_16x16_neon
684    vld1.64         {d16-d17}, [r0,:128], r1
685    vmull.u8        q12, d16, d16
686    vmovl.u8        q0,  d16
687    vmull.u8        q13, d17, d17
688    vaddw.u8        q0,  q0,  d17
689
690    vld1.64         {d18-d19}, [r0,:128], r1
691    VAR_SQR_SUM     q1,  q12,  q14, d18, vpaddl.u16
692    VAR_SQR_SUM     q2,  q13,  q15, d19, vpaddl.u16
693
694    mov             ip,  #7
695var16_loop:
696    subs            ip,  ip,  #1
697    vld1.64         {d16-d17}, [r0,:128], r1
698    VAR_SQR_SUM     q1,  q14,  q12, d16
699    VAR_SQR_SUM     q2,  q15,  q13, d17
700
701    vld1.64         {d18-d19}, [r0,:128], r1
702    VAR_SQR_SUM     q1,  q12,  q14, d18
703    VAR_SQR_SUM     q2,  q13,  q15, d19
704    bgt             var16_loop
705endfunc
706
707function var_end, export=0
708    vpaddl.u16      q8,  q14
709    vpaddl.u16      q9,  q15
710    vadd.u32        q1,  q1,  q8
711    vadd.u16        d0,  d0,  d1
712    vadd.u32        q1,  q1,  q9
713    vadd.u32        q1,  q1,  q2
714    vpaddl.u16      d0,  d0
715    vadd.u32        d2,  d2,  d3
716    vpadd.u32       d0,  d0,  d2
717
718    vmov            r0,  r1,  d0
719    bx              lr
720endfunc
721
722.macro DIFF_SUM diff1 diff2 da1 db1 da2 db2 lastdiff1 lastdiff2 acc1 acc2
723    vld1.64         {\da1}, [r0,:64]!
724    vld1.64         {\db1}, [r1,:64], r3
725.ifnb \lastdiff1
726    vadd.s16        \acc1, \acc1, \lastdiff1
727    vadd.s16        \acc2, \acc2, \lastdiff2
728.endif
729    vld1.64         {\da2}, [r0,:64]!
730    vld1.64         {\db2}, [r1,:64], r3
731    vsubl.u8        \diff1, \da1, \db1
732    vsubl.u8        \diff2, \da2, \db2
733.endm
734
735.macro SQR_ACC_DOUBLE acc1 acc2 d0 d1 d2 d3 vmlal=vmlal.s16
736    \vmlal          \acc1, \d0, \d0
737    vmlal.s16       \acc1, \d1, \d1
738    \vmlal          \acc2, \d2, \d2
739    vmlal.s16       \acc2, \d3, \d3
740.endm
741
742.macro SQR_ACC acc d0 d1 vmlal=vmlal.s16
743    \vmlal          \acc, \d0, \d0
744    vmlal.s16       \acc, \d1, \d1
745.endm
746
747function pixel_var2_8x8_neon
748    mov             r3,  #16
749    DIFF_SUM        q0,  q10, d0,  d1,  d20, d21
750    DIFF_SUM        q8,  q11, d16, d17, d22, d23
751    SQR_ACC_DOUBLE  q1,  q13, d0,  d1,  d20, d21, vmull.s16
752    DIFF_SUM        q9,  q12, d18, d19, d24, d25, q8,  q11, q0,  q10
753    SQR_ACC_DOUBLE  q2,  q14, d16, d17, d22, d23, vmull.s16
754.rept 2
755    DIFF_SUM        q8,  q11, d16, d17, d22, d23, q9,  q12, q0,  q10
756    SQR_ACC_DOUBLE  q1,  q13, d18, d19, d24, d25
757    DIFF_SUM        q9,  q12, d18, d19, d24, d25, q8,  q11, q0,  q10
758    SQR_ACC_DOUBLE  q2,  q14, d16, d17, d22, d23
759.endr
760    DIFF_SUM        q8,  q11, d16, d17, d22, d23, q9,  q12, q0,  q10
761    SQR_ACC_DOUBLE  q1,  q13, d18, d19, d24, d25
762    vadd.s16        q0,  q0,  q8
763    vadd.s16        q10, q10, q11
764    SQR_ACC_DOUBLE  q2,  q14, d16, d17, d22, d23
765
766    vadd.s16        d0,  d0,  d1
767    vadd.s16        d20, d20, d21
768    vadd.s32        q1,  q1,  q2
769    vadd.s32        q13, q13, q14
770    vpaddl.s16      d0,  d0
771    vpaddl.s16      d20, d20
772    vadd.s32        d1,  d2,  d3
773    vadd.s32        d26, d26, d27
774    vpadd.s32       d0,  d0,  d20 @ sum
775    vpadd.s32       d1,  d1,  d26 @ sqr
776    vmul.s32        d0,  d0,  d0  @ sum*sum
777    vshr.s32        d0,  d0,  #6
778    vsub.s32        d0,  d1,  d0
779    vpadd.s32       d0,  d0,  d0
780
781    vmov            r0,  r1,  d0
782    vst1.32         {d1}, [r2,:64]
783    bx              lr
784endfunc
785
786function pixel_var2_8x16_neon
787    mov             r3,  #16
788    vld1.64         {d16}, [r0,:64]!
789    vld1.64         {d17}, [r1,:64], r3
790    vld1.64         {d18}, [r0,:64]!
791    vld1.64         {d19}, [r1,:64], r3
792    vsubl.u8        q0,  d16, d17
793    vsubl.u8        q3,  d18, d19
794    SQR_ACC         q1,  d0,  d1,   vmull.s16
795    vld1.64         {d16}, [r0,:64]!
796    mov             ip,  #15
797    vld1.64         {d17}, [r1,:64], r3
798    SQR_ACC         q2,  d6,  d7,   vmull.s16
7991:  subs            ip,  ip,  #1
800    vld1.64         {d18}, [r0,:64]!
801    vsubl.u8        q10, d16, d17
802    vld1.64         {d19}, [r1,:64], r3
803    vadd.s16        q0,  q0,  q10
804    SQR_ACC         q1,  d20, d21
805    vsubl.u8        q11, d18, d19
806    beq             2f
807    vld1.64         {d16}, [r0,:64]!
808    vadd.s16        q3,  q3,  q11
809    vld1.64         {d17}, [r1,:64], r3
810    SQR_ACC         q2,  d22, d23
811    b               1b
8122:
813    vadd.s16        q3,  q3,  q11
814    SQR_ACC         q2,  d22, d23
815
816    vadd.s16        d0,  d0,  d1
817    vadd.s16        d6,  d6,  d7
818    vpaddl.s16      d0,  d0
819    vpaddl.s16      d6,  d6
820    vadd.s32        d2,  d2,  d3
821    vadd.s32        d4,  d4,  d5
822    vpadd.s32       d0,  d0,  d6 @ sum
823    vpadd.s32       d2,  d2,  d4 @ sqr
824    vmul.s32        d0,  d0,  d0 @ sum*sum
825    vshr.s32        d0,  d0,  #7
826    vsub.s32        d0,  d2,  d0
827    vpadd.s32       d0,  d0,  d0
828
829    vmov            r0,  r1,  d0
830    vst1.32         {d2}, [r2,:64]
831    bx              lr
832endfunc
833
834.macro LOAD_DIFF_8x4 q0 q1 q2 q3
835    vld1.32     {d1}, [r2], r3
836    vld1.32     {d0}, [r0,:64], r1
837    vsubl.u8    \q0, d0,  d1
838    vld1.32     {d3}, [r2], r3
839    vld1.32     {d2}, [r0,:64], r1
840    vsubl.u8    \q1, d2,  d3
841    vld1.32     {d5}, [r2], r3
842    vld1.32     {d4}, [r0,:64], r1
843    vsubl.u8    \q2, d4,  d5
844    vld1.32     {d7}, [r2], r3
845    vld1.32     {d6}, [r0,:64], r1
846    vsubl.u8    \q3, d6,  d7
847.endm
848
849function pixel_satd_4x4_neon
850    vld1.32     {d1[]},  [r2], r3
851    vld1.32     {d0[]},  [r0,:32], r1
852    vld1.32     {d3[]},  [r2], r3
853    vld1.32     {d2[]},  [r0,:32], r1
854    vld1.32     {d1[1]}, [r2], r3
855    vld1.32     {d0[1]}, [r0,:32], r1
856    vld1.32     {d3[1]}, [r2], r3
857    vld1.32     {d2[1]}, [r0,:32], r1
858    vsubl.u8    q0,  d0,  d1
859    vsubl.u8    q1,  d2,  d3
860
861    SUMSUB_AB   q2, q3, q0, q1
862    SUMSUB_ABCD d0, d2, d1, d3, d4, d5, d6, d7
863    HADAMARD    1, sumsub, q2, q3, q0, q1
864    HADAMARD    2, amax,   q0,,    q2, q3
865
866    HORIZ_ADD   d0,  d0,  d1
867    vmov.32     r0,  d0[0]
868    bx          lr
869endfunc
870
871function pixel_satd_4x8_neon
872    vld1.32     {d1[]},  [r2], r3
873    vld1.32     {d0[]},  [r0,:32], r1
874    vld1.32     {d3[]},  [r2], r3
875    vld1.32     {d2[]},  [r0,:32], r1
876    vld1.32     {d5[]},  [r2], r3
877    vld1.32     {d4[]},  [r0,:32], r1
878    vld1.32     {d7[]},  [r2], r3
879    vld1.32     {d6[]},  [r0,:32], r1
880
881    vld1.32     {d1[1]}, [r2], r3
882    vld1.32     {d0[1]}, [r0,:32], r1
883    vsubl.u8    q0,  d0,  d1
884    vld1.32     {d3[1]}, [r2], r3
885    vld1.32     {d2[1]}, [r0,:32], r1
886    vsubl.u8    q1,  d2,  d3
887    vld1.32     {d5[1]}, [r2], r3
888    vld1.32     {d4[1]}, [r0,:32], r1
889    vsubl.u8    q2,  d4,  d5
890    vld1.32     {d7[1]}, [r2], r3
891    SUMSUB_AB   q8,  q9,  q0,  q1
892    vld1.32     {d6[1]}, [r0,:32], r1
893    vsubl.u8    q3,  d6,  d7
894    SUMSUB_AB   q10, q11, q2,  q3
895    b           satd_4x8_8x4_end_neon
896endfunc
897
898function pixel_satd_8x4_neon
899    vld1.64     {d1}, [r2], r3
900    vld1.64     {d0}, [r0,:64], r1
901    vsubl.u8    q0,  d0,  d1
902    vld1.64     {d3}, [r2], r3
903    vld1.64     {d2}, [r0,:64], r1
904    vsubl.u8    q1,  d2,  d3
905    vld1.64     {d5}, [r2], r3
906    vld1.64     {d4}, [r0,:64], r1
907    vsubl.u8    q2,  d4,  d5
908    vld1.64     {d7}, [r2], r3
909    SUMSUB_AB   q8,  q9,  q0,  q1
910    vld1.64     {d6}, [r0,:64], r1
911    vsubl.u8    q3,  d6,  d7
912    SUMSUB_AB   q10, q11, q2,  q3
913endfunc
914
915function satd_4x8_8x4_end_neon, export=0
916    vadd.s16    q0,  q8,  q10
917    vadd.s16    q1,  q9,  q11
918    vsub.s16    q2,  q8,  q10
919    vsub.s16    q3,  q9,  q11
920
921    vtrn.16     q0,  q1
922    vadd.s16    q8,  q0,  q1
923    vtrn.16     q2,  q3
924    vsub.s16    q9,  q0,  q1
925    vadd.s16    q10, q2,  q3
926    vsub.s16    q11, q2,  q3
927    vtrn.32     q8,  q10
928    vabs.s16    q8,  q8
929    vtrn.32     q9,  q11
930    vabs.s16    q10, q10
931    vabs.s16    q9,  q9
932    vabs.s16    q11, q11
933    vmax.u16    q0,  q8,  q10
934    vmax.u16    q1,  q9,  q11
935
936    vadd.u16    q0,  q0,  q1
937    HORIZ_ADD   d0,  d0,  d1
938    vmov.32     r0,  d0[0]
939    bx          lr
940endfunc
941
942function pixel_satd_8x8_neon
943    mov         ip,  lr
944
945    bl satd_8x8_neon
946    vadd.u16    q0,  q12, q13
947    vadd.u16    q1,  q14, q15
948
949    vadd.u16    q0,  q0,  q1
950    HORIZ_ADD   d0,  d0,  d1
951    mov         lr,  ip
952    vmov.32     r0,  d0[0]
953    bx          lr
954endfunc
955
956function pixel_satd_8x16_neon
957    vpush       {d8-d11}
958    mov         ip,  lr
959
960    bl satd_8x8_neon
961    vadd.u16    q4,  q12, q13
962    vadd.u16    q5,  q14, q15
963
964    bl satd_8x8_neon
965    vadd.u16    q4,  q4,  q12
966    vadd.u16    q5,  q5,  q13
967    vadd.u16    q4,  q4,  q14
968    vadd.u16    q5,  q5,  q15
969
970    vadd.u16    q0,  q4,  q5
971    HORIZ_ADD   d0,  d0,  d1
972    vpop        {d8-d11}
973    mov         lr,  ip
974    vmov.32     r0,  d0[0]
975    bx          lr
976endfunc
977
978function satd_8x8_neon, export=0
979    LOAD_DIFF_8x4 q8,  q9,  q10, q11
980    vld1.64     {d7}, [r2], r3
981    SUMSUB_AB   q0,  q1,  q8,  q9
982    vld1.64     {d6}, [r0,:64], r1
983    vsubl.u8    q12, d6,  d7
984    vld1.64     {d17}, [r2], r3
985    SUMSUB_AB   q2,  q3,  q10, q11
986    vld1.64     {d16}, [r0,:64], r1
987    vsubl.u8    q13, d16, d17
988    vld1.64     {d19}, [r2], r3
989    SUMSUB_AB   q8,  q10, q0,  q2
990    vld1.64     {d18}, [r0,:64], r1
991    vsubl.u8    q14, d18, d19
992    vld1.64     {d1}, [r2], r3
993    SUMSUB_AB   q9,  q11, q1,  q3
994    vld1.64     {d0}, [r0,:64], r1
995    vsubl.u8    q15, d0,  d1
996endfunc
997
998// one vertical hadamard pass and two horizontal
999function satd_8x4v_8x8h_neon, export=0
1000    SUMSUB_ABCD q0, q1, q2, q3, q12, q13, q14, q15
1001    vtrn.16     q8,  q9
1002    SUMSUB_AB   q12, q14, q0,  q2
1003    vtrn.16     q10, q11
1004    SUMSUB_AB   q13, q15, q1,  q3
1005    SUMSUB_AB   q0,  q1,  q8,  q9
1006    vtrn.16     q12, q13
1007    SUMSUB_AB   q2,  q3,  q10, q11
1008    vtrn.16     q14, q15
1009    SUMSUB_AB   q8,  q9,  q12, q13
1010    vtrn.32     q0,  q2
1011    SUMSUB_AB   q10, q11, q14, q15
1012
1013    vtrn.32     q1,  q3
1014    ABS2        q0,  q2
1015    vtrn.32     q8,  q10
1016    ABS2        q1,  q3
1017    vtrn.32     q9,  q11
1018    ABS2        q8,  q10
1019    ABS2        q9,  q11
1020    vmax.s16    q12, q0,  q2
1021    vmax.s16    q13, q1,  q3
1022    vmax.s16    q14, q8,  q10
1023    vmax.s16    q15, q9,  q11
1024    bx          lr
1025endfunc
1026
1027function pixel_satd_16x8_neon
1028    vpush       {d8-d11}
1029    mov         ip, lr
1030
1031    bl          satd_16x4_neon
1032    vadd.u16    q4,  q12, q13
1033    vadd.u16    q5,  q14, q15
1034
1035    bl          satd_16x4_neon
1036    vadd.u16    q4,  q4,  q12
1037    vadd.u16    q5,  q5,  q13
1038    vadd.u16    q4,  q4,  q14
1039    vadd.u16    q5,  q5,  q15
1040
1041    vadd.u16    q0,  q4,  q5
1042    HORIZ_ADD   d0,  d0,  d1
1043    vpop        {d8-d11}
1044    mov         lr,  ip
1045    vmov.32     r0,  d0[0]
1046    bx          lr
1047endfunc
1048
1049function pixel_satd_16x16_neon
1050    vpush       {d8-d11}
1051    mov         ip, lr
1052
1053    bl          satd_16x4_neon
1054    vadd.u16    q4,  q12, q13
1055    vadd.u16    q5,  q14, q15
1056
1057    bl          satd_16x4_neon
1058    vadd.u16    q4,  q4,  q12
1059    vadd.u16    q5,  q5,  q13
1060    vadd.u16    q4,  q4,  q14
1061    vadd.u16    q5,  q5,  q15
1062
1063    bl          satd_16x4_neon
1064    vadd.u16    q4,  q4,  q12
1065    vadd.u16    q5,  q5,  q13
1066    vadd.u16    q4,  q4,  q14
1067    vadd.u16    q5,  q5,  q15
1068
1069    bl          satd_16x4_neon
1070    vadd.u16    q4,  q4,  q12
1071    vadd.u16    q5,  q5,  q13
1072    vadd.u16    q4,  q4,  q14
1073    vadd.u16    q5,  q5,  q15
1074
1075    vadd.u16    q0,  q4,  q5
1076    HORIZ_ADD   d0,  d0,  d1
1077    vpop        {d8-d11}
1078    mov         lr,  ip
1079    vmov.32     r0,  d0[0]
1080    bx          lr
1081endfunc
1082
1083function satd_16x4_neon, export=0
1084    vld1.64     {d2-d3}, [r2], r3
1085    vld1.64     {d0-d1}, [r0,:128], r1
1086    vsubl.u8    q8,  d0,  d2
1087    vld1.64     {d6-d7}, [r2], r3
1088    vsubl.u8    q12, d1,  d3
1089    vld1.64     {d4-d5}, [r0,:128], r1
1090    vsubl.u8    q9,  d4,  d6
1091    vld1.64     {d2-d3}, [r2], r3
1092    vsubl.u8    q13, d5,  d7
1093    vld1.64     {d0-d1}, [r0,:128], r1
1094    vsubl.u8    q10, d0,  d2
1095    vld1.64     {d6-d7}, [r2], r3
1096    vsubl.u8    q14, d1,  d3
1097    vadd.s16    q0,  q8,  q9
1098    vld1.64     {d4-d5}, [r0,:128], r1
1099    vsub.s16    q1,  q8,  q9
1100    vsubl.u8    q11, d4,  d6
1101    vsubl.u8    q15, d5,  d7
1102    SUMSUB_AB   q2,  q3,  q10, q11
1103    SUMSUB_ABCD q8,  q10, q9,  q11, q0,  q2,  q1,  q3
1104    b           satd_8x4v_8x8h_neon
1105endfunc
1106
1107
1108function pixel_sa8d_8x8_neon
1109    mov             ip,  lr
1110    bl              sa8d_8x8_neon
1111    vadd.u16        q0,  q8,  q9
1112    HORIZ_ADD       d0,  d0,  d1
1113    mov             lr,  ip
1114    vmov.32         r0,  d0[0]
1115    add             r0,  r0,  #1
1116    lsr             r0,  r0,  #1
1117    bx              lr
1118endfunc
1119
1120function pixel_sa8d_16x16_neon
1121    vpush           {d8-d11}
1122    mov             ip,  lr
1123    bl              sa8d_8x8_neon
1124    vpaddl.u16      q4,  q8
1125    vpaddl.u16      q5,  q9
1126    bl              sa8d_8x8_neon
1127    vpadal.u16      q4,  q8
1128    vpadal.u16      q5,  q9
1129    sub             r0,  r0,  r1,  lsl #4
1130    sub             r2,  r2,  r3,  lsl #4
1131    add             r0,  r0,  #8
1132    add             r2,  r2,  #8
1133    bl              sa8d_8x8_neon
1134    vpadal.u16      q4,  q8
1135    vpadal.u16      q5,  q9
1136    bl              sa8d_8x8_neon
1137    vpaddl.u16      q8,  q8
1138    vpaddl.u16      q9,  q9
1139    vadd.u32        q0,  q4,  q8
1140    vadd.u32        q1,  q5,  q9
1141    vadd.u32        q0,  q0,  q1
1142    vadd.u32        d0,  d0,  d1
1143    vpadd.u32       d0,  d0,  d0
1144    vpop            {d8-d11}
1145    mov             lr,  ip
1146    vmov.32         r0,  d0[0]
1147    add             r0,  r0,  #1
1148    lsr             r0,  r0,  #1
1149    bx              lr
1150endfunc
1151
1152.macro HADAMARD4_V r1, r2, r3, r4, t1, t2, t3, t4
1153    SUMSUB_ABCD \t1, \t2, \t3, \t4, \r1, \r2, \r3, \r4
1154    SUMSUB_ABCD \r1, \r3, \r2, \r4, \t1, \t3, \t2, \t4
1155.endm
1156
1157.macro integrated_satd dst, s0, s1, s2, s3
1158    vmov            q0,  \s0
1159    vmov            q1,  \s1
1160    vmov            q2,  \s2
1161    vmov            q3,  \s3
1162
1163    vtrn.16         q0,  q1
1164    vtrn.16         q2,  q3
1165
1166    SUMSUB_AB       q6,  q7,  q0,  q1
1167    SUMSUB_AB       q0,  q1,  q2,  q3
1168
1169    vtrn.32         q6,  q0
1170    vtrn.32         q7,  q1
1171
1172    vabs.s16        q6,  q6
1173    vabs.s16        q0,  q0
1174    vabs.s16        q7,  q7
1175    vabs.s16        q1,  q1
1176
1177    vmax.u16        q6,  q6,  q0
1178    vmax.u16        q7,  q7,  q1
1179
1180    vadd.i16        q6,  q6,  q7
1181    vpadal.u16      \dst,  q6
1182.endm
1183
1184.macro sa8d_satd_8x8 satd=
1185function sa8d_\satd\()8x8_neon, export=0
1186    LOAD_DIFF_8x4   q8,  q9,  q10, q11
1187    vld1.64         {d7}, [r2], r3
1188    SUMSUB_AB       q0,  q1,  q8,  q9
1189    vld1.64         {d6}, [r0,:64], r1
1190    vsubl.u8        q12, d6,  d7
1191    vld1.64         {d17}, [r2], r3
1192    SUMSUB_AB       q2,  q3,  q10, q11
1193    vld1.64         {d16}, [r0,:64], r1
1194    vsubl.u8        q13, d16, d17
1195    vld1.64         {d19}, [r2], r3
1196    SUMSUB_AB       q8,  q10, q0,  q2
1197    vld1.64         {d18}, [r0,:64], r1
1198    vsubl.u8        q14, d18, d19
1199    vld1.64         {d1}, [r2], r3
1200    SUMSUB_AB       q9,  q11, q1,  q3
1201    vld1.64         {d0}, [r0,:64], r1
1202    vsubl.u8        q15, d0,  d1
1203
1204    HADAMARD4_V     q12, q13, q14, q15,  q0,  q1,  q2,  q3
1205
1206.ifc \satd, satd_
1207    integrated_satd q4,  q8,  q9,  q10, q11
1208    integrated_satd q4,  q12, q13, q14, q15
1209.endif
1210
1211    SUMSUB_ABCD     q0,  q8,  q1,  q9,   q8,  q12, q9,  q13
1212    SUMSUB_AB       q2,  q10, q10, q14
1213    vtrn.16         q8,  q9
1214    SUMSUB_AB       q3,  q11, q11, q15
1215    vtrn.16         q0,  q1
1216    SUMSUB_AB       q12, q13, q8,  q9
1217    vtrn.16         q10, q11
1218    SUMSUB_AB       q8,  q9,  q0,  q1
1219    vtrn.16         q2,  q3
1220    SUMSUB_AB       q14, q15, q10, q11
1221    vadd.i16        q10, q2,  q3
1222    vtrn.32         q12, q14
1223    vsub.i16        q11, q2,  q3
1224    vtrn.32         q13, q15
1225    SUMSUB_AB       q0,  q2,  q12, q14
1226    vtrn.32         q8,  q10
1227    SUMSUB_AB       q1,  q3,  q13, q15
1228    vtrn.32         q9,  q11
1229    SUMSUB_AB       q12, q14, q8,  q10
1230    SUMSUB_AB       q13, q15, q9,  q11
1231
1232    vswp            d1,  d24
1233    ABS2            q0,  q12
1234    vswp            d3,  d26
1235    ABS2            q1,  q13
1236    vswp            d5,  d28
1237    ABS2            q2,  q14
1238    vswp            d7,  d30
1239    ABS2            q3,  q15
1240    vmax.s16        q8,  q0,  q12
1241    vmax.s16        q9,  q1,  q13
1242    vmax.s16        q10, q2,  q14
1243    vmax.s16        q11, q3,  q15
1244    vadd.i16        q8,  q8,  q9
1245    vadd.i16        q9,  q10, q11
1246.ifc \satd, satd_
1247    vpadal.u16      q5,  q8
1248    vpadal.u16      q5,  q9
1249.endif
1250    bx              lr
1251endfunc
1252.endm
1253
1254sa8d_satd_8x8
1255sa8d_satd_8x8 satd_
1256
1257function pixel_sa8d_satd_16x16_neon
1258    push            {lr}
1259    vpush           {q4-q7}
1260    vmov.u32        q4,  #0
1261    vmov.u32        q5,  #0
1262    bl              sa8d_satd_8x8_neon
1263    bl              sa8d_satd_8x8_neon
1264    sub             r0,  r0,  r1,  lsl #4
1265    sub             r2,  r2,  r3,  lsl #4
1266    add             r0,  r0,  #8
1267    add             r2,  r2,  #8
1268    bl              sa8d_satd_8x8_neon
1269    bl              sa8d_satd_8x8_neon
1270    vadd.u32        d1,  d10, d11
1271    vadd.u32        d0,  d8,  d9
1272    vpadd.u32       d1,  d1,  d1
1273    vpadd.u32       d0,  d0,  d0
1274    vrshr.u32       d1,  d1,  #1
1275    vmov.32         r1,  d0[0]
1276    vmov.32         r0,  d1[0]
1277    vpop            {q4-q7}
1278    pop             {pc}
1279endfunc
1280
1281
1282.macro HADAMARD_AC w h
1283function pixel_hadamard_ac_\w\()x\h\()_neon
1284    vpush           {d8-d15}
1285    movrel          ip, mask_ac4
1286    vmov.i8         q4, #0
1287    // note: this assumes mask_ac8 is after mask_ac4 (so don't move it)
1288    vld1.64         {d12-d15}, [ip,:128]
1289    vmov.i8         q5, #0
1290
1291    mov             ip,  lr
1292    bl              hadamard_ac_8x8_neon
1293.if \h > 8
1294    bl              hadamard_ac_8x8_neon
1295.endif
1296.if \w > 8
1297    sub             r0,  r0,  r1,  lsl #3
1298    add             r0,  r0,  #8
1299    bl              hadamard_ac_8x8_neon
1300.endif
1301.if \w * \h == 256
1302    sub             r0,  r0,  r1,  lsl #4
1303    bl              hadamard_ac_8x8_neon
1304.endif
1305
1306    vadd.s32        d8,  d8,  d9
1307    vadd.s32        d10, d10, d11
1308    vpadd.s32       d0,  d8,  d10
1309    vpop            {d8-d15}
1310    mov             lr,  ip
1311    vmov            r0,  r1,  d0
1312    lsr             r0,  r0,  #1
1313    lsr             r1,  r1,  #2
1314    bx              lr
1315endfunc
1316.endm
1317
1318HADAMARD_AC  8, 8
1319HADAMARD_AC  8, 16
1320HADAMARD_AC 16, 8
1321HADAMARD_AC 16, 16
1322
1323// q4: satd  q5: sa8d  q6: mask_ac4  q7: mask_ac8
1324function hadamard_ac_8x8_neon, export=0
1325    vld1.64         {d2},  [r0,:64], r1
1326    vld1.64         {d3},  [r0,:64], r1
1327    vaddl.u8        q0,  d2,  d3
1328    vld1.64         {d6},  [r0,:64], r1
1329    vsubl.u8        q1,  d2,  d3
1330    vld1.64         {d7},  [r0,:64], r1
1331    vaddl.u8        q2,  d6,  d7
1332    vld1.64         {d18}, [r0,:64], r1
1333    vsubl.u8        q3,  d6,  d7
1334    vld1.64         {d19}, [r0,:64], r1
1335    vaddl.u8        q8,  d18, d19
1336    vld1.64         {d22}, [r0,:64], r1
1337    vsubl.u8        q9,  d18, d19
1338    vld1.64         {d23}, [r0,:64], r1
1339
1340    SUMSUB_ABCD     q12, q14, q13, q15, q0,  q2,  q1,  q3
1341    vaddl.u8        q10, d22, d23
1342    vsubl.u8        q11, d22, d23
1343    vtrn.16         q12, q13
1344    SUMSUB_ABCD     q0,  q2,  q1,  q3,  q8,  q10, q9,  q11
1345
1346    vtrn.16         q14, q15
1347    SUMSUB_AB       q8,  q9,  q12, q13
1348    vtrn.16         q0,  q1
1349    SUMSUB_AB       q10, q11, q14, q15
1350    vtrn.16         q2,  q3
1351    SUMSUB_AB       q12, q13, q0,  q1
1352    vtrn.32         q8,  q10
1353    SUMSUB_AB       q14, q15, q2,  q3
1354    vtrn.32         q9,  q11
1355    SUMSUB_AB       q0,  q2,  q8,  q10
1356    vtrn.32         q12, q14
1357    SUMSUB_AB       q1,  q3,  q9,  q11
1358    vtrn.32         q13, q15
1359    SUMSUB_ABCD     q8,  q10, q9,  q11, q12, q14, q13, q15
1360
1361    vabs.s16        q12, q0
1362    vabs.s16        q13, q8
1363    vabs.s16        q15, q1
1364    vadd.s16        q12, q12, q13
1365    vabs.s16        q14, q2
1366    vand.s16        q12, q12, q6
1367    vabs.s16        q13, q3
1368    vadd.s16        q12, q12, q15
1369    vabs.s16        q15, q9
1370    vadd.s16        q12, q12, q14
1371    vabs.s16        q14, q10
1372    vadd.s16        q12, q12, q13
1373    vabs.s16        q13, q11
1374    vadd.s16        q12, q12, q15
1375    vsub.s16        q15, q11, q3
1376    vadd.s16        q12, q12, q14
1377    vadd.s16        q14, q11, q3
1378    vadd.s16        q12, q12, q13
1379    vsub.s16        q13, q10, q2
1380    vadd.s16        q2,  q10, q2
1381    vpadal.u16      q4,  q12
1382
1383    SUMSUB_AB       q10, q11, q9,  q1
1384    SUMSUB_AB       q9,  q8,  q0,  q8
1385    vswp            d29, d30
1386    vabs.s16        q14, q14
1387    vabs.s16        q15, q15
1388    vswp            d5,  d26
1389    vabs.s16        q2,  q2
1390    vabs.s16        q13, q13
1391    vswp            d21, d22
1392    vabs.s16        q10, q10
1393    vabs.s16        q11, q11
1394    vmax.s16        q3,  q14, q15
1395    vmax.s16        q2,  q2,  q13
1396    vmax.s16        q1,  q10, q11
1397    vswp            d19, d16
1398    SUMSUB_AB       q14, q15, q9,  q8
1399
1400    vadd.s16        q2,  q2,  q3
1401    vadd.s16        q2,  q2,  q1
1402    vand            q14, q14, q7
1403    vadd.s16        q2,  q2,  q2
1404    vabs.s16        q15, q15
1405    vabs.s16        q14, q14
1406    vadd.s16        q2,  q2,  q15
1407    vadd.s16        q2,  q2,  q14
1408    vpadal.u16      q5,  q2
1409    bx              lr
1410endfunc
1411
1412
1413.macro SSIM_ITER n ssa s12 ssb lastssa lasts12 lastssb da db dnext
1414    vld1.64     {\db}, [r2], r3
1415    vmull.u8    \ssa,  \da, \da
1416    vmull.u8    \s12,  \da, \db
1417.if \n == 1
1418    vpaddl.u16  q2,  \lastssa
1419    vpaddl.u16  q3,  \lasts12
1420    vaddl.u8    q0,  d0,  \da
1421.else
1422    vpadal.u16  q2,  \lastssa
1423    vpadal.u16  q3,  \lasts12
1424    vaddw.u8    q0,  q0,  \da
1425.endif
1426    vpadal.u16  q2,  \lastssb
1427.if \n < 3
1428    vld1.64     {\dnext}, [r0], r1
1429.endif
1430.if \n == 1
1431    vaddl.u8    q1,  d2,  \db
1432.else
1433    vaddw.u8    q1,  q1,  \db
1434.endif
1435    vmull.u8    \ssb, \db, \db
1436.endm
1437
1438function pixel_ssim_4x4x2_core_neon
1439    ldr         ip, [sp]
1440    vld1.64     {d0}, [r0], r1
1441    vld1.64     {d2}, [r2], r3
1442    vmull.u8    q2,  d0,  d0
1443    vmull.u8    q3,  d0,  d2
1444    vld1.64     {d28}, [r0], r1
1445    vmull.u8    q15, d2,  d2
1446
1447    SSIM_ITER 1, q8, q9, q14,  q2, q3, q15,  d28, d29, d26
1448    SSIM_ITER 2, q10,q11,q13,  q8, q9, q14,  d26, d27, d28
1449    SSIM_ITER 3, q8, q9, q15,  q10,q11,q13,  d28, d29
1450
1451    vpadal.u16  q2,  q8
1452    vpaddl.u16  q0,  q0
1453    vpaddl.u16  q1,  q1
1454    vpadal.u16  q2,  q15
1455    vpadal.u16  q3,  q9
1456
1457    vpadd.u32   d0,  d0,  d1
1458    vpadd.u32   d1,  d2,  d3
1459    vpadd.u32   d2,  d4,  d5
1460    vpadd.u32   d3,  d6,  d7
1461
1462    vst4.32     {d0-d3}, [ip]
1463    bx          lr
1464endfunc
1465
1466// FIXME: see about doing 16x16 -> 32 bit multiplies for s1/s2
1467function pixel_ssim_end4_neon
1468    vld1.32     {d16-d19}, [r0,:128]!
1469    vld1.32     {d20-d23}, [r1,:128]!
1470    vadd.s32    q0,  q8,  q10
1471    vadd.s32    q1,  q9,  q11
1472    vld1.32     {d24-d27}, [r0,:128]!
1473    vadd.s32    q0,  q0,  q1
1474    vld1.32     {d28-d31}, [r1,:128]!
1475    vadd.s32    q2,  q12, q14
1476    vadd.s32    q3,  q13, q15
1477    vld1.32     {d16-d17}, [r0,:128]
1478    vadd.s32    q1,  q1,  q2
1479    vld1.32     {d18-d19}, [r1,:128]
1480    vadd.s32    q8,  q8,  q9
1481    vadd.s32    q2,  q2,  q3
1482    vadd.s32    q3,  q3,  q8
1483
1484    vtrn.32     q0,  q1
1485    vtrn.32     q2,  q3
1486    vswp        d1,  d4
1487    vswp        d3,  d6
1488
1489//  s1=q0, s2=q1, ss=q2, s12=q3
1490    vmul.s32    q8,  q0,  q1    // s1*s2
1491    vmul.s32    q0,  q0,  q0
1492    vmla.s32    q0,  q1,  q1    // s1*s1 + s2*s2
1493
1494    vshl.s32    q3,  q3,  #7
1495    vshl.s32    q2,  q2,  #6
1496    vadd.s32    q1,  q8,  q8
1497
1498    mov         r3, #416        // ssim_c1 = .01*.01*255*255*64
1499    movconst    ip, 235963      // ssim_c2 = .03*.03*255*255*64*63
1500    vdup.32     q14, r3
1501    vdup.32     q15, ip
1502
1503    vsub.s32    q2,  q2,  q0    // vars
1504    vsub.s32    q3,  q3,  q1    // covar*2
1505    vadd.s32    q0,  q0,  q14
1506    vadd.s32    q2,  q2,  q15
1507    vadd.s32    q1,  q1,  q14
1508    vadd.s32    q3,  q3,  q15
1509
1510    vcvt.f32.s32    q0,  q0
1511    vcvt.f32.s32    q2,  q2
1512    vcvt.f32.s32    q1,  q1
1513    vcvt.f32.s32    q3,  q3
1514
1515    vmul.f32    q0,  q0,  q2
1516    vmul.f32    q1,  q1,  q3
1517
1518    cmp         r2,  #4
1519
1520    vdiv.f32    s0,  s4,  s0
1521    vdiv.f32    s1,  s5,  s1
1522    vdiv.f32    s2,  s6,  s2
1523    vdiv.f32    s3,  s7,  s3
1524
1525    beq         ssim_skip
1526    movrel      r3,  mask_ff
1527    sub         r3,  r3,  r2,  lsl #2
1528    vld1.64     {d6-d7}, [r3]
1529    vand        q0,  q0,  q3
1530ssim_skip:
1531    vadd.f32    d0,  d0,  d1
1532    vpadd.f32   d0,  d0,  d0
1533    vmov.32     r0,  d0[0]
1534    bx          lr
1535endfunc
1536