/*
* Copyright © 2018, VideoLAN and dav1d authors
* Copyright © 2018, Janne Grunau
* Copyright © 2020, Martin Storsjo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "src/arm/asm.S"
#include "util.S"
#define PREP_BIAS 8192
.macro avg d0, d00, d01, d1, d10, d11
vld1.16 {q0, q1}, [r2, :128]!
vld1.16 {q2, q3}, [r3, :128]!
vqadd.s16 q0, q0, q2
vqadd.s16 q1, q1, q3
vmax.s16 q0, q0, q12 // -2*PREP_BIAS - 1 << intermediate_bits
vmax.s16 q1, q1, q12 // -2*PREP_BIAS - 1 << intermediate_bits
vqsub.s16 q0, q0, q12 // -2*PREP_BIAS - 1 << intermediate_bits
vqsub.s16 q1, q1, q12 // -2*PREP_BIAS - 1 << intermediate_bits
vshl.s16 \d0, q0, q13 // -(intermediate_bits+1)
vshl.s16 \d1, q1, q13 // -(intermediate_bits+1)
.endm
.macro w_avg d0, d00, d01, d1, d10, d11
vld1.16 {q0, q1}, [r2, :128]!
vld1.16 {q2, q3}, [r3, :128]!
// This difference requires a 17 bit range, and all bits are
// significant for the following multiplication.
vsubl.s16 \d0, d4, d0
vsubl.s16 q0, d5, d1
vsubl.s16 \d1, d6, d2
vsubl.s16 q1, d7, d3
vmul.s32 \d0, \d0, q4
vmul.s32 q0, q0, q4
vmul.s32 \d1, \d1, q4
vmul.s32 q1, q1, q4
vshr.s32 \d0, \d0, #4
vshr.s32 q0, q0, #4
vshr.s32 \d1, \d1, #4
vshr.s32 q1, q1, #4
vaddw.s16 \d0, \d0, d4
vaddw.s16 q0, q0, d5
vaddw.s16 \d1, \d1, d6
vaddw.s16 q1, q1, d7
vmovn.i32 \d00, \d0
vmovn.i32 \d01, q0
vmovn.i32 \d10, \d1
vmovn.i32 \d11, q1
vrshl.s16 \d0, \d0, q13 // -intermediate_bits
vrshl.s16 \d1, \d1, q13 // -intermediate_bits
vadd.s16 \d0, \d0, q12 // PREP_BIAS >> intermediate_bits
vadd.s16 \d1, \d1, q12 // PREP_BIAS >> intermediate_bits
vmin.s16 \d0, \d0, q15 // bitdepth_max
vmin.s16 \d1, \d1, q15 // bitdepth_max
vmax.s16 \d0, \d0, q14 // 0
vmax.s16 \d1, \d1, q14 // 0
.endm
.macro mask d0, d00, d01, d1, d10, d11
vld1.8 {q7}, [r6, :128]!
vld1.16 {q0, q1}, [r2, :128]!
vneg.s8 q7, q7
vld1.16 {q2, q3}, [r3, :128]!
vmovl.s8 q6, d14
vmovl.s8 q7, d15
vmovl.s16 q4, d12
vmovl.s16 q5, d13
vmovl.s16 q6, d14
vmovl.s16 q7, d15
vsubl.s16 \d0, d4, d0
vsubl.s16 q0, d5, d1
vsubl.s16 \d1, d6, d2
vsubl.s16 q1, d7, d3
vmul.s32 \d0, \d0, q4
vmul.s32 q0, q0, q5
vmul.s32 \d1, \d1, q6
vmul.s32 q1, q1, q7
vshr.s32 \d0, \d0, #6
vshr.s32 q0, q0, #6
vshr.s32 \d1, \d1, #6
vshr.s32 q1, q1, #6
vaddw.s16 \d0, \d0, d4
vaddw.s16 q0, q0, d5
vaddw.s16 \d1, \d1, d6
vaddw.s16 q1, q1, d7
vmovn.i32 \d00, \d0
vmovn.i32 \d01, q0
vmovn.i32 \d10, \d1
vmovn.i32 \d11, q1
vrshl.s16 \d0, \d0, q13 // -intermediate_bits
vrshl.s16 \d1, \d1, q13 // -intermediate_bits
vadd.s16 \d0, \d0, q12 // PREP_BIAS >> intermediate_bits
vadd.s16 \d1, \d1, q12 // PREP_BIAS >> intermediate_bits
vmin.s16 \d0, \d0, q15 // bitdepth_max
vmin.s16 \d1, \d1, q15 // bitdepth_max
vmax.s16 \d0, \d0, q14 // 0
vmax.s16 \d1, \d1, q14 // 0
.endm
.macro bidir_fn type, bdmax
function \type\()_16bpc_neon, export=1
push {r4-r7,lr}
ldrd r4, r5, [sp, #20]
ldr r6, [sp, #28]
clz r4, r4
.ifnc \type, avg
ldr r7, [sp, #32]
vmov.i16 q14, #0
vdup.16 q15, r7 // bitdepth_max
.endif
.ifc \type, w_avg
vpush {q4}
.endif
.ifc \type, mask
vpush {q4-q7}
.endif
clz r7, \bdmax
sub r7, r7, #18 // intermediate_bits = clz(bitdepth_max) - 18
.ifc \type, avg
mov lr, #1
movw r12, #2*PREP_BIAS
lsl lr, lr, r7 // 1 << intermediate_bits
neg r12, r12 // -2*PREP_BIAS
add r7, r7, #1
sub r12, r12, lr // -2*PREP_BIAS - 1 << intermediate_bits
neg r7, r7 // -(intermediate_bits+1)
vdup.16 q12, r12 // -2*PREP_BIAS - 1 << intermediate_bits
vdup.16 q13, r7 // -(intermediate_bits+1)
.else
mov r12, #PREP_BIAS
lsr r12, r12, r7 // PREP_BIAS >> intermediate_bits
neg r7, r7 // -intermediate_bits
vdup.16 q12, r12 // PREP_BIAS >> intermediate_bits
vdup.16 q13, r7 // -intermediate_bits
.endif
.ifc \type, w_avg
vdup.32 q4, r6
vneg.s32 q4, q4
.endif
adr r7, L(\type\()_tbl)
sub r4, r4, #24
\type q8, d16, d17, q9, d18, d19
ldr r4, [r7, r4, lsl #2]
add r7, r7, r4
bx r7
.align 2
L(\type\()_tbl):
.word 1280f - L(\type\()_tbl) + CONFIG_THUMB
.word 640f - L(\type\()_tbl) + CONFIG_THUMB
.word 320f - L(\type\()_tbl) + CONFIG_THUMB
.word 160f - L(\type\()_tbl) + CONFIG_THUMB
.word 80f - L(\type\()_tbl) + CONFIG_THUMB
.word 40f - L(\type\()_tbl) + CONFIG_THUMB
40:
add r7, r0, r1
lsl r1, r1, #1
4:
subs r5, r5, #4
vst1.16 {d16}, [r0, :64], r1
vst1.16 {d17}, [r7, :64], r1
vst1.16 {d18}, [r0, :64], r1
vst1.16 {d19}, [r7, :64], r1
ble 0f
\type q8, d16, d17, q9, d18, d19
b 4b
80:
add r7, r0, r1
lsl r1, r1, #1
8:
vst1.16 {q8}, [r0, :128], r1
subs r5, r5, #2
vst1.16 {q9}, [r7, :128], r1
ble 0f
\type q8, d16, d17, q9, d18, d19
b 8b
160:
16:
\type q10, d20, d21, q11, d22, d23
vst1.16 {q8, q9}, [r0, :128], r1
subs r5, r5, #2
vst1.16 {q10, q11}, [r0, :128], r1
ble 0f
\type q8, d16, d17, q9, d18, d19
b 16b
320:
add r7, r0, #32
32:
\type q10, d20, d21, q11, d22, d23
vst1.16 {q8, q9}, [r0, :128], r1
subs r5, r5, #1
vst1.16 {q10, q11}, [r7, :128], r1
ble 0f
\type q8, d16, d17, q9, d18, d19
b 32b
640:
add r7, r0, #32
mov r12, #64
sub r1, r1, #64
64:
\type q10, d20, d21, q11, d22, d23
vst1.16 {q8, q9}, [r0, :128], r12
\type q8, d16, d17, q9, d18, d19
vst1.16 {q10, q11}, [r7, :128], r12
\type q10, d20, d21, q11, d22, d23
vst1.16 {q8, q9}, [r0, :128], r1
subs r5, r5, #1
vst1.16 {q10, q11}, [r7, :128], r1
ble 0f
\type q8, d16, d17, q9, d18, d19
b 64b
1280:
add r7, r0, #32
mov r12, #64
sub r1, r1, #192
128:
\type q10, d20, d21, q11, d22, d23
vst1.16 {q8, q9}, [r0, :128], r12
\type q8, d16, d17, q9, d18, d19
vst1.16 {q10, q11}, [r7, :128], r12
\type q10, d20, d21, q11, d22, d23
vst1.16 {q8, q9}, [r0, :128], r12
\type q8, d16, d17, q9, d18, d19
vst1.16 {q10, q11}, [r7, :128], r12
\type q10, d20, d21, q11, d22, d23
vst1.16 {q8, q9}, [r0, :128], r12
\type q8, d16, d17, q9, d18, d19
vst1.16 {q10, q11}, [r7, :128], r12
\type q10, d20, d21, q11, d22, d23
vst1.16 {q8, q9}, [r0, :128], r1
subs r5, r5, #1
vst1.16 {q10, q11}, [r7, :128], r1
ble 0f
\type q8, d16, d17, q9, d18, d19
b 128b
0:
.ifc \type, mask
vpop {q4-q7}
.endif
.ifc \type, w_avg
vpop {q4}
.endif
pop {r4-r7,pc}
endfunc
.endm
bidir_fn avg, r6
bidir_fn w_avg, r7
bidir_fn mask, r7
.macro w_mask_fn type
function w_mask_\type\()_16bpc_neon, export=1
push {r4-r10,lr}
vpush {q4-q7}
ldrd r4, r5, [sp, #96]
ldrd r6, r7, [sp, #104]
ldr r8, [sp, #112]
clz r9, r4
adr lr, L(w_mask_\type\()_tbl)
vdup.16 q15, r8 // bitdepth_max
sub r9, r9, #24
clz r8, r8 // clz(bitdepth_max)
ldr r9, [lr, r9, lsl #2]
add r9, lr, r9
sub r8, r8, #12 // sh = intermediate_bits + 6 = clz(bitdepth_max) - 12
mov r10, #PREP_BIAS*64
neg r8, r8 // -sh
movw r12, #27615 // (64 + 1 - 38)<<mask_sh - 1 - mask_rnd
vdup.32 q14, r8 // -sh
vdup.16 q0, r12
.if \type == 444
vmov.i8 q1, #64
.elseif \type == 422
vdup.8 d4, r7
vmov.i8 d2, #129
vsub.i16 d2, d2, d4
.elseif \type == 420
vdup.16 q2, r7
vmov.i16 q1, #0x100
vsub.i16 q1, q1, q2
.endif
add r12, r0, r1
lsl r1, r1, #1
bx r9
.align 2
L(w_mask_\type\()_tbl):
.word 1280f - L(w_mask_\type\()_tbl) + CONFIG_THUMB
.word 640f - L(w_mask_\type\()_tbl) + CONFIG_THUMB
.word 320f - L(w_mask_\type\()_tbl) + CONFIG_THUMB
.word 160f - L(w_mask_\type\()_tbl) + CONFIG_THUMB
.word 8f - L(w_mask_\type\()_tbl) + CONFIG_THUMB
.word 4f - L(w_mask_\type\()_tbl) + CONFIG_THUMB
4:
vld1.16 {q2, q3}, [r2, :128]! // tmp1 (four rows at once)
vld1.16 {q4, q5}, [r3, :128]! // tmp2 (four rows at once)
subs r5, r5, #4
vdup.32 q13, r10 // PREP_BIAS*64
vabd.s16 q6, q2, q4 // abs(tmp1 - tmp2)
vabd.s16 q7, q3, q5
vsubl.s16 q8, d8, d4 // tmp2 - tmp1 (requires 17 bit)
vsubl.s16 q9, d9, d5
vsubl.s16 q10, d10, d6
vsubl.s16 q11, d11, d7
vqsub.u16 q6, q0, q6 // 27615 - abs()
vqsub.u16 q7, q0, q7
vshll.s16 q5, d7, #6 // tmp1 << 6
vshll.s16 q4, d6, #6
vshll.s16 q3, d5, #6
vshll.s16 q2, d4, #6
vshr.u16 q6, q6, #10 // 64-m = (27615 - abs()) >> mask_sh
vshr.u16 q7, q7, #10
vadd.i32 q2, q2, q13 // += PREP_BIAS*64
vadd.i32 q3, q3, q13
vadd.i32 q4, q4, q13
vadd.i32 q5, q5, q13
vmovl.u16 q12, d12
vmovl.u16 q13, d13
vmla.i32 q2, q8, q12 // (tmp2-tmp1)*(64-m)
vmovl.u16 q12, d14
vmla.i32 q3, q9, q13
vmovl.u16 q13, d15
vmla.i32 q4, q10, q12
vmla.i32 q5, q11, q13
vrshl.s32 q2, q2, q14 // (tmp1<<6 + (tmp2-tmp1)*(64-m) + (1 << (sh-1)) + PREP_BIAS*64) >> sh
vrshl.s32 q3, q3, q14
vrshl.s32 q4, q4, q14
vrshl.s32 q5, q5, q14
vqmovun.s32 d4, q2 // iclip_pixel
vqmovun.s32 d5, q3
vqmovun.s32 d6, q4
vqmovun.s32 d7, q5
vmin.u16 q2, q2, q15 // iclip_pixel
vmin.u16 q3, q3, q15 // iclip_pixel
.if \type == 444
vmovn.i16 d12, q6 // 64 - m
vmovn.i16 d13, q7
vsub.i16 q6, q1, q6 // m
vst1.8 {q6}, [r6, :128]!
.elseif \type == 422
vpadd.i16 d12, d12, d13 // (64 - m) + (64 - n) (column wise addition)
vpadd.i16 d13, d14, d15
vmovn.i16 d12, q6
vhsub.u8 d12, d2, d12 // ((129 - sign) - ((64 - m) + (64 - n)) >> 1
vst1.8 {d12}, [r6, :64]!
.elseif \type == 420
vadd.i16 d12, d12, d13 // (64 - my1) + (64 - my2) (row wise addition)
vadd.i16 d13, d14, d15
vpadd.i16 d12, d12, d13 // (128 - m) + (128 - n) (column wise addition)
vsub.i16 d12, d2, d12 // (256 - sign) - ((128 - m) + (128 - n))
vrshrn.i16 d12, q6, #2 // ((256 - sign) - ((128 - m) + (128 - n)) + 2) >> 2
vst1.32 {d12[0]}, [r6, :32]!
.endif
vst1.16 {d4}, [r0, :64], r1
vst1.16 {d5}, [r12, :64], r1
vst1.16 {d6}, [r0, :64], r1
vst1.16 {d7}, [r12, :64], r1
bgt 4b
vpop {q4-q7}
pop {r4-r10,pc}
8:
vld1.16 {q2, q3}, [r2, :128]! // tmp1
vld1.16 {q4, q5}, [r3, :128]! // tmp2
subs r5, r5, #2
vdup.32 q13, r10 // PREP_BIAS*64
vabd.s16 q6, q2, q4 // abs(tmp1 - tmp2)
vabd.s16 q7, q3, q5
vsubl.s16 q8, d8, d4 // tmp2 - tmp1 (requires 17 bit)
vsubl.s16 q9, d9, d5
vsubl.s16 q10, d10, d6
vsubl.s16 q11, d11, d7
vqsub.u16 q6, q0, q6 // 27615 - abs()
vqsub.u16 q7, q0, q7
vshll.s16 q5, d7, #6 // tmp1 << 6
vshll.s16 q4, d6, #6
vshll.s16 q3, d5, #6
vshll.s16 q2, d4, #6
vshr.u16 q6, q6, #10 // 64-m = (27615 - abs()) >> mask_sh
vshr.u16 q7, q7, #10
vadd.i32 q2, q2, q13 // += PREP_BIAS*64
vadd.i32 q3, q3, q13
vadd.i32 q4, q4, q13
vadd.i32 q5, q5, q13
vmovl.u16 q12, d12
vmovl.u16 q13, d13
vmla.i32 q2, q8, q12 // (tmp2-tmp1)*(64-m)
vmovl.u16 q12, d14
vmla.i32 q3, q9, q13
vmovl.u16 q13, d15
vmla.i32 q4, q10, q12
vmla.i32 q5, q11, q13
vrshl.s32 q2, q2, q14 // (tmp1<<6 + (tmp2-tmp1)*(64-m) + (1 << (sh-1)) + PREP_BIAS*64) >> sh
vrshl.s32 q3, q3, q14
vrshl.s32 q4, q4, q14
vrshl.s32 q5, q5, q14
vqmovun.s32 d4, q2 // iclip_pixel
vqmovun.s32 d5, q3
vqmovun.s32 d6, q4
vqmovun.s32 d7, q5
vmin.u16 q2, q2, q15 // iclip_pixel
vmin.u16 q3, q3, q15 // iclip_pixel
.if \type == 444
vmovn.i16 d12, q6 // 64 - m
vmovn.i16 d13, q7
vsub.i16 q6, q1, q6 // m
vst1.8 {q6}, [r6, :128]!
.elseif \type == 422
vpadd.i16 d12, d12, d13 // (64 - m) + (64 - n) (column wise addition)
vpadd.i16 d13, d14, d15
vmovn.i16 d12, q6
vhsub.u8 d12, d2, d12 // ((129 - sign) - ((64 - m) + (64 - n)) >> 1
vst1.8 {d12}, [r6, :64]!
.elseif \type == 420
vadd.i16 q6, q6, q7 // (64 - my1) + (64 - my2) (row wise addition)
vpadd.i16 d12, d12, d13 // (128 - m) + (128 - n) (column wise addition)
vsub.i16 d12, d2, d12 // (256 - sign) - ((128 - m) + (128 - n))
vrshrn.i16 d12, q6, #2 // ((256 - sign) - ((128 - m) + (128 - n)) + 2) >> 2
vst1.32 {d12[0]}, [r6, :32]!
.endif
vst1.16 {q2}, [r0, :128], r1
vst1.16 {q3}, [r12, :128], r1
bgt 8b
vpop {q4-q7}
pop {r4-r10,pc}
1280:
640:
320:
160:
sub r1, r1, r4, lsl #1
.if \type == 444
add lr, r6, r4
.elseif \type == 422
add lr, r6, r4, lsr #1
.endif
add r7, r2, r4, lsl #1
add r9, r3, r4, lsl #1
161:
mov r8, r4
16:
vld1.16 {q2}, [r2, :128]! // tmp1
vld1.16 {q4}, [r3, :128]! // tmp2
vld1.16 {q3}, [r7, :128]!
vld1.16 {q5}, [r9, :128]!
subs r8, r8, #8
vdup.32 q13, r10 // PREP_BIAS*64
vabd.s16 q6, q2, q4 // abs(tmp1 - tmp2)
vabd.s16 q7, q3, q5
vsubl.s16 q8, d8, d4 // tmp2 - tmp1 (requires 17 bit)
vsubl.s16 q9, d9, d5
vsubl.s16 q10, d10, d6
vsubl.s16 q11, d11, d7
vqsub.u16 q6, q0, q6 // 27615 - abs()
vqsub.u16 q7, q0, q7
vshll.s16 q5, d7, #6 // tmp1 << 6
vshll.s16 q4, d6, #6
vshll.s16 q3, d5, #6
vshll.s16 q2, d4, #6
vshr.u16 q6, q6, #10 // 64-m = (27615 - abs()) >> mask_sh
vshr.u16 q7, q7, #10
vadd.i32 q2, q2, q13 // += PREP_BIAS*64
vadd.i32 q3, q3, q13
vadd.i32 q4, q4, q13
vadd.i32 q5, q5, q13
vmovl.u16 q12, d12
vmovl.u16 q13, d13
vmla.i32 q2, q8, q12 // (tmp2-tmp1)*(64-m)
vmovl.u16 q12, d14
vmla.i32 q3, q9, q13
vmovl.u16 q13, d15
vmla.i32 q4, q10, q12
vmla.i32 q5, q11, q13
vrshl.s32 q2, q2, q14 // (tmp1<<6 + (tmp2-tmp1)*(64-m) + (1 << (sh-1)) + PREP_BIAS*64) >> sh
vrshl.s32 q3, q3, q14
vrshl.s32 q4, q4, q14
vrshl.s32 q5, q5, q14
vqmovun.s32 d4, q2 // iclip_pixel
vqmovun.s32 d5, q3
vqmovun.s32 d6, q4
vqmovun.s32 d7, q5
vmin.u16 q2, q2, q15 // iclip_pixel
vmin.u16 q3, q3, q15 // iclip_pixel
.if \type == 444
vmovn.i16 d12, q6 // 64 - m
vmovn.i16 d13, q7
vsub.i16 q6, q1, q6 // m
vst1.8 {d12}, [r6, :64]!
vst1.8 {d13}, [lr, :64]!
.elseif \type == 422
vpadd.i16 d12, d12, d13 // (64 - m) + (64 - n) (column wise addition)
vpadd.i16 d13, d14, d15
vmovn.i16 d12, q6
vhsub.u8 d12, d2, d12 // ((129 - sign) - ((64 - m) + (64 - n)) >> 1
vst1.32 {d12[0]}, [r6, :32]!
vst1.32 {d12[1]}, [lr, :32]!
.elseif \type == 420
vadd.i16 q6, q6, q7 // (64 - my1) + (64 - my2) (row wise addition)
vpadd.i16 d12, d12, d13 // (128 - m) + (128 - n) (column wise addition)
vsub.i16 d12, d2, d12 // (256 - sign) - ((128 - m) + (128 - n))
vrshrn.i16 d12, q6, #2 // ((256 - sign) - ((128 - m) + (128 - n)) + 2) >> 2
vst1.32 {d12[0]}, [r6, :32]!
.endif
vst1.16 {q2}, [r0, :128]!
vst1.16 {q3}, [r12, :128]!
bgt 16b
subs r5, r5, #2
add r2, r2, r4, lsl #1
add r3, r3, r4, lsl #1
add r7, r7, r4, lsl #1
add r9, r9, r4, lsl #1
.if \type == 444
add r6, r6, r4
add lr, lr, r4
.elseif \type == 422
add r6, r6, r4, lsr #1
add lr, lr, r4, lsr #1
.endif
add r0, r0, r1
add r12, r12, r1
bgt 161b
vpop {q4-q7}
pop {r4-r10,pc}
endfunc
.endm
w_mask_fn 444
w_mask_fn 422
w_mask_fn 420
function blend_16bpc_neon, export=1
push {r4-r5,lr}
ldrd r4, r5, [sp, #12]
clz lr, r3
adr r3, L(blend_tbl)
sub lr, lr, #26
ldr lr, [r3, lr, lsl #2]
add r3, r3, lr
bx r3
.align 2
L(blend_tbl):
.word 320f - L(blend_tbl) + CONFIG_THUMB
.word 160f - L(blend_tbl) + CONFIG_THUMB
.word 80f - L(blend_tbl) + CONFIG_THUMB
.word 40f - L(blend_tbl) + CONFIG_THUMB
40:
add r12, r0, r1
lsl r1, r1, #1
4:
vld1.8 {d4}, [r5, :64]!
vld1.16 {q1}, [r2, :128]!
vld1.16 {d0}, [r0, :64]
vneg.s8 d4, d4 // -m
subs r4, r4, #2
vld1.16 {d1}, [r12, :64]
vmovl.s8 q2, d4
vshl.i16 q2, q2, #9 // -m << 9
vsub.i16 q1, q0, q1 // a - b
vqrdmulh.s16 q1, q1, q2 // ((a-b)*-m + 32) >> 6
vadd.i16 q0, q0, q1
vst1.16 {d0}, [r0, :64], r1
vst1.16 {d1}, [r12, :64], r1
bgt 4b
pop {r4-r5,pc}
80:
add r12, r0, r1
lsl r1, r1, #1
8:
vld1.8 {q8}, [r5, :128]!
vld1.16 {q2, q3}, [r2, :128]!
vneg.s8 q9, q8 // -m
vld1.16 {q0}, [r0, :128]
vld1.16 {q1}, [r12, :128]
vmovl.s8 q8, d18
vmovl.s8 q9, d19
vshl.i16 q8, q8, #9 // -m << 9
vshl.i16 q9, q9, #9
vsub.i16 q2, q0, q2 // a - b
vsub.i16 q3, q1, q3
subs r4, r4, #2
vqrdmulh.s16 q2, q2, q8 // ((a-b)*-m + 32) >> 6
vqrdmulh.s16 q3, q3, q9
vadd.i16 q0, q0, q2
vadd.i16 q1, q1, q3
vst1.16 {q0}, [r0, :128], r1
vst1.16 {q1}, [r12, :128], r1
bgt 8b
pop {r4-r5,pc}
160:
add r12, r0, r1
lsl r1, r1, #1
16:
vld1.8 {q12, q13}, [r5, :128]!
vld1.16 {q8, q9}, [r2, :128]!
subs r4, r4, #2
vneg.s8 q14, q12 // -m
vld1.16 {q0, q1}, [r0, :128]
vneg.s8 q15, q13
vld1.16 {q10, q11}, [r2, :128]!
vmovl.s8 q12, d28
vmovl.s8 q13, d29
vmovl.s8 q14, d30
vmovl.s8 q15, d31
vld1.16 {q2, q3}, [r12, :128]
vshl.i16 q12, q12, #9 // -m << 9
vshl.i16 q13, q13, #9
vshl.i16 q14, q14, #9
vshl.i16 q15, q15, #9
vsub.i16 q8, q0, q8 // a - b
vsub.i16 q9, q1, q9
vsub.i16 q10, q2, q10
vsub.i16 q11, q3, q11
vqrdmulh.s16 q8, q8, q12 // ((a-b)*-m + 32) >> 6
vqrdmulh.s16 q9, q9, q13
vqrdmulh.s16 q10, q10, q14
vqrdmulh.s16 q11, q11, q15
vadd.i16 q0, q0, q8
vadd.i16 q1, q1, q9
vadd.i16 q2, q2, q10
vst1.16 {q0, q1}, [r0, :128], r1
vadd.i16 q3, q3, q11
vst1.16 {q2, q3}, [r12, :128], r1
bgt 16b
pop {r4-r5,pc}
320:
add r12, r0, #32
32:
vld1.8 {q12, q13}, [r5, :128]!
vld1.16 {q8, q9}, [r2, :128]!
subs r4, r4, #1
vneg.s8 q14, q12 // -m
vld1.16 {q0, q1}, [r0, :128]
vneg.s8 q15, q13
vld1.16 {q10, q11}, [r2, :128]!
vmovl.s8 q12, d28
vmovl.s8 q13, d29
vmovl.s8 q14, d30
vmovl.s8 q15, d31
vld1.16 {q2, q3}, [r12, :128]
vshl.i16 q12, q12, #9 // -m << 9
vshl.i16 q13, q13, #9
vshl.i16 q14, q14, #9
vshl.i16 q15, q15, #9
vsub.i16 q8, q0, q8 // a - b
vsub.i16 q9, q1, q9
vsub.i16 q10, q2, q10
vsub.i16 q11, q3, q11
vqrdmulh.s16 q8, q8, q12 // ((a-b)*-m + 32) >> 6
vqrdmulh.s16 q9, q9, q13
vqrdmulh.s16 q10, q10, q14
vqrdmulh.s16 q11, q11, q15
vadd.i16 q0, q0, q8
vadd.i16 q1, q1, q9
vadd.i16 q2, q2, q10
vst1.16 {q0, q1}, [r0, :128], r1
vadd.i16 q3, q3, q11
vst1.16 {q2, q3}, [r12, :128], r1
bgt 32b
pop {r4-r5,pc}
endfunc
function blend_h_16bpc_neon, export=1
push {r4-r5,lr}
ldr r4, [sp, #12]
movrel r5, X(obmc_masks)
add r5, r5, r4
sub r4, r4, r4, lsr #2
clz lr, r3
adr r12, L(blend_h_tbl)
sub lr, lr, #24
ldr lr, [r12, lr, lsl #2]
add r12, r12, lr
bx r12
.align 2
L(blend_h_tbl):
.word 1280f - L(blend_h_tbl) + CONFIG_THUMB
.word 640f - L(blend_h_tbl) + CONFIG_THUMB
.word 320f - L(blend_h_tbl) + CONFIG_THUMB
.word 160f - L(blend_h_tbl) + CONFIG_THUMB
.word 80f - L(blend_h_tbl) + CONFIG_THUMB
.word 40f - L(blend_h_tbl) + CONFIG_THUMB
.word 20f - L(blend_h_tbl) + CONFIG_THUMB
20:
add r12, r0, r1
lsl r1, r1, #1
2:
vld2.8 {d4[], d5[]}, [r5, :16]!
vld1.16 {d2}, [r2, :64]!
vext.8 d4, d4, d5, #6
subs r4, r4, #2
vneg.s8 d4, d4 // -m
vld1.32 {d0[]}, [r0, :32]
vld1.32 {d0[1]}, [r12, :32]
vmovl.s8 q2, d4
vshl.i16 d4, d4, #9 // -m << 9
vsub.i16 d2, d0, d2 // a - b
vqrdmulh.s16 d2, d2, d4 // ((a-b)*-m + 32) >> 6
vadd.i16 d0, d0, d2
vst1.32 {d0[0]}, [r0, :32], r1
vst1.32 {d0[1]}, [r12, :32], r1
bgt 2b
pop {r4-r5,pc}
40:
add r12, r0, r1
lsl r1, r1, #1
4:
vld2.8 {d4[], d5[]}, [r5, :16]!
vld1.16 {q1}, [r2, :128]!
vext.8 d4, d4, d5, #4
subs r4, r4, #2
vneg.s8 d4, d4 // -m
vld1.16 {d0}, [r0, :64]
vld1.16 {d1}, [r12, :64]
vmovl.s8 q2, d4
vshl.i16 q2, q2, #9 // -m << 9
vsub.i16 q1, q0, q1 // a - b
vqrdmulh.s16 q1, q1, q2 // ((a-b)*-m + 32) >> 6
vadd.i16 q0, q0, q1
vst1.16 {d0}, [r0, :64], r1
vst1.16 {d1}, [r12, :64], r1
bgt 4b
pop {r4-r5,pc}
80:
add r12, r0, r1
lsl r1, r1, #1
8:
vld2.8 {d16[], d17[]}, [r5, :16]!
vld1.16 {q2, q3}, [r2, :128]!
vneg.s8 q9, q8 // -m
vld1.16 {q0}, [r0, :128]
subs r4, r4, #2
vmovl.s8 q8, d18
vmovl.s8 q9, d19
vld1.16 {q1}, [r12, :128]
vshl.i16 q8, q8, #9 // -m << 9
vshl.i16 q9, q9, #9
vsub.i16 q2, q0, q2 // a - b
vsub.i16 q3, q1, q3
vqrdmulh.s16 q2, q2, q8 // ((a-b)*-m + 32) >> 6
vqrdmulh.s16 q3, q3, q9
vadd.i16 q0, q0, q2
vadd.i16 q1, q1, q3
vst1.16 {q0}, [r0, :128], r1
vst1.16 {q1}, [r12, :128], r1
bgt 8b
pop {r4-r5,pc}
160:
add r12, r0, r1
lsl r1, r1, #1
16:
vld2.8 {d24[], d25[]}, [r5, :16]!
vld1.16 {q8, q9}, [r2, :128]!
subs r4, r4, #2
vneg.s8 q13, q12 // -m
vld1.16 {q0, q1}, [r0, :128]
vmovl.s8 q12, d26
vld1.16 {q10, q11}, [r2, :128]!
vmovl.s8 q13, d27
vld1.16 {q2, q3}, [r12, :128]
vshl.i16 q12, q12, #9 // -m << 9
vshl.i16 q13, q13, #9
vsub.i16 q8, q0, q8 // a - b
vsub.i16 q9, q1, q9
vsub.i16 q10, q2, q10
vsub.i16 q11, q3, q11
vqrdmulh.s16 q8, q8, q12 // ((a-b)*-m + 32) >> 6
vqrdmulh.s16 q9, q9, q12
vqrdmulh.s16 q10, q10, q13
vqrdmulh.s16 q11, q11, q13
vadd.i16 q0, q0, q8
vadd.i16 q1, q1, q9
vadd.i16 q2, q2, q10
vadd.i16 q3, q3, q11
vst1.16 {q0, q1}, [r0, :128], r1
vst1.16 {q2, q3}, [r12, :128], r1
bgt 16b
pop {r4-r5,pc}
1280:
640:
320:
sub r1, r1, r3, lsl #1
321:
vld1.8 {d24[]}, [r5]!
mov r12, r3
vneg.s8 d24, d24 // -m
vmovl.s8 q12, d24
vshl.i16 q12, q12, #9 // -m << 9
32:
vld1.16 {q8, q9}, [r2, :128]!
vld1.16 {q0, q1}, [r0, :128]!
subs r12, r12, #32
vld1.16 {q10, q11}, [r2, :128]!
vld1.16 {q2, q3}, [r0, :128]
vsub.i16 q8, q0, q8 // a - b
vsub.i16 q9, q1, q9
vsub.i16 q10, q2, q10
vsub.i16 q11, q3, q11
sub r0, r0, #32
vqrdmulh.s16 q8, q8, q12 // ((a-b)*-m + 32) >> 6
vqrdmulh.s16 q9, q9, q12
vqrdmulh.s16 q10, q10, q12
vqrdmulh.s16 q11, q11, q12
vadd.i16 q0, q0, q8
vadd.i16 q1, q1, q9
vadd.i16 q2, q2, q10
vst1.16 {q0, q1}, [r0, :128]!
vadd.i16 q3, q3, q11
vst1.16 {q2, q3}, [r0, :128]!
bgt 32b
subs r4, r4, #1
add r0, r0, r1
bgt 321b
pop {r4-r5,pc}
endfunc
function blend_v_16bpc_neon, export=1
push {r4,lr}
ldr r4, [sp, #8]
movrel lr, X(obmc_masks)
add lr, lr, r3
clz r12, r3
adr r3, L(blend_v_tbl)
sub r12, r12, #26
ldr r12, [r3, r12, lsl #2]
add r3, r3, r12
bx r3
.align 2
L(blend_v_tbl):
.word 320f - L(blend_v_tbl) + CONFIG_THUMB
.word 160f - L(blend_v_tbl) + CONFIG_THUMB
.word 80f - L(blend_v_tbl) + CONFIG_THUMB
.word 40f - L(blend_v_tbl) + CONFIG_THUMB
.word 20f - L(blend_v_tbl) + CONFIG_THUMB
20:
add r12, r0, r1
lsl r1, r1, #1
vld1.8 {d4[]}, [lr]
vneg.s8 d4, d4 // -m
vmovl.s8 q2, d4
vshl.i16 d4, d4, #9 // -m << 9
2:
vld1.32 {d2[]}, [r2, :32]!
vld1.16 {d0[]}, [r0, :16]
subs r4, r4, #2
vld1.16 {d2[1]}, [r2, :16]
vld1.16 {d0[1]}, [r12, :16]
add r2, r2, #4
vsub.i16 d2, d0, d2 // a - b
vqrdmulh.s16 d2, d2, d4 // ((a-b)*-m + 32) >> 6
vadd.i16 d0, d0, d2
vst1.16 {d0[0]}, [r0, :16], r1
vst1.16 {d0[1]}, [r12, :16], r1
bgt 2b
pop {r4,pc}
40:
vld1.32 {d4[]}, [lr, :32]
add r12, r0, r1
vneg.s8 d4, d4 // -m
lsl r1, r1, #1
vmovl.s8 q2, d4
sub r1, r1, #4
vshl.i16 q2, q2, #9 // -m << 9
4:
vld1.16 {q1}, [r2, :128]!
vld1.16 {d0}, [r0, :64]
vld1.16 {d1}, [r12, :64]
subs r4, r4, #2
vsub.i16 q1, q0, q1 // a - b
vqrdmulh.s16 q1, q1, q2 // ((a-b)*-m + 32) >> 6
vadd.i16 q0, q0, q1
vst1.32 {d0[0]}, [r0, :32]!
vst1.32 {d1[0]}, [r12, :32]!
vst1.16 {d0[2]}, [r0, :16], r1
vst1.16 {d1[2]}, [r12, :16], r1
bgt 4b
pop {r4,pc}
80:
vld1.8 {d16}, [lr, :64]
add r12, r0, r1
vneg.s8 d16, d16 // -m
lsl r1, r1, #1
vmovl.s8 q8, d16
sub r1, r1, #8
vshl.i16 q8, q8, #9 // -m << 9
8:
vld1.16 {q2, q3}, [r2, :128]!
vld1.16 {q0}, [r0, :128]
vld1.16 {q1}, [r12, :128]
subs r4, r4, #2
vsub.i16 q2, q0, q2 // a - b
vsub.i16 q3, q1, q3
vqrdmulh.s16 q2, q2, q8 // ((a-b)*-m + 32) >> 6
vqrdmulh.s16 q3, q3, q8
vadd.i16 q0, q0, q2
vadd.i16 q1, q1, q3
vst1.16 {d0}, [r0, :64]!
vst1.16 {d2}, [r12, :64]!
vst1.32 {d1[0]}, [r0, :32], r1
vst1.32 {d3[0]}, [r12, :32], r1
bgt 8b
pop {r4,pc}
160:
vld1.8 {q12}, [lr, :128]
add r12, r0, r1
vneg.s8 q13, q12 // -m
lsl r1, r1, #1
vmovl.s8 q12, d26
vmovl.s8 q13, d27
vshl.i16 q12, q12, #9 // -m << 9
vshl.i16 d26, d26, #9
16:
vld1.16 {q8, q9}, [r2, :128]!
vld1.16 {d0, d1, d2}, [r0, :64]
subs r4, r4, #2
vld1.16 {q10, q11}, [r2, :128]!
vsub.i16 q8, q0, q8 // a - b
vld1.16 {d4, d5, d6}, [r12, :64]
vsub.i16 d18, d2, d18
vsub.i16 q10, q2, q10
vsub.i16 d22, d6, d22
vqrdmulh.s16 q8, q8, q12 // ((a-b)*-m + 32) >> 6
vqrdmulh.s16 d18, d18, d26
vqrdmulh.s16 q10, q10, q12
vqrdmulh.s16 d22, d22, d26
vadd.i16 q0, q0, q8
vadd.i16 d2, d2, d18
vadd.i16 q2, q2, q10
vst1.16 {d0, d1, d2}, [r0, :64], r1
vadd.i16 d6, d6, d22
vst1.16 {d4, d5, d6}, [r12, :64], r1
bgt 16b
pop {r4,pc}
320:
vld1.8 {d24, d25, d26}, [lr, :64]
vneg.s8 q14, q12 // -m
vneg.s8 d30, d26
vmovl.s8 q12, d28
vmovl.s8 q13, d29
vmovl.s8 q14, d30
sub r1, r1, #32
vshl.i16 q12, q12, #9 // -m << 9
vshl.i16 q13, q13, #9
vshl.i16 q14, q14, #9
32:
vld1.16 {q8, q9}, [r2, :128]!
vld1.16 {q0, q1}, [r0, :128]!
subs r4, r4, #1
vld1.16 {q10}, [r2, :128]
vsub.i16 q8, q0, q8 // a - b
vld1.16 {q2}, [r0, :128]
sub r0, r0, #32
vsub.i16 q9, q1, q9
vsub.i16 q10, q2, q10
vqrdmulh.s16 q8, q8, q12 // ((a-b)*-m + 32) >> 6
vqrdmulh.s16 q9, q9, q13
vqrdmulh.s16 q10, q10, q14
vadd.i16 q0, q0, q8
vadd.i16 q1, q1, q9
vadd.i16 q2, q2, q10
vst1.16 {q0, q1}, [r0, :128]!
add r2, r2, #32
vst1.16 {q2}, [r0, :128], r1
bgt 32b
pop {r4,pc}
endfunc
// This has got the same signature as the put_8tap functions,
// and assumes that r9 is set to (clz(w)-24).
function put_neon
adr r10, L(put_tbl)
ldr r9, [r10, r9, lsl #2]
add r10, r10, r9
bx r10
.align 2
L(put_tbl):
.word 1280f - L(put_tbl) + CONFIG_THUMB
.word 640f - L(put_tbl) + CONFIG_THUMB
.word 320f - L(put_tbl) + CONFIG_THUMB
.word 16f - L(put_tbl) + CONFIG_THUMB
.word 80f - L(put_tbl) + CONFIG_THUMB
.word 4f - L(put_tbl) + CONFIG_THUMB
.word 2f - L(put_tbl) + CONFIG_THUMB
2:
vld1.32 {d0[]}, [r2], r3
vld1.32 {d1[]}, [r2], r3
subs r5, r5, #2
vst1.32 {d0[0]}, [r0, :32], r1
vst1.32 {d1[1]}, [r0, :32], r1
bgt 2b
pop {r4-r11,pc}
4:
vld1.16 {d0}, [r2], r3
vld1.16 {d1}, [r2], r3
subs r5, r5, #2
vst1.16 {d0}, [r0, :64], r1
vst1.16 {d1}, [r0, :64], r1
bgt 4b
pop {r4-r11,pc}
80:
add r8, r0, r1
lsl r1, r1, #1
add r9, r2, r3
lsl r3, r3, #1
8:
vld1.16 {q0}, [r2], r3
vld1.16 {q1}, [r9], r3
subs r5, r5, #2
vst1.16 {q0}, [r0, :128], r1
vst1.16 {q1}, [r8, :128], r1
bgt 8b
pop {r4-r11,pc}
16:
vld1.16 {q0, q1}, [r2], r3
subs r5, r5, #1
vst1.16 {q0, q1}, [r0, :128], r1
bgt 16b
pop {r4-r11,pc}
320:
sub r1, r1, #32
sub r3, r3, #32
32:
vld1.16 {q0, q1}, [r2]!
vst1.16 {q0, q1}, [r0, :128]!
vld1.16 {q2, q3}, [r2], r3
subs r5, r5, #1
vst1.16 {q2, q3}, [r0, :128], r1
bgt 32b
pop {r4-r11,pc}
640:
sub r1, r1, #96
sub r3, r3, #96
64:
vld1.16 {q8, q9}, [r2]!
vst1.16 {q8, q9}, [r0, :128]!
vld1.16 {q10, q11}, [r2]!
vst1.16 {q10, q11}, [r0, :128]!
vld1.16 {q12, q13}, [r2]!
vst1.16 {q12, q13}, [r0, :128]!
vld1.16 {q14, q15}, [r2], r3
subs r5, r5, #1
vst1.16 {q14, q15}, [r0, :128], r1
bgt 64b
pop {r4-r11,pc}
1280:
sub r1, r1, #224
sub r3, r3, #224
128:
vld1.16 {q8, q9}, [r2]!
vst1.16 {q8, q9}, [r0, :128]!
vld1.16 {q10, q11}, [r2]!
vst1.16 {q10, q11}, [r0, :128]!
vld1.16 {q12, q13}, [r2]!
vst1.16 {q12, q13}, [r0, :128]!
vld1.16 {q14, q15}, [r2]!
vst1.16 {q14, q15}, [r0, :128]!
vld1.16 {q8, q9}, [r2]!
vst1.16 {q8, q9}, [r0, :128]!
vld1.16 {q10, q11}, [r2]!
vst1.16 {q10, q11}, [r0, :128]!
vld1.16 {q12, q13}, [r2]!
vst1.16 {q12, q13}, [r0, :128]!
vld1.16 {q14, q15}, [r2], r3
subs r5, r5, #1
vst1.16 {q14, q15}, [r0, :128], r1
bgt 128b
pop {r4-r11,pc}
endfunc
// This has got the same signature as the prep_8tap functions,
// and assumes that r9 is set to (clz(w)-24), r7 to intermediate_bits and
// r8 to w*2.
function prep_neon
adr r10, L(prep_tbl)
ldr r9, [r10, r9, lsl #2]
vdup.16 q15, r7 // intermediate_bits
vmov.i16 q14, #PREP_BIAS
add r10, r10, r9
bx r10
.align 2
L(prep_tbl):
.word 1280f - L(prep_tbl) + CONFIG_THUMB
.word 640f - L(prep_tbl) + CONFIG_THUMB
.word 320f - L(prep_tbl) + CONFIG_THUMB
.word 16f - L(prep_tbl) + CONFIG_THUMB
.word 80f - L(prep_tbl) + CONFIG_THUMB
.word 40f - L(prep_tbl) + CONFIG_THUMB
40:
add r9, r1, r2
lsl r2, r2, #1
4:
vld1.16 {d0}, [r1], r2
vld1.16 {d1}, [r9], r2
subs r4, r4, #2
vshl.s16 q0, q0, q15
vsub.i16 q0, q0, q14
vst1.16 {q0}, [r0, :128]!
bgt 4b
pop {r4-r11,pc}
80:
add r9, r1, r2
lsl r2, r2, #1
8:
vld1.16 {q0}, [r1], r2
vld1.16 {q1}, [r9], r2
subs r4, r4, #2
vshl.s16 q0, q0, q15
vshl.s16 q1, q1, q15
vsub.i16 q0, q0, q14
vsub.i16 q1, q1, q14
vst1.16 {q0, q1}, [r0, :128]!
bgt 8b
pop {r4-r11,pc}
16:
vld1.16 {q0, q1}, [r1], r2
vshl.s16 q0, q0, q15
vld1.16 {q2, q3}, [r1], r2
subs r4, r4, #2
vshl.s16 q1, q1, q15
vshl.s16 q2, q2, q15
vshl.s16 q3, q3, q15
vsub.i16 q0, q0, q14
vsub.i16 q1, q1, q14
vsub.i16 q2, q2, q14
vst1.16 {q0, q1}, [r0, :128]!
vsub.i16 q3, q3, q14
vst1.16 {q2, q3}, [r0, :128]!
bgt 16b
pop {r4-r11,pc}
320:
sub r2, r2, #32
32:
vld1.16 {q0, q1}, [r1]!
subs r4, r4, #1
vshl.s16 q0, q0, q15
vld1.16 {q2, q3}, [r1], r2
vshl.s16 q1, q1, q15
vshl.s16 q2, q2, q15
vshl.s16 q3, q3, q15
vsub.i16 q0, q0, q14
vsub.i16 q1, q1, q14
vsub.i16 q2, q2, q14
vst1.16 {q0, q1}, [r0, :128]!
vsub.i16 q3, q3, q14
vst1.16 {q2, q3}, [r0, :128]!
bgt 32b
pop {r4-r11,pc}
640:
sub r2, r2, #96
64:
vld1.16 {q0, q1}, [r1]!
subs r4, r4, #1
vshl.s16 q0, q0, q15
vld1.16 {q2, q3}, [r1]!
vshl.s16 q1, q1, q15
vld1.16 {q8, q9}, [r1]!
vshl.s16 q2, q2, q15
vld1.16 {q10, q11}, [r1], r2
vshl.s16 q3, q3, q15
vshl.s16 q8, q8, q15
vshl.s16 q9, q9, q15
vshl.s16 q10, q10, q15
vshl.s16 q11, q11, q15
vsub.i16 q0, q0, q14
vsub.i16 q1, q1, q14
vsub.i16 q2, q2, q14
vsub.i16 q3, q3, q14
vsub.i16 q8, q8, q14
vst1.16 {q0, q1}, [r0, :128]!
vsub.i16 q9, q9, q14
vst1.16 {q2, q3}, [r0, :128]!
vsub.i16 q10, q10, q14
vst1.16 {q8, q9}, [r0, :128]!
vsub.i16 q11, q11, q14
vst1.16 {q10, q11}, [r0, :128]!
bgt 64b
pop {r4-r11,pc}
1280:
sub r2, r2, #224
128:
vld1.16 {q0, q1}, [r1]!
subs r4, r4, #1
vshl.s16 q0, q0, q15
vld1.16 {q2, q3}, [r1]!
vshl.s16 q1, q1, q15
vld1.16 {q8, q9}, [r1]!
vshl.s16 q2, q2, q15
vld1.16 {q10, q11}, [r1]!
vshl.s16 q3, q3, q15
vshl.s16 q8, q8, q15
vshl.s16 q9, q9, q15
vshl.s16 q10, q10, q15
vshl.s16 q11, q11, q15
vsub.i16 q0, q0, q14
vsub.i16 q1, q1, q14
vsub.i16 q2, q2, q14
vsub.i16 q3, q3, q14
vsub.i16 q8, q8, q14
vst1.16 {q0, q1}, [r0, :128]!
vld1.16 {q0, q1}, [r1]!
vsub.i16 q9, q9, q14
vsub.i16 q10, q10, q14
vst1.16 {q2, q3}, [r0, :128]!
vld1.16 {q2, q3}, [r1]!
vsub.i16 q11, q11, q14
vshl.s16 q0, q0, q15
vst1.16 {q8, q9}, [r0, :128]!
vld1.16 {q8, q9}, [r1]!
vshl.s16 q1, q1, q15
vshl.s16 q2, q2, q15
vst1.16 {q10, q11}, [r0, :128]!
vld1.16 {q10, q11}, [r1], r2
vshl.s16 q3, q3, q15
vshl.s16 q8, q8, q15
vshl.s16 q9, q9, q15
vshl.s16 q10, q10, q15
vshl.s16 q11, q11, q15
vsub.i16 q0, q0, q14
vsub.i16 q1, q1, q14
vsub.i16 q2, q2, q14
vsub.i16 q3, q3, q14
vsub.i16 q8, q8, q14
vst1.16 {q0, q1}, [r0, :128]!
vsub.i16 q9, q9, q14
vst1.16 {q2, q3}, [r0, :128]!
vsub.i16 q10, q10, q14
vst1.16 {q8, q9}, [r0, :128]!
vsub.i16 q11, q11, q14
vst1.16 {q10, q11}, [r0, :128]!
bgt 128b
pop {r4-r11,pc}
endfunc
.macro load_slice s0, s1, strd, wd, d0, d1, d2, d3, d4, d5, d6
vld1.\wd {\d0[]}, [\s0], \strd
vld1.\wd {\d1[]}, [\s1], \strd
.ifnb \d2
vld1.\wd {\d2[]}, [\s0], \strd
vld1.\wd {\d3[]}, [\s1], \strd
.endif
.ifnb \d4
vld1.\wd {\d4[]}, [\s0], \strd
.endif
.ifnb \d5
vld1.\wd {\d5[]}, [\s1], \strd
.endif
.ifnb \d6
vld1.\wd {\d6[]}, [\s0], \strd
.endif
.endm
.macro load_reg s0, s1, strd, d0, d1, d2, d3, d4, d5, d6
vld1.16 {\d0}, [\s0], \strd
vld1.16 {\d1}, [\s1], \strd
.ifnb \d2
vld1.16 {\d2}, [\s0], \strd
vld1.16 {\d3}, [\s1], \strd
.endif
.ifnb \d4
vld1.16 {\d4}, [\s0], \strd
.endif
.ifnb \d5
vld1.16 {\d5}, [\s1], \strd
.endif
.ifnb \d6
vld1.16 {\d6}, [\s0], \strd
.endif
.endm
.macro load_regpair s0, s1, strd, d0, d1, d2, d3, d4, d5
vld1.16 {\d0, \d1}, [\s0], \strd
.ifnb \d2
vld1.16 {\d2, \d3}, [\s1], \strd
.endif
.ifnb \d4
vld1.16 {\d4, \d5}, [\s0], \strd
.endif
.endm
.macro load_32 s0, s1, strd, d0, d1, d2, d3, d4, d5, d6
load_slice \s0, \s1, \strd, 32, \d0, \d1, \d2, \d3, \d4, \d5, \d6
.endm
.macro load_16s16 s0, s1, strd, d0, d1, d2, d3, d4, d5
load_regpair \s0, \s1, \strd, \d0, \d1, \d2, \d3, \d4, \d5
.endm
.macro interleave_1_32 r0, r1, r2, r3, r4
vext.8 \r0, \r0, \r1, #4
vext.8 \r1, \r1, \r2, #4
.ifnb \r3
vext.8 \r2, \r2, \r3, #4
vext.8 \r3, \r3, \r4, #4
.endif
.endm
.macro vmin_u16 c, r0, r1, r2, r3
vmin.u16 \r0, \r0, \c
.ifnb \r1
vmin.u16 \r1, \r1, \c
.endif
.ifnb \r2
vmin.u16 \r2, \r2, \c
vmin.u16 \r3, \r3, \c
.endif
.endm
.macro vsub_i16 c, r0, r1, r2, r3
vsub.i16 \r0, \r0, \c
.ifnb \r1
vsub.i16 \r1, \r1, \c
.endif
.ifnb \r2
vsub.i16 \r2, \r2, \c
vsub.i16 \r3, \r3, \c
.endif
.endm
.macro vmull_vmlal_4 d, s0, s1, s2, s3
vmull.s16 \d, \s0, d0[0]
vmlal.s16 \d, \s1, d0[1]
vmlal.s16 \d, \s2, d0[2]
vmlal.s16 \d, \s3, d0[3]
.endm
.macro vmull_vmlal_8 d, s0, s1, s2, s3, s4, s5, s6, s7
vmull.s16 \d, \s0, d0[0]
vmlal.s16 \d, \s1, d0[1]
vmlal.s16 \d, \s2, d0[2]
vmlal.s16 \d, \s3, d0[3]
vmlal.s16 \d, \s4, d1[0]
vmlal.s16 \d, \s5, d1[1]
vmlal.s16 \d, \s6, d1[2]
vmlal.s16 \d, \s7, d1[3]
.endm
.macro vqrshrun_s32 shift, q0, d0, q1, d1, q2, d2, q3, d3
vqrshrun.s32 \d0, \q0, #\shift
.ifnb \q1
vqrshrun.s32 \d1, \q1, #\shift
.endif
.ifnb \q2
vqrshrun.s32 \d2, \q2, #\shift
vqrshrun.s32 \d3, \q3, #\shift
.endif
.endm
.macro vmovn_i32 q0, d0, q1, d1, q2, d2, q3, d3
vmovn.i32 \d0, \q0
.ifnb \q1
vmovn.i32 \d1, \q1
.endif
.ifnb \q2
vmovn.i32 \d2, \q2
vmovn.i32 \d3, \q3
.endif
.endm
.macro vrshl_s32 shift, r0, r1, r2, r3
vrshl.s32 \r0, \r0, \shift
vrshl.s32 \r1, \r1, \shift
.ifnb \r2
vrshl.s32 \r2, \r2, \shift
vrshl.s32 \r3, \r3, \shift
.endif
.endm
.macro vst1_32 strd, r0, r1
vst1.32 {\r0[0]}, [r0, :32], \strd
vst1.32 {\r0[1]}, [r9, :32], \strd
.ifnb \r1
vst1.32 {\r1[0]}, [r0, :32], \strd
vst1.32 {\r1[1]}, [r9, :32], \strd
.endif
.endm
.macro vst1_reg strd, align , r0, r1, r2, r3, r4, r5, r6, r7
vst1.16 {\r0}, [r0, \align ], \strd
vst1.16 {\r1}, [r9, \align ], \strd
.ifnb \r2
vst1.16 {\r2}, [r0, \align ], \strd
vst1.16 {\r3}, [r9, \align ], \strd
.endif
.ifnb \r4
vst1.16 {\r4}, [r0, \align ], \strd
vst1.16 {\r5}, [r9, \align ], \strd
vst1.16 {\r6}, [r0, \align ], \strd
vst1.16 {\r7}, [r9, \align ], \strd
.endif
.endm
.macro finalize type, q0, q1, d0, d1, q2, q3, d2, d3
.ifc \type, put
vqrshrun_s32 6, \q0, \d0, \q1, \d1, \q2, \d2, \q3, \d3
vmin_u16 q15, \q0, \q1
.else
vrshl_s32 q14, \q0, \q1, \q2, \q3 // -(6-intermediate_bits)
vmovn_i32 \q0, \d0, \q1, \d1, \q2, \d2, \q3, \d3
vsub_i16 q15, \q0, \q1 // PREP_BIAS
.endif
.endm
.macro shift_store_4 type, strd, q0, q1, d0, d1, q2, q3, d2, d3
finalize \type, \q0, \q1, \d0, \d1, \q2, \q3, \d2, \d3
vst1_reg \strd, :64, \d0, \d1, \d2, \d3
.endm
.macro shift_store_8 type, strd, q0, q1, d0, d1, q2, q3, d2, d3
finalize \type, \q0, \q1, \d0, \d1, \q2, \q3, \d2, \d3
vst1_reg \strd, :128, \q0, \q1
.endm
.macro shift_store_16 type, strd, q0, q1, d0, d1, q2, q3, d2, d3
finalize \type, \q0, \q1, \d0, \d1, \q2, \q3, \d2, \d3
vst1.16 {\q0, \q1}, [r0, :128], \strd
.endm
.macro make_8tap_fn op, type, type_h, type_v
function \op\()_8tap_\type\()_16bpc_neon, export=1
push {r4-r11,lr}
movw r9, \type_h
movw r10, \type_v
b \op\()_8tap_neon
endfunc
.endm
// No spaces in these expressions, due to gas-preprocessor.
#define REGULAR ((0*15<<7)|3*15)
#define SMOOTH ((1*15<<7)|4*15)
#define SHARP ((2*15<<7)|3*15)
.macro filter_fn type, dst, d_strd, src, s_strd, w, h, mx, my, bdmax, ds2, sr2
make_8tap_fn \type, regular, REGULAR, REGULAR
make_8tap_fn \type, regular_smooth, REGULAR, SMOOTH
make_8tap_fn \type, regular_sharp, REGULAR, SHARP
make_8tap_fn \type, smooth, SMOOTH, SMOOTH
make_8tap_fn \type, smooth_regular, SMOOTH, REGULAR
make_8tap_fn \type, smooth_sharp, SMOOTH, SHARP
make_8tap_fn \type, sharp, SHARP, SHARP
make_8tap_fn \type, sharp_regular, SHARP, REGULAR
make_8tap_fn \type, sharp_smooth, SHARP, SMOOTH
function \type\()_8tap_neon
ldrd r4, r5, [sp, #36]
ldrd r6, r7, [sp, #44]
.ifc \bdmax, r8
ldr r8, [sp, #52]
.endif
movw r11, #0x4081 // (1 << 14) | (1 << 7) | (1 << 0)
mul \mx, \mx, r11
mul \my, \my, r11
add \mx, \mx, r9 // mx, 8tap_h, 4tap_h
add \my, \my, r10 // my, 8tap_v, 4tap_v
.ifc \type, prep
lsl \d_strd, \w, #1
.endif
vdup.16 q15, \bdmax // bitdepth_max
clz \bdmax, \bdmax
clz r9, \w
sub \bdmax, \bdmax, #18 // intermediate_bits = clz(bitdepth_max) - 18
tst \mx, #(0x7f << 14)
sub r9, r9, #24
add lr, \bdmax, #6 // 6 + intermediate_bits
rsb r12, \bdmax, #6 // 6 - intermediate_bits
movrel r11, X(mc_subpel_filters), -8
bne L(\type\()_8tap_h)
tst \my, #(0x7f << 14)
bne L(\type\()_8tap_v)
b \type\()_neon
L(\type\()_8tap_h):
cmp \w, #4
ubfx r10, \mx, #7, #7
and \mx, \mx, #0x7f
it gt
movgt \mx, r10
tst \my, #(0x7f << 14)
add \mx, r11, \mx, lsl #3
bne L(\type\()_8tap_hv)
adr r10, L(\type\()_8tap_h_tbl)
vdup.32 q14, r12 // 6 - intermediate_bits
ldr r9, [r10, r9, lsl #2]
vneg.s32 q14, q14 // -(6-intermediate_bits)
.ifc \type, put
vdup.16 q13, \bdmax // intermediate_bits
.else
vmov.i16 q13, #PREP_BIAS
.endif
add r10, r10, r9
.ifc \type, put
vneg.s16 q13, q13 // -intermediate_bits
.endif
bx r10
.align 2
L(\type\()_8tap_h_tbl):
.word 1280f - L(\type\()_8tap_h_tbl) + CONFIG_THUMB
.word 640f - L(\type\()_8tap_h_tbl) + CONFIG_THUMB
.word 320f - L(\type\()_8tap_h_tbl) + CONFIG_THUMB
.word 160f - L(\type\()_8tap_h_tbl) + CONFIG_THUMB
.word 80f - L(\type\()_8tap_h_tbl) + CONFIG_THUMB
.word 40f - L(\type\()_8tap_h_tbl) + CONFIG_THUMB
.word 20f - L(\type\()_8tap_h_tbl) + CONFIG_THUMB
20: // 2xN h
.ifc \type, put
add \mx, \mx, #2
vld1.32 {d0[]}, [\mx]
sub \src, \src, #2
add \ds2, \dst, \d_strd
add \sr2, \src, \s_strd
lsl \d_strd, \d_strd, #1
lsl \s_strd, \s_strd, #1
vmovl.s8 q0, d0
2:
vld1.16 {q2}, [\src], \s_strd
vld1.16 {q3}, [\sr2], \s_strd
vext.8 d5, d4, d5, #2
vext.8 d7, d6, d7, #2
subs \h, \h, #2
vtrn.32 d4, d6
vtrn.32 d5, d7
vmull.s16 q1, d4, d0[0]
vmlal.s16 q1, d5, d0[1]
vmlal.s16 q1, d6, d0[2]
vmlal.s16 q1, d7, d0[3]
vrshl.s32 q1, q1, q14 // -(6-intermediate_bits)
vqmovun.s32 d2, q1
vrshl.s16 d2, d2, d26 // -intermediate_bits
vmin.u16 d2, d2, d30
vst1.32 {d2[0]}, [\dst, :32], \d_strd
vst1.32 {d2[1]}, [\ds2, :32], \d_strd
bgt 2b
pop {r4-r11,pc}
.endif
40: // 4xN h
add \mx, \mx, #2
vld1.32 {d0[]}, [\mx]
sub \src, \src, #2
add \ds2, \dst, \d_strd
add \sr2, \src, \s_strd
lsl \d_strd, \d_strd, #1
lsl \s_strd, \s_strd, #1
vmovl.s8 q0, d0
4:
vld1.16 {q8}, [\src], \s_strd
vld1.16 {q11}, [\sr2], \s_strd
vext.8 d18, d16, d17, #2
vext.8 d19, d16, d17, #4
vext.8 d20, d16, d17, #6
vext.8 d24, d22, d23, #2
vext.8 d25, d22, d23, #4
vext.8 d21, d22, d23, #6
subs \h, \h, #2
vmull.s16 q2, d16, d0[0]
vmlal.s16 q2, d18, d0[1]
vmlal.s16 q2, d19, d0[2]
vmlal.s16 q2, d20, d0[3]
vmull.s16 q3, d22, d0[0]
vmlal.s16 q3, d24, d0[1]
vmlal.s16 q3, d25, d0[2]
vmlal.s16 q3, d21, d0[3]
vrshl.s32 q2, q2, q14 // -(6-intermediate_bits)
vrshl.s32 q3, q3, q14 // -(6-intermediate_bits)
.ifc \type, put
vqmovun.s32 d4, q2
vqmovun.s32 d5, q3
vrshl.s16 q2, q2, q13 // -intermediate_bits
vmin.u16 q2, q2, q15
.else
vmovn.s32 d4, q2
vmovn.s32 d5, q3
vsub.i16 q2, q2, q13 // PREP_BIAS
.endif
vst1.16 {d4}, [\dst, :64], \d_strd
vst1.16 {d5}, [\ds2, :64], \d_strd
bgt 4b
pop {r4-r11,pc}
80:
160:
320:
640:
1280: // 8xN, 16xN, 32xN, ... h
vpush {q4-q5}
vld1.8 {d0}, [\mx, :64]
sub \src, \src, #6
add \ds2, \dst, \d_strd
add \sr2, \src, \s_strd
lsl \s_strd, \s_strd, #1
vmovl.s8 q0, d0
sub \s_strd, \s_strd, \w, lsl #1
sub \s_strd, \s_strd, #16
.ifc \type, put
lsl \d_strd, \d_strd, #1
sub \d_strd, \d_strd, \w, lsl #1
.endif
81:
vld1.16 {q8, q9}, [\src]!
vld1.16 {q10, q11}, [\sr2]!
mov \mx, \w
8:
vmull.s16 q1, d16, d0[0]
vmull.s16 q2, d17, d0[0]
vmull.s16 q3, d20, d0[0]
vmull.s16 q4, d21, d0[0]
.irpc i, 1234567
vext.8 q12, q8, q9, #(2*\i)
vext.8 q5, q10, q11, #(2*\i)
.if \i < 4
vmlal.s16 q1, d24, d0[\i]
vmlal.s16 q2, d25, d0[\i]
vmlal.s16 q3, d10, d0[\i]
vmlal.s16 q4, d11, d0[\i]
.else
vmlal.s16 q1, d24, d1[\i-4]
vmlal.s16 q2, d25, d1[\i-4]
vmlal.s16 q3, d10, d1[\i-4]
vmlal.s16 q4, d11, d1[\i-4]
.endif
.endr
subs \mx, \mx, #8
vrshl.s32 q1, q1, q14 // -(6-intermediate_bits)
vrshl.s32 q2, q2, q14 // -(6-intermediate_bits)
vrshl.s32 q3, q3, q14 // -(6-intermediate_bits)
vrshl.s32 q4, q4, q14 // -(6-intermediate_bits)
.ifc \type, put
vqmovun.s32 d2, q1
vqmovun.s32 d3, q2
vqmovun.s32 d4, q3
vqmovun.s32 d5, q4
vrshl.s16 q1, q1, q13 // -intermediate_bits
vrshl.s16 q2, q2, q13 // -intermediate_bits
vmin.u16 q1, q1, q15
vmin.u16 q2, q2, q15
.else
vmovn.s32 d2, q1
vmovn.s32 d3, q2
vmovn.s32 d4, q3
vmovn.s32 d5, q4
vsub.i16 q1, q1, q13 // PREP_BIAS
vsub.i16 q2, q2, q13 // PREP_BIAS
.endif
vst1.16 {q1}, [\dst, :128]!
vst1.16 {q2}, [\ds2, :128]!
ble 9f
vmov q8, q9
vmov q10, q11
vld1.16 {q9}, [\src]!
vld1.16 {q11}, [\sr2]!
b 8b
9:
add \dst, \dst, \d_strd
add \ds2, \ds2, \d_strd
add \src, \src, \s_strd
add \sr2, \sr2, \s_strd
subs \h, \h, #2
bgt 81b
vpop {q4-q5}
pop {r4-r11,pc}
L(\type\()_8tap_v):
cmp \h, #4
ubfx r10, \my, #7, #7
and \my, \my, #0x7f
it gt
movgt \my, r10
add \my, r11, \my, lsl #3
.ifc \type, prep
vdup.32 q14, r12 // 6 - intermediate_bits
vmov.i16 q15, #PREP_BIAS
.endif
adr r10, L(\type\()_8tap_v_tbl)
ldr r9, [r10, r9, lsl #2]
.ifc \type, prep
vneg.s32 q14, q14 // -(6-intermediate_bits)
.endif
add r10, r10, r9
bx r10
.align 2
L(\type\()_8tap_v_tbl):
.word 1280f - L(\type\()_8tap_v_tbl) + CONFIG_THUMB
.word 640f - L(\type\()_8tap_v_tbl) + CONFIG_THUMB
.word 320f - L(\type\()_8tap_v_tbl) + CONFIG_THUMB
.word 160f - L(\type\()_8tap_v_tbl) + CONFIG_THUMB
.word 80f - L(\type\()_8tap_v_tbl) + CONFIG_THUMB
.word 40f - L(\type\()_8tap_v_tbl) + CONFIG_THUMB
.word 20f - L(\type\()_8tap_v_tbl) + CONFIG_THUMB
20: // 2xN v
.ifc \type, put
bgt 28f
cmp \h, #2
add \my, \my, #2
vld1.32 {d0[]}, [\my]
sub \src, \src, \s_strd
add \ds2, \dst, \d_strd
add \sr2, \src, \s_strd
lsl \s_strd, \s_strd, #1
lsl \d_strd, \d_strd, #1
vmovl.s8 q0, d0
// 2x2 v
load_32 \src, \sr2, \s_strd, d1, d2, d3, d4, d5
interleave_1_32 d1, d2, d3, d4, d5
bgt 24f
vmull_vmlal_4 q8, d1, d2, d3, d4
vqrshrun_s32 6, q8, d16
vmin_u16 d30, d16
vst1_32 \d_strd, d16
pop {r4-r11,pc}
24: // 2x4 v
load_32 \sr2, \src, \s_strd, d6, d7
interleave_1_32 d5, d6, d7
vmull_vmlal_4 q8, d1, d2, d3, d4
vmull_vmlal_4 q9, d3, d4, d5, d6
vqrshrun_s32 6, q8, d16, q9, d17
vmin_u16 q15, q8
vst1_32 \d_strd, d16, d17
pop {r4-r11,pc}
28: // 2x6, 2x8, 2x12, 2x16 v
vld1.8 {d0}, [\my, :64]
sub \sr2, \src, \s_strd, lsl #1
add \ds2, \dst, \d_strd
sub \src, \sr2, \s_strd
lsl \d_strd, \d_strd, #1
lsl \s_strd, \s_strd, #1
vmovl.s8 q0, d0
load_32 \src, \sr2, \s_strd, d2, d3, d4, d5, d6, d7, d16
interleave_1_32 d2, d3, d4, d5, d6
interleave_1_32 d6, d7, d16
216:
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5 C=97 H=96 G=96