@/*****************************************************************************
@*
@* Copyright (C) 2012 Ittiam Systems Pvt Ltd, Bangalore
@*
@* Licensed under the Apache License, Version 2.0 (the "License");
@* you may not use this file except in compliance with the License.
@* You may obtain a copy of the License at:
@*
@* http://www.apache.org/licenses/LICENSE-2.0
@*
@* Unless required by applicable law or agreed to in writing, software
@* distributed under the License is distributed on an "AS IS" BASIS,
@* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@* See the License for the specific language governing permissions and
@* limitations under the License.
@*
@*****************************************************************************/
@/**
@ *******************************************************************************
@ * @file
@ *  ihevc_itrans_recon_8x8_neon.s
@ *
@ * @brief
@ *  contains function definitions for single stage  inverse transform
@ *
@ * @author
@ * anand s
@ *
@ * @par list of functions:
@ *  - ihevc_itrans_recon_16x16()
@ *
@ * @remarks
@ *  none
@ *
@ *******************************************************************************
@*/

@/**
@ *******************************************************************************
@ *
@ * @brief
@ *  this function performs inverse transform  and reconstruction for 8x8
@ * input block
@ *
@ * @par description:
@ *  performs inverse transform and adds the prediction  data and clips output
@ * to 8 bit
@ *
@ * @param[in] pi2_src
@ *  input 16x16 coefficients
@ *
@ * @param[in] pi2_tmp
@ *  temporary 16x16 buffer for storing inverse
@ *
@ *  transform
@ *  1st stage output
@ *
@ * @param[in] pu1_pred
@ *  prediction 16x16 block
@ *
@ * @param[out] pu1_dst
@ *  output 8x8 block
@ *
@ * @param[in] src_strd
@ *  input stride
@ *
@ * @param[in] pred_strd
@ *  prediction stride
@ *
@ * @param[in] dst_strd
@ *  output stride
@ *
@ * @param[in] shift
@ *  output shift
@ *
@ * @param[in] r12
@ *  zero columns in pi2_src
@ *
@ * @returns  void
@ *
@ * @remarks
@ *  none
@ *
@ *******************************************************************************
@ */

@void ihevc_itrans_recon_16x16(word16 *pi2_src,
@                            word16 *pi2_tmp,
@                            uword8 *pu1_pred,
@                            uword8 *pu1_dst,
@                            word32 src_strd,
@                            word32 pred_strd,
@                            word32 dst_strd,
@                            word32 r12
@                            word32 r11             )

@**************variables vs registers*************************
@   r0 => *pi2_src
@   r1 => *pi2_tmp
@   r2 => *pu1_pred
@   r3 => *pu1_dst
@   src_strd
@   pred_strd
@   dst_strd
@   r12
@   r11

.equ    src_stride_offset,     104
.equ    pred_stride_offset,    108
.equ    out_stride_offset,     112
.equ    zero_cols_offset,      116
.equ    zero_rows_offset,      120

.text
.align 4






.set shift_stage1_idct ,   7
.set shift_stage2_idct ,   12
@#define zero_cols       r12
@#define zero_rows       r11
.globl ihevc_itrans_recon_16x16_a9q

.extern g_ai2_ihevc_trans_16_transpose

g_ai2_ihevc_trans_16_transpose_addr:
.long g_ai2_ihevc_trans_16_transpose - ulbl1 - 8

.type ihevc_itrans_recon_16x16_a9q, %function

