;

    AREA |A$$code|, CODE, READONLY

    ALIGN 32
;---------------
; r0 uint32_t* pdst
; r1 const uint32_t* line0
; r2 const uint32_t* line1
; r4 width (in words)
; q0 4x32 sc
; q1 4x32 sc2
; q2 4x32 mask
merge_lines_tsh5

merge_tsh5_1more
    tst        r4, #1
    beq        merge_tsh5_2more

    vld1.32    {d16[0]},[r1]!
    vld1.32    {d24[0]},[r2]!
    vand       d8 , d16, d4   ; 0b
    vand       d9 , d24, d4   ; 1b
    vbic       d16, d16, d4   ; 0a
    vbic       d24, d24, d4   ; 1a
    vshr.u32   d16, d16, #5
    vshr.u32   d24, d24, #5
    vmul.u32   d16, d16, d2   ; b1 = 0a * sc2
    vmla.u32   d16, d24, d0   ;    + 1a * sc
    vmul.u32   d24, d8 , d2   ; b2 = 0b * sc2
    vmla.u32   d24, d9 , d0   ;    + 1b * sc
    vbic       d16, d16, d4
    vshr.u32   d24, d24, #5
    vand       d24, d24, d4
    vorr       d16, d16, d24
    vst1.32    {d16[0]},[r0]!

merge_tsh5_2more
    tst        r4, #2
    beq        merge_tsh5_4more

    vld1.32    {d16},[r1]!
    vld1.32    {d24},[r2]!
    vand       d8 , d16, d4   ; 0b
    vand       d9 , d24, d4   ; 1b
    vbic       d16, d16, d4   ; 0a
    vbic       d24, d24, d4   ; 1a
    vshr.u32   d16, d16, #5
    vshr.u32   d24, d24, #5
    vmul.u32   d16, d16, d2   ; b1 = 0a * sc2
    vmla.u32   d16, d24, d0   ;    + 1a * sc
    vmul.u32   d24, d8 , d2   ; b2 = 0b * sc2
    vmla.u32   d24, d9 , d0   ;    + 1b * sc
    vbic       d16, d16, d4
    vshr.u32   d24, d24, #5
    vand       d24, d24, d4
    vorr       d16, d16, d24
    vst1.32    {d16},[r0]!

merge_tsh5_4more
    tst        r4, #4
    beq        merge_tsh5_8more

    vld1.32    {d16,d17},[r1]!
    vld1.32    {d24,d25},[r2]!
    vand       q4 , q8 , q2   ; 0b
    vand       q5 , q12, q2   ; 1b
    vbic       q8 , q8 , q2   ; 0a
    vbic       q12, q12, q2   ; 1a
    vshr.u32   q8 , q8 , #5
    vshr.u32   q12, q12, #5
    vmul.u32   q8 , q8 , q1   ; b1 = 0a * sc2
    vmla.u32   q8 , q12, q0   ;    + 1a * sc
    vmul.u32   q12, q4 , q1   ; b2 = 0b * sc2
    vmla.u32   q12, q5 , q0   ;    + 1b * sc
    vbic       q8 , q8 , q2
    vshr.u32   q12, q12, #5
    vand       q12, q12, q2
    vorr       q8 , q8 , q12
    vst1.32    {d16,d17},[r0]!

merge_tsh5_8more
    tst        r4, #8
    beq        merge_tsh5_16more

    vld1.32    {d16,d17,d18,d19},[r1]!
    vld1.32    {d24,d25,d26,d27},[r2]!
    vand       q4 , q8 , q2   ; 0b
    vand       q5 , q12, q2   ; 1b
    vbic       q8 , q8 , q2   ; 0a
    vbic       q12, q12, q2   ; 1a
    vshr.u32   q8 , q8 , #5
    vshr.u32   q12, q12, #5
    vmul.u32   q8 , q8 , q1   ; b1 = 0a * sc2
    vmla.u32   q8 , q12, q0   ;    + 1a * sc
    vmul.u32   q12, q4 , q1   ; b2 = 0b * sc2
    vmla.u32   q12, q5 , q0   ;    + 1b * sc
    vbic       q8 , q8 , q2
    vshr.u32   q12, q12, #5
    vand       q12, q12, q2
    vorr       q8 , q8 , q12

    vand       q4 , q9 , q2   ; 0b
    vand       q5 , q13, q2   ; 1b
    vbic       q9 , q9 , q2   ; 0a
    vbic       q13, q13, q2   ; 1a
    vshr.u32   q9 , q9 , #5
    vshr.u32   q13, q13, #5
    vmul.u32   q9 , q9 , q1   ; b1 = 0a * sc2
    vmla.u32   q9 , q13, q0   ;    + 1a * sc
    vmul.u32   q13, q4 , q1   ; b2 = 0b * sc2
    vmla.u32   q13, q5 , q0   ;    + 1b * sc
    vbic       q9 , q9 , q2
    vshr.u32   q13, q13, #5
    vand       q13, q13, q2
    vorr       q9 , q9 , q13
    vst1.32    {d16,d17,d18,d19},[r0]!

merge_tsh5_16more
    bic        r4, r4, #15
    cmp        r4, #0
    beq        merge_tsh5_end

merge_tsh5_loop16
    vld1.32    {d16,d17,d18,d19},[r1]!
    vld1.32    {d24,d25,d26,d27},[r2]!
    vld1.32    {d20,d21,d22,d23},[r1]!
    vld1.32    {d28,d29,d30,d31},[r2]!
    vand       q4 , q8 , q2   ; 0b
    vand       q5 , q12, q2   ; 1b
    vbic       q8 , q8 , q2   ; 0a
    vbic       q12, q12, q2   ; 1a
    vshr.u32   q8 , q8 , #5
    vshr.u32   q12, q12, #5
    vmul.u32   q8 , q8 , q1   ; b1 = 0a * sc2
    vmla.u32   q8 , q12, q0   ;    + 1a * sc
    vmul.u32   q12, q4 , q1   ; b2 = 0b * sc2
    vmla.u32   q12, q5 , q0   ;    + 1b * sc
    vbic       q8 , q8 , q2
    vshr.u32   q12, q12, #5
    vand       q12, q12, q2
    vorr       q8 , q8 , q12

    vand       q4 , q9 , q2   ; 0b
    vand       q5 , q13, q2   ; 1b
    vbic       q9 , q9 , q2   ; 0a
    vbic       q13, q13, q2   ; 1a
    vshr.u32   q9 , q9 , #5
    vshr.u32   q13, q13, #5
    vmul.u32   q9 , q9 , q1   ; b1 = 0a * sc2
    vmla.u32   q9 , q13, q0   ;    + 1a * sc
    vmul.u32   q13, q4 , q1   ; b2 = 0b * sc2
    vmla.u32   q13, q5 , q0   ;    + 1b * sc
    vbic       q9 , q9 , q2
    vshr.u32   q13, q13, #5
    vand       q13, q13, q2
    vorr       q9 , q9 , q13

    vand       q4 , q10, q2   ; 0b
    vand       q5 , q14, q2   ; 1b
    vbic       q10, q10, q2   ; 0a
    vbic       q14, q14, q2   ; 1a
    vshr.u32   q10, q10, #5
    vshr.u32   q14, q14, #5
    vmul.u32   q10, q10, q1   ; b1 = 0a * sc2
    vmla.u32   q10, q14, q0   ;    + 1a * sc
    vmul.u32   q14, q4 , q1   ; b2 = 0b * sc2
    vmla.u32   q14, q5 , q0   ;    + 1b * sc
    vbic       q10, q10, q2
    vshr.u32   q14, q14, #5
    vand       q14, q14, q2
    vorr       q10, q10, q14
    vst1.32    {d16,d17,d18,d19},[r0]!

    vand       q4 , q11, q2   ; 0b
    vand       q5 , q15, q2   ; 1b
    vbic       q11, q11, q2   ; 0a
    vbic       q15, q15, q2   ; 1a
    vshr.u32   q11, q11, #5
    vshr.u32   q15, q15, #5
    vmul.u32   q11, q11, q1   ; b1 = 0a * sc2
    vmla.u32   q11, q15, q0   ;    + 1a * sc
    vmul.u32   q15, q4 , q1   ; b2 = 0b * sc2
    vmla.u32   q15, q5 , q0   ;    + 1b * sc
    vbic       q11, q11, q2
    vshr.u32   q15, q15, #5
    vand       q15, q15, q2
    vorr       q11, q11, q15
    vst1.32    {d20,d21,d22,d23},[r0]!
    subs       r4, r4, #16
    bgt        merge_tsh5_loop16

merge_tsh5_end
    mov        pc, lr

    ALIGN 32
;---------------
; r0 uint32_t* pdst
; r1 const uint32_t* line0
; r2 const uint32_t* line1
; r4 width (in words)
; q0 4x32 sc
; q1 4x32 sc2
; q2 4x32 mask
; q3 4x32 alpha mask
merge_lines_ash5

merge_ash5_1more
    tst        r4, #1
    beq        merge_ash5_2more

    vld1.32    {d16[0]},[r1]!
    vld1.32    {d24[0]},[r2]!
    vbic       d16, d16, d6
    vbic       d24, d24, d6
    vand       d8 , d16, d4   ; 0b
    vand       d9 , d24, d4   ; 1b
    vbic       d16, d16, d4   ; 0a
    vbic       d24, d24, d4   ; 1a
    vshr.u32   d16, d16, #5
    vshr.u32   d24, d24, #5
    vmul.u32   d16, d16, d2   ; b1 = 0a * sc2
    vmla.u32   d16, d24, d0   ;    + 1a * sc
    vmul.u32   d24, d8 , d2   ; b2 = 0b * sc2
    vmla.u32   d24, d9 , d0   ;    + 1b * sc
    vbic       d16, d16, d4
    vshr.u32   d24, d24, #5
    vand       d24, d24, d4
    vorr       d16, d16, d24
    vorr       d16, d16, d6
    vst1.32    {d16[0]},[r0]!

