shithub: dav1d

Download patch

ref: 856662b429dc016e366332f9648ac590ce5d6c92
parent: 4ae3f5f7f330fa8b5d3ae0794eaac3c25dc4ae48
author: Martin Storsjö <[email protected]>
date: Fri Aug 28 06:43:20 EDT 2020

arm32: mc: NEON implementation of put/prep 8tap/bilin for 16 bpc

Examples of checkasm benchmarks:
                                  Cortex A7      A8      A9     A53     A72     A73
mc_8tap_regular_w8_0_16bpc_neon:      158.7   106.2   167.0   127.9    55.0    77.2
mc_8tap_regular_w8_h_16bpc_neon:     1000.8   557.5   749.2   609.2   401.4   485.4
mc_8tap_regular_w8_hv_16bpc_neon:    2278.9  1255.4  1352.5  1277.2   867.8   915.9
mc_8tap_regular_w8_v_16bpc_neon:     1060.0   393.6   485.5   448.3   298.0   298.2
mc_bilinear_w8_0_16bpc_neon:          159.7    96.6   161.1   123.7    55.4    74.7
mc_bilinear_w8_h_16bpc_neon:          342.3   250.8   352.9   239.0   158.4   165.1
mc_bilinear_w8_hv_16bpc_neon:         587.7   373.8   469.0   339.8   244.4   247.5
mc_bilinear_w8_v_16bpc_neon:          285.8   189.3   284.9   180.4   103.4   100.9
mct_8tap_regular_w8_0_16bpc_neon:     233.0   136.6   229.3   169.3    86.2    98.3
mct_8tap_regular_w8_h_16bpc_neon:    1106.8   588.3   817.9   654.1   406.4   489.8
mct_8tap_regular_w8_hv_16bpc_neon:   2473.3  1326.3  1428.2  1373.7   903.3   951.1
mct_8tap_regular_w8_v_16bpc_neon:    1266.0   474.1   581.3   505.9   382.0   373.4
mct_bilinear_w8_0_16bpc_neon:         232.9   126.2   225.0   166.3    86.2    91.7
mct_bilinear_w8_h_16bpc_neon:         380.6   270.6   386.0   259.7   154.1   151.9
mct_bilinear_w8_hv_16bpc_neon:        631.4   409.2   509.4   372.1   243.1   244.1
mct_bilinear_w8_v_16bpc_neon:         349.5   233.5   347.9   212.4   138.7   138.4

For comparison, the corresponding numbers for the existing arm64
implementation:

                                                         Cortex A53     A72     A73
mc_8tap_regular_w8_0_16bpc_neon:                               94.1    48.9    62.3
mc_8tap_regular_w8_h_16bpc_neon:                              570.4   388.1   467.3
mc_8tap_regular_w8_hv_16bpc_neon:                            1035.8   775.0   891.2
mc_8tap_regular_w8_v_16bpc_neon:                              399.8   284.5   278.2
mc_bilinear_w8_0_16bpc_neon:                                   90.0    44.3    57.4
mc_bilinear_w8_h_16bpc_neon:                                  191.7   158.7   156.4
mc_bilinear_w8_hv_16bpc_neon:                                 295.6   235.0   244.9
mc_bilinear_w8_v_16bpc_neon:                                  147.2    99.0    88.8
mct_8tap_regular_w8_0_16bpc_neon:                             139.4    78.4    84.9
mct_8tap_regular_w8_h_16bpc_neon:                             612.3   395.9   478.6
mct_8tap_regular_w8_hv_16bpc_neon:                           1113.0   804.3   963.5
mct_8tap_regular_w8_v_16bpc_neon:                             462.1   370.8   353.3
mct_bilinear_w8_0_16bpc_neon:                                 135.6    77.0    80.5
mct_bilinear_w8_h_16bpc_neon:                                 210.8   159.2   141.7
mct_bilinear_w8_hv_16bpc_neon:                                325.7   238.4   227.3
mct_bilinear_w8_v_16bpc_neon:                                 180.7   136.7   129.5

--- a/src/arm/32/mc16.S
+++ b/src/arm/32/mc16.S
@@ -272,3 +272,2158 @@
 bidir_fn avg, r6
 bidir_fn w_avg, r7
 bidir_fn mask, r7
