Home | History | Annotate | Download | only in arm
      1 ;
      2 ;  Copyright (c) 2013 The WebM project authors. All Rights Reserved.
      3 ;
      4 ;  Use of this source code is governed by a BSD-style license
      5 ;  that can be found in the LICENSE file in the root of the source
      6 ;  tree. An additional intellectual property rights grant can be found
      7 ;  in the file PATENTS.  All contributing project authors may
      8 ;  be found in the AUTHORS file in the root of the source tree.
      9 ;
     10 
     11     EXPORT  |vpx_idct8x8_64_add_neon|
     12     EXPORT  |vpx_idct8x8_12_add_neon|
     13     ARM
     14     REQUIRE8
     15     PRESERVE8
     16 
     17     AREA ||.text||, CODE, READONLY, ALIGN=2
     18 
     19     ; Parallel 1D IDCT on all the columns of a 8x8 16bit data matrix which are
     20     ; loaded in q8-q15. The output will be stored back into q8-q15 registers.
     21     ; This macro will touch q0-q7 registers and use them as buffer during
     22     ; calculation.
     23     MACRO
     24     IDCT8x8_1D
     25     ; stage 1
     26     vdup.16         d0, r3                    ; duplicate cospi_28_64
     27     vdup.16         d1, r4                    ; duplicate cospi_4_64
     28     vdup.16         d2, r5                    ; duplicate cospi_12_64
     29     vdup.16         d3, r6                    ; duplicate cospi_20_64
     30 
     31     ; input[1] * cospi_28_64
     32     vmull.s16       q2, d18, d0
     33     vmull.s16       q3, d19, d0
     34 
     35     ; input[5] * cospi_12_64
     36     vmull.s16       q5, d26, d2
     37     vmull.s16       q6, d27, d2
     38 
     39     ; input[1]*cospi_28_64-input[7]*cospi_4_64
     40     vmlsl.s16       q2, d30, d1
     41     vmlsl.s16       q3, d31, d1
     42 
     43     ; input[5] * cospi_12_64 - input[3] * cospi_20_64
     44     vmlsl.s16       q5, d22, d3
     45     vmlsl.s16       q6, d23, d3
     46 
     47     ; dct_const_round_shift(input_dc * cospi_16_64)
     48     vqrshrn.s32     d8, q2, #14               ; >> 14
     49     vqrshrn.s32     d9, q3, #14               ; >> 14
     50 
     51     ; dct_const_round_shift(input_dc * cospi_16_64)
     52     vqrshrn.s32     d10, q5, #14              ; >> 14
     53     vqrshrn.s32     d11, q6, #14              ; >> 14
     54 
     55     ; input[1] * cospi_4_64
     56     vmull.s16       q2, d18, d1
     57     vmull.s16       q3, d19, d1
     58 
     59     ; input[5] * cospi_20_64
     60     vmull.s16       q9, d26, d3
     61     vmull.s16       q13, d27, d3
     62 
     63     ; input[1]*cospi_4_64+input[7]*cospi_28_64
     64     vmlal.s16       q2, d30, d0
     65     vmlal.s16       q3, d31, d0
     66 
     67     ; input[5] * cospi_20_64 + input[3] * cospi_12_64
     68     vmlal.s16       q9, d22, d2
     69     vmlal.s16       q13, d23, d2
     70 
     71     ; dct_const_round_shift(input_dc * cospi_16_64)
     72     vqrshrn.s32     d14, q2, #14              ; >> 14
     73     vqrshrn.s32     d15, q3, #14              ; >> 14
     74 
     75     ; stage 2 & stage 3 - even half
     76     vdup.16         d0, r7                    ; duplicate cospi_16_64
     77 
     78     ; dct_const_round_shift(input_dc * cospi_16_64)
     79     vqrshrn.s32     d12, q9, #14              ; >> 14
     80     vqrshrn.s32     d13, q13, #14              ; >> 14
     81 
     82     ; input[0] * cospi_16_64
     83     vmull.s16       q2, d16, d0
     84     vmull.s16       q3, d17, d0
     85 
     86     ; input[0] * cospi_16_64
     87     vmull.s16       q13, d16, d0
     88     vmull.s16       q15, d17, d0
     89 
     90     ; (input[0] + input[2]) * cospi_16_64
     91     vmlal.s16       q2,  d24, d0
     92     vmlal.s16       q3, d25, d0
     93 
     94     ; (input[0] - input[2]) * cospi_16_64
     95     vmlsl.s16       q13, d24, d0
     96     vmlsl.s16       q15, d25, d0
     97 
     98     vdup.16         d0, r8                    ; duplicate cospi_24_64
     99     vdup.16         d1, r9                    ; duplicate cospi_8_64
    100 
    101     ; dct_const_round_shift(input_dc * cospi_16_64)
    102     vqrshrn.s32     d18, q2, #14              ; >> 14
    103     vqrshrn.s32     d19, q3, #14              ; >> 14
    104 
    105     ; dct_const_round_shift(input_dc * cospi_16_64)
    106     vqrshrn.s32     d22, q13, #14              ; >> 14
    107     vqrshrn.s32     d23, q15, #14              ; >> 14
    108 
    109     ; input[1] * cospi_24_64 - input[3] * cospi_8_64
    110     ; input[1] * cospi_24_64
    111     vmull.s16       q2, d20, d0
    112     vmull.s16       q3, d21, d0
    113 
    114     ; input[1] * cospi_8_64
    115     vmull.s16       q8, d20, d1
    116     vmull.s16       q12, d21, d1
    117 
    118     ; input[1] * cospi_24_64 - input[3] * cospi_8_64
    119     vmlsl.s16       q2, d28, d1
    120     vmlsl.s16       q3, d29, d1
    121 
    122     ; input[1] * cospi_8_64 + input[3] * cospi_24_64
    123     vmlal.s16       q8, d28, d0
    124     vmlal.s16       q12, d29, d0
    125 
    126     ; dct_const_round_shift(input_dc * cospi_16_64)
    127     vqrshrn.s32     d26, q2, #14              ; >> 14
    128     vqrshrn.s32     d27, q3, #14              ; >> 14
    129 
    130     ; dct_const_round_shift(input_dc * cospi_16_64)
    131     vqrshrn.s32     d30, q8, #14              ; >> 14
    132     vqrshrn.s32     d31, q12, #14              ; >> 14
    133 
    134     vadd.s16        q0, q9, q15               ; output[0] = step[0] + step[3]
    135     vadd.s16        q1, q11, q13              ; output[1] = step[1] + step[2]
    136     vsub.s16        q2, q11, q13              ; output[2] = step[1] - step[2]
    137     vsub.s16        q3, q9, q15               ; output[3] = step[0] - step[3]
    138 
    139     ; stage 3 -odd half
    140     vdup.16         d16, r7                   ; duplicate cospi_16_64
    141 
    142     ; stage 2 - odd half
    143     vsub.s16        q13, q4, q5               ; step2[5] = step1[4] - step1[5]
    144     vadd.s16        q4, q4, q5                ; step2[4] = step1[4] + step1[5]
    145     vsub.s16        q14, q7, q6               ; step2[6] = -step1[6] + step1[7]
    146     vadd.s16        q7, q7, q6                ; step2[7] = step1[6] + step1[7]
    147 
    148     ; step2[6] * cospi_16_64
    149     vmull.s16       q9, d28, d16
    150     vmull.s16       q10, d29, d16
    151 
    152     ; step2[6] * cospi_16_64
    153     vmull.s16       q11, d28, d16
    154     vmull.s16       q12, d29, d16
    155 
    156     ; (step2[6] - step2[5]) * cospi_16_64
    157     vmlsl.s16       q9, d26, d16
    158     vmlsl.s16       q10, d27, d16
    159 
    160     ; (step2[5] + step2[6]) * cospi_16_64
    161     vmlal.s16       q11, d26, d16
    162     vmlal.s16       q12, d27, d16
    163 
    164     ; dct_const_round_shift(input_dc * cospi_16_64)
    165     vqrshrn.s32     d10, q9, #14              ; >> 14
    166     vqrshrn.s32     d11, q10, #14             ; >> 14
    167 
    168     ; dct_const_round_shift(input_dc * cospi_16_64)
    169     vqrshrn.s32     d12, q11, #14              ; >> 14
    170     vqrshrn.s32     d13, q12, #14             ; >> 14
    171 
    172     ; stage 4
    173     vadd.s16        q8, q0, q7                ; output[0] = step1[0] + step1[7];
    174     vadd.s16        q9, q1, q6                ; output[1] = step1[1] + step1[6];
    175     vadd.s16        q10, q2, q5               ; output[2] = step1[2] + step1[5];
    176     vadd.s16        q11, q3, q4               ; output[3] = step1[3] + step1[4];
    177     vsub.s16        q12, q3, q4               ; output[4] = step1[3] - step1[4];
    178     vsub.s16        q13, q2, q5               ; output[5] = step1[2] - step1[5];
    179     vsub.s16        q14, q1, q6               ; output[6] = step1[1] - step1[6];
    180     vsub.s16        q15, q0, q7               ; output[7] = step1[0] - step1[7];
    181     MEND
    182 
    183     ; Transpose a 8x8 16bit data matrix. Datas are loaded in q8-q15.
    184     MACRO
    185     TRANSPOSE8X8
    186     vswp            d17, d24
    187     vswp            d23, d30
    188     vswp            d21, d28
    189     vswp            d19, d26
    190     vtrn.32         q8, q10
    191     vtrn.32         q9, q11
    192     vtrn.32         q12, q14
    193     vtrn.32         q13, q15
    194     vtrn.16         q8, q9
    195     vtrn.16         q10, q11
    196     vtrn.16         q12, q13
    197     vtrn.16         q14, q15
    198     MEND
    199 
    200     AREA    Block, CODE, READONLY ; name this block of code
    201 ;void vpx_idct8x8_64_add_neon(int16_t *input, uint8_t *dest, int dest_stride)
    202 ;
    203 ; r0  int16_t input
    204 ; r1  uint8_t *dest
    205 ; r2  int dest_stride)
    206 
    207 |vpx_idct8x8_64_add_neon| PROC
    208     push            {r4-r9}
    209     vpush           {d8-d15}
    210     vld1.s16        {q8,q9}, [r0]!
    211     vld1.s16        {q10,q11}, [r0]!
    212     vld1.s16        {q12,q13}, [r0]!
    213     vld1.s16        {q14,q15}, [r0]!
    214 
    215     ; transpose the input data
    216     TRANSPOSE8X8
    217 
    218     ; generate  cospi_28_64 = 3196
    219     mov             r3, #0x0c00
    220     add             r3, #0x7c
    221 
    222     ; generate cospi_4_64  = 16069
    223     mov             r4, #0x3e00
    224     add             r4, #0xc5
    225 
    226     ; generate cospi_12_64 = 13623
    227     mov             r5, #0x3500
    228     add             r5, #0x37
    229 
    230     ; generate cospi_20_64 = 9102
    231     mov             r6, #0x2300
    232     add             r6, #0x8e
    233 
    234     ; generate cospi_16_64 = 11585
    235     mov             r7, #0x2d00
    236     add             r7, #0x41
    237 
    238     ; generate cospi_24_64 = 6270
    239     mov             r8, #0x1800
    240     add             r8, #0x7e
    241 
    242     ; generate cospi_8_64 = 15137
    243     mov             r9, #0x3b00
    244     add             r9, #0x21
    245 
    246     ; First transform rows
    247     IDCT8x8_1D
    248 
    249     ; Transpose the matrix
    250     TRANSPOSE8X8
    251 
    252     ; Then transform columns
    253     IDCT8x8_1D
    254 
    255     ; ROUND_POWER_OF_TWO(temp_out[j], 5)
    256     vrshr.s16       q8, q8, #5
    257     vrshr.s16       q9, q9, #5
    258     vrshr.s16       q10, q10, #5
    259     vrshr.s16       q11, q11, #5
    260     vrshr.s16       q12, q12, #5
    261     vrshr.s16       q13, q13, #5
    262     vrshr.s16       q14, q14, #5
    263     vrshr.s16       q15, q15, #5
    264 
    265     ; save dest pointer
    266     mov             r0, r1
    267 
    268     ; load destination data
    269     vld1.64         {d0}, [r1], r2
    270     vld1.64         {d1}, [r1], r2
    271     vld1.64         {d2}, [r1], r2
    272     vld1.64         {d3}, [r1], r2
    273     vld1.64         {d4}, [r1], r2
    274     vld1.64         {d5}, [r1], r2
    275     vld1.64         {d6}, [r1], r2
    276     vld1.64         {d7}, [r1]
    277 
    278     ; ROUND_POWER_OF_TWO(temp_out[j], 5) + dest[j * dest_stride + i]
    279     vaddw.u8        q8, q8, d0
    280     vaddw.u8        q9, q9, d1
    281     vaddw.u8        q10, q10, d2
    282     vaddw.u8        q11, q11, d3
    283     vaddw.u8        q12, q12, d4
    284     vaddw.u8        q13, q13, d5
    285     vaddw.u8        q14, q14, d6
    286     vaddw.u8        q15, q15, d7
    287 
    288     ; clip_pixel
    289     vqmovun.s16     d0, q8
    290     vqmovun.s16     d1, q9
    291     vqmovun.s16     d2, q10
    292     vqmovun.s16     d3, q11
    293     vqmovun.s16     d4, q12
    294     vqmovun.s16     d5, q13
    295     vqmovun.s16     d6, q14
    296     vqmovun.s16     d7, q15
    297 
    298     ; store the data
    299     vst1.64         {d0}, [r0], r2
    300     vst1.64         {d1}, [r0], r2
    301     vst1.64         {d2}, [r0], r2
    302     vst1.64         {d3}, [r0], r2
    303     vst1.64         {d4}, [r0], r2
    304     vst1.64         {d5}, [r0], r2
    305     vst1.64         {d6}, [r0], r2
    306     vst1.64         {d7}, [r0], r2
    307 
    308     vpop            {d8-d15}
    309     pop             {r4-r9}
    310     bx              lr
    311     ENDP  ; |vpx_idct8x8_64_add_neon|
    312 
    313 ;void vpx_idct8x8_12_add_neon(int16_t *input, uint8_t *dest, int dest_stride)
    314 ;
    315 ; r0  int16_t input
    316 ; r1  uint8_t *dest
    317 ; r2  int dest_stride)
    318 
    319 |vpx_idct8x8_12_add_neon| PROC
    320     push            {r4-r9}
    321     vpush           {d8-d15}
    322     vld1.s16        {q8,q9}, [r0]!
    323     vld1.s16        {q10,q11}, [r0]!
    324     vld1.s16        {q12,q13}, [r0]!
    325     vld1.s16        {q14,q15}, [r0]!
    326 
    327     ; transpose the input data
    328     TRANSPOSE8X8
    329 
    330     ; generate  cospi_28_64 = 3196
    331     mov             r3, #0x0c00
    332     add             r3, #0x7c
    333 
    334     ; generate cospi_4_64  = 16069
    335     mov             r4, #0x3e00
    336     add             r4, #0xc5
    337 
    338     ; generate cospi_12_64 = 13623
    339     mov             r5, #0x3500
    340     add             r5, #0x37
    341 
    342     ; generate cospi_20_64 = 9102
    343     mov             r6, #0x2300
    344     add             r6, #0x8e
    345 
    346     ; generate cospi_16_64 = 11585
    347     mov             r7, #0x2d00
    348     add             r7, #0x41
    349 
    350     ; generate cospi_24_64 = 6270
    351     mov             r8, #0x1800
    352     add             r8, #0x7e
    353 
    354     ; generate cospi_8_64 = 15137
    355     mov             r9, #0x3b00
    356     add             r9, #0x21
    357 
    358     ; First transform rows
    359     ; stage 1
    360     ; The following instructions use vqrdmulh to do the
    361     ; dct_const_round_shift(input[1] * cospi_28_64). vqrdmulh will do doubling
    362     ; multiply and shift the result by 16 bits instead of 14 bits. So we need
    363     ; to double the constants before multiplying to compensate this.
    364     mov             r12, r3, lsl #1
    365     vdup.16         q0, r12                   ; duplicate cospi_28_64*2
    366     mov             r12, r4, lsl #1
    367     vdup.16         q1, r12                   ; duplicate cospi_4_64*2
    368 
    369     ; dct_const_round_shift(input[1] * cospi_28_64)
    370     vqrdmulh.s16    q4, q9, q0
    371 
    372     mov             r12, r6, lsl #1
    373     rsb             r12, #0
    374     vdup.16         q0, r12                   ; duplicate -cospi_20_64*2
    375 
    376     ; dct_const_round_shift(input[1] * cospi_4_64)
    377     vqrdmulh.s16    q7, q9, q1
    378 
    379     mov             r12, r5, lsl #1
    380     vdup.16         q1, r12                   ; duplicate cospi_12_64*2
    381 
    382     ; dct_const_round_shift(- input[3] * cospi_20_64)
    383     vqrdmulh.s16    q5, q11, q0
    384 
    385     mov             r12, r7, lsl #1
    386     vdup.16         q0, r12                   ; duplicate cospi_16_64*2
    387 
    388     ; dct_const_round_shift(input[3] * cospi_12_64)
    389     vqrdmulh.s16    q6, q11, q1
    390 
    391     ; stage 2 & stage 3 - even half
    392     mov             r12, r8, lsl #1
    393     vdup.16         q1, r12                   ; duplicate cospi_24_64*2
    394 
    395     ; dct_const_round_shift(input_dc * cospi_16_64)
    396     vqrdmulh.s16    q9, q8, q0
    397 
    398     mov             r12, r9, lsl #1
    399     vdup.16         q0, r12                   ; duplicate cospi_8_64*2
    400 
    401     ; dct_const_round_shift(input[1] * cospi_24_64)
    402     vqrdmulh.s16    q13, q10, q1
    403 
    404     ; dct_const_round_shift(input[1] * cospi_8_64)
    405     vqrdmulh.s16    q15, q10, q0
    406 
    407     ; stage 3 -odd half
    408     vdup.16         d16, r7                   ; duplicate cospi_16_64
    409 
    410     vadd.s16        q0, q9, q15               ; output[0] = step[0] + step[3]
    411     vadd.s16        q1, q9, q13               ; output[1] = step[1] + step[2]
    412     vsub.s16        q2, q9, q13               ; output[2] = step[1] - step[2]
    413     vsub.s16        q3, q9, q15               ; output[3] = step[0] - step[3]
    414 
    415     ; stage 2 - odd half
    416     vsub.s16        q13, q4, q5               ; step2[5] = step1[4] - step1[5]
    417     vadd.s16        q4, q4, q5                ; step2[4] = step1[4] + step1[5]
    418     vsub.s16        q14, q7, q6               ; step2[6] = -step1[6] + step1[7]
    419     vadd.s16        q7, q7, q6                ; step2[7] = step1[6] + step1[7]
    420 
    421     ; step2[6] * cospi_16_64
    422     vmull.s16       q9, d28, d16
    423     vmull.s16       q10, d29, d16
    424 
    425     ; step2[6] * cospi_16_64
    426     vmull.s16       q11, d28, d16
    427     vmull.s16       q12, d29, d16
    428 
    429     ; (step2[6] - step2[5]) * cospi_16_64
    430     vmlsl.s16       q9, d26, d16
    431     vmlsl.s16       q10, d27, d16
    432 
    433     ; (step2[5] + step2[6]) * cospi_16_64
    434     vmlal.s16       q11, d26, d16
    435     vmlal.s16       q12, d27, d16
    436 
    437     ; dct_const_round_shift(input_dc * cospi_16_64)
    438     vqrshrn.s32     d10, q9, #14              ; >> 14
    439     vqrshrn.s32     d11, q10, #14             ; >> 14
    440 
    441     ; dct_const_round_shift(input_dc * cospi_16_64)
    442     vqrshrn.s32     d12, q11, #14              ; >> 14
    443     vqrshrn.s32     d13, q12, #14             ; >> 14
    444 
    445     ; stage 4
    446     vadd.s16        q8, q0, q7                ; output[0] = step1[0] + step1[7];
    447     vadd.s16        q9, q1, q6                ; output[1] = step1[1] + step1[6];
    448     vadd.s16        q10, q2, q5               ; output[2] = step1[2] + step1[5];
    449     vadd.s16        q11, q3, q4               ; output[3] = step1[3] + step1[4];
    450     vsub.s16        q12, q3, q4               ; output[4] = step1[3] - step1[4];
    451     vsub.s16        q13, q2, q5               ; output[5] = step1[2] - step1[5];
    452     vsub.s16        q14, q1, q6               ; output[6] = step1[1] - step1[6];
    453     vsub.s16        q15, q0, q7               ; output[7] = step1[0] - step1[7];
    454 
    455     ; Transpose the matrix
    456     TRANSPOSE8X8
    457 
    458     ; Then transform columns
    459     IDCT8x8_1D
    460 
    461     ; ROUND_POWER_OF_TWO(temp_out[j], 5)
    462     vrshr.s16       q8, q8, #5
    463     vrshr.s16       q9, q9, #5
    464     vrshr.s16       q10, q10, #5
    465     vrshr.s16       q11, q11, #5
    466     vrshr.s16       q12, q12, #5
    467     vrshr.s16       q13, q13, #5
    468     vrshr.s16       q14, q14, #5
    469     vrshr.s16       q15, q15, #5
    470 
    471     ; save dest pointer
    472     mov             r0, r1
    473 
    474     ; load destination data
    475     vld1.64         {d0}, [r1], r2
    476     vld1.64         {d1}, [r1], r2
    477     vld1.64         {d2}, [r1], r2
    478     vld1.64         {d3}, [r1], r2
    479     vld1.64         {d4}, [r1], r2
    480     vld1.64         {d5}, [r1], r2
    481     vld1.64         {d6}, [r1], r2
    482     vld1.64         {d7}, [r1]
    483 
    484     ; ROUND_POWER_OF_TWO(temp_out[j], 5) + dest[j * dest_stride + i]
    485     vaddw.u8        q8, q8, d0
    486     vaddw.u8        q9, q9, d1
    487     vaddw.u8        q10, q10, d2
    488     vaddw.u8        q11, q11, d3
    489     vaddw.u8        q12, q12, d4
    490     vaddw.u8        q13, q13, d5
    491     vaddw.u8        q14, q14, d6
    492     vaddw.u8        q15, q15, d7
    493 
    494     ; clip_pixel
    495     vqmovun.s16     d0, q8
    496     vqmovun.s16     d1, q9
    497     vqmovun.s16     d2, q10
    498     vqmovun.s16     d3, q11
    499     vqmovun.s16     d4, q12
    500     vqmovun.s16     d5, q13
    501     vqmovun.s16     d6, q14
    502     vqmovun.s16     d7, q15
    503 
    504     ; store the data
    505     vst1.64         {d0}, [r0], r2
    506     vst1.64         {d1}, [r0], r2
    507     vst1.64         {d2}, [r0], r2
    508     vst1.64         {d3}, [r0], r2
    509     vst1.64         {d4}, [r0], r2
    510     vst1.64         {d5}, [r0], r2
    511     vst1.64         {d6}, [r0], r2
    512     vst1.64         {d7}, [r0], r2
    513 
    514     vpop            {d8-d15}
    515     pop             {r4-r9}
    516     bx              lr
    517     ENDP  ; |vpx_idct8x8_12_add_neon|
    518 
    519     END
    520