merge_ash5_2more
    tst        r4, #2
    beq        merge_ash5_4more

    vld1.32    {d16},[r1]!
    vld1.32    {d24},[r2]!
    vbic       d16, d16, d6
    vbic       d24, d24, d6
    vand       d8 , d16, d4   ; 0b
    vand       d9 , d24, d4   ; 1b
    vbic       d16, d16, d4   ; 0a
    vbic       d24, d24, d4   ; 1a
    vshr.u32   d16, d16, #5
    vshr.u32   d24, d24, #5
    vmul.u32   d16, d16, d2   ; b1 = 0a * sc2
    vmla.u32   d16, d24, d0   ;    + 1a * sc
    vmul.u32   d24, d8 , d2   ; b2 = 0b * sc2
    vmla.u32   d24, d9 , d0   ;    + 1b * sc
    vbic       d16, d16, d4
    vshr.u32   d24, d24, #5
    vand       d24, d24, d4
    vorr       d16, d16, d24
    vorr       d16, d16, d6
    vst1.32    {d16},[r0]!

merge_ash5_4more
    tst        r4, #4
    beq        merge_ash5_8more

    vld1.32    {d16,d17},[r1]!
    vld1.32    {d24,d25},[r2]!
    vbic       q8 , q8 , q3
    vbic       q12, q12, q3
    vand       q4 , q8 , q2   ; 0b
    vand       q5 , q12, q2   ; 1b
    vbic       q8 , q8 , q2   ; 0a
    vbic       q12, q12, q2   ; 1a
    vshr.u32   q8 , q8 , #5
    vshr.u32   q12, q12, #5
    vmul.u32   q8 , q8 , q1   ; b1 = 0a * sc2
    vmla.u32   q8 , q12, q0   ;    + 1a * sc
    vmul.u32   q12, q4 , q1   ; b2 = 0b * sc2
    vmla.u32   q12, q5 , q0   ;    + 1b * sc
    vbic       q8 , q8 , q2
    vshr.u32   q12, q12, #5
    vand       q12, q12, q2
    vorr       q8 , q8 , q12
    vorr       q8 , q8 , q3
    vst1.32    {d16,d17},[r0]!

merge_ash5_8more
    tst        r4, #8
    beq        merge_ash5_16more

    vld1.32    {d16,d17,d18,d19},[r1]!
    vld1.32    {d24,d25,d26,d27},[r2]!
    vbic       q8 , q8 , q3
    vbic       q12, q12, q3
    vand       q4 , q8 , q2   ; 0b
    vand       q5 , q12, q2   ; 1b
    vbic       q8 , q8 , q2   ; 0a
    vbic       q12, q12, q2   ; 1a
    vshr.u32   q8 , q8 , #5
    vshr.u32   q12, q12, #5
    vmul.u32   q8 , q8 , q1   ; b1 = 0a * sc2
    vmla.u32   q8 , q12, q0   ;    + 1a * sc
    vmul.u32   q12, q4 , q1   ; b2 = 0b * sc2
    vmla.u32   q12, q5 , q0   ;    + 1b * sc
    vbic       q8 , q8 , q2
    vshr.u32   q12, q12, #5
    vand       q12, q12, q2
    vorr       q8 , q8 , q12
    vorr       q8 , q8 , q3

    vbic       q9 , q9 , q3
    vbic       q13, q13, q3
    vand       q4 , q9 , q2   ; 0b
    vand       q5 , q13, q2   ; 1b
    vbic       q9 , q9 , q2   ; 0a
    vbic       q13, q13, q2   ; 1a
    vshr.u32   q9 , q9 , #5
    vshr.u32   q13, q13, #5
    vmul.u32   q9 , q9 , q1   ; b1 = 0a * sc2
    vmla.u32   q9 , q13, q0   ;    + 1a * sc
    vmul.u32   q13, q4 , q1   ; b2 = 0b * sc2
    vmla.u32   q13, q5 , q0   ;    + 1b * sc
    vbic       q9 , q9 , q2
    vshr.u32   q13, q13, #5
    vand       q13, q13, q2
    vorr       q9 , q9 , q13
    vorr       q9 , q9 , q3
    vst1.32    {d16,d17,d18,d19},[r0]!

merge_ash5_16more
    bic        r4, r4, #15
    cmp        r4, #0
    beq        merge_ash5_end

merge_ash5_loop16
    vld1.32    {d16,d17,d18,d19},[r1]!
    vld1.32    {d24,d25,d26,d27},[r2]!
    vld1.32    {d20,d21,d22,d23},[r1]!
    vld1.32    {d28,d29,d30,d31},[r2]!
    vbic       q8 , q8 , q3
    vbic       q12, q12, q3
    vand       q4 , q8 , q2   ; 0b
    vand       q5 , q12, q2   ; 1b
    vbic       q8 , q8 , q2   ; 0a
    vbic       q12, q12, q2   ; 1a
    vshr.u32   q8 , q8 , #5
    vshr.u32   q12, q12, #5
    vmul.u32   q8 , q8 , q1   ; b1 = 0a * sc2
    vmla.u32   q8 , q12, q0   ;    + 1a * sc
    vmul.u32   q12, q4 , q1   ; b2 = 0b * sc2
    vmla.u32   q12, q5 , q0   ;    + 1b * sc
    vbic       q8 , q8 , q2
    vshr.u32   q12, q12, #5
    vand       q12, q12, q2
    vorr       q8 , q8 , q12
    vorr       q8 , q8 , q3

    vbic       q9 , q9 , q3
    vbic       q13, q13, q3
    vand       q4 , q9 , q2   ; 0b
    vand       q5 , q13, q2   ; 1b
    vbic       q9 , q9 , q2   ; 0a
    vbic       q13, q13, q2   ; 1a
    vshr.u32   q9 , q9 , #5
    vshr.u32   q13, q13, #5
    vmul.u32   q9 , q9 , q1   ; b1 = 0a * sc2
    vmla.u32   q9 , q13, q0   ;    + 1a * sc
    vmul.u32   q13, q4 , q1   ; b2 = 0b * sc2
    vmla.u32   q13, q5 , q0   ;    + 1b * sc
    vbic       q9 , q9 , q2
    vshr.u32   q13, q13, #5
    vand       q13, q13, q2
    vorr       q9 , q9 , q13
    vorr       q9 , q9 , q3

    vbic       q10, q10, q3
    vbic       q14, q14, q3
    vand       q4 , q10, q2   ; 0b
    vand       q5 , q14, q2   ; 1b
    vbic       q10, q10, q2   ; 0a
    vbic       q14, q14, q2   ; 1a
    vshr.u32   q10, q10, #5
    vshr.u32   q14, q14, #5
    vmul.u32   q10, q10, q1   ; b1 = 0a * sc2
    vmla.u32   q10, q14, q0   ;    + 1a * sc
    vmul.u32   q14, q4 , q1   ; b2 = 0b * sc2
    vmla.u32   q14, q5 , q0   ;    + 1b * sc
    vbic       q10, q10, q2
    vshr.u32   q14, q14, #5
    vand       q14, q14, q2
    vorr       q10, q10, q14
    vorr       q10, q10, q3
    vst1.32    {d16,d17,d18,d19},[r0]!

    vbic       q11, q11, q3
    vbic       q15, q15, q3
    vand       q4 , q11, q2   ; 0b
    vand       q5 , q15, q2   ; 1b
    vbic       q11, q11, q2   ; 0a
    vbic       q15, q15, q2   ; 1a
    vshr.u32   q11, q11, #5
    vshr.u32   q15, q15, #5
    vmul.u32   q11, q11, q1   ; b1 = 0a * sc2
    vmla.u32   q11, q15, q0   ;    + 1a * sc
    vmul.u32   q15, q4 , q1   ; b2 = 0b * sc2
    vmla.u32   q15, q5 , q0   ;    + 1b * sc
    vbic       q11, q11, q2
    vshr.u32   q15, q15, #5
    vand       q15, q15, q2
    vorr       q11, q11, q15
    vorr       q11, q11, q3
    vst1.32    {d20,d21,d22,d23},[r0]!
    subs       r4, r4, #16
    bgt        merge_ash5_loop16

merge_ash5_end
    mov        pc, lr

    ALIGN 32
;---------------
; r0 uint32_t* pdst
; r1 const uint32_t* line0
; r2 const uint32_t* line1
; r4 width (in words)
; q0 4x32 sc
; q1 4x32 sc2
; q2 4x32 mask
merge_lines_sh4

merge_sh4_1more
    tst        r4, #1
    beq        merge_sh4_2more

    vld1.32    {d16[0]},[r1]!
    vld1.32    {d24[0]},[r2]!
    vand       d8 , d16, d4   ; 0b
    vand       d9 , d24, d4   ; 1b
    vbic       d16, d16, d4   ; 0a
    vbic       d24, d24, d4   ; 1a
    vshr.u32   d16, d16, #4
    vshr.u32   d24, d24, #4
    vmul.u32   d16, d16, d2   ; b1 = 0a * sc2
    vmla.u32   d16, d24, d0   ;    + 1a * sc
    vmul.u32   d24, d8 , d2   ; b2 = 0b * sc2
    vmla.u32   d24, d9 , d0   ;    + 1b * sc
    vbic       d16, d16, d4
    vshr.u32   d24, d24, #4
    vand       d24, d24, d4
    vorr       d16, d16, d24
    vst1.32    {d16[0]},[r0]!