+
+
+// 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:     // 2x8, 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:
+        subs            \h,  \h,  #8
+        load_32         \sr2, \src, \s_strd, d17, d18, d19, d20
+        load_32         \sr2, \src, \s_strd, d21, d22, d23, d24
+        interleave_1_32 d16, d17, d18, d19, d20
+        interleave_1_32 d20, d21, d22, d23, d24
+        vmull_vmlal_8   q13, d2,  d3,  d4,  d5,  d6,  d7,  d16, d17
+        vmull_vmlal_8   q1,  d4,  d5,  d6,  d7,  d16, d17, d18, d19
+        vmull_vmlal_8   q2,  d6,  d7,  d16, d17, d18, d19, d20, d21
+        vmull_vmlal_8   q3,  d16, d17, d18, d19, d20, d21, d22, d23
+        vqrshrun_s32    6,   q13, d26, q1,  d27, q2,  d2,  q3,  d3
+        vmin_u16        q15, q13, q1
+        vst1_32         \d_strd,  d26, d27
+        vst1_32         \d_strd,  d2,  d3
+        ble             0f
+        vmov            q1,  q9
+        vmov            q2,  q10
+        vmov            q3,  q11
+        vmov            d16, d24
+        b               216b
+0:
+        pop             {r4-r11,pc}
+.endif
+
+40:
+        bgt             480f
+
+        // 4x2, 4x4 v
+        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
+
+        load_reg        \src, \sr2, \s_strd, d1, d2, d3, d4, d5
+        vmull_vmlal_4   q8,  d1,  d2,  d3,  d4
+        vmull_vmlal_4   q9,  d2,  d3,  d4,  d5
+        shift_store_4   \type, \d_strd, q8, q9, d16, d17
+        ble             0f
+        load_reg        \sr2, \src, \s_strd, d6, d7
+        vmull_vmlal_4   q8,  d3,  d4,  d5,  d6
+        vmull_vmlal_4   q9,  d4,  d5,  d6,  d7
+        shift_store_4   \type, \d_strd, q8, q9, d16, d17
+0:
+        pop             {r4-r11,pc}
+
+480:    // 4x8, 4x16 v
+        vld1.8          {d0}, [\my, :64]
+        sub             \sr2, \src, \s_strd, lsl #1
+        add             \ds2, \dst, \d_strd
+        sub             \src, \sr2, \s_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+        vmovl.s8        q0,  d0
+
+        load_reg        \src, \sr2, \s_strd, d16, d17, d18, d19, d20, d21, d22
+
+48:
+        subs            \h,  \h,  #4
+        load_reg        \sr2, \src, \s_strd, d23, d24, d25, d26
+        vmull_vmlal_8   q1,  d16, d17, d18, d19, d20, d21, d22, d23
+        vmull_vmlal_8   q2,  d17, d18, d19, d20, d21, d22, d23, d24
+        vmull_vmlal_8   q3,  d18, d19, d20, d21, d22, d23, d24, d25
+        vmull_vmlal_8   q8,  d19, d20, d21, d22, d23, d24, d25, d26
+        shift_store_4   \type, \d_strd, q1, q2, d2, d3, q3, q8, d4, d5
+        ble             0f
+        vmov            q8,  q10
+        vmov            q9,  q11
+        vmov            q10, q12
+        vmov            d22, d26
+        b               48b
+0:
+        pop             {r4-r11,pc}
+
+80:
+        bgt             880f
+
+        // 8x2, 8x4 v
+        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
+
+        load_reg        \src, \sr2, \s_strd, q1, q2, q3, q8, q9
+        vmull_vmlal_4   q10, d2,  d4,  d6,  d16
+        vmull_vmlal_4   q11, d3,  d5,  d7,  d17
+        vmull_vmlal_4   q12, d4,  d6,  d16, d18
+        vmull_vmlal_4   q13, d5,  d7,  d17, d19
+        shift_store_8   \type, \d_strd, q10, q11, d20, d21, q12, q13, d22, d23
+        ble             0f
+        load_reg        \sr2, \src, \s_strd, q10, q11
+        vmull_vmlal_4   q1,  d6,  d16, d18, d20
+        vmull_vmlal_4   q2,  d7,  d17, d19, d21
+        vmull_vmlal_4   q12, d16, d18, d20, d22
+        vmull_vmlal_4   q13, d17, d19, d21, d23
+        shift_store_8   \type, \d_strd, q1, q2, d2, d3, q12, q13, d4, d5
+0:
+        pop             {r4-r11,pc}
+
+880:    // 8x6, 8x8, 8x16, 8x32 v
+1680:   // 16x8, 16x16, ...
+320:    // 32x8, 32x16, ...
+640:
+1280:
+        vpush           {q4-q7}
+        vld1.8          {d0}, [\my, :64]
+        sub             \src, \src, \s_strd
+        sub             \src, \src, \s_strd, lsl #1
+        vmovl.s8        q0,  d0
+        mov             \my, \h
+168:
+        add             \ds2, \dst, \d_strd
+        add             \sr2, \src, \s_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+
+        load_reg        \src, \sr2, \s_strd, q5, q6, q7, q8, q9, q10, q11
+
+88:
+        subs            \h,  \h,  #2
+        load_reg        \sr2, \src, \s_strd, q12, q13
+        vmull_vmlal_8   q1,  d10, d12, d14, d16, d18, d20, d22, d24
+        vmull_vmlal_8   q2,  d11, d13, d15, d17, d19, d21, d23, d25
+        vmull_vmlal_8   q3,  d12, d14, d16, d18, d20, d22, d24, d26
+        vmull_vmlal_8   q4,  d13, d15, d17, d19, d21, d23, d25, d27
+        shift_store_8   \type, \d_strd, q1, q2,  d2,  d3,  q3,  q4,  d4,  d5
+        ble             9f
+        subs            \h,  \h,  #2
+        load_reg        \sr2, \src, \s_strd, q1,  q2
+        vmull_vmlal_8   q3,  d14, d16, d18, d20, d22, d24, d26, d2
+        vmull_vmlal_8   q4,  d15, d17, d19, d21, d23, d25, d27, d3
+        vmull_vmlal_8   q5,  d16, d18, d20, d22, d24, d26, d2,  d4
+        vmull_vmlal_8   q6,  d17, d19, d21, d23, d25, d27, d3,  d5
+        shift_store_8   \type, \d_strd, q3, q4,  d6,  d7,  q5,  q6,  d8,  d9
+        ble             9f
+        vmov            q5,  q9
+        vmov            q6,  q10
+        vmov            q7,  q11
+        vmov            q8,  q12
+        vmov            q9,  q13
+        vmov            q10, q1
+        vmov            q11, q2
+        b               88b
+9:
+        subs            \w,  \w,  #8
+        ble             0f
+        asr             \s_strd, \s_strd, #1
+        asr             \d_strd, \d_strd, #1
+        mls             \src, \s_strd, \my, \src
+        mls             \dst, \d_strd, \my, \dst
+        sub             \src, \src, \s_strd, lsl #3
+        mov             \h,  \my
+        add             \src, \src, #16
+        add             \dst, \dst, #16
+        b               168b
+0:
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+
+160:
+        bgt             1680b
+
+        // 16x2, 16x4 v
+        vpush           {q6-q7}
+        add             \my, \my, #2
+        vld1.32         {d0[]}, [\my]
+        sub             \src, \src, \s_strd
+        vmovl.s8        q0,  d0
+
+        load_16s16      \src, \src, \s_strd, q6,  q7,  q8,  q9, q10, q11
+16:
+        load_16s16      \src, \src, \s_strd, q12, q13
+        subs            \h,  \h,  #1
+        vmull_vmlal_4   q1,  d12, d16, d20, d24
+        vmull_vmlal_4   q2,  d13, d17, d21, d25
+        vmull_vmlal_4   q3,  d14, d18, d22, d26
+        vmull_vmlal_4   q6,  d15, d19, d23, d27
+        shift_store_16  \type, \d_strd, q1, q2, d2, d3, q3, q6, d4, d5
+        ble             0f
+        vmov            q6,  q8
+        vmov            q7,  q9
+        vmov            q8,  q10
+        vmov            q9,  q11
+        vmov            q10, q12
+        vmov            q11, q13
+        b               16b
+0:
+        vpop            {q6-q7}
+        pop             {r4-r11,pc}
+
+
+L(\type\()_8tap_hv):
+        cmp             \h,  #4
+        ubfx            r10, \my, #7,  #7
+        and             \my, \my, #0x7f
+        it              gt
+        movgt           \my, r10
+4:
+        add             \my, r11, \my, lsl #3
+
+        adr             r10, L(\type\()_8tap_hv_tbl)
+        neg             r12, r12           // -(6-intermediate_bits)
+        ldr             r9,  [r10, r9, lsl #2]
+        vdup.32         q14, r12           // -(6-intermediate_bits)
+.ifc \type, put
+        neg             r8,  lr            // -(6+intermeidate_bits)
+.else
+        vmov.i16        q13, #PREP_BIAS
+.endif
+        add             r10, r10, r9
+.ifc \type, put
+        vdup.32         q13, r8            // -(6+intermediate_bits)
+.endif
+        bx              r10
+
+        .align 2
+L(\type\()_8tap_hv_tbl):
+        .word 1280f - L(\type\()_8tap_hv_tbl) + CONFIG_THUMB
+        .word 640f  - L(\type\()_8tap_hv_tbl) + CONFIG_THUMB
+        .word 320f  - L(\type\()_8tap_hv_tbl) + CONFIG_THUMB
+        .word 160f  - L(\type\()_8tap_hv_tbl) + CONFIG_THUMB
+        .word 80f   - L(\type\()_8tap_hv_tbl) + CONFIG_THUMB
+        .word 40f   - L(\type\()_8tap_hv_tbl) + CONFIG_THUMB
+        .word 20f   - L(\type\()_8tap_hv_tbl) + CONFIG_THUMB
+
+20:
+.ifc \type, put
+        add             \mx, \mx, #2
+        vld1.32         {d0[]}, [\mx]
+        bgt             280f
+        add             \my, \my, #2
+        vld1.32         {d2[]}, [\my]
+
+        // 2x2, 2x4 hv
+        sub             \sr2, \src, #2
+        sub             \src, \sr2, \s_strd
+        add             \ds2, \dst, \d_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+        vmovl.s8        q0,  d0
+        vmovl.s8        q1,  d2
+
+        vld1.16         {q11}, [\src], \s_strd
+        vext.8          d24, d22, d23, #2
+        vmull.s16       q11, d22, d0
+        vmull.s16       q12, d24, d0
+        vpadd.s32       d22, d22, d23
+        vpadd.s32       d23, d24, d25
+        vpadd.s32       d22, d22, d23
+        vrshl.s32       d16, d22, d28 // -(6-intermediate_bits)
+        vmovn.i32       d16, q8
+        bl              L(\type\()_8tap_filter_2)
+
+        vext.8          d16, d16, d16, #4
+        vext.8          d16, d16, d24, #4
+        vmov            d17, d24
+
+2:
+        bl              L(\type\()_8tap_filter_2)
+
+        vext.8          d18, d17, d24, #4
+        vmull.s16       q2,  d16, d2[0]
+        vmlal.s16       q2,  d17, d2[1]
+        vmlal.s16       q2,  d18, d2[2]
+        vmlal.s16       q2,  d24, d2[3]
+
+        vrshl.s32       q2,  q2,  q13 // -(6+intermediate_bits)
+        vqmovun.s32     d4,  q2
+        vmin.u16        d4,  d4,  d30
+        subs            \h,  \h,  #2
+        vst1.32         {d4[0]}, [\dst, :32], \d_strd
+        vst1.32         {d4[1]}, [\ds2, :32], \d_strd
+        ble             0f
+        vmov            d16, d18
+        vmov            d17, d24
+        b               2b
+
+280:    // 2x8, 2x16, 2x32 hv
+        vld1.8          {d2},  [\my, :64]
+        sub             \src, \src, #2
+        sub             \sr2, \src, \s_strd, lsl #1
+        sub             \src, \sr2, \s_strd
+        add             \ds2, \dst, \d_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+        vmovl.s8        q0,  d0
+        vmovl.s8        q1,  d2
+
+        vld1.16         {q11}, [\src], \s_strd
+        vext.8          d24, d22, d23, #2
+        vmull.s16       q11, d22, d0
+        vmull.s16       q12, d24, d0
+        vpadd.s32       d22, d22, d23
+        vpadd.s32       d23, d24, d25
+        vpadd.s32       d22, d22, d23
+        vrshl.s32       d16, d22, d28 // -(6-intermediate_bits)
+        vmovn.i32       d16, q8
+
+        bl              L(\type\()_8tap_filter_2)
+
+        vext.8          d16, d16, d16, #4
+        vext.8          d16, d16, d24, #4
+        vmov            d17, d24
+        bl              L(\type\()_8tap_filter_2)
+        vext.8          d18, d17, d24, #4
+        vmov            d19, d24
+        bl              L(\type\()_8tap_filter_2)
+        vext.8          d20, d19, d24, #4
+        vmov            d21, d24
+
+28:
+        bl              L(\type\()_8tap_filter_2)
+        vext.8          d22, d21, d24, #4
+        vmull.s16       q3,  d16, d2[0]
+        vmlal.s16       q3,  d17, d2[1]
+        vmlal.s16       q3,  d18, d2[2]
+        vmlal.s16       q3,  d19, d2[3]
+        vmlal.s16       q3,  d20, d3[0]
+        vmlal.s16       q3,  d21, d3[1]
+        vmlal.s16       q3,  d22, d3[2]
+        vmlal.s16       q3,  d24, d3[3]
+
+        vrshl.s32       q3,  q3,  q13 // -(6+intermediate_bits)
+        vqmovun.s32     d6,  q3
+        vmin.u16        d6,  d6,  d30
+        subs            \h,  \h,  #2
+        vst1.32         {d6[0]}, [\dst, :32], \d_strd
+        vst1.32         {d6[1]}, [\ds2, :32], \d_strd
+        ble             0f
+        vmov            q8,  q9
+        vmov            q9,  q10
+        vmov            d20, d22
+        vmov            d21, d24
+        b               28b
+0:
+        pop             {r4-r11,pc}
+
+L(\type\()_8tap_filter_2):
+        vld1.16         {q11}, [\sr2], \s_strd
+        vld1.16         {q12}, [\src], \s_strd
+        vext.8          d23, d22, d23, #2
+        vext.8          d25, d24, d25, #2
+        vtrn.32         q11, q12
+        vmull.s16       q3,  d22, d0[0]
+        vmlal.s16       q3,  d23, d0[1]
+        vmlal.s16       q3,  d24, d0[2]
+        vmlal.s16       q3,  d25, d0[3]
+        vrshl.s32       q3,  q3,  q14 // -(6-intermediate_bits)
+        vmovn.i32       d24, q3
+        bx              lr
+.endif
+
+40:
+        add             \mx, \mx, #2
+        vld1.32         {d0[]}, [\mx]
+        bgt             480f
+        add             \my, \my, #2
+        vld1.32         {d2[]}, [\my]
+        sub             \sr2, \src, #2
+        sub             \src, \sr2, \s_strd
+        add             \ds2, \dst, \d_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+        vmovl.s8        q0,  d0
+        vmovl.s8        q1,  d2
+
+        // 4x2, 4x4 hv
+        vld1.16         {q11}, [\src], \s_strd
+        vext.8          d24, d22, d23, #2
+        vext.8          d25, d22, d23, #4
+        vext.8          d23, d22, d23, #6
+        vmull.s16       q10, d22, d0[0]
+        vmlal.s16       q10, d24, d0[1]
+        vmlal.s16       q10, d25, d0[2]
+        vmlal.s16       q10, d23, d0[3]
+        vrshl.s32       q10, q10, q14 // -(6-intermediate_bits)
+        vmovn.i32       d17, q10
+
+        bl              L(\type\()_8tap_filter_4)
+        vmov            q9,  q12
+
+4:
+        bl              L(\type\()_8tap_filter_4)
+        vmull.s16       q2,  d17, d2[0]
+        vmlal.s16       q2,  d18, d2[1]
+        vmlal.s16       q2,  d19, d2[2]
+        vmlal.s16       q2,  d24, d2[3]
+        vmull.s16       q3,  d18, d2[0]
+        vmlal.s16       q3,  d19, d2[1]
+        vmlal.s16       q3,  d24, d2[2]
+        vmlal.s16       q3,  d25, d2[3]
+.ifc \type, put
+        vrshl.s32       q2,  q2,  q13 // -(6+intermediate_bits)
+        vrshl.s32       q3,  q3,  q13 // -(6+intermediate_bits)
+        vqmovun.s32     d4,  q2
+        vqmovun.s32     d5,  q3
+        vmin.u16        q2,  q2,  q15
+.else
+        vrshrn.i32      d4,  q2,  #6
+        vrshrn.i32      d5,  q3,  #6
+        vsub.i16        q2,  q2,  q13 // PREP_BIAS
+.endif
+        subs            \h,  \h,  #2
+
+        vst1.16         {d4}, [\dst, :64], \d_strd
+        vst1.16         {d5}, [\ds2, :64], \d_strd
+        ble             0f
+        vmov            d17, d19
+        vmov            q9,  q12
+        b               4b
+0:
+        pop             {r4-r11,pc}
+
+480:    // 4x8, 4x16, 4x32 hv
+        vpush           {d13-d15}
+        vld1.8          {d2},  [\my, :64]
+        sub             \src, \src, #2
+        sub             \sr2, \src, \s_strd, lsl #1
+        sub             \src, \sr2, \s_strd
+        add             \ds2, \dst, \d_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+        vmovl.s8        q0,  d0
+        vmovl.s8        q1,  d2
+
+        vld1.16         {q11}, [\src], \s_strd
+        vext.8          d24, d22, d23, #2
+        vext.8          d25, d22, d23, #4
+        vext.8          d23, d22, d23, #6
+        vmull.s16       q10, d22, d0[0]
+        vmlal.s16       q10, d24, d0[1]
+        vmlal.s16       q10, d25, d0[2]
+        vmlal.s16       q10, d23, d0[3]
+        vrshl.s32       q10, q10, q14 // -(6-intermediate_bits)
+        vmovn.i32       d13, q10
+
+        bl              L(\type\()_8tap_filter_4)
+        vmov            q7,  q12
+        bl              L(\type\()_8tap_filter_4)
+        vmov            q8,  q12
+        bl              L(\type\()_8tap_filter_4)
+        vmov            q9,  q12
+
+48:
+        bl              L(\type\()_8tap_filter_4)
+        vmull.s16       q2,  d13, d2[0]
+        vmlal.s16       q2,  d14, d2[1]
+        vmlal.s16       q2,  d15, d2[2]
+        vmlal.s16       q2,  d16, d2[3]
+        vmlal.s16       q2,  d17, d3[0]
+        vmlal.s16       q2,  d18, d3[1]
+        vmlal.s16       q2,  d19, d3[2]
+        vmlal.s16       q2,  d24, d3[3]
+        vmull.s16       q3,  d14, d2[0]
+        vmlal.s16       q3,  d15, d2[1]
+        vmlal.s16       q3,  d16, d2[2]
+        vmlal.s16       q3,  d17, d2[3]
+        vmlal.s16       q3,  d18, d3[0]
+        vmlal.s16       q3,  d19, d3[1]
+        vmlal.s16       q3,  d24, d3[2]
+        vmlal.s16       q3,  d25, d3[3]
+.ifc \type, put
+        vrshl.s32       q2,  q2,  q13 // -(6+intermediate_bits)
+        vrshl.s32       q3,  q3,  q13 // -(6+intermediate_bits)
+        vqmovun.s32     d4,  q2
+        vqmovun.s32     d5,  q3
+        vmin.u16        q2,  q2,  q15
+.else
+        vrshrn.i32      d4,  q2,  #6
+        vrshrn.i32      d5,  q3,  #6
+        vsub.i16        q2,  q2,  q13 // PREP_BIAS
+.endif
+        subs            \h,  \h,  #2
+        vst1.16         {d4}, [\dst, :64], \d_strd
+        vst1.16         {d5}, [\ds2, :64], \d_strd
+        ble             0f
+        vmov            d13, d15
+        vmov            q7,  q8
+        vmov            q8,  q9
+        vmov            q9,  q12
+        b               48b
+0:
+        vpop            {d13-d15}
+        pop             {r4-r11,pc}
+
+L(\type\()_8tap_filter_4):
+        vld1.16         {q10}, [\sr2], \s_strd
+        vld1.16         {q11}, [\src], \s_strd
+        vext.8          d24, d20, d21, #2
+        vext.8          d25, d20, d21, #4
+        vext.8          d21, d20, d21, #6
+        vmull.s16       q3,  d20, d0[0]
+        vmlal.s16       q3,  d24, d0[1]
+        vmlal.s16       q3,  d25, d0[2]
+        vmlal.s16       q3,  d21, d0[3]
+        vext.8          d24, d22, d23, #2
+        vext.8          d25, d22, d23, #4
+        vext.8          d23, d22, d23, #6
+        vmull.s16       q10, d22, d0[0]
+        vmlal.s16       q10, d24, d0[1]
+        vmlal.s16       q10, d25, d0[2]
+        vmlal.s16       q10, d23, d0[3]
+        vrshl.s32       q3,  q3,  q14 // -(6-intermediate_bits)
+        vrshl.s32       q10, q10, q14 // -(6-intermediate_bits)
+        vmovn.i32       d24, q3
+        vmovn.i32       d25, q10
+        bx              lr
+
+80:
+160:
+320:
+        bgt             880f
+        add             \my, \my, #2
+        vld1.8          {d0},  [\mx, :64]
+        vld1.32         {d2[]}, [\my]
+        sub             \src,  \src,  #6
+        sub             \src,  \src,  \s_strd
+        vmovl.s8        q0,  d0
+        vmovl.s8        q1,  d2
+        mov             \my, \h
+
+164:    // 8x2, 8x4, 16x2, 16x4, 32x2, 32x4 hv
+        add             \ds2, \dst, \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \d_strd, \d_strd, #1
+        lsl             \s_strd, \s_strd, #1
+
+        vld1.16         {q11, q12}, [\src], \s_strd
+        vmull.s16       q2,  d22, d0[0]
+        vmull.s16       q3,  d23, d0[0]
+        vdup.32         q14, r12      // -(6-intermediate_bits)
+.irpc i, 1234567
+        vext.8          q10, q11, q12, #(2*\i)
+.if \i < 4
+        vmlal.s16       q2,  d20, d0[\i]
+        vmlal.s16       q3,  d21, d0[\i]
+.else
+        vmlal.s16       q2,  d20, d1[\i - 4]
+        vmlal.s16       q3,  d21, d1[\i - 4]
+.endif
+.endr
+        vrshl.s32       q2,  q2,  q14 // -(6-intermediate_bits)
+        vrshl.s32       q3,  q3,  q14 // -(6-intermediate_bits)
+        vmovn.i32       d16, q2
+        vmovn.i32       d17, q3
+
+        bl              L(\type\()_8tap_filter_8)
+        vmov            q9,  q11
+        vmov            q10, q12
+
+8:
+        bl              L(\type\()_8tap_filter_8)
+        vmull.s16       q2,  d16, d2[0]
+        vmull.s16       q3,  d17, d2[0]
+        vmull.s16       q13, d18, d2[0]
+        vmull.s16       q14, d19, d2[0]
+.ifc \type, put
+        vdup.32         q8,  r8      // -(6+intermediate_bits)
+.endif
+        vmlal.s16       q2,  d18, d2[1]
+        vmlal.s16       q3,  d19, d2[1]
+        vmlal.s16       q13, d20, d2[1]
+        vmlal.s16       q14, d21, d2[1]
+        vmlal.s16       q2,  d20, d2[2]
+        vmlal.s16       q3,  d21, d2[2]
+        vmlal.s16       q13, d22, d2[2]
+        vmlal.s16       q14, d23, d2[2]
+        vmlal.s16       q2,  d22, d2[3]
+        vmlal.s16       q3,  d23, d2[3]
+        vmlal.s16       q13, d24, d2[3]
+        vmlal.s16       q14, d25, d2[3]
+.ifc \type, put
+        vdup.16         q9,  \bdmax  // bitdepth_max
+        vrshl.s32       q2,  q2,  q8 // -(6+intermediate_bits)
+        vrshl.s32       q3,  q3,  q8 // -(6+intermediate_bits)
+        vrshl.s32       q13, q13, q8 // -(6+intermediate_bits)
+        vrshl.s32       q14, q14, q8 // -(6+intermediate_bits)
+        vqmovun.s32     d4,  q2
+        vqmovun.s32     d5,  q3
+        vqmovun.s32     d6,  q13
+        vqmovun.s32     d7,  q14
+        vmin.u16        q2,  q2,  q15
+        vmin.u16        q3,  q3,  q15
+.else
+        vmov.i16        q9,  #PREP_BIAS
+        vrshrn.i32      d4,  q2,  #6
+        vrshrn.i32      d5,  q3,  #6
+        vrshrn.i32      d6,  q13, #6
+        vrshrn.i32      d7,  q14, #6
+        vsub.i16        q2,  q2,  q9 // PREP_BIAS
+        vsub.i16        q3,  q3,  q9 // PREP_BIAS
+.endif
+        subs            \h,  \h,  #2
+        vst1.16         {q2}, [\dst, :128], \d_strd
+        vst1.16         {q3}, [\ds2, :128], \d_strd
+        ble             9f
+        vmov            q8,  q10
+        vmov            q9,  q11
+        vmov            q10, q12
+        b               8b
+9:
+        subs            \w,  \w,  #8
+        ble             0f
+        asr             \s_strd,  \s_strd,  #1
+        asr             \d_strd,  \d_strd,  #1
+        mls             \src,  \s_strd,  \my,  \src
+        mls             \dst,  \d_strd,  \my,  \dst
+        sub             \src,  \src,  \s_strd,  lsl #2
+        mov             \h,  \my
+        add             \src,  \src,  #16
+        add             \dst,  \dst,  #16
+        b               164b
+0:
+        pop             {r4-r11,pc}
+
+880:    // 8x8, 8x16, ..., 16x8, ..., 32x8, ... hv
+640:
+1280:
+        vpush           {q4-q7}
+        vld1.8          {d0}, [\mx, :64]
+        vld1.8          {d2}, [\my, :64]
+        sub             \src,  \src,  #6
+        sub             \src,  \src,  \s_strd
+        sub             \src,  \src,  \s_strd, lsl #1
+        vmovl.s8        q0,  d0
+        vmovl.s8        q1,  d2
+        mov             \my, \h
+
+168:
+        add             \ds2, \dst, \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \d_strd, \d_strd, #1
+        lsl             \s_strd, \s_strd, #1
+
+        vld1.16         {q11, q12}, [\src], \s_strd
+        vmull.s16       q2,  d22, d0[0]
+        vmull.s16       q3,  d23, d0[0]
+        vdup.32         q14, r12      // -(6-intermediate_bits)
+.irpc i, 1234567
+        vext.8          q10, q11, q12, #(2*\i)
+.if \i < 4
+        vmlal.s16       q2,  d20, d0[\i]
+        vmlal.s16       q3,  d21, d0[\i]
+.else
+        vmlal.s16       q2,  d20, d1[\i - 4]
+        vmlal.s16       q3,  d21, d1[\i - 4]
+.endif
+.endr
+        vrshl.s32       q2,  q2,  q14 // -(6-intermediate_bits)
+        vrshl.s32       q3,  q3,  q14 // -(6-intermediate_bits)
+        vmovn.i32       d8,  q2
+        vmovn.i32       d9,  q3
+
+        bl              L(\type\()_8tap_filter_8)
+        vmov            q5,  q11
+        vmov            q6,  q12
+        bl              L(\type\()_8tap_filter_8)
+        vmov            q7,  q11
+        vmov            q8,  q12
+        bl              L(\type\()_8tap_filter_8)
+        vmov            q9,  q11
+        vmov            q10, q12
+
+88:
+        bl              L(\type\()_8tap_filter_8)
+        vmull.s16       q2,  d8,  d2[0]
+        vmull.s16       q3,  d9,  d2[0]
+        vmull.s16       q13, d10, d2[0]
+        vmull.s16       q14, d11, d2[0]
+.ifc \type, put
+        vdup.32         q4,  r8      // -(6+intermediate_bits)
+.endif
+        vmlal.s16       q2,  d10, d2[1]
+        vmlal.s16       q3,  d11, d2[1]
+        vmlal.s16       q13, d12, d2[1]
+        vmlal.s16       q14, d13, d2[1]
+        vmlal.s16       q2,  d12, d2[2]
+        vmlal.s16       q3,  d13, d2[2]
+        vmlal.s16       q13, d14, d2[2]
+        vmlal.s16       q14, d15, d2[2]
+        vmlal.s16       q2,  d14, d2[3]
+        vmlal.s16       q3,  d15, d2[3]
+        vmlal.s16       q13, d16, d2[3]
+        vmlal.s16       q14, d17, d2[3]
+        vmlal.s16       q2,  d16, d3[0]
+        vmlal.s16       q3,  d17, d3[0]
+        vmlal.s16       q13, d18, d3[0]
+        vmlal.s16       q14, d19, d3[0]
+        vmlal.s16       q2,  d18, d3[1]
+        vmlal.s16       q3,  d19, d3[1]
+        vmlal.s16       q13, d20, d3[1]
+        vmlal.s16       q14, d21, d3[1]
+        vmlal.s16       q2,  d20, d3[2]
+        vmlal.s16       q3,  d21, d3[2]
+        vmlal.s16       q13, d22, d3[2]
+        vmlal.s16       q14, d23, d3[2]
+        vmlal.s16       q2,  d22, d3[3]
+        vmlal.s16       q3,  d23, d3[3]
+        vmlal.s16       q13, d24, d3[3]
+        vmlal.s16       q14, d25, d3[3]
+.ifc \type, put
+        vrshl.s32       q2,  q2,  q4 // -(6+intermediate_bits)
+        vrshl.s32       q3,  q3,  q4 // -(6+intermediate_bits)
+        vrshl.s32       q13, q13, q4 // -(6+intermediate_bits)
+        vrshl.s32       q14, q14, q4 // -(6+intermediate_bits)
+        vqmovun.s32     d4,  q2
+        vqmovun.s32     d5,  q3
+        vqmovun.s32     d6,  q13
+        vqmovun.s32     d7,  q14
+        vmin.u16        q2,  q2,  q15
+        vmin.u16        q3,  q3,  q15
+.else
+        vmov.i16        q5,  #PREP_BIAS
+        vrshrn.i32      d4,  q2,  #6
+        vrshrn.i32      d5,  q3,  #6
+        vrshrn.i32      d6,  q13, #6
+        vrshrn.i32      d7,  q14, #6
+        vsub.i16        q2,  q2,  q5 // PREP_BIAS
+        vsub.i16        q3,  q3,  q5 // PREP_BIAS
+.endif
+        subs            \h,  \h,  #2
+        vst1.16         {q2}, [\dst, :128], \d_strd
+        vst1.16         {q3}, [\ds2, :128], \d_strd
+        ble             9f
+        vmov            q4,  q6
+        vmov            q5,  q7
+        vmov            q6,  q8
+        vmov            q7,  q9
+        vmov            q8,  q10
+        vmov            q9,  q11
+        vmov            q10, q12
+        b               88b
+9:
+        subs            \w,  \w,  #8
+        ble             0f
+        asr             \s_strd,  \s_strd,  #1
+        asr             \d_strd,  \d_strd,  #1
+        mls             \src,  \s_strd,  \my,  \src
+        mls             \dst,  \d_strd,  \my,  \dst
+        sub             \src,  \src,  \s_strd,  lsl #3
+        mov             \h,  \my
+        add             \src,  \src,  #16
+        add             \dst,  \dst,  #16
+        b               168b
+0:
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+
+L(\type\()_8tap_filter_8):
+        vld1.16         {q13, q14}, [\sr2], \s_strd
+        vmull.s16       q2,  d26, d0[0]
+        vmull.s16       q3,  d27, d0[0]
+.irpc i, 1234567
+        vext.8          q12, q13, q14, #(2*\i)
+.if \i < 4
+        vmlal.s16       q2,  d24, d0[\i]
+        vmlal.s16       q3,  d25, d0[\i]
+.else
+        vmlal.s16       q2,  d24, d1[\i - 4]
+        vmlal.s16       q3,  d25, d1[\i - 4]
+.endif
+.endr
+        vdup.32         q12, r12      // -(6-intermediate_bits)
+        vld1.16         {q13, q14}, [\src], \s_strd
+        vrshl.s32       q2,  q2,  q12 // -(6-intermediate_bits)
+        vrshl.s32       q3,  q3,  q12 // -(6-intermediate_bits)
+        vmovn.i32       d4,  q2
+        vmovn.i32       d5,  q3
+
+        vmull.s16       q3,  d26, d0[0]
+        vmull.s16       q11, d27, d0[0]
+.irpc i, 1234567
+        vext.8          q12, q13, q14, #(2*\i)
+.if \i < 4
+        vmlal.s16       q3,  d24, d0[\i]
+        vmlal.s16       q11, d25, d0[\i]
+.else
+        vmlal.s16       q3,  d24, d1[\i - 4]
+        vmlal.s16       q11, d25, d1[\i - 4]
+.endif
+.endr
+        vdup.32         q13, r12      // -(6-intermediate_bits)
+        vrshl.s32       q3,  q3,  q13 // -(6-intermediate_bits)
+        vrshl.s32       q11, q11, q13 // -(6-intermediate_bits)
+
+        vmovn.i32       d24, q3
+        vmovn.i32       d25, q11
+        vmov            q11, q2
+        bx              lr
+endfunc
+
+function \type\()_bilin_16bpc_neon, export=1
+        push            {r4-r11,lr}
+        ldrd            r4,  r5,  [sp, #36]
+        ldrd            r6,  r7,  [sp, #44]
+.ifc \bdmax, r8
+        ldr             r8,  [sp, #52]
+.endif
+        vdup.16         q1,  \mx
+        vdup.16         q3,  \my
+        rsb             r9,  \mx, #16
+        rsb             r10, \my, #16
+        vdup.16         q0,  r9
+        vdup.16         q2,  r10
+.ifc \type, prep
+        lsl             \d_strd, \w, #1
+.endif
+        clz             \bdmax,   \bdmax       // bitdepth_max
+        clz             r9,  \w
+        sub             \bdmax,   \bdmax,  #18 // intermediate_bits = clz(bitdepth_max) - 18
+        cmp             \mx, #0
+        sub             r9,  r9,  #24
+        rsb             r11, \bdmax, #4        // 4 - intermediate_bits
+        add             r12, \bdmax, #4        // 4 + intermediate_bits
+        bne             L(\type\()_bilin_h)
+        cmp             \my, #0
+        bne             L(\type\()_bilin_v)
+        b               \type\()_neon
+
+L(\type\()_bilin_h):
+        cmp             \my, #0
+        bne             L(\type\()_bilin_hv)
+
+        adr             r10, L(\type\()_bilin_h_tbl)
+        vdup.16         q15, r11               // 4 - intermediate_bits
+        ldr             r9,  [r10, r9, lsl #2]
+        vneg.s16        q15, q15               // -(4-intermediate_bits)
+.ifc \type, put
+        vdup.16         q14, \bdmax            // intermediate_bits
+.else
+        vmov.i16        q14, #PREP_BIAS
+.endif
+        add             r10, r10, r9
+.ifc \type, put
+        vneg.s16        q14, q14               // -intermediate_bits
+.endif
+        bx              r10
+
+        .align 2
+L(\type\()_bilin_h_tbl):
+        .word 1280f - L(\type\()_bilin_h_tbl) + CONFIG_THUMB
+        .word 640f  - L(\type\()_bilin_h_tbl) + CONFIG_THUMB
+        .word 320f  - L(\type\()_bilin_h_tbl) + CONFIG_THUMB
+        .word 160f  - L(\type\()_bilin_h_tbl) + CONFIG_THUMB
+        .word 80f   - L(\type\()_bilin_h_tbl) + CONFIG_THUMB
+        .word 40f   - L(\type\()_bilin_h_tbl) + CONFIG_THUMB
+        .word 20f   - L(\type\()_bilin_h_tbl) + CONFIG_THUMB
+
+20:     // 2xN h
+.ifc \type, put
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \d_strd,  \d_strd,  #1
+        lsl             \s_strd,  \s_strd,  #1
+2:
+        vld1.16         {d16}, [\src], \s_strd
+        vld1.16         {d18}, [\sr2], \s_strd
+        vext.8          d17, d16, d16, #2
+        vext.8          d19, d18, d18, #2
+        vtrn.32         d16, d18
+        vtrn.32         d17, d19
+        subs            \h,  \h,  #2
+        vmul.i16        d16, d16, d0
+        vmla.i16        d16, d17, d2
+        vrshl.u16       d16, d16, d30
+        vrshl.u16       d16, d16, d28
+        vst1.32         {d16[0]}, [\dst, :32], \d_strd
+        vst1.32         {d16[1]}, [\ds2, :32], \d_strd
+        bgt             2b
+        pop             {r4-r11,pc}
+.endif
+
+40:     // 4xN h
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \d_strd,  \d_strd,  #1
+        lsl             \s_strd,  \s_strd,  #1
+4:
+        vld1.16         {q8},  [\src], \s_strd
+        vld1.16         {q10}, [\sr2], \s_strd
+        vext.8          q9,  q8,  q8,  #2
+        vext.8          q11, q10, q10, #2
+        vmov            d17, d20
+        vmov            d19, d22
+        subs            \h,  \h,  #2
+        vmul.i16        q8,  q8,  q0
+        vmla.i16        q8,  q9,  q1
+        vrshl.u16       q8,  q8,  q15
+.ifc \type, put
+        vrshl.u16       q8,  q8,  q14
+.else
+        vsub.i16        q8,  q8,  q14
+.endif
+        vst1.16         {d16}, [\dst, :64], \d_strd
+        vst1.16         {d17}, [\ds2, :64], \d_strd
+        bgt             4b
+        pop             {r4-r11,pc}
+
+80:     // 8xN h
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \d_strd,  \d_strd,  #1
+        lsl             \s_strd,  \s_strd,  #1
+8:
+        vld1.16         {d16, d17, d18}, [\src], \s_strd
+        vld1.16         {d20, d21, d22}, [\sr2], \s_strd
+        vext.8          q9,  q8,  q9,  #2
+        vext.8          q11, q10, q11, #2
+        subs            \h,  \h,  #2
+        vmul.i16        q8,  q8,  q0
+        vmla.i16        q8,  q9,  q1
+        vmul.i16        q10, q10, q0
+        vmla.i16        q10, q11, q1
+        vrshl.u16       q8,  q8,  q15
+        vrshl.u16       q10, q10, q15
+.ifc \type, put
+        vrshl.u16       q8,  q8,  q14
+        vrshl.u16       q10, q10, q14
+.else
+        vsub.i16        q8,  q8,  q14
+        vsub.i16        q10, q10, q14
+.endif
+        vst1.16         {q8},  [\dst, :128], \d_strd
+        vst1.16         {q10}, [\ds2, :128], \d_strd
+        bgt             8b
+        pop             {r4-r11,pc}
+160:
+320:
+640:
+1280:   // 16xN, 32xN, ... h
+        vpush           {q4-q7}
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \s_strd,  \s_strd,  #1
+
+        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
+161:
+        vld1.16         {q4}, [\src]!
+        vld1.16         {q9}, [\sr2]!
+        mov             \mx, \w
+
+16:
+        vld1.16         {q5,  q6},  [\src]!
+        vld1.16         {q10, q11}, [\sr2]!
+        vext.8          q7,  q4,  q5,  #2
+        vext.8          q8,  q5,  q6,  #2
+        vext.8          q12, q9,  q10, #2
+        vext.8          q13, q10, q11, #2
+        vmul.i16        q4,  q4,  q0
+        vmla.i16        q4,  q7,  q1
+        vmul.i16        q5,  q5,  q0
+        vmla.i16        q5,  q8,  q1
+        vmul.i16        q9,  q9,  q0
+        vmla.i16        q9,  q12, q1
+        vmul.i16        q10, q10, q0
+        vmla.i16        q10, q13, q1
+        vrshl.u16       q4,  q4,  q15
+        vrshl.u16       q5,  q5,  q15
+        vrshl.u16       q9,  q9,  q15
+        vrshl.u16       q10, q10, q15
+        subs            \mx, \mx, #16
+.ifc \type, put
+        vrshl.u16       q4,  q4,  q14
+        vrshl.u16       q5,  q5,  q14
+        vrshl.u16       q9,  q9,  q14
+        vrshl.u16       q10, q10, q14
+.else
+        vsub.i16        q4,  q4,  q14
+        vsub.i16        q5,  q5,  q14
+        vsub.i16        q9,  q9,  q14
+        vsub.i16        q10, q10, q14
+.endif
+        vst1.16         {q4, q5},  [\dst, :128]!
+        vst1.16         {q9, q10}, [\ds2, :128]!
+        ble             9f
+
+        vmov            q4,  q6
+        vmov            q9,  q11
+        b               16b
+
+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             161b
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+
+
+L(\type\()_bilin_v):
+        cmp             \h,  #4
+        adr             r10, L(\type\()_bilin_v_tbl)
+.ifc \type, prep
+        vdup.16         q15, r11      // 4 - intermediate_bits
+.endif
+        ldr             r9,  [r10, r9, lsl #2]
+.ifc \type, prep
+        vmov.i16        q14, #PREP_BIAS
+        vneg.s16        q15, q15      // -(4-intermediate_bits)
+.endif
+        add             r10, r10, r9
+        bx              r10
+
+        .align 2
+L(\type\()_bilin_v_tbl):
+        .word 1280f - L(\type\()_bilin_v_tbl) + CONFIG_THUMB
+        .word 640f  - L(\type\()_bilin_v_tbl) + CONFIG_THUMB
+        .word 320f  - L(\type\()_bilin_v_tbl) + CONFIG_THUMB
+        .word 160f  - L(\type\()_bilin_v_tbl) + CONFIG_THUMB
+        .word 80f   - L(\type\()_bilin_v_tbl) + CONFIG_THUMB
+        .word 40f   - L(\type\()_bilin_v_tbl) + CONFIG_THUMB
+        .word 20f   - L(\type\()_bilin_v_tbl) + CONFIG_THUMB
+
+20:     // 2xN v
+.ifc \type, put
+        cmp             \h,  #2
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \s_strd,  \s_strd,  #1
+        lsl             \d_strd,  \d_strd,  #1
+
+        // 2x2 v
+        vld1.32         {d16[]}, [\src], \s_strd
+        bgt             24f
+        vld1.32         {d17[]}, [\sr2], \s_strd
+        vld1.32         {d18[]}, [\src], \s_strd
+        vext.8          d16, d16, d17, #4
+        vext.8          d17, d17, d18, #4
+        vmul.i16        d16, d16, d4
+        vmla.i16        d16, d17, d6
+        vrshr.u16       d16, d16, #4
+        vst1.32         {d16[0]}, [\dst, :32]
+        vst1.32         {d16[1]}, [\ds2, :32]
+        pop             {r4-r11,pc}
+24:     // 2x4, 2x8, ... v
+        vld1.32         {d17[]}, [\sr2], \s_strd
+        vld1.32         {d18[]}, [\src], \s_strd
+        vld1.32         {d19[]}, [\sr2], \s_strd
+        vld1.32         {d20[]}, [\src], \s_strd
+        vext.8          d16, d16, d17, #4
+        vext.8          d17, d17, d18, #4
+        vext.8          d18, d18, d19, #4
+        vext.8          d19, d19, d20, #4
+        vswp            d17, d18
+        vmul.i16        q8,  q8,  q2
+        vmla.i16        q8,  q9,  q3
+        subs            \h,  \h,  #4
+        vrshr.u16       q8,  q8,  #4
+        vst1.32         {d16[0]}, [\dst, :32], \d_strd
+        vst1.32         {d16[1]}, [\ds2, :32], \d_strd
+        vst1.32         {d17[0]}, [\dst, :32], \d_strd
+        vst1.32         {d17[1]}, [\ds2, :32], \d_strd
+        ble             0f
+        vmov            d16, d20
+        b               24b
+0:
+        pop             {r4-r11,pc}
+.endif
+
+40:     // 4xN v
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \s_strd,  \s_strd,  #1
+        lsl             \d_strd,  \d_strd,  #1
+        vld1.16         {d16}, [\src], \s_strd
+4:
+        vld1.16         {d17}, [\sr2], \s_strd
+        vld1.16         {d19}, [\src], \s_strd
+        vmov            d18, d17
+        vmul.i16        q8,  q8,  q2
+        vmla.i16        q8,  q9,  q3
+        subs            \h,  \h,  #2
+.ifc \type, put
+        vrshr.u16       q8,  q8,  #4
+.else
+        vrshl.u16       q8,  q8,  q15
+        vsub.i16        q8,  q8,  q14
+.endif
+        vst1.16         {d16}, [\dst, :64], \d_strd
+        vst1.16         {d17}, [\ds2, :64], \d_strd
+        ble             0f
+        vmov            d16, d19
+        b               4b
+0:
+        pop             {r4-r11,pc}
+
+80:     // 8xN v
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \s_strd,  \s_strd,  #1
+        lsl             \d_strd,  \d_strd,  #1
+        vld1.16         {q8},  [\src], \s_strd
+8:
+        vld1.16         {q9},  [\sr2], \s_strd
+        vld1.16         {q10}, [\src], \s_strd
+        vmul.i16        q8,  q8,  q2
+        vmla.i16        q8,  q9,  q3
+        vmul.i16        q9,  q9,  q2
+        vmla.i16        q9,  q10, q3
+        subs            \h,  \h,  #2
+.ifc \type, put
+        vrshr.u16       q8,  q8,  #4
+        vrshr.u16       q9,  q9,  #4
+.else
+        vrshl.u16       q8,  q8,  q15
+        vrshl.u16       q9,  q9,  q15
+        vsub.i16        q8,  q8,  q14
+        vsub.i16        q9,  q9,  q14
+.endif
+        vst1.16         {q8}, [\dst, :128], \d_strd
+        vst1.16         {q9}, [\ds2, :128], \d_strd
+        ble             0f
+        vmov            q8,  q10
+        b               8b
+0:
+        pop             {r4-r11,pc}
+
+160:    // 16xN, 32xN, ...
+320:
+640:
+1280:
+        mov             \my, \h
+1:
+        add             \ds2, \dst, \d_strd
+        add             \sr2, \src, \s_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+
+        vld1.16         {q8,  q9},  [\src], \s_strd
+2:
+        vld1.16         {q10, q11}, [\sr2], \s_strd
+        vld1.16         {q12, q13}, [\src], \s_strd
+        vmul.i16        q8,  q8,  q2
+        vmla.i16        q8,  q10, q3
+        vmul.i16        q9,  q9,  q2
+        vmla.i16        q9,  q11, q3
+        vmul.i16        q10, q10, q2
+        vmla.i16        q10, q12, q3
+        vmul.i16        q11, q11, q2
+        vmla.i16        q11, q13, q3
+        subs            \h,  \h,  #2
+.ifc \type, put
+        vrshr.u16       q8,  q8,  #4
+        vrshr.u16       q9,  q9,  #4
+        vrshr.u16       q10, q10, #4
+        vrshr.u16       q11, q11, #4
+.else
+        vrshl.u16       q8,  q8,  q15
+        vrshl.u16       q9,  q9,  q15
+        vrshl.u16       q10, q10, q15
+        vrshl.u16       q11, q11, q15
+        vsub.i16        q8,  q8,  q14
+        vsub.i16        q9,  q9,  q14
+        vsub.i16        q10, q10, q14
+        vsub.i16        q11, q11, q14
+.endif
+        vst1.16         {q8,  q9},  [\dst, :128], \d_strd
+        vst1.16         {q10, q11}, [\ds2, :128], \d_strd
+        ble             9f
+        vmov            q8,  q12
+        vmov            q9,  q13
+        b               2b
+9:
+        subs            \w,  \w,  #16
+        ble             0f
+        asr             \s_strd, \s_strd, #1
+        asr             \d_strd, \d_strd, #1
+        mls             \src, \s_strd, \my, \src
+        mls             \dst, \d_strd, \my, \dst
+        sub             \src, \src, \s_strd, lsl #1
+        mov             \h,  \my
+        add             \src, \src, #32
+        add             \dst, \dst, #32
+        b               1b
+0:
+        pop             {r4-r11,pc}
+
+L(\type\()_bilin_hv):
+        adr             r10, L(\type\()_bilin_hv_tbl)
+        vdup.16         q15, r11          // 4 - intermediate_bits
+        ldr             r9,  [r10, r9, lsl #2]
+        vneg.s16        q15, q15          // -(4-intermediate_bits)
+.ifc \type, put
+        vdup.32         q14, r12          // 4 + intermediate_bits
+.else
+        vmov.i16        q14, #PREP_BIAS
+.endif
+        add             r10, r10, r9
+.ifc \type, put
+        vneg.s32        q14, q14          // -(4+intermediate_bits)
+.endif
+        bx              r10
+
+        .align 2
+L(\type\()_bilin_hv_tbl):
+        .word 1280f - L(\type\()_bilin_hv_tbl) + CONFIG_THUMB
+        .word 640f  - L(\type\()_bilin_hv_tbl) + CONFIG_THUMB
+        .word 320f  - L(\type\()_bilin_hv_tbl) + CONFIG_THUMB
+        .word 160f  - L(\type\()_bilin_hv_tbl) + CONFIG_THUMB
+        .word 80f   - L(\type\()_bilin_hv_tbl) + CONFIG_THUMB
+        .word 40f   - L(\type\()_bilin_hv_tbl) + CONFIG_THUMB
+        .word 20f   - L(\type\()_bilin_hv_tbl) + CONFIG_THUMB
+
+20:     // 2xN hv
+.ifc \type, put
+        add             \sr2, \src, \s_strd
+        add             \ds2, \dst, \d_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+
+        vld1.16         {d20}, [\src], \s_strd
+        vext.8          d21, d20, d20, #2
+        vmul.i16        d16, d20, d0
+        vmla.i16        d16, d21, d2
+        vrshl.u16       d16, d16, d30
+        vext.8          d16, d16, d16, #4
+
+2:
+        vld1.16         {d20}, [\sr2], \s_strd
+        vld1.16         {d22}, [\src], \s_strd
+        vext.8          d21, d20, d20, #2
+        vext.8          d23, d22, d22, #2
+        vtrn.32         d20, d22
+        vtrn.32         d21, d23
+        vmul.i16        d18, d20, d0
+        vmla.i16        d18, d21, d2
+        vrshl.u16       d18, d18, d30
+
+        vext.8          d16, d16, d18, #4
+
+        vmull.u16       q8,  d16, d4
+        vmlal.u16       q8,  d18, d6
+        vrshl.u32       q8,  q8,  q14
+        vmovn.i32       d16, q8
+        subs            \h,  \h,  #2
+        vst1.32         {d16[0]}, [\dst, :32], \d_strd
+        vst1.32         {d16[1]}, [\ds2, :32], \d_strd
+        ble             0f
+        vmov            d16, d18
+        b               2b
+0:
+        pop             {r4-r11,pc}
+.endif
+
+40:     // 4xN hv
+        add             \sr2, \src, \s_strd
+        add             \ds2, \dst, \d_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+
+        vld1.16         {q10}, [\src], \s_strd
+        vext.8          d21, d20, d21, #2
+        vmul.i16        d16, d20, d0
+        vmla.i16        d16, d21, d2
+        vrshl.u16       d16, d16, d30
+
+4:
+        vld1.16         {q10}, [\sr2], \s_strd
+        vld1.16         {q11}, [\src], \s_strd
+        vext.8          d21, d20, d21, #2
+        vext.8          d23, d22, d23, #2
+        vswp            d21, d22
+        vmul.i16        q9,  q10, q0
+        vmla.i16        q9,  q11, q1
+        vrshl.u16       q9,  q9,  q15
+
+        vmull.u16       q10, d16, d4
+        vmlal.u16       q10, d18, d6
+        vmull.u16       q11, d18, d4
+        vmlal.u16       q11, d19, d6
+.ifc \type, put
+        vrshl.u32       q10, q10, q14
+        vrshl.u32       q11, q11, q14
+        vmovn.i32       d20, q10
+        vmovn.i32       d21, q11
+.else
+        vrshrn.i32      d20, q10, #4
+        vrshrn.i32      d21, q11, #4
+        vsub.i16        q10, q10, q14
+.endif
+        subs            \h,  \h,  #2
+        vst1.16         {d20}, [\dst, :64], \d_strd
+        vst1.16         {d21}, [\ds2, :64], \d_strd
+        ble             0f
+        vmov            d16, d19
+        b               4b
+0:
+        pop             {r4-r11,pc}
+
+80:     // 8xN, 16xN, ... hv
+160:
+320:
+640:
+1280:
+        mov             \my, \h
+
+1:
+        add             \sr2, \src, \s_strd
+        add             \ds2, \dst, \d_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+
+        vld1.16         {d20, d21, d22}, [\src], \s_strd
+        vext.8          q11, q10, q11, #2
+        vmul.i16        q8,  q10, q0
+        vmla.i16        q8,  q11, q1
+        vrshl.u16       q8,  q8,  q15
+
+2:
+        vld1.16         {d20, d21, d22}, [\sr2], \s_strd
+        vld1.16         {d24, d25, d26}, [\src], \s_strd
+        vext.8          q11, q10, q11, #2
+        vext.8          q13, q12, q13, #2
+        vmul.i16        q9,  q10, q0
+        vmla.i16        q9,  q11, q1
+        vmul.i16        q10, q12, q0
+        vmla.i16        q10, q13, q1
+        vrshl.u16       q9,  q9,  q15
+        vrshl.u16       q10, q10, q15
+
+        vmull.u16       q11, d16, d4
+        vmlal.u16       q11, d18, d6
+        vmull.u16       q12, d17, d4
+        vmlal.u16       q12, d19, d6
+        vmull.u16       q8,  d18, d4
+        vmlal.u16       q8,  d20, d6
+        vmull.u16       q9,  d19, d4
+        vmlal.u16       q9,  d21, d6
+.ifc \type, put
+        vrshl.u32       q11, q11, q14
+        vrshl.u32       q12, q12, q14
+        vrshl.u32       q8,  q8,  q14
+        vrshl.u32       q9,  q9,  q14
+        vmovn.i32       d22, q11
+        vmovn.i32       d23, q12
+        vmovn.i32       d16, q8
+        vmovn.i32       d17, q9
+.else
+        vrshrn.i32      d22, q11, #4
+        vrshrn.i32      d23, q12, #4
+        vrshrn.i32      d16, q8,  #4
+        vrshrn.i32      d17, q9,  #4
+        vsub.i16        q11, q11, q14
+        vsub.i16        q8,  q8,  q14
+.endif
+        subs            \h,  \h,  #2
+        vst1.16         {q11}, [\dst, :128], \d_strd
+        vst1.16         {q8},  [\ds2, :128], \d_strd
+        ble             9f
+        vmov            q8,  q10
+        b               2b
+9:
+        subs            \w,  \w,  #8
+        ble             0f
+        asr             \s_strd,  \s_strd,  #1
+        asr             \d_strd,  \d_strd,  #1
+        mls             \src,  \s_strd,  \my,  \src
+        mls             \dst,  \d_strd,  \my,  \dst
+        sub             \src,  \src,  \s_strd,  lsl #1
+        mov             \h,  \my
+        add             \src,  \src,  #16
+        add             \dst,  \dst,  #16
+        b               1b
+0:
+        pop             {r4-r11,pc}
+endfunc
+.endm
+
+filter_fn put,  r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10
+filter_fn prep, r0, r8, r1, r2, r3, r4, r5, r6, r7, r9, r10
--- a/src/arm/mc_init_tmpl.c
+++ b/src/arm/mc_init_tmpl.c
@@ -77,7 +77,6 @@
 
     if (!(flags & DAV1D_ARM_CPU_FLAG_NEON)) return;
 
-#if BITDEPTH == 8 || ARCH_AARCH64
     init_mc_fn (FILTER_2D_8TAP_REGULAR,        8tap_regular,        neon);
     init_mc_fn (FILTER_2D_8TAP_REGULAR_SMOOTH, 8tap_regular_smooth, neon);
     init_mc_fn (FILTER_2D_8TAP_REGULAR_SHARP,  8tap_regular_sharp,  neon);
@@ -99,7 +98,6 @@
     init_mct_fn(FILTER_2D_8TAP_SHARP_SMOOTH,   8tap_sharp_smooth,   neon);
     init_mct_fn(FILTER_2D_8TAP_SHARP,          8tap_sharp,          neon);
     init_mct_fn(FILTER_2D_BILINEAR,            bilin,               neon);
-#endif
 
     c->avg = BF(dav1d_avg, neon);
     c->w_avg = BF(dav1d_w_avg, neon);