ihevc_itrans_recon_16x16_a9q:

    stmfd       sp!,{r4-r12,lr}
    vpush       {d8  -  d15}
    ldr         r6,[sp,#src_stride_offset]  @ src stride
    ldr         r12,[sp,#zero_cols_offset]
    ldr         r11,[sp,#zero_rows_offset]



    ldr         r14,g_ai2_ihevc_trans_16_transpose_addr
ulbl1:
    add         r14,r14,pc
    vld1.16     {d0,d1,d2,d3},[r14]         @//d0,d1 are used for storing the constant data
    movw        r7,#0xffff
    and         r12,r12,r7
    and         r11,r11,r7
    mov         r6,r6,lsl #1                @ x sizeof(word16)
    add         r9,r0,r6, lsl #1            @ 2 rows

    add         r10,r6,r6, lsl #1           @ 3 rows
    add         r5,r6,r6,lsl #2
    movw        r7,#0xfff0

    cmp         r12,r7
    bge         zero_12cols_decision

    cmp         r12,#0xff00
    bge         zero_8cols_decision




    mov         r14,#4
    cmp         r11,r7
    rsbge       r10,r6,#0

    cmp         r11,#0xff00
    movge       r8,r5
    rsbge       r8,r8,#0
    movlt       r8,r10
    add         r5,r5,r6,lsl #3
    rsb         r5,r5,#0

    b           first_stage_top_four_bottom_four

zero_12cols_decision:
    mov         r14,#1
    cmp         r11,#0xff00
    movge       r8,r5
    movlt       r8,r10
    add         r5,r5,r6,lsl #3
    rsb         r5,r5,#0

    b           first_stage_top_four_bottom_four

zero_8cols_decision:
    mov         r14,#2
    mov         r8,r5
    rsb         r8,r8,#0
    cmp         r11,#0xff00
    movlt       r8,r10
    add         r5,r5,r6,lsl #3
    rsb         r5,r5,#0
    cmp         r11,r7
    rsbge       r10,r6,#0


    b           first_stage_top_four_bottom_four


@d0[0]= 64      d2[0]=64
@d0[1]= 90      d2[1]=57
@d0[2]= 89      d2[2]=50
@d0[3]= 87      d2[3]=43
@d1[0]= 83      d3[0]=36
@d1[1]= 80      d3[1]=25
@d1[2]= 75      d3[2]=18
@d1[3]= 70      d3[3]=9



first_stage:
    add         r0,r0,#8
    add         r9,r9,#8

first_stage_top_four_bottom_four:

    vld1.16     d10,[r0],r6
    vld1.16     d11,[r9],r6
    vld1.16     d6,[r0],r10
    vld1.16     d7,[r9],r10
    cmp         r11,r7
    bge         skip_load4rows

    vld1.16     d4,[r0],r6
    vld1.16     d5,[r9],r6
    vld1.16     d8,[r0],r8
    vld1.16     d9,[r9],r8

@ registers used: q0,q1,q3,q5,q2,q4

@ d10 =r0
@d6= r1
@d11=r2
@d7=r3

skip_load4rows:
    vmull.s16   q12,d6,d0[1]                @// y1 * cos1(part of b0)
    vmull.s16   q13,d6,d0[3]                @// y1 * cos3(part of b1)
    vmull.s16   q14,d6,d1[1]                @// y1 * sin3(part of b2)
    vmull.s16   q15,d6,d1[3]                @// y1 * sin1(part of b3)

    vmlal.s16   q12,d7,d0[3]                @// y1 * cos1 + y3 * cos3(part of b0)
    vmlal.s16   q13,d7,d2[1]                @// y1 * cos3 - y3 * sin1(part of b1)
    vmlal.s16   q14,d7,d3[3]                @// y1 * sin3 - y3 * cos1(part of b2)
    vmlsl.s16   q15,d7,d2[3]                @// y1 * sin1 - y3 * sin3(part of b3)






    vmull.s16   q6,d10,d0[0]
    vmlal.s16   q6,d11,d0[2]
    vmull.s16   q7,d10,d0[0]
    vmlal.s16   q7,d11,d1[2]
    vmull.s16   q8,d10,d0[0]
    vmlal.s16   q8,d11,d2[2]
    vmull.s16   q9,d10,d0[0]
    vmlal.s16   q9,d11,d3[2]

    bge         skip_last12rows_kernel1


    vmlal.s16   q12,d8,d1[1]
    vmlal.s16   q13,d8,d3[3]
    vmlsl.s16   q14,d8,d1[3]
    vmlsl.s16   q15,d8,d0[3]


    vmlal.s16   q12,d9,d1[3]
    vmlsl.s16   q13,d9,d2[3]
    vmlsl.s16   q14,d9,d0[3]
    vmlal.s16   q15,d9,d3[3]





    vmlal.s16   q6,d4,d1[0]
    vmlal.s16   q6,d5,d1[2]
    vmlal.s16   q7,d4,d3[0]
    vmlsl.s16   q7,d5,d3[2]
    vmlsl.s16   q8,d4,d3[0]
    vmlsl.s16   q8,d5,d0[2]
    vmlsl.s16   q9,d4,d1[0]
    vmlsl.s16   q9,d5,d2[2]

@d0[0]= 64      d2[0]=64
@d0[1]= 90      d2[1]=57
@d0[2]= 89      d2[2]=50
@d0[3]= 87      d2[3]=43
@d1[0]= 83      d3[0]=36
@d1[1]= 80      d3[1]=25
@d1[2]= 75      d3[2]=18
@d1[3]= 70      d3[3]=9
    cmp         r11,#0xff00
    bge         skip_last12rows_kernel1


    vld1.16     d10,[r0],r6
    vld1.16     d11,[r9],r6
    vld1.16     d6,[r0],r10
    vld1.16     d7,[r9],r10
    vld1.16     d4,[r0],r6
    vld1.16     d5,[r9],r6
    vld1.16     d8,[r0],r5
    vld1.16     d9,[r9],r5




    vmlal.s16   q12,d6,d2[1]                @// y1 * cos1(part of b0)
    vmlsl.s16   q13,d6,d1[1]                @// y1 * cos3(part of b1)
    vmlsl.s16   q14,d6,d3[1]                @// y1 * sin3(part of b2)
    vmlal.s16   q15,d6,d0[1]                @// y1 * sin1(part of b3)

    vmlal.s16   q12,d7,d2[3]                @// y1 * cos1 + y3 * cos3(part of b0)
    vmlsl.s16   q13,d7,d0[1]                @// y1 * cos3 - y3 * sin1(part of b1)
    vmlal.s16   q14,d7,d2[1]                @// y1 * sin3 - y3 * cos1(part of b2)
    vmlal.s16   q15,d7,d3[1]                @// y1 * sin1 - y3 * sin3(part of b3)



    vmlal.s16   q12,d8,d3[1]
    vmlsl.s16   q13,d8,d1[3]
    vmlal.s16   q14,d8,d0[1]
    vmlsl.s16   q15,d8,d1[1]


    vmlal.s16   q12,d9,d3[3]
    vmlsl.s16   q13,d9,d3[1]
    vmlal.s16   q14,d9,d2[3]
    vmlsl.s16   q15,d9,d2[1]





    vmlal.s16   q6,d10,d0[0]
    vmlal.s16   q6,d11,d2[2]
    vmlal.s16   q6,d4,d3[0]
    vmlal.s16   q6,d5,d3[2]




    vmlsl.s16   q7,d10,d0[0]
    vmlsl.s16   q7,d11,d0[2]
    vmlsl.s16   q7,d4,d1[0]
    vmlsl.s16   q7,d5,d2[2]


    vmlsl.s16   q8,d10,d0[0]
    vmlal.s16   q8,d11,d3[2]
    vmlal.s16   q8,d4,d1[0]
    vmlal.s16   q8,d5,d1[2]


    vmlal.s16   q9,d10,d0[0]
    vmlal.s16   q9,d11,d1[2]
    vmlsl.s16   q9,d4,d3[0]
    vmlsl.s16   q9,d5,d0[2]

skip_last12rows_kernel1:
    vadd.s32    q10,q6,q12
    vsub.s32    q11,q6,q12

    vadd.s32    q6,q7,q13
    vsub.s32    q12,q7,q13

    vadd.s32    q7,q8,q14
    vsub.s32    q13,q8,q14


    vadd.s32    q8,q9,q15
    vsub.s32    q14,q9,q15







    vqrshrn.s32 d30,q10,#shift_stage1_idct  @// r0 = (a0 + b0 + rnd) >> 7(shift_stage1_idct)
    vqrshrn.s32 d19,q11,#shift_stage1_idct  @// r7 = (a0 - b0 + rnd) >> 7(shift_stage1_idct)
    vqrshrn.s32 d31,q7,#shift_stage1_idct   @// r2 = (a2 + b2 + rnd) >> 7(shift_stage1_idct)
    vqrshrn.s32 d18,q13,#shift_stage1_idct  @// r5 = (a2 - b2 + rnd) >> 7(shift_stage1_idct)
    vqrshrn.s32 d12,q6,#shift_stage1_idct   @// r1 = (a1 + b1 + rnd) >> 7(shift_stage1_idct)
    vqrshrn.s32 d15,q12,#shift_stage1_idct  @// r6 = (a1 - b1 + rnd) >> 7(shift_stage1_idct)
    vqrshrn.s32 d13,q8,#shift_stage1_idct   @// r3 = (a3 + b3 + rnd) >> 7(shift_stage1_idct)
    vqrshrn.s32 d14,q14,#shift_stage1_idct  @// r4 = (a3 - b3 + rnd) >> 7(shift_stage1_idct)

    vst1.16     {d30,d31},[r1]!
    vst1.16     {d18,d19},[r1]!
    sub         r1,r1,#32

    bge         skip_stage1_kernel_load

first_stage_middle_eight:



    vld1.16     d10,[r0],r6
    vld1.16     d11,[r9],r6
    vld1.16     d6,[r0],r10
    vld1.16     d7,[r9],r10
    vld1.16     d4,[r0],r6
    vld1.16     d5,[r9],r6
    vld1.16     d8,[r0],r8
    vld1.16     d9,[r9],r8


skip_stage1_kernel_load:
    vmull.s16   q12,d6,d2[1]                @// y1 * cos1(part of b0)
    vmull.s16   q13,d6,d2[3]                @// y1 * cos3(part of b1)
    vmull.s16   q14,d6,d3[1]                @// y1 * sin3(part of b2)
    vmull.s16   q15,d6,d3[3]                @// y1 * sin1(part of b3)

    vmlsl.s16   q12,d7,d1[1]                @// y1 * cos1 + y3 * cos3(part of b0)
    vmlsl.s16   q13,d7,d0[1]                @// y1 * cos3 - y3 * sin1(part of b1)
    vmlsl.s16   q14,d7,d1[3]                @// y1 * sin3 - y3 * cos1(part of b2)
    vmlsl.s16   q15,d7,d3[1]                @// y1 * sin1 - y3 * sin3(part of b3)






    vmull.s16   q11,d10,d0[0]
    vmlsl.s16   q11,d11,d3[2]
    vmull.s16   q10,d10,d0[0]
    vmlsl.s16   q10,d11,d2[2]
    vmull.s16   q8,d10,d0[0]
    vmlsl.s16   q8,d11,d1[2]
    vmull.s16   q9,d10,d0[0]
    vmlsl.s16   q9,d11,d0[2]


    cmp         r11,r7
    bge         skip_last12rows_kernel2

    vmlsl.s16   q12,d8,d3[1]
    vmlal.s16   q13,d8,d2[1]
    vmlal.s16   q14,d8,d0[1]
    vmlal.s16   q15,d8,d2[3]


    vmlal.s16   q12,d9,d0[1]
    vmlal.s16   q13,d9,d3[1]
    vmlsl.s16   q14,d9,d1[1]
    vmlsl.s16   q15,d9,d2[1]



    vmlsl.s16   q11,d4,d1[0]
    vmlal.s16   q11,d5,d2[2]
    vmlsl.s16   q10,d4,d3[0]
    vmlal.s16   q10,d5,d0[2]
    vmlal.s16   q8,d4,d3[0]
    vmlal.s16   q8,d5,d3[2]
    vmlal.s16   q9,d4,d1[0]
    vmlsl.s16   q9,d5,d1[2]

@d0[0]= 64      d2[0]=64
@d0[1]= 90      d2[1]=57
@d0[2]= 89      d2[2]=50
@d0[3]= 87      d2[3]=43
@d1[0]= 83      d3[0]=36
@d1[1]= 80      d3[1]=25
@d1[2]= 75      d3[2]=18
@d1[3]= 70      d3[3]=9
    cmp         r11,#0xff00
    bge         skip_last12rows_kernel2

    vld1.16     d10,[r0],r6
    vld1.16     d11,[r9],r6
    vld1.16     d6,[r0],r10
    vld1.16     d7,[r9],r10
    vld1.16     d4,[r0],r6
    vld1.16     d5,[r9],r6
    vld1.16     d8,[r0],r5
    vld1.16     d9,[r9],r5


    vmlsl.s16   q12,d6,d3[3]                @// y1 * cos1(part of b0)
    vmlsl.s16   q13,d6,d0[3]                @// y1 * cos3(part of b1)
    vmlal.s16   q14,d6,d2[3]                @// y1 * sin3(part of b2)
    vmlal.s16   q15,d6,d1[3]                @// y1 * sin1(part of b3)

    vmlsl.s16   q12,d7,d0[3]                @// y1 * cos1 + y3 * cos3(part of b0)
    vmlal.s16   q13,d7,d1[3]                @// y1 * cos3 - y3 * sin1(part of b1)
    vmlal.s16   q14,d7,d3[3]                @// y1 * sin3 - y3 * cos1(part of b2)
    vmlsl.s16   q15,d7,d1[1]                @// y1 * sin1 - y3 * sin3(part of b3)


    vmlal.s16   q12,d8,d2[3]
    vmlal.s16   q13,d8,d3[3]
    vmlsl.s16   q14,d8,d2[1]
    vmlal.s16   q15,d8,d0[3]


    vmlal.s16   q12,d9,d1[3]
    vmlsl.s16   q13,d9,d1[1]
    vmlal.s16   q14,d9,d0[3]
    vmlsl.s16   q15,d9,d0[1]




    vmlal.s16   q11,d10,d0[0]
    vmlsl.s16   q11,d11,d1[2]
    vmlsl.s16   q11,d4,d3[0]
    vmlal.s16   q11,d5,d0[2]



    vmlsl.s16   q10,d10,d0[0]
    vmlsl.s16   q10,d11,d3[2]
    vmlal.s16   q10,d4,d1[0]
    vmlsl.s16   q10,d5,d1[2]


    vmlsl.s16   q8,d10,d0[0]
    vmlal.s16   q8,d11,d0[2]
    vmlsl.s16   q8,d4,d1[0]
    vmlal.s16   q8,d5,d2[2]



    vmlal.s16   q9,d10,d0[0]
    vmlsl.s16   q9,d11,d2[2]
    vmlal.s16   q9,d4,d3[0]
    vmlsl.s16   q9,d5,d3[2]

skip_last12rows_kernel2:

    vadd.s32    q2,q11,q12
    vsub.s32    q11,q11,q12

    vadd.s32    q3,q10,q13
    vsub.s32    q12,q10,q13

    vadd.s32    q5,q8,q14
    vsub.s32    q13,q8,q14


    vadd.s32    q8,q9,q15
    vsub.s32    q14,q9,q15


    vqrshrn.s32 d18,q2,#shift_stage1_idct   @// r0 = (a0 + b0 + rnd) >> 7(shift_stage1_idct)
    vqrshrn.s32 d31,q11,#shift_stage1_idct  @// r7 = (a0 - b0 + rnd) >> 7(shift_stage1_idct)
    vqrshrn.s32 d19,q5,#shift_stage1_idct   @// r2 = (a2 + b2 + rnd) >> 7(shift_stage1_idct)
    vqrshrn.s32 d30,q13,#shift_stage1_idct  @// r5 = (a2 - b2 + rnd) >> 7(shift_stage1_idct)
    vqrshrn.s32 d20,q3,#shift_stage1_idct   @// r1 = (a1 + b1 + rnd) >> 7(shift_stage1_idct)
    vqrshrn.s32 d23,q12,#shift_stage1_idct  @// r6 = (a1 - b1 + rnd) >> 7(shift_stage1_idct)
    vqrshrn.s32 d21,q8,#shift_stage1_idct   @// r3 = (a3 + b3 + rnd) >> 7(shift_stage1_idct)
    vqrshrn.s32 d22,q14,#shift_stage1_idct  @// r4 = (a3 - b3 + rnd) >> 7(shift_stage1_idct)


    @ registers used:   {q2,q4,q6,q7}, {q9,q15,q10,q11}






    vld1.16     {d4,d5},[r1]!
    vld1.16     {d8,d9},[r1]!
    sub         r1,r1,#32

@d4=r0
@d12=r1
@d5=r2
@d13=r3

@d18=r4
@d20=r5
@d19=r6
@d21=r7

@d22=r8
@d30=r9
@d23=r10
@d31=r11

@d14=r12
@d8=r13
@d15=r14
@d9=r15


    vtrn.16     q2,q6
    vtrn.16     q9,q10
    vtrn.16     q11,q15
    vtrn.16     q7,q4



    vtrn.32     d4,d5
    vtrn.32     d12,d13

    vtrn.32     d18,d19
    vtrn.32     d20,d21

    vtrn.32     d22,d23
    vtrn.32     d30,d31

    vtrn.32     d14,d15
    vtrn.32     d8,d9


@ d4 =r0 1- 4 values
@ d5 =r2 1- 4 values
@ d12=r1 1- 4 values
@ d13=r3 1- 4 values

@ d18 =r0 5- 8 values
@ d19 =r2 5- 8 values
@ d20=r1 5- 8 values
@ d21=r3 5- 8 values

@ d22 =r0 9- 12 values
@ d23 =r2 9- 12 values
@ d30=r1 9- 12 values
@ d31=r3 9- 12 values

@ d14 =r0 13-16 values
@ d15 =r2 13- 16 values
@ d8=r1 13- 16 values
@ d9=r3 13- 16 values


    vst1.16     {q2},[r1]!
    vst1.16     {q6},[r1]!

    vst1.16     {q9},[r1]!
    vst1.16     {q10},[r1]!
    vst1.16     {q11},[r1]!
    vst1.16     {q15},[r1]!
    vst1.16     {q7},[r1]!
    vst1.16     {q4},[r1]!


    subs        r14,r14,#1
    bne         first_stage










    mov         r6,r7

    ldr         r8,[sp,#pred_stride_offset] @ prediction stride
    ldr         r7,[sp,#out_stride_offset]  @ destination stride

    mov         r10,#16

    cmp         r12,r6
    subge       r1,r1,#128
    bge         label1

    cmp         r12,#0xff00
    subge       r1,r1,#256
    bge         label_2

    sub         r1,r1,#512
    rsb         r10,r10,#0

label_2:
    add         r9,r1,#128
    add         r11,r9,#128
    add         r0,r11,#128



label1:
@   mov   r6,r1


    mov         r14,#4
    add         r4,r2,r8, lsl #1            @ r4 = r2 + pred_strd * 2    => r4 points to 3rd row of pred data
    add         r5,r8,r8, lsl #1            @
@   add r0,r3,r7, lsl #1    @ r0 points to 3rd row of dest data
@   add r10,r7,r7, lsl #1   @




second_stage:
    vld1.16     {d10,d11},[r1]!
    vld1.16     {d6,d7},[r1],r10
    cmp         r12,r6
    bge         second_stage_process
    vld1.16     {d4,d5},[r9]!
    vld1.16     {d8,d9},[r9],r10

second_stage_process:


    vmull.s16   q12,d6,d0[1]                @// y1 * cos1(part of b0)
    vmull.s16   q13,d6,d0[3]                @// y1 * cos3(part of b1)
    vmull.s16   q14,d6,d1[1]                @// y1 * sin3(part of b2)
    vmull.s16   q15,d6,d1[3]                @// y1 * sin1(part of b3)

    vmlal.s16   q12,d7,d0[3]                @// y1 * cos1 + y3 * cos3(part of b0)
    vmlal.s16   q13,d7,d2[1]                @// y1 * cos3 - y3 * sin1(part of b1)
    vmlal.s16   q14,d7,d3[3]                @// y1 * sin3 - y3 * cos1(part of b2)
    vmlsl.s16   q15,d7,d2[3]                @// y1 * sin1 - y3 * sin3(part of b3)


    vmull.s16   q6,d10,d0[0]
    vmlal.s16   q6,d11,d0[2]
    vmull.s16   q7,d10,d0[0]
    vmlal.s16   q7,d11,d1[2]
    vmull.s16   q8,d10,d0[0]
    vmlal.s16   q8,d11,d2[2]
    vmull.s16   q9,d10,d0[0]
    vmlal.s16   q9,d11,d3[2]

    bge         skip_last8rows_stage2_kernel1

    vmlal.s16   q12,d8,d1[1]
    vmlal.s16   q13,d8,d3[3]
    vmlsl.s16   q14,d8,d1[3]
    vmlsl.s16   q15,d8,d0[3]


    vmlal.s16   q12,d9,d1[3]
    vmlsl.s16   q13,d9,d2[3]
    vmlsl.s16   q14,d9,d0[3]
    vmlal.s16   q15,d9,d3[3]


    vmlal.s16   q6,d4,d1[0]
    vmlal.s16   q6,d5,d1[2]
    vmlal.s16   q7,d4,d3[0]
    vmlsl.s16   q7,d5,d3[2]
    vmlsl.s16   q8,d4,d3[0]
    vmlsl.s16   q8,d5,d0[2]
    vmlsl.s16   q9,d4,d1[0]
    vmlsl.s16   q9,d5,d2[2]

    cmp         r12,#0xff00
    bge         skip_last8rows_stage2_kernel1


    vld1.16     {d10,d11},[r11]!
    vld1.16     {d6,d7},[r11],r10
    vld1.16     {d4,d5},[r0]!
    vld1.16     {d8,d9},[r0],r10





    vmlal.s16   q12,d6,d2[1]                @// y1 * cos1(part of b0)
    vmlsl.s16   q13,d6,d1[1]                @// y1 * cos3(part of b1)
    vmlsl.s16   q14,d6,d3[1]                @// y1 * sin3(part of b2)
    vmlal.s16   q15,d6,d0[1]                @// y1 * sin1(part of b3)

    vmlal.s16   q12,d7,d2[3]                @// y1 * cos1 + y3 * cos3(part of b0)
    vmlsl.s16   q13,d7,d0[1]                @// y1 * cos3 - y3 * sin1(part of b1)
    vmlal.s16   q14,d7,d2[1]                @// y1 * sin3 - y3 * cos1(part of b2)
    vmlal.s16   q15,d7,d3[1]                @// y1 * sin1 - y3 * sin3(part of b3)



    vmlal.s16   q12,d8,d3[1]
    vmlsl.s16   q13,d8,d1[3]
    vmlal.s16   q14,d8,d0[1]
    vmlsl.s16   q15,d8,d1[1]


    vmlal.s16   q12,d9,d3[3]
    vmlsl.s16   q13,d9,d3[1]
    vmlal.s16   q14,d9,d2[3]
    vmlsl.s16   q15,d9,d2[1]





    vmlal.s16   q6,d10,d0[0]
    vmlal.s16   q6,d11,d2[2]
    vmlal.s16   q6,d4,d3[0]
    vmlal.s16   q6,d5,d3[2]




    vmlsl.s16   q7,d10,d0[0]
    vmlsl.s16   q7,d11,d0[2]
    vmlsl.s16   q7,d4,d1[0]
    vmlsl.s16   q7,d5,d2[2]


    vmlsl.s16   q8,d10,d0[0]
    vmlal.s16   q8,d11,d3[2]
    vmlal.s16   q8,d4,d1[0]
    vmlal.s16   q8,d5,d1[2]


    vmlal.s16   q9,d10,d0[0]
    vmlal.s16   q9,d11,d1[2]
    vmlsl.s16   q9,d4,d3[0]
    vmlsl.s16   q9,d5,d0[2]






skip_last8rows_stage2_kernel1:



    vadd.s32    q10,q6,q12
    vsub.s32    q11,q6,q12

    vadd.s32    q6,q7,q13
    vsub.s32    q12,q7,q13

    vadd.s32    q7,q8,q14
    vsub.s32    q13,q8,q14


    vadd.s32    q8,q9,q15
    vsub.s32    q14,q9,q15







    vqrshrn.s32 d30,q10,#shift_stage2_idct  @// r0 = (a0 + b0 + rnd) >> 7(shift_stage1_idct)
    vqrshrn.s32 d19,q11,#shift_stage2_idct  @// r7 = (a0 - b0 + rnd) >> 7(shift_stage1_idct)
    vqrshrn.s32 d31,q7,#shift_stage2_idct   @// r2 = (a2 + b2 + rnd) >> 7(shift_stage1_idct)
    vqrshrn.s32 d18,q13,#shift_stage2_idct  @// r5 = (a2 - b2 + rnd) >> 7(shift_stage1_idct)
    vqrshrn.s32 d12,q6,#shift_stage2_idct   @// r1 = (a1 + b1 + rnd) >> 7(shift_stage1_idct)
    vqrshrn.s32 d15,q12,#shift_stage2_idct  @// r6 = (a1 - b1 + rnd) >> 7(shift_stage1_idct)
    vqrshrn.s32 d13,q8,#shift_stage2_idct   @// r3 = (a3 + b3 + rnd) >> 7(shift_stage1_idct)
    vqrshrn.s32 d14,q14,#shift_stage2_idct  @// r4 = (a3 - b3 + rnd) >> 7(shift_stage1_idct)

    bge         skip_stage2_kernel_load

    @q2,q4,q6,q7 is used
    vld1.16     {d10,d11},[r1]!
    vld1.16     {d6,d7},[r1]!
    vld1.16     {d4,d5},[r9]!
    vld1.16     {d8,d9},[r9]!
skip_stage2_kernel_load:
    sub         r1,r1,#32
    vst1.16     {d30,d31},[r1]!
    vst1.16     {d18,d19},[r1]!
    sub         r1,r1,#32

    vmull.s16   q12,d6,d2[1]                @// y1 * cos1(part of b0)
    vmull.s16   q13,d6,d2[3]                @// y1 * cos3(part of b1)
    vmull.s16   q14,d6,d3[1]                @// y1 * sin3(part of b2)
    vmull.s16   q15,d6,d3[3]                @// y1 * sin1(part of b3)

    vmlsl.s16   q12,d7,d1[1]                @// y1 * cos1 + y3 * cos3(part of b0)
    vmlsl.s16   q13,d7,d0[1]                @// y1 * cos3 - y3 * sin1(part of b1)
    vmlsl.s16   q14,d7,d1[3]                @// y1 * sin3 - y3 * cos1(part of b2)
    vmlsl.s16   q15,d7,d3[1]                @// y1 * sin1 - y3 * sin3(part of b3)


    vmull.s16   q11,d10,d0[0]
    vmlsl.s16   q11,d11,d3[2]
    vmull.s16   q10,d10,d0[0]
    vmlsl.s16   q10,d11,d2[2]
    vmull.s16   q8,d10,d0[0]
    vmlsl.s16   q8,d11,d1[2]
    vmull.s16   q9,d10,d0[0]
    vmlsl.s16   q9,d11,d0[2]



    cmp         r12,r6
    bge         skip_last8rows_stage2_kernel2


    vmlsl.s16   q12,d8,d3[1]
    vmlal.s16   q13,d8,d2[1]
    vmlal.s16   q14,d8,d0[1]
    vmlal.s16   q15,d8,d2[3]


    vmlal.s16   q12,d9,d0[1]
    vmlal.s16   q13,d9,d3[1]
    vmlsl.s16   q14,d9,d1[1]
    vmlsl.s16   q15,d9,d2[1]



    vmlsl.s16   q11,d4,d1[0]
    vmlal.s16   q11,d5,d2[2]
    vmlsl.s16   q10,d4,d3[0]
    vmlal.s16   q10,d5,d0[2]
    vmlal.s16   q8,d4,d3[0]
    vmlal.s16   q8,d5,d3[2]
    vmlal.s16   q9,d4,d1[0]
    vmlsl.s16   q9,d5,d1[2]
    cmp         r12,#0xff00
    bge         skip_last8rows_stage2_kernel2

    vld1.16     {d10,d11},[r11]!
    vld1.16     {d6,d7},[r11]!
    vld1.16     {d4,d5},[r0]!
    vld1.16     {d8,d9},[r0]!

    vmlsl.s16   q12,d6,d3[3]                @// y1 * cos1(part of b0)
    vmlsl.s16   q13,d6,d0[3]                @// y1 * cos3(part of b1)
    vmlal.s16   q14,d6,d2[3]                @// y1 * sin3(part of b2)
    vmlal.s16   q15,d6,d1[3]                @// y1 * sin1(part of b3)

    vmlsl.s16   q12,d7,d0[3]                @// y1 * cos1 + y3 * cos3(part of b0)
    vmlal.s16   q13,d7,d1[3]                @// y1 * cos3 - y3 * sin1(part of b1)
    vmlal.s16   q14,d7,d3[3]                @// y1 * sin3 - y3 * cos1(part of b2)
    vmlsl.s16   q15,d7,d1[1]                @// y1 * sin1 - y3 * sin3(part of b3)


    vmlal.s16   q12,d8,d2[3]
    vmlal.s16   q13,d8,d3[3]
    vmlsl.s16   q14,d8,d2[1]
    vmlal.s16   q15,d8,d0[3]


    vmlal.s16   q12,d9,d1[3]
    vmlsl.s16   q13,d9,d1[1]
    vmlal.s16   q14,d9,d0[3]
    vmlsl.s16   q15,d9,d0[1]




    vmlal.s16   q11,d10,d0[0]
    vmlsl.s16   q11,d11,d1[2]
    vmlsl.s16   q11,d4,d3[0]
    vmlal.s16   q11,d5,d0[2]



    vmlsl.s16   q10,d10,d0[0]
    vmlsl.s16   q10,d11,d3[2]
    vmlal.s16   q10,d4,d1[0]
    vmlsl.s16   q10,d5,d1[2]


    vmlsl.s16   q8,d10,d0[0]
    vmlal.s16   q8,d11,d0[2]
    vmlsl.s16   q8,d4,d1[0]
    vmlal.s16   q8,d5,d2[2]



    vmlal.s16   q9,d10,d0[0]
    vmlsl.s16   q9,d11,d2[2]
    vmlal.s16   q9,d4,d3[0]
    vmlsl.s16   q9,d5,d3[2]


skip_last8rows_stage2_kernel2:



    vadd.s32    q2,q11,q12
    vsub.s32    q11,q11,q12

    vadd.s32    q3,q10,q13
    vsub.s32    q12,q10,q13

    vadd.s32    q5,q8,q14
    vsub.s32    q13,q8,q14


    vadd.s32    q8,q9,q15
    vsub.s32    q14,q9,q15


    vqrshrn.s32 d18,q2,#shift_stage2_idct   @// r0 = (a0 + b0 + rnd) >> 7(shift_stage1_idct)
    vqrshrn.s32 d31,q11,#shift_stage2_idct  @// r7 = (a0 - b0 + rnd) >> 7(shift_stage1_idct)
    vqrshrn.s32 d19,q5,#shift_stage2_idct   @// r2 = (a2 + b2 + rnd) >> 7(shift_stage1_idct)
    vqrshrn.s32 d30,q13,#shift_stage2_idct  @// r5 = (a2 - b2 + rnd) >> 7(shift_stage1_idct)
    vqrshrn.s32 d20,q3,#shift_stage2_idct   @// r1 = (a1 + b1 + rnd) >> 7(shift_stage1_idct)
    vqrshrn.s32 d23,q12,#shift_stage2_idct  @// r6 = (a1 - b1 + rnd) >> 7(shift_stage1_idct)
    vqrshrn.s32 d21,q8,#shift_stage2_idct   @// r3 = (a3 + b3 + rnd) >> 7(shift_stage1_idct)
    vqrshrn.s32 d22,q14,#shift_stage2_idct  @// r4 = (a3 - b3 + rnd) >> 7(shift_stage1_idct)

    vld1.16     {d4,d5},[r1]!
    vld1.16     {d8,d9},[r1]!



    @ registers used:   {q2,q4,q6,q7}, {q9,q15,q10,q11}

@d4=r0
@d12=r1
@d5=r2
@d13=r3

@d18=r4
@d20=r5
@d19=r6
@d21=r7

@d22=r8
@d30=r9
@d23=r10
@d31=r11

@d14=r12
@d8=r13
@d15=r14
@d9=r15


    vtrn.16     q2,q6
    vtrn.16     q9,q10
    vtrn.16     q11,q15
    vtrn.16     q7,q4



    vtrn.32     d4,d5
    vtrn.32     d12,d13

    vtrn.32     d18,d19
    vtrn.32     d20,d21

    vtrn.32     d22,d23
    vtrn.32     d30,d31

    vtrn.32     d14,d15
    vtrn.32     d8,d9

@ d4 =r0 1- 4 values
@ d5 =r2 1- 4 values
@ d12=r1 1- 4 values
@ d13=r3 1- 4 values

@ d18 =r0 5- 8 values
@ d19 =r2 5- 8 values
@ d20=r1 5- 8 values
@ d21=r3 5- 8 values

@ d22 =r0 9- 12 values
@ d23 =r2 9- 12 values
@ d30=r1 9- 12 values
@ d31=r3 9- 12 values

@ d14 =r0 13-16 values
@ d15 =r2 13- 16 values
@ d8=r1 13- 16 values
@ d9=r3 13- 16 values


    vswp        d5,d18
    vswp        d23,d14
    vswp        d13,d20
    vswp        d31,d8

@ q2: r0 1-8 values
@ q11: r0 9-16 values
@ q9 : r2 1-8 values
@ q7 : r2 9-16 values
@ q6 : r1 1- 8 values
@ q10: r3 1-8 values
@ q15: r1 9-16 values
@ q4:  r3 9-16 values


@   registers free: q8,q14,q12,q13


    vld1.8      {d16,d17},[r2],r8
    vld1.8      {d28,d29},[r2],r5
    vld1.8      {d24,d25},[r4],r8
    vld1.8      {d26,d27},[r4],r5




    vaddw.u8    q2,q2,d16
    vaddw.u8    q11,q11,d17
    vaddw.u8    q6,q6,d28
    vaddw.u8    q15,q15,d29
    vaddw.u8    q9,q9,d24
    vaddw.u8    q7,q7,d25
    vaddw.u8    q10,q10,d26
    vaddw.u8    q4,q4,d27


    vqmovun.s16 d16,q2
    vqmovun.s16 d17,q11
    vqmovun.s16 d28,q6
    vqmovun.s16 d29,q15
    vqmovun.s16 d24,q9
    vqmovun.s16 d25,q7
    vqmovun.s16 d26,q10
    vqmovun.s16 d27,q4



    vst1.8      {d16,d17},[r3],r7
    vst1.8      {d28,d29},[r3],r7
    vst1.8      {d24,d25},[r3],r7
    vst1.8      {d26,d27},[r3],r7

    subs        r14,r14,#1



    bne         second_stage


    vpop        {d8  -  d15}
    ldmfd       sp!,{r4-r12,pc}