merge_sh4_2more
    tst        r4, #2
    beq        merge_sh4_4more

    vld1.32    {d16},[r1]!
    vld1.32    {d24},[r2]!
    vand       d8 , d16, d4   ; 0b
    vand       d9 , d24, d4   ; 1b
    vbic       d16, d16, d4   ; 0a
    vbic       d24, d24, d4   ; 1a
    vshr.u32   d16, d16, #4
    vshr.u32   d24, d24, #4
    vmul.u32   d16, d16, d2   ; b1 = 0a * sc2
    vmla.u32   d16, d24, d0   ;    + 1a * sc
    vmul.u32   d24, d8 , d2   ; b2 = 0b * sc2
    vmla.u32   d24, d9 , d0   ;    + 1b * sc
    vbic       d16, d16, d4
    vshr.u32   d24, d24, #4
    vand       d24, d24, d4
    vorr       d16, d16, d24
    vst1.32    {d16},[r0]!

merge_sh4_4more
    tst        r4, #4
    beq        merge_sh4_8more

    vld1.32    {d16,d17},[r1]!
    vld1.32    {d24,d25},[r2]!
    vand       q4 , q8 , q2   ; 0b
    vand       q5 , q12, q2   ; 1b
    vbic       q8 , q8 , q2   ; 0a
    vbic       q12, q12, q2   ; 1a
    vshr.u32   q8 , q8 , #4
    vshr.u32   q12, q12, #4
    vmul.u32   q8 , q8 , q1   ; b1 = 0a * sc2
    vmla.u32   q8 , q12, q0   ;    + 1a * sc
    vmul.u32   q12, q4 , q1   ; b2 = 0b * sc2
    vmla.u32   q12, q5 , q0   ;    + 1b * sc
    vbic       q8 , q8 , q2
    vshr.u32   q12, q12, #4
    vand       q12, q12, q2
    vorr       q8 , q8 , q12
    vst1.32    {d16,d17},[r0]!

merge_sh4_8more
    tst        r4, #8
    beq        merge_sh4_16more

    vld1.32    {d16,d17,d18,d19},[r1]!
    vld1.32    {d24,d25,d26,d27},[r2]!
    vand       q4 , q8 , q2   ; 0b
    vand       q5 , q12, q2   ; 1b
    vbic       q8 , q8 , q2   ; 0a
    vbic       q12, q12, q2   ; 1a
    vshr.u32   q8 , q8 , #4
    vshr.u32   q12, q12, #4
    vmul.u32   q8 , q8 , q1   ; b1 = 0a * sc2
    vmla.u32   q8 , q12, q0   ;    + 1a * sc
    vmul.u32   q12, q4 , q1   ; b2 = 0b * sc2
    vmla.u32   q12, q5 , q0   ;    + 1b * sc
    vbic       q8 , q8 , q2
    vshr.u32   q12, q12, #4
    vand       q12, q12, q2
    vorr       q8 , q8 , q12

    vand       q4 , q9 , q2   ; 0b
    vand       q5 , q13, q2   ; 1b
    vbic       q9 , q9 , q2   ; 0a
    vbic       q13, q13, q2   ; 1a
    vshr.u32   q9 , q9 , #4
    vshr.u32   q13, q13, #4
    vmul.u32   q9 , q9 , q1   ; b1 = 0a * sc2
    vmla.u32   q9 , q13, q0   ;    + 1a * sc
    vmul.u32   q13, q4 , q1   ; b2 = 0b * sc2
    vmla.u32   q13, q5 , q0   ;    + 1b * sc
    vbic       q9 , q9 , q2
    vshr.u32   q13, q13, #4
    vand       q13, q13, q2
    vorr       q9 , q9 , q13
    vst1.32    {d16,d17,d18,d19},[r0]!

merge_sh4_16more
    bics       r4, r4, #15
    beq        merge_sh4_end

merge_sh4_loop16
    vld1.32    {d16,d17,d18,d19},[r1]!
    vld1.32    {d24,d25,d26,d27},[r2]!
    vld1.32    {d20,d21,d22,d23},[r1]!
    vld1.32    {d28,d29,d30,d31},[r2]!
    vand       q4 , q8 , q2   ; 0b
    vand       q5 , q12, q2   ; 1b
    vbic       q8 , q8 , q2   ; 0a
    vbic       q12, q12, q2   ; 1a
    vshr.u32   q8 , q8 , #4
    vshr.u32   q12, q12, #4
    vmul.u32   q8 , q8 , q1   ; b1 = 0a * sc2
    vmla.u32   q8 , q12, q0   ;    + 1a * sc
    vmul.u32   q12, q4 , q1   ; b2 = 0b * sc2
    vmla.u32   q12, q5 , q0   ;    + 1b * sc
    vbic       q8 , q8 , q2
    vshr.u32   q12, q12, #4
    vand       q12, q12, q2
    vorr       q8 , q8 , q12

    vand       q4 , q9 , q2   ; 0b
    vand       q5 , q13, q2   ; 1b
    vbic       q9 , q9 , q2   ; 0a
    vbic       q13, q13, q2   ; 1a
    vshr.u32   q9 , q9 , #4
    vshr.u32   q13, q13, #4
    vmul.u32   q9 , q9 , q1   ; b1 = 0a * sc2
    vmla.u32   q9 , q13, q0   ;    + 1a * sc
    vmul.u32   q13, q4 , q1   ; b2 = 0b * sc2
    vmla.u32   q13, q5 , q0   ;    + 1b * sc
    vbic       q9 , q9 , q2
    vshr.u32   q13, q13, #4
    vand       q13, q13, q2
    vorr       q9 , q9 , q13

    vand       q4 , q10, q2   ; 0b
    vand       q5 , q14, q2   ; 1b
    vbic       q10, q10, q2   ; 0a
    vbic       q14, q14, q2   ; 1a
    vshr.u32   q10, q10, #4
    vshr.u32   q14, q14, #4
    vmul.u32   q10, q10, q1   ; b1 = 0a * sc2
    vmla.u32   q10, q14, q0   ;    + 1a * sc
    vmul.u32   q14, q4 , q1   ; b2 = 0b * sc2
    vmla.u32   q14, q5 , q0   ;    + 1b * sc
    vbic       q10, q10, q2
    vshr.u32   q14, q14, #4
    vand       q14, q14, q2
    vorr       q10, q10, q14
    vst1.32    {d16,d17,d18,d19},[r0]!

    vand       q4 , q11, q2   ; 0b
    vand       q5 , q15, q2   ; 1b
    vbic       q11, q11, q2   ; 0a
    vbic       q15, q15, q2   ; 1a
    vshr.u32   q11, q11, #4
    vshr.u32   q15, q15, #4
    vmul.u32   q11, q11, q1   ; b1 = 0a * sc2
    vmla.u32   q11, q15, q0   ;    + 1a * sc
    vmul.u32   q15, q4 , q1   ; b2 = 0b * sc2
    vmla.u32   q15, q5 , q0   ;    + 1b * sc
    vbic       q11, q11, q2
    vshr.u32   q15, q15, #4
    vand       q15, q15, q2
    vorr       q11, q11, q15
    vst1.32    {d20,d21,d22,d23},[r0]!
    subs       r4, r4, #16
    bgt        merge_sh4_loop16

merge_sh4_end
    mov        pc, lr

    ALIGN 32
;---------------
; r0 uint32_t* pdst
; r1 const uint32_t* line0
; r2 width (in words)
dup_lines_neon

dup_1more
    tst        r2, #1
    beq        dup_2more

    vld1.32    {d12[0]},[r1]!
    vst1.32    {d12[0]},[r0]!

dup_2more
    tst        r2, #2
    beq        dup_4more

    vld1.32    {d12},[r1]!
    vst1.32    {d12},[r0]!

dup_4more
    tst        r2, #4
    beq        dup_8more

    vld1.32    {d12,d13},[r1]!
    vst1.32    {d12,d13},[r0]!

dup_8more
    tst        r2, #8
    beq        dup_16more
    vld1.32    {d12,d13,d14,d15},[r1]!
    vst1.32    {d12,d13,d14,d15},[r0]!

dup_16more
    bics       r2, r2, #15
    beq        dup_end

dup_loop16
    vld1.32    {d12,d13,d14,d15},[r1]!
    vst1.32    {d12,d13,d14,d15},[r0]!
    vld1.32    {d16,d17,d18,d19},[r1]!
    vst1.32    {d16,d17,d18,d19},[r0]!
    subs       r2, r2, #16
    bgt        dup_loop16

dup_end
    mov        pc, lr


    ALIGN 32
;---------------
; uint32_t* pdst
; const uint32_t* line0
; const uint32_t* line1
; uint32_t sc
; int width
    EXPORT merge_lines32_8_neon
merge_lines32_8_neon
    stmfd      sp!, {r4, lr}
    ldr        r4, [sp, #2*4] ; width is on stack
    cmp        r3, #0
    bne        merge_32_8
    mov        r2, r4
    bl         dup_lines_neon
    ldmfd      sp!, {r4, pc}

merge_32_8
    vdup.8     d0, r3
    rsb        r3, r3, #256
    vdup.8     d1, r3

merge_32_8_1more
    tst        r4, #1
    beq        merge_32_8_2more

    vld1.32    {d23[0]},[r1]!
    vld1.32    {d31[0]},[r2]!
    vmull.u8   q8, d23, d1
    vmlal.u8   q8, d31, d0
    vrshrn.u16 d31, q8, #8
    vst1.32    {d31[0]},[r0]!

merge_32_8_2more
    tst        r4, #2
    beq        merge_32_8_4more

    vld1.32    {d23},[r1]!
    vld1.32    {d31},[r2]!
    vmull.u8   q8, d23, d1
    vmlal.u8   q8, d31, d0
    vrshrn.u16 d31, q8, #8
    vst1.32    {d31},[r0]!

merge_32_8_4more
    tst        r4, #4
    beq        merge_32_8_8more

    vld1.32    {d22,d23},[r1]!
    vld1.32    {d30,d31},[r2]!
    vmull.u8   q7, d22, d1
    vmull.u8   q8, d23, d1
    vmlal.u8   q7, d30, d0
    vmlal.u8   q8, d31, d0
    vrshrn.u16 d30, q7, #8
    vrshrn.u16 d31, q8, #8
    vst1.32    {d30,d31},[r0]!

merge_32_8_8more
    tst        r4, #8
    beq        merge_32_8_16more

    vld1.32    {d20,d21,d22,d23},[r1]!
    vld1.32    {d28,d29,d30,d31},[r2]!
    vmull.u8   q5, d20, d1
    vmull.u8   q6, d21, d1
    vmull.u8   q7, d22, d1
    vmull.u8   q8, d23, d1
    vmlal.u8   q5, d28, d0
    vmlal.u8   q6, d29, d0
    vmlal.u8   q7, d30, d0
    vmlal.u8   q8, d31, d0
    vrshrn.u16 d28, q5, #8
    vrshrn.u16 d29, q6, #8
    vrshrn.u16 d30, q7, #8
    vrshrn.u16 d31, q8, #8
    vst1.32    {d28,d29,d30,d31},[r0]!


merge_32_8_16more
    bics       r4, r4, #15
    beq        merge_32_8_end

merge_32_8_loop16
    vld1.32    {d16,d17,d18,d19},[r1]!
    vld1.32    {d24,d25,d26,d27},[r2]!
    vld1.32    {d20,d21,d22,d23},[r1]!
    vld1.32    {d28,d29,d30,d31},[r2]!
    vmull.u8   q1, d16, d1
    vmull.u8   q2, d17, d1
    vmull.u8   q3, d18, d1
    vmull.u8   q4, d19, d1
    vmull.u8   q5, d20, d1
    vmull.u8   q6, d21, d1
    vmull.u8   q7, d22, d1
    vmull.u8   q8, d23, d1
    vmlal.u8   q1, d24, d0
    vmlal.u8   q2, d25, d0
    vmlal.u8   q3, d26, d0
    vmlal.u8   q4, d27, d0
    vmlal.u8   q5, d28, d0
    vmlal.u8   q6, d29, d0
    vmlal.u8   q7, d30, d0
    vmlal.u8   q8, d31, d0
    vrshrn.u16 d24, q1, #8
    vrshrn.u16 d25, q2, #8
    vrshrn.u16 d26, q3, #8
    vrshrn.u16 d27, q4, #8
    vrshrn.u16 d28, q5, #8
    vrshrn.u16 d29, q6, #8
    vrshrn.u16 d30, q7, #8
    vrshrn.u16 d31, q8, #8
    vst1.32    {d24,d25,d26,d27},[r0]!
    vst1.32    {d28,d29,d30,d31},[r0]!
    subs       r4, r4, #16
    bgt        merge_32_8_loop16

merge_32_8_end
    ldmfd      sp!, {r4, pc}


mask_565
    DCD        &07e0f81f

;---------------
; uint32_t* pdst
; const uint32_t* line0
; const uint32_t* line1
; uint32_t sc
; int width (in words)
    EXPORT merge_lines_565_neon
merge_lines_565_neon
    stmfd      sp!, {r4, lr}
    ldr        r4, [sp, #2*4] ; width is on stack
    movs       r3, r3, lsr #11
    bne        merge_565
    mov        r2, r4
    bl         dup_lines_neon
    ldmfd      sp!, {r4, pc}

merge_565
    vdup.32    q0, r3         ; sc
    rsb        r3, r3, #32
    vdup.32    q1, r3         ; sc2
    ldr        r3, mask_565
    vdup.32    q2, r3
    bl         merge_lines_tsh5
    ldmfd      sp!, {r4, pc}

mask_555
    DCD        &03e07c1f
mask_alpha_555
    DCD        &80008000

;---------------
; uint32_t* pdst
; const uint32_t* line0
; const uint32_t* line1
; uint32_t sc
; int width (in words)
    EXPORT merge_lines_t555_neon
merge_lines_t555_neon
    stmfd      sp!, {r4, lr}
    ldr        r4, [sp, #2*4] ; width is on stack
    movs       r3, r3, lsr #11
    bne        merge_t555
    mov        r2, r4
    bl         dup_lines_neon
    ldmfd      sp!, {r4, pc}

merge_t555
    vdup.32    q0, r3         ; sc
    rsb        r3, r3, #32
    vdup.32    q1, r3         ; sc2
    ldr        r3, mask_555
    vdup.32    q2, r3
    bl         merge_lines_tsh5
    ldmfd      sp!, {r4, pc}

;---------------
; uint32_t* pdst
; const uint32_t* line0
; const uint32_t* line1
; uint32_t sc
; int width (in words)
    EXPORT merge_lines_a555_neon
merge_lines_a555_neon
    stmfd      sp!, {r4, lr}
    ldr        r4, [sp, #2*4] ; width is on stack
    movs       r3, r3, lsr #11
    bne        merge_a555
    mov        r2, r4
    bl         dup_lines_neon
    ldmfd      sp!, {r4, pc}

merge_a555
    vdup.32    q0, r3         ; sc
    rsb        r3, r3, #32
    vdup.32    q1, r3         ; sc2
    ldr        r3, mask_555
    vdup.32    q2, r3
    ldr        r3, mask_alpha_555
    vdup.32    q3, r3
    bl         merge_lines_ash5
    ldmfd      sp!, {r4, pc}

mask_444
    DCD        &0f0f0f0f

;---------------
; uint32_t* pdst
; const uint32_t* line0
; const uint32_t* line1
; uint32_t sc
; int width (in words)
    EXPORT merge_lines_444_neon
merge_lines_444_neon
    stmfd      sp!, {r4, lr}
    ldr        r4, [sp, #2*4] ; width is on stack
    movs       r3, r3, lsr #12
    bne        merge_444
    mov        r2, r4
    bl         dup_lines_neon
    ldmfd      sp!, {r4, pc}

merge_444
    vdup.32    q0, r3         ; sc
    rsb        r3, r3, #16
    vdup.32    q1, r3         ; sc2
    ldr        r3, mask_444
    vdup.32    q2, r3
    bl         merge_lines_sh4
    ldmfd      sp!, {r4, pc}

;-------------------------------------------------------------------------------

    ALIGN 32
;---------------
; uint32_t* pdst
; uint32_t  width
; const uint32_t* psrc
; int       x0
; int       x_mag < 1 << 16
    EXPORT scaleup_line32_8_neon
scaleup_line32_8_neon
    stmfd      sp!, {r4-r7, lr}
    ldr        r4, [sp, #5*4] ; x_mag is on stack

    mov        r5, r3, lsr #16 ; psrc += x0 >> 16
    add        r2, r2, r5, lsl #2
    sub        r3, r3, r5, lsl #16 ; x0 &= 0xffff

    mov        r5, #0x80
    vdup.8     d31, r5

    mov        r5, #0x10000
    ldr        r6, [r2], #4
    mov        r7, r6

scaleup_line32_8_neon_1more
    tst        r1, #1
    beq        scaleup_line32_8_neon_2more

    vdup.16    d0, r3      ; replicate, 4 x frac as 16-bit
    vmov.32    d16, r6, r7 ; val0 & val1
    add        r3, r3, r4  ; x0 += x_mag
    cmp        r3, r5      ; x0 >= 1<<16 ?
    subge      r3, r3, r5  ;   x0 &= 0xffff (works because x_mag < 1<<16)
    movge      r6, r7      ;   val0 = val1
    ldrge      r7, [r2], #4;   load new val1

    vshr.u16   q4, q0, #9  ; 4 x frac, keep top 7-bits
    vtrn.32    d16, d24    ; rearrange, all val0 in one d and val1 in the other
    vmovn.u16  d0, q4      ; 4 x frac, narrow to 8-bit

    vsub.u8    d4, d31, d0 ; 4 x (128 - 7-bit frac)

    ; (frac * val0 + (128 - frac) * val1) >> 7
    ; on each r, g, b, a at the same time
    vmull.u8   q4, d16, d4
    vmlal.u8   q4, d24, d0
    vrshrn.u16 d24, q4, #7
    vst1.32    {d24[0]},[r0]!

scaleup_line32_8_neon_2more
    tst        r1, #2
    beq        scaleup_line32_8_neon_4more

    vdup.16    d0, r3      ; replicate, 4 x frac as 16-bit
    vmov.32    d16, r6, r7 ; val0 & val1
    add        r3, r3, r4  ; x0 += x_mag
    cmp        r3, r5      ; x0 >= 1<<16 ?
    subge      r3, r3, r5  ;   x0 &= 0xffff
    movge      r6, r7      ;   val0 = val1
    ldrge      r7, [r2], #4;   load new val1

    vdup.16    d1, r3      ; replicate, 4 x  frac as 16-bit
    vmov.32    d24, r6, r7 ; val0 & val1
    add        r3, r3, r4  ; x0 += x_mag
    cmp        r3, r5      ; x0 >= 1<<16 ?
    subge      r3, r3, r5  ;   x0 &= 0xffff
    movge      r6, r7      ;   val0 = val1
    ldrge      r7, [r2], #4;   load new val1

    vshr.u16   q4, q0, #9  ; 4 x frac, keep top 7-bits
    vtrn.32    d16, d24    ; rearrange, all val0 in one d and val1 in the other
    vmovn.u16  d0, q4      ; 4 x frac, narrow to 8-bit

    vsub.u8    d4, d31, d0 ; 4 x (128 - 7-bit frac)

    ; (frac * val0 + (128 - frac) * val1) >> 7
    ; on each r, g, b, a at the same time
    vmull.u8   q4, d16, d4
    vmlal.u8   q4, d24, d0
    vrshrn.u16 d24, q4, #7
    vst1.32    {d24},[r0]!

scaleup_line32_8_neon_4more
    tst        r1, #4
    beq        scaleup_line32_8_neon_8more

    vdup.16    d0, r3      ; replicate, 4 x frac as 16-bit
    vmov.32    d16, r6, r7 ; val0 & val1
    add        r3, r3, r4  ; x0 += x_mag
    cmp        r3, r5      ; x0 >= 1<<16 ?
    subge      r3, r3, r5  ;   x0 &= 0xffff
    movge      r6, r7      ;   val0 = val1
    ldrge      r7, [r2], #4;   load new val1

    vdup.16    d1, r3      ; replicate, 4 x frac as 16-bit
    vmov.32    d24, r6, r7 ; val0 & val1
    add        r3, r3, r4  ; x0 += x_mag
    cmp        r3, r5      ; x0 >= 1<<16 ?
    subge      r3, r3, r5  ;   x0 &= 0xffff
    movge      r6, r7      ;   val0 = val1
    ldrge      r7, [r2], #4;   load new val1

    vshr.u16   q4, q0, #9  ; 4 x frac, keep top 7-bits
    vtrn.32    d16, d24    ; rearrange, all val0 in one d and val1 in the other
    vmovn.u16  d0, q4      ; 4 x frac, narrow to 8-bit

    vdup.16    d2, r3      ; replicate, 4 x frac as 16-bit
    vmov.32    d17, r6, r7 ; val0 & val1
    add        r3, r3, r4  ; x0 += x_mag
    cmp        r3, r5      ; x0 >= 1<<16 ?
    subge      r3, r3, r5  ;   x0 &= 0xffff
    movge      r6, r7      ;   val0 = val1
    ldrge      r7, [r2], #4;   load new val1

    vdup.16    d3, r3      ; replicate, 4 x frac as 16-bit
    vmov.32    d25, r6, r7 ; val0 & val1
    add        r3, r3, r4  ; x0 += x_mag
    cmp        r3, r5      ; x0 >= 1<<16 ?
    subge      r3, r3, r5  ;   x0 &= 0xffff
    movge      r6, r7      ;   val0 = val1
    ldrge      r7, [r2], #4;   load new val1

    vshr.u16   q5, q1, #9  ; 4 x frac, keep top 7-bits
    vtrn.32    d17, d25    ; rearrange, all val0 in one d and val1 in the other
    vmovn.u16  d1, q5      ; 4 x frac, narrow to 8-bit

    vsub.u8    d4, d31, d0 ; 4 x (128 - 7-bit frac)
    vsub.u8    d5, d31, d1 ; 4 x (128 - 7-bit frac)

    ; (frac * val0 + (128 - frac) * val1) >> 7
    ; on each r, g, b, a at the same time
    vmull.u8   q4, d16, d4
    vmull.u8   q5, d17, d5
    vmlal.u8   q4, d24, d0
    vmlal.u8   q5, d25, d1
    vrshrn.u16 d24, q4, #7
    vrshrn.u16 d25, q5, #7
    vst1.32    {d24,d25},[r0]!

scaleup_line32_8_neon_8more
    bics       r1, r1, #7
    beq        scaleup_line32_8_neon_end

scaleup_line32_8_neon_loop8
    vdup.16    d0, r3      ; replicate, 4 x frac as 16-bit
    vmov.32    d16, r6, r7 ; val0 & val1
    add        r3, r3, r4  ; x0 += x_mag
    cmp        r3, r5      ; x0 >= 1<<16 ?
    subge      r3, r3, r5  ;   x0 &= 0xffff
    movge      r6, r7      ;   val0 = val1
    ldrge      r7, [r2], #4;   load new val1

    vdup.16    d1, r3      ; replicate, 4 x frac as 16-bit
    vmov.32    d24, r6, r7 ; val0 & val1
    add        r3, r3, r4  ; x0 += x_mag
    cmp        r3, r5      ; x0 >= 1<<16 ?
    subge      r3, r3, r5  ;   x0 &= 0xffff
    movge      r6, r7      ;   val0 = val1
    ldrge      r7, [r2], #4;   load new val1

    vshr.u16   q4, q0, #9  ; 4 x frac, keep top 7-bits
    vtrn.32    d16, d24    ; rearrange, all val0 in one d and val1 in the other
    vmovn.u16  d0, q4      ; 4 x frac, narrow to 8-bit

    vdup.16    d2, r3      ; replicate, 4 x frac as 16-bit
    vmov.32    d17, r6, r7 ; val0 & val1
    add        r3, r3, r4  ; x0 += x_mag
    cmp        r3, r5      ; x0 >= 1<<16 ?
    subge      r3, r3, r5  ;   x0 &= 0xffff
    movge      r6, r7      ;   val0 = val1
    ldrge      r7, [r2], #4;   load new val1

    vdup.16    d3, r3      ; replicate, 4 x frac as 16-bit
    vmov.32    d25, r6, r7 ; val0 & val1
    add        r3, r3, r4  ; x0 += x_mag
    cmp        r3, r5      ; x0 >= 1<<16 ?
    subge      r3, r3, r5  ;   x0 &= 0xffff
    movge      r6, r7      ;   val0 = val1
    ldrge      r7, [r2], #4;   load new val1

    vshr.u16   q5, q1, #9  ; 4 x frac, keep top 7-bits
    vtrn.32    d17, d25    ; rearrange, all val0 in one d and val1 in the other
    vmovn.u16  d1, q5      ; 4 x frac, narrow to 8-bit

    vdup.16    d4, r3      ; replicate, 4 x frac as 16-bit
    vmov.32    d18, r6, r7 ; val0 & val1
    add        r3, r3, r4  ; x0 += x_mag
    cmp        r3, r5      ; x0 >= 1<<16 ?
    subge      r3, r3, r5  ;   x0 &= 0xffff
    movge      r6, r7      ;   val0 = val1
    ldrge      r7, [r2], #4;   load new val1

    vdup.16    d5, r3      ; replicate, 4 x frac as 16-bit
    vmov.32    d26, r6, r7 ; val0 & val1
    add        r3, r3, r4  ; x0 += x_mag
    cmp        r3, r5      ; x0 >= 1<<16 ?
    subge      r3, r3, r5  ;   x0 &= 0xffff
    movge      r6, r7      ;   val0 = val1
    ldrge      r7, [r2], #4;   load new val1

    vshr.u16   q6, q2, #9  ; 4 x frac, keep top 7-bits
    vtrn.32    d18, d26    ; rearrange, all val0 in one d and val1 in the other
    vmovn.u16  d2, q6      ; 4 x frac, narrow to 8-bit

    vdup.16    d6, r3      ; replicate, 4 x frac as 16-bit
    vmov.32    d19, r6, r7 ; val0 & val1
    add        r3, r3, r4  ; x0 += x_mag
    cmp        r3, r5      ; x0 >= 1<<16 ?
    subge      r3, r3, r5  ;   x0 &= 0xffff
    movge      r6, r7      ;   val0 = val1
    ldrge      r7, [r2], #4;   load new val1

    vdup.16    d7, r3      ; replicate, 4 x frac as 16-bit
    vmov.32    d27, r6, r7 ; val0 & val1
    add        r3, r3, r4  ; x0 += x_mag
    cmp        r3, r5      ; x0 >= 1<<16 ?
    subge      r3, r3, r5  ;   x0 &= 0xffff
    movge      r6, r7      ;   val0 = val1
    ldrge      r7, [r2], #4;   load new val1

    vshr.u16   q7, q3, #9  ; 4 x frac, keep top 7-bits
    vtrn.32    d19, d27    ; rearrange, all val0 in one d and val1 in the other
    vmovn.u16  d3, q7      ; 4 x frac, narrow to 8-bit

    vsub.u8    d4, d31, d0 ; 4 x (128 - 7-bit frac)
    vsub.u8    d5, d31, d1 ; 4 x (128 - 7-bit frac)
    vsub.u8    d6, d31, d2 ; 4 x (128 - 7-bit frac)
    vsub.u8    d7, d31, d3 ; 4 x (128 - 7-bit frac)

    ; (frac * val0 + (128 - frac) * val1) >> 7
    ; on each r, g, b, a at the same time
    vmull.u8   q4, d16, d4
    vmull.u8   q5, d17, d5
    vmull.u8   q6, d18, d6
    vmull.u8   q7, d19, d7
    vmlal.u8   q4, d24, d0
    vmlal.u8   q5, d25, d1
    vmlal.u8   q6, d26, d2
    vmlal.u8   q7, d27, d3
    vrshrn.u16 d24, q4, #7
    vrshrn.u16 d25, q5, #7
    vrshrn.u16 d26, q6, #7
    vrshrn.u16 d27, q7, #7
    vst1.32    {d24,d25,d26,d27},[r0]!
    subs       r1, r1, #8
    bgt        scaleup_line32_8_neon_loop8

scaleup_line32_8_neon_end
    ldmfd      sp!, {r4-r7, pc}

    ALIGN 32
;---------------
; r0 uint16_t* pdst
; r1 uint32_t  width
; r2 const uint16_t* psrc
; r3 int       x0
; r4 int       x_mag < 1 << 16
; r9 uint16_t  mask
scaleup_line_sh5_neon
    vdup.32    q15, r9

    mov        r5, r3, lsr #16 ; psrc += x0 >> 16
    add        r2, r2, r5, lsl #1
    sub        r3, r3, r5, lsl #16 ; x0 &= 0xffff

    mov        r5, #0x10000
    ldrh       r6, [r2], #2
    mov        r7, r6

scaleup_sh5_1more
    tst        r1, #1
    beq        scaleup_sh5_2more

    mov        r8, r3, lsr #11
    vmov.32    d0[0], r8   ; frac as 32-bit
    rsb        r8, r8, #32
    vmov.32    d2[0], r8   ; (32 - frac) as 32-bit
    vmov.32    d4[0], r6   ; val0
    vmov.32    d8[0], r7   ; val1
    add        r3, r3, r4  ; x0 += x_mag
    cmp        r3, r5      ; x0 >= 1<<16 ?
    subge      r3, r3, r5  ;   x0 &= 0xffff
    movge      r6, r7      ;   val0 = val1
    ldrhge     r7, [r2], #2;   load new val1

    vand       d6 , d4, d31; val0a
    vand       d10, d8, d31; val1a
    vbic       d4 , d4, d31; val0b
    vbic       d8 , d8, d31; val1b
    vmul.u32   d4, d4 , d2 ; valb = val0b * (32 - sc)
    vmul.u32   d6, d6 , d2 ; vala = val0a * (32 - sc)
    vmla.u32   d4, d8 , d0 ; valb += val1b * sc
    vmla.u32   d6, d10, d0 ; vala += val1a * sc
    vshr.u32   d4, d4, #5  ; valb >>= 5
    vshr.u32   d6, d6, #5  ; vala >>= 5
    vbic.u32   d4, d4, d31 ; valb &= mask
    vand.u32   d6, d6, d31 ; vala &= ~mask
    vorr.u32   d4, d4, d6  ; val = vala | valb
    vst1.16    {d4[0]}, [r0]!

scaleup_sh5_2more
    tst        r1, #2
    beq        scaleup_sh5_4more

    mov        r8, r3, lsr #11
    vmov.32    d0[0], r8   ; frac as 32-bit
    rsb        r8, r8, #32
    vmov.32    d2[0], r8   ; (32 - frac) as 32-bit
    vmov.32    d4[0], r6   ; val0
    vmov.32    d8[0], r7   ; val1
    add        r3, r3, r4  ; x0 += x_mag
    cmp        r3, r5      ; x0 >= 1<<16 ?
    subge      r3, r3, r5  ;   x0 &= 0xffff
    movge      r6, r7      ;   val0 = val1
    ldrhge     r7, [r2], #2;   load new val1

    mov        r8, r3, lsr #11
    vmov.32    d0[1], r8   ; frac as 32-bit
    rsb        r8, r8, #32
    vmov.32    d2[1], r8   ; (32 - frac) as 32-bit
    vmov.32    d4[1], r6   ; val0
    vmov.32    d8[1], r7   ; val1
    add        r3, r3, r4  ; x0 += x_mag
    cmp        r3, r5      ; x0 >= 1<<16 ?
    subge      r3, r3, r5  ;   x0 &= 0xffff
    movge      r6, r7      ;   val0 = val1
    ldrhge     r7, [r2], #2;   load new val1

    vand       d6 , d4, d31; val0a
    vand       d10, d8, d31; val1a
    vbic       d4 , d4, d31; val0b
    vbic       d8 , d8, d31; val1b
    vmul.u32   d4, d4 , d2 ; valb = val0b * (32 - sc)
    vmul.u32   d6, d6 , d2 ; vala = val0a * (32 - sc)
    vmla.u32   d4, d8 , d0 ; valb += val1b * sc
    vmla.u32   d6, d10, d0 ; vala += val1a * sc
    vshr.u32   d4, d4, #5  ; valb >>= 5
    vshr.u32   d6, d6, #5  ; vala >>= 5
    vbic.u32   d4, d4, d31 ; valb &= mask
    vand.u32   d6, d6, d31 ; vala &= ~mask
    vorr.u32   d4, d4, d6  ; val = vala | valb
    vst1.16    {d4[0]}, [r0]!
    vst1.16    {d4[2]}, [r0]!

scaleup_sh5_4more
    tst        r1, #4
    beq        scaleup_sh5_8more

    mov        r8, r3, lsr #11
    vmov.32    d0[0], r8   ; frac as 32-bit
    rsb        r8, r8, #32
    vmov.32    d2[0], r8   ; (32 - frac) as 32-bit
    vmov.32    d4[0], r6   ; val0
    vmov.32    d8[0], r7   ; val1
    add        r3, r3, r4  ; x0 += x_mag
    cmp        r3, r5      ; x0 >= 1<<16 ?
    subge      r3, r3, r5  ;   x0 &= 0xffff
    movge      r6, r7      ;   val0 = val1
    ldrhge     r7, [r2], #2;   load new val1

    mov        r8, r3, lsr #11
    vmov.32    d0[1], r8   ; frac as 32-bit
    rsb        r8, r8, #32
    vmov.32    d2[1], r8   ; (32 - frac) as 32-bit
    vmov.32    d4[1], r6   ; val0
    vmov.32    d8[1], r7   ; val1
    add        r3, r3, r4  ; x0 += x_mag
    cmp        r3, r5      ; x0 >= 1<<16 ?
    subge      r3, r3, r5  ;   x0 &= 0xffff
    movge      r6, r7      ;   val0 = val1
    ldrhge     r7, [r2], #2;   load new val1

    mov        r8, r3, lsr #11
    vmov.32    d1[0], r8   ; frac as 32-bit
    rsb        r8, r8, #32
    vmov.32    d3[0], r8   ; (32 - frac) as 32-bit
    vmov.32    d5[0], r6   ; val0
    vmov.32    d9[0], r7   ; val1
    add        r3, r3, r4  ; x0 += x_mag
    cmp        r3, r5      ; x0 >= 1<<16 ?
    subge      r3, r3, r5  ;   x0 &= 0xffff
    movge      r6, r7      ;   val0 = val1
    ldrhge     r7, [r2], #2;   load new val1

    mov        r8, r3, lsr #11
    vmov.32    d1[1], r8   ; frac as 32-bit
    rsb        r8, r8, #32
    vmov.32    d3[1], r8   ; (32 - frac) as 32-bit
    vmov.32    d5[1], r6   ; val0
    vmov.32    d9[1], r7   ; val1
    add        r3, r3, r4  ; x0 += x_mag
    cmp        r3, r5      ; x0 >= 1<<16 ?
    subge      r3, r3, r5  ;   x0 &= 0xffff
    movge      r6, r7      ;   val0 = val1
    ldrhge     r7, [r2], #2;   load new val1

    vand       q3, q2, q15 ; val0a
    vand       q5, q4, q15 ; val1a
    vbic       q2, q2, q15 ; val0b
    vbic       q4, q4, q15 ; val1b
    vmul.u32   q2, q2, q1  ; valb = val0b * (32 - sc)
    vmul.u32   q3, q3, q1  ; vala = val0a * (32 - sc)
    vmla.u32   q2, q4, q0  ; valb += val1b * sc
    vmla.u32   q3, q5, q0  ; vala += val1a * sc
    vshr.u32   q2, q2, #5  ; valb >>= 5
    vshr.u32   q3, q3, #5  ; vala >>= 5
    vbic.u32   q2, q2, q15 ; valb &= mask
    vand.u32   q3, q3, q15 ; vala &= ~mask
    vorr.u32   q2, q2, q3  ; val = vala | valb
    vmovn.u32  d4, q2      ; val -> 16-bit
    vst1.16    {d4}, [r0]!

scaleup_sh5_8more
    bics       r1, r1, #7
    beq        scaleup_sh5_end

scaleup_sh5_loop8

    mov        r8, r3, lsr #11
    vmov.32    d0[0], r8   ; frac as 32-bit
    rsb        r8, r8, #32
    vmov.32    d2[0], r8   ; (32 - frac) as 32-bit
    vmov.32    d4[0], r6   ; val0
    vmov.32    d8[0], r7   ; val1
    add        r3, r3, r4  ; x0 += x_mag
    cmp        r3, r5      ; x0 >= 1<<16 ?
    subge      r3, r3, r5  ;   x0 &= 0xffff
    movge      r6, r7      ;   val0 = val1
    ldrhge     r7, [r2], #2;   load new val1

    mov        r8, r3, lsr #11
    vmov.32    d0[1], r8   ; frac as 32-bit
    rsb        r8, r8, #32
    vmov.32    d2[1], r8   ; (32 - frac) as 32-bit
    vmov.32    d4[1], r6   ; val0
    vmov.32    d8[1], r7   ; val1
    add        r3, r3, r4  ; x0 += x_mag
    cmp        r3, r5      ; x0 >= 1<<16 ?
    subge      r3, r3, r5  ;   x0 &= 0xffff
    movge      r6, r7      ;   val0 = val1
    ldrhge     r7, [r2], #2;   load new val1

    mov        r8, r3, lsr #11
    vmov.32    d1[0], r8   ; frac as 32-bit
    rsb        r8, r8, #32
    vmov.32    d3[0], r8   ; (32 - frac) as 32-bit
    vmov.32    d5[0], r6   ; val0
    vmov.32    d9[0], r7   ; val1
    add        r3, r3, r4  ; x0 += x_mag
    cmp        r3, r5      ; x0 >= 1<<16 ?
    subge      r3, r3, r5  ;   x0 &= 0xffff
    movge      r6, r7      ;   val0 = val1
    ldrhge     r7, [r2], #2;   load new val1

    mov        r8, r3, lsr #11
    vmov.32    d1[1], r8   ; frac as 32-bit
    rsb        r8, r8, #32
    vmov.32    d3[1], r8   ; (32 - frac) as 32-bit
    vmov.32    d5[1], r6   ; val0
    vmov.32    d9[1], r7   ; val1
    add        r3, r3, r4  ; x0 += x_mag
    cmp        r3, r5      ; x0 >= 1<<16 ?
    subge      r3, r3, r5  ;   x0 &= 0xffff
    movge      r6, r7      ;   val0 = val1
    ldrhge     r7, [r2], #2;   load new val1

    mov        r8, r3, lsr #11
    vmov.32    d12[0], r8  ; frac as 32-bit
    rsb        r8, r8, #32
    vmov.32    d14[0], r8  ; (32 - frac) as 32-bit
    vmov.32    d16[0], r6  ; val0
    vmov.32    d20[0], r7  ; val1
    add        r3, r3, r4  ; x0 += x_mag
    cmp        r3, r5      ; x0 >= 1<<16 ?
    subge      r3, r3, r5  ;   x0 &= 0xffff
    movge      r6, r7      ;   val0 = val1
    ldrhge     r7, [r2], #2;   load new val1

    mov        r8, r3, lsr #11
    vmov.32    d12[1], r8  ; frac as 32-bit
    rsb        r8, r8, #32
    vmov.32    d14[1], r8  ; (32 - frac) as 32-bit
    vmov.32    d16[1], r6  ; val0
    vmov.32    d20[1], r7  ; val1
    add        r3, r3, r4  ; x0 += x_mag
    cmp        r3, r5      ; x0 >= 1<<16 ?
    subge      r3, r3, r5  ;   x0 &= 0xffff
    movge      r6, r7      ;   val0 = val1
    ldrhge     r7, [r2], #2;   load new val1

    mov        r8, r3, lsr #11
    vmov.32    d13[0], r8  ; frac as 32-bit
    rsb        r8, r8, #32
    vmov.32    d15[0], r8  ; (32 - frac) as 32-bit
    vmov.32    d17[0], r6  ; val0
    vmov.32    d21[0], r7  ; val1
    add        r3, r3, r4  ; x0 += x_mag
    cmp        r3, r5      ; x0 >= 1<<16 ?
    subge      r3, r3, r5  ;   x0 &= 0xffff
    movge      r6, r7      ;   val0 = val1
    ldrhge     r7, [r2], #2;   load new val1

    mov        r8, r3, lsr #11
    vmov.32    d13[1], r8  ; frac as 32-bit
    rsb        r8, r8, #32
    vmov.32    d15[1], r8  ; (32 - frac) as 32-bit
    vmov.32    d17[1], r6  ; val0
    vmov.32    d21[1], r7  ; val1
    add        r3, r3, r4  ; x0 += x_mag
    cmp        r3, r5      ; x0 >= 1<<16 ?
    subge      r3, r3, r5  ;   x0 &= 0xffff
    movge      r6, r7      ;   val0 = val1
    ldrhge     r7, [r2], #2;   load new val1

    vand       q3, q2, q15 ; val0a
    vand       q5, q4, q15 ; val1a
    vbic       q2, q2, q15 ; val0b
    vbic       q4, q4, q15 ; val1b
    vmul.u32   q2, q2, q1  ; valb = val0b * (32 - sc)
    vmul.u32   q3, q3, q1  ; vala = val0a * (32 - sc)
    vmla.u32   q2, q4, q0  ; valb += val1b * sc
    vmla.u32   q3, q5, q0  ; vala += val1a * sc
    vshr.u32   q2, q2, #5  ; valb >>= 5
    vshr.u32   q3, q3, #5  ; vala >>= 5
    vbic.u32   q2, q2, q15 ; valb &= mask
    vand.u32   q3, q3, q15 ; vala &= ~mask
    vorr.u32   q2, q2, q3  ; val = vala | valb
    vmovn.u32  d4, q2      ; val -> 16-bit

    vand       q9, q8, q15 ; val0a
    vand       q11,q10,q15 ; val1a
    vbic       q8, q8, q15 ; val0b
    vbic       q10,q10,q15 ; val1b
    vmul.u32   q8, q8, q7  ; valb = val0b * (32 - sc)
    vmul.u32   q9, q9, q7  ; vala = val0a * (32 - sc)
    vmla.u32   q8, q10,q6  ; valb += val1b * sc
    vmla.u32   q9, q11,q6  ; vala += val1a * sc
    vshr.u32   q8, q8, #5  ; valb >>= 5
    vshr.u32   q9, q9, #5  ; vala >>= 5
    vbic.u32   q8, q8, q15 ; valb &= mask
    vand.u32   q9, q9, q15 ; vala &= ~mask
    vorr.u32   q8, q8, q9  ; val = vala | valb
    vmovn.u32  d5, q8      ; val -> 16-bit

    vst1.16    {q2}, [r0]!

    subs       r1, r1, #8
    bgt        scaleup_sh5_loop8

scaleup_sh5_end
    mov        pc, r14


scale_mask_565
    DCD &f81f

;---------------
; uint16_t* pdst
; uint32_t  width
; const uint16_t* psrc
; int       x0
; int       x_mag < 1 << 16
    EXPORT scaleup_line_565_neon
scaleup_line_565_neon
    stmfd      sp!, {r4-r9, lr}
    ldr        r4, [sp, #7*4] ; x_mag is on stack
    ldr        r9, scale_mask_565
    bl         scaleup_line_sh5_neon
    ldmfd      sp!, {r4-r9, pc}


scale_mask_555
    DCD &7c1f

;---------------
; uint16_t* pdst
; uint32_t  width
; const uint16_t* psrc
; int       x0
; int       x_mag < 1 << 16
    EXPORT scaleup_line_555_neon
scaleup_line_555_neon
    stmfd      sp!, {r4-r9, lr}
    ldr        r4, [sp, #7*4] ; x_mag is on stack
    ldr        r9, scale_mask_555
    bl         scaleup_line_sh5_neon
    ldmfd      sp!, {r4-r9, pc}


scale_mask_444
    DCD &0f0f

    ALIGN 32

;---------------
; uint16_t* pdst
; uint32_t  width
; const uint16_t* psrc
; int       x0
; int       x_mag < 1 << 16
    EXPORT scaleup_line_444_neon
scaleup_line_444_neon
    stmfd      sp!, {r4-r9, lr}
    ldr        r4, [sp, #7*4] ; x_mag is on stack
    ldr        r9, scale_mask_444
    vdup.32    q15, r9

    mov        r5, r3, lsr #16 ; psrc += x0 >> 16
    add        r2, r2, r5, lsl #1
    sub        r3, r3, r5, lsl #16 ; x0 &= 0xffff

    mov        r5, #0x10000
    ldrh       r6, [r2], #2
    mov        r7, r6

scaleup_444_1more
    tst        r1, #1
    beq        scaleup_444_2more

    mov        r8, r3, lsr #12
    vmov.32    d0[0], r8   ; frac as 32-bit
    rsb        r8, r8, #16
    vmov.32    d2[0], r8   ; (16 - frac) as 32-bit
    vmov.32    d4[0], r6   ; val0
    vmov.32    d8[0], r7   ; val1
    add        r3, r3, r4  ; x0 += x_mag
    cmp        r3, r5      ; x0 >= 1<<16 ?
    subge      r3, r3, r5  ;   x0 &= 0xffff
    movge      r6, r7      ;   val0 = val1
    ldrhge     r7, [r2], #2;   load new val1

    vand       d6 , d4, d31; val0a
    vand       d10, d8, d31; val1a
    vbic       d4 , d4, d31; val0b
    vbic       d8 , d8, d31; val1b
    vmul.u32   d4, d4 , d2 ; valb = val0b * (16 - sc)
    vmul.u32   d6, d6 , d2 ; vala = val0a * (16 - sc)
    vmla.u32   d4, d8 , d0 ; valb += val1b * sc
    vmla.u32   d6, d10, d0 ; vala += val1a * sc
    vshr.u32   d4, d4, #4  ; valb >>= 5
    vshr.u32   d6, d6, #4  ; vala >>= 5
    vbic.u32   d4, d4, d31 ; valb &= mask
    vand.u32   d6, d6, d31 ; vala &= ~mask
    vorr.u32   d4, d4, d6  ; val = vala | valb
    vst1.16    {d4[0]}, [r0]!

scaleup_444_2more
    tst        r1, #2
    beq        scaleup_444_4more

    mov        r8, r3, lsr #12
    vmov.32    d0[0], r8   ; frac as 32-bit
    rsb        r8, r8, #16
    vmov.32    d2[0], r8   ; (16 - frac) as 32-bit
    vmov.32    d4[0], r6   ; val0
    vmov.32    d8[0], r7   ; val1
    add        r3, r3, r4  ; x0 += x_mag
    cmp        r3, r5      ; x0 >= 1<<16 ?
    subge      r3, r3, r5  ;   x0 &= 0xffff
    movge      r6, r7      ;   val0 = val1
    ldrhge     r7, [r2], #2;   load new val1

    mov        r8, r3, lsr #12
    vmov.32    d0[1], r8   ; frac as 32-bit
    rsb        r8, r8, #16
    vmov.32    d2[1], r8   ; (16 - frac) as 32-bit
    vmov.32    d4[1], r6   ; val0
    vmov.32    d8[1], r7   ; val1
    add        r3, r3, r4  ; x0 += x_mag
    cmp        r3, r5      ; x0 >= 1<<16 ?
    subge      r3, r3, r5  ;   x0 &= 0xffff
    movge      r6, r7      ;   val0 = val1
    ldrhge     r7, [r2], #2;   load new val1

    vand       d6 , d4, d31; val0a
    vand       d10, d8, d31; val1a
    vbic       d4 , d4, d31; val0b
    vbic       d8 , d8, d31; val1b
    vmul.u32   d4, d4 , d2 ; valb = val0b * (16 - sc)
    vmul.u32   d6, d6 , d2 ; vala = val0a * (16 - sc)
    vmla.u32   d4, d8 , d0 ; valb += val1b * sc
    vmla.u32   d6, d10, d0 ; vala += val1a * sc
    vshr.u32   d4, d4, #4  ; valb >>= 5
    vshr.u32   d6, d6, #4  ; vala >>= 5
    vbic.u32   d4, d4, d31 ; valb &= mask
    vand.u32   d6, d6, d31 ; vala &= ~mask
    vorr.u32   d4, d4, d6  ; val = vala | valb
    vst1.16    {d4[0]}, [r0]!
    vst1.16    {d4[2]}, [r0]!

scaleup_444_4more
    tst        r1, #4
    beq        scaleup_444_8more

    mov        r8, r3, lsr #12
    vmov.32    d0[0], r8   ; frac as 32-bit
    rsb        r8, r8, #16
    vmov.32    d2[0], r8   ; (16 - frac) as 32-bit
    vmov.32    d4[0], r6   ; val0
    vmov.32    d8[0], r7   ; val1
    add        r3, r3, r4  ; x0 += x_mag
    cmp        r3, r5      ; x0 >= 1<<16 ?
    subge      r3, r3, r5  ;   x0 &= 0xffff
    movge      r6, r7      ;   val0 = val1
    ldrhge     r7, [r2], #2;   load new val1

    mov        r8, r3, lsr #12
    vmov.32    d0[1], r8   ; frac as 32-bit
    rsb        r8, r8, #16
    vmov.32    d2[1], r8   ; (16 - frac) as 32-bit
    vmov.32    d4[1], r6   ; val0
    vmov.32    d8[1], r7   ; val1
    add        r3, r3, r4  ; x0 += x_mag
    cmp        r3, r5      ; x0 >= 1<<16 ?
    subge      r3, r3, r5  ;   x0 &= 0xffff
    movge      r6, r7      ;   val0 = val1
    ldrhge     r7, [r2], #2;   load new val1

    mov        r8, r3, lsr #12
    vmov.32    d1[0], r8   ; frac as 32-bit
    rsb        r8, r8, #16
    vmov.32    d3[0], r8   ; (16 - frac) as 32-bit
    vmov.32    d5[0], r6   ; val0
    vmov.32    d9[0], r7   ; val1
    add        r3, r3, r4  ; x0 += x_mag
    cmp        r3, r5      ; x0 >= 1<<16 ?
    subge      r3, r3, r5  ;   x0 &= 0xffff
    movge      r6, r7      ;   val0 = val1
    ldrhge     r7, [r2], #2;   load new val1

    mov        r8, r3, lsr #12
    vmov.32    d1[1], r8   ; frac as 32-bit
    rsb        r8, r8, #16
    vmov.32    d3[1], r8   ; (16 - frac) as 32-bit
    vmov.32    d5[1], r6   ; val0
    vmov.32    d9[1], r7   ; val1
    add        r3, r3, r4  ; x0 += x_mag
    cmp        r3, r5      ; x0 >= 1<<16 ?
    subge      r3, r3, r5  ;   x0 &= 0xffff
    movge      r6, r7      ;   val0 = val1
    ldrhge     r7, [r2], #2;   load new val1

    vand       q3, q2, q15 ; val0a
    vand       q5, q4, q15 ; val1a
    vbic       q2, q2, q15 ; val0b
    vbic       q4, q4, q15 ; val1b
    vmul.u32   q2, q2, q1  ; valb = val0b * (16 - sc)
    vmul.u32   q3, q3, q1  ; vala = val0a * (16 - sc)
    vmla.u32   q2, q4, q0  ; valb += val1b * sc
    vmla.u32   q3, q5, q0  ; vala += val1a * sc
    vshr.u32   q2, q2, #4  ; valb >>= 5
    vshr.u32   q3, q3, #4  ; vala >>= 5
    vbic.u32   q2, q2, q15 ; valb &= mask
    vand.u32   q3, q3, q15 ; vala &= ~mask
    vorr.u32   q2, q2, q3  ; val = vala | valb
    vmovn.u32  d4, q2      ; val -> 16-bit
    vst1.16    {d4}, [r0]!

scaleup_444_8more
    bics       r1, r1, #7
    beq        scaleup_444_end

scaleup_444_loop8

    mov        r8, r3, lsr #12
    vmov.32    d0[0], r8   ; frac as 32-bit
    rsb        r8, r8, #16
    vmov.32    d2[0], r8   ; (16 - frac) as 32-bit
    vmov.32    d4[0], r6   ; val0
    vmov.32    d8[0], r7   ; val1
    add        r3, r3, r4  ; x0 += x_mag
    cmp        r3, r5      ; x0 >= 1<<16 ?
    subge      r3, r3, r5  ;   x0 &= 0xffff
    movge      r6, r7      ;   val0 = val1
    ldrhge     r7, [r2], #2;   load new val1

    mov        r8, r3, lsr #12
    vmov.32    d0[1], r8   ; frac as 32-bit
    rsb        r8, r8, #16
    vmov.32    d2[1], r8   ; (16 - frac) as 32-bit
    vmov.32    d4[1], r6   ; val0
    vmov.32    d8[1], r7   ; val1
    add        r3, r3, r4  ; x0 += x_mag
    cmp        r3, r5      ; x0 >= 1<<16 ?
    subge      r3, r3, r5  ;   x0 &= 0xffff
    movge      r6, r7      ;   val0 = val1
    ldrhge     r7, [r2], #2;   load new val1

    mov        r8, r3, lsr #12
    vmov.32    d1[0], r8   ; frac as 32-bit
    rsb        r8, r8, #16
    vmov.32    d3[0], r8   ; (16 - frac) as 32-bit
    vmov.32    d5[0], r6   ; val0
    vmov.32    d9[0], r7   ; val1
    add        r3, r3, r4  ; x0 += x_mag
    cmp        r3, r5      ; x0 >= 1<<16 ?
    subge      r3, r3, r5  ;   x0 &= 0xffff
    movge      r6, r7      ;   val0 = val1
    ldrhge     r7, [r2], #2;   load new val1

    mov        r8, r3, lsr #12
    vmov.32    d1[1], r8   ; frac as 32-bit
    rsb        r8, r8, #16
    vmov.32    d3[1], r8   ; (16 - frac) as 32-bit
    vmov.32    d5[1], r6   ; val0
    vmov.32    d9[1], r7   ; val1
    add        r3, r3, r4  ; x0 += x_mag
    cmp        r3, r5      ; x0 >= 1<<16 ?
    subge      r3, r3, r5  ;   x0 &= 0xffff
    movge      r6, r7      ;   val0 = val1
    ldrhge     r7, [r2], #2;   load new val1

    mov        r8, r3, lsr #12
    vmov.32    d12[0], r8  ; frac as 32-bit
    rsb        r8, r8, #16
    vmov.32    d14[0], r8  ; (16 - frac) as 32-bit
    vmov.32    d16[0], r6  ; val0
    vmov.32    d20[0], r7  ; val1
    add        r3, r3, r4  ; x0 += x_mag
    cmp        r3, r5      ; x0 >= 1<<16 ?
    subge      r3, r3, r5  ;   x0 &= 0xffff
    movge      r6, r7      ;   val0 = val1
    ldrhge     r7, [r2], #2;   load new val1

    mov        r8, r3, lsr #12
    vmov.32    d12[1], r8  ; frac as 32-bit
    rsb        r8, r8, #16
    vmov.32    d14[1], r8  ; (16 - frac) as 32-bit
    vmov.32    d16[1], r6  ; val0
    vmov.32    d20[1], r7  ; val1
    add        r3, r3, r4  ; x0 += x_mag
    cmp        r3, r5      ; x0 >= 1<<16 ?
    subge      r3, r3, r5  ;   x0 &= 0xffff
    movge      r6, r7      ;   val0 = val1
    ldrhge     r7, [r2], #2;   load new val1

    mov        r8, r3, lsr #12
    vmov.32    d13[0], r8  ; frac as 32-bit
    rsb        r8, r8, #16
    vmov.32    d15[0], r8  ; (16 - frac) as 32-bit
    vmov.32    d17[0], r6  ; val0
    vmov.32    d21[0], r7  ; val1
    add        r3, r3, r4  ; x0 += x_mag
    cmp        r3, r5      ; x0 >= 1<<16 ?
    subge      r3, r3, r5  ;   x0 &= 0xffff
    movge      r6, r7      ;   val0 = val1
    ldrhge     r7, [r2], #2;   load new val1

    mov        r8, r3, lsr #12
    vmov.32    d13[1], r8  ; frac as 32-bit
    rsb        r8, r8, #16
    vmov.32    d15[1], r8  ; (16 - frac) as 32-bit
    vmov.32    d17[1], r6  ; val0
    vmov.32    d21[1], r7  ; val1
    add        r3, r3, r4  ; x0 += x_mag
    cmp        r3, r5      ; x0 >= 1<<16 ?
    subge      r3, r3, r5  ;   x0 &= 0xffff
    movge      r6, r7      ;   val0 = val1
    ldrhge     r7, [r2], #2;   load new val1

    vand       q3, q2, q15 ; val0a
    vand       q5, q4, q15 ; val1a
    vbic       q2, q2, q15 ; val0b
    vbic       q4, q4, q15 ; val1b
    vmul.u32   q2, q2, q1  ; valb = val0b * (16 - sc)
    vmul.u32   q3, q3, q1  ; vala = val0a * (16 - sc)
    vmla.u32   q2, q4, q0  ; valb += val1b * sc
    vmla.u32   q3, q5, q0  ; vala += val1a * sc
    vshr.u32   q2, q2, #4  ; valb >>= 5
    vshr.u32   q3, q3, #4  ; vala >>= 5
    vbic.u32   q2, q2, q15 ; valb &= mask
    vand.u32   q3, q3, q15 ; vala &= ~mask
    vorr.u32   q2, q2, q3  ; val = vala | valb
    vmovn.u32  d4, q2      ; val -> 16-bit

    vand       q9, q8, q15 ; val0a
    vand       q11,q10,q15 ; val1a
    vbic       q8, q8, q15 ; val0b
    vbic       q10,q10,q15 ; val1b
    vmul.u32   q8, q8, q7  ; valb = val0b * (16 - sc)
    vmul.u32   q9, q9, q7  ; vala = val0a * (16 - sc)
    vmla.u32   q8, q10,q6  ; valb += val1b * sc
    vmla.u32   q9, q11,q6  ; vala += val1a * sc
    vshr.u32   q8, q8, #4  ; valb >>= 5
    vshr.u32   q9, q9, #4  ; vala >>= 5
    vbic.u32   q8, q8, q15 ; valb &= mask
    vand.u32   q9, q9, q15 ; vala &= ~mask
    vorr.u32   q8, q8, q9  ; val = vala | valb
    vmovn.u32  d5, q8      ; val -> 16-bit

    vst1.16    {q2}, [r0]!

    subs       r1, r1, #8
    bgt        scaleup_444_loop8

scaleup_444_end
    ldmfd      sp!, {r4-r9, pc}

;-----------------------------------------------------------
    ALIGN 32
    END
