tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

fwd_txfm_neon.c (14127B)


      1 /*
      2 * Copyright (c) 2016, Alliance for Open Media. All rights reserved.
      3 *
      4 * This source code is subject to the terms of the BSD 2 Clause License and
      5 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
      6 * was not distributed with this source code in the LICENSE file, you can
      7 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
      8 * Media Patent License 1.0 was not distributed with this source code in the
      9 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
     10 */
     11 
     12 #include <arm_neon.h>
     13 
     14 #include "config/aom_config.h"
     15 #include "config/aom_dsp_rtcd.h"
     16 
     17 #include "aom_dsp/txfm_common.h"
     18 #include "aom_dsp/arm/mem_neon.h"
     19 #include "aom_dsp/arm/transpose_neon.h"
     20 
     21 static void aom_fdct4x4_helper(const int16_t *input, int stride,
     22                               int16x4_t *input_0, int16x4_t *input_1,
     23                               int16x4_t *input_2, int16x4_t *input_3) {
     24  *input_0 = vshl_n_s16(vld1_s16(input + 0 * stride), 4);
     25  *input_1 = vshl_n_s16(vld1_s16(input + 1 * stride), 4);
     26  *input_2 = vshl_n_s16(vld1_s16(input + 2 * stride), 4);
     27  *input_3 = vshl_n_s16(vld1_s16(input + 3 * stride), 4);
     28  // If the very first value != 0, then add 1.
     29  if (input[0] != 0) {
     30    const int16x4_t one = vreinterpret_s16_s64(vdup_n_s64(1));
     31    *input_0 = vadd_s16(*input_0, one);
     32  }
     33 
     34  for (int i = 0; i < 2; ++i) {
     35    const int16x8_t input_01 = vcombine_s16(*input_0, *input_1);
     36    const int16x8_t input_32 = vcombine_s16(*input_3, *input_2);
     37 
     38    // in_0 +/- in_3, in_1 +/- in_2
     39    const int16x8_t s_01 = vaddq_s16(input_01, input_32);
     40    const int16x8_t s_32 = vsubq_s16(input_01, input_32);
     41 
     42    // step_0 +/- step_1, step_2 +/- step_3
     43    const int16x4_t s_0 = vget_low_s16(s_01);
     44    const int16x4_t s_1 = vget_high_s16(s_01);
     45    const int16x4_t s_2 = vget_high_s16(s_32);
     46    const int16x4_t s_3 = vget_low_s16(s_32);
     47 
     48    // (s_0 +/- s_1) * cospi_16_64
     49    // Must expand all elements to s32. See 'needs32' comment in fwd_txfm.c.
     50    const int32x4_t s_0_p_s_1 = vaddl_s16(s_0, s_1);
     51    const int32x4_t s_0_m_s_1 = vsubl_s16(s_0, s_1);
     52    const int32x4_t temp1 = vmulq_n_s32(s_0_p_s_1, (int32_t)cospi_16_64);
     53    const int32x4_t temp2 = vmulq_n_s32(s_0_m_s_1, (int32_t)cospi_16_64);
     54 
     55    // fdct_round_shift
     56    int16x4_t out_0 = vrshrn_n_s32(temp1, DCT_CONST_BITS);
     57    int16x4_t out_2 = vrshrn_n_s32(temp2, DCT_CONST_BITS);
     58 
     59    // s_3 * cospi_8_64 + s_2 * cospi_24_64
     60    // s_3 * cospi_24_64 - s_2 * cospi_8_64
     61    const int32x4_t s_3_cospi_8_64 = vmull_n_s16(s_3, (int32_t)cospi_8_64);
     62    const int32x4_t s_3_cospi_24_64 = vmull_n_s16(s_3, (int32_t)cospi_24_64);
     63 
     64    const int32x4_t temp3 =
     65        vmlal_n_s16(s_3_cospi_8_64, s_2, (int32_t)cospi_24_64);
     66    const int32x4_t temp4 =
     67        vmlsl_n_s16(s_3_cospi_24_64, s_2, (int32_t)cospi_8_64);
     68 
     69    // fdct_round_shift
     70    int16x4_t out_1 = vrshrn_n_s32(temp3, DCT_CONST_BITS);
     71    int16x4_t out_3 = vrshrn_n_s32(temp4, DCT_CONST_BITS);
     72 
     73    // Only transpose the first pass
     74    if (i == 0) {
     75      transpose_elems_inplace_s16_4x4(&out_0, &out_1, &out_2, &out_3);
     76    }
     77 
     78    *input_0 = out_0;
     79    *input_1 = out_1;
     80    *input_2 = out_2;
     81    *input_3 = out_3;
     82  }
     83 }
     84 
     85 void aom_fdct4x4_neon(const int16_t *input, tran_low_t *final_output,
     86                      int stride) {
     87  // input[M * stride] * 16
     88  int16x4_t input_0, input_1, input_2, input_3;
     89 
     90  aom_fdct4x4_helper(input, stride, &input_0, &input_1, &input_2, &input_3);
     91 
     92  // Not quite a rounding shift. Only add 1 despite shifting by 2.
     93  const int16x8_t one = vdupq_n_s16(1);
     94  int16x8_t out_01 = vcombine_s16(input_0, input_1);
     95  int16x8_t out_23 = vcombine_s16(input_2, input_3);
     96  out_01 = vshrq_n_s16(vaddq_s16(out_01, one), 2);
     97  out_23 = vshrq_n_s16(vaddq_s16(out_23, one), 2);
     98  store_s16q_to_tran_low(final_output + 0 * 8, out_01);
     99  store_s16q_to_tran_low(final_output + 1 * 8, out_23);
    100 }
    101 
    102 void aom_fdct4x4_lp_neon(const int16_t *input, int16_t *final_output,
    103                         int stride) {
    104  // input[M * stride] * 16
    105  int16x4_t input_0, input_1, input_2, input_3;
    106 
    107  aom_fdct4x4_helper(input, stride, &input_0, &input_1, &input_2, &input_3);
    108 
    109  // Not quite a rounding shift. Only add 1 despite shifting by 2.
    110  const int16x8_t one = vdupq_n_s16(1);
    111  int16x8_t out_01 = vcombine_s16(input_0, input_1);
    112  int16x8_t out_23 = vcombine_s16(input_2, input_3);
    113  out_01 = vshrq_n_s16(vaddq_s16(out_01, one), 2);
    114  out_23 = vshrq_n_s16(vaddq_s16(out_23, one), 2);
    115  vst1q_s16(final_output + 0 * 8, out_01);
    116  vst1q_s16(final_output + 1 * 8, out_23);
    117 }
    118 
    119 #if CONFIG_INTERNAL_STATS
    120 void aom_fdct8x8_neon(const int16_t *input, int16_t *final_output, int stride) {
    121  // stage 1
    122  int16x8_t input_0 = vshlq_n_s16(vld1q_s16(&input[0 * stride]), 2);
    123  int16x8_t input_1 = vshlq_n_s16(vld1q_s16(&input[1 * stride]), 2);
    124  int16x8_t input_2 = vshlq_n_s16(vld1q_s16(&input[2 * stride]), 2);
    125  int16x8_t input_3 = vshlq_n_s16(vld1q_s16(&input[3 * stride]), 2);
    126  int16x8_t input_4 = vshlq_n_s16(vld1q_s16(&input[4 * stride]), 2);
    127  int16x8_t input_5 = vshlq_n_s16(vld1q_s16(&input[5 * stride]), 2);
    128  int16x8_t input_6 = vshlq_n_s16(vld1q_s16(&input[6 * stride]), 2);
    129  int16x8_t input_7 = vshlq_n_s16(vld1q_s16(&input[7 * stride]), 2);
    130  for (int i = 0; i < 2; ++i) {
    131    int16x8_t out_0, out_1, out_2, out_3, out_4, out_5, out_6, out_7;
    132    const int16x8_t v_s0 = vaddq_s16(input_0, input_7);
    133    const int16x8_t v_s1 = vaddq_s16(input_1, input_6);
    134    const int16x8_t v_s2 = vaddq_s16(input_2, input_5);
    135    const int16x8_t v_s3 = vaddq_s16(input_3, input_4);
    136    const int16x8_t v_s4 = vsubq_s16(input_3, input_4);
    137    const int16x8_t v_s5 = vsubq_s16(input_2, input_5);
    138    const int16x8_t v_s6 = vsubq_s16(input_1, input_6);
    139    const int16x8_t v_s7 = vsubq_s16(input_0, input_7);
    140    // fdct4(step, step);
    141    int16x8_t v_x0 = vaddq_s16(v_s0, v_s3);
    142    int16x8_t v_x1 = vaddq_s16(v_s1, v_s2);
    143    int16x8_t v_x2 = vsubq_s16(v_s1, v_s2);
    144    int16x8_t v_x3 = vsubq_s16(v_s0, v_s3);
    145    // fdct4(step, step);
    146    int32x4_t v_t0_lo = vaddl_s16(vget_low_s16(v_x0), vget_low_s16(v_x1));
    147    int32x4_t v_t0_hi = vaddl_s16(vget_high_s16(v_x0), vget_high_s16(v_x1));
    148    int32x4_t v_t1_lo = vsubl_s16(vget_low_s16(v_x0), vget_low_s16(v_x1));
    149    int32x4_t v_t1_hi = vsubl_s16(vget_high_s16(v_x0), vget_high_s16(v_x1));
    150    int32x4_t v_t2_lo = vmull_n_s16(vget_low_s16(v_x2), (int16_t)cospi_24_64);
    151    int32x4_t v_t2_hi = vmull_n_s16(vget_high_s16(v_x2), (int16_t)cospi_24_64);
    152    int32x4_t v_t3_lo = vmull_n_s16(vget_low_s16(v_x3), (int16_t)cospi_24_64);
    153    int32x4_t v_t3_hi = vmull_n_s16(vget_high_s16(v_x3), (int16_t)cospi_24_64);
    154    v_t2_lo = vmlal_n_s16(v_t2_lo, vget_low_s16(v_x3), (int16_t)cospi_8_64);
    155    v_t2_hi = vmlal_n_s16(v_t2_hi, vget_high_s16(v_x3), (int16_t)cospi_8_64);
    156    v_t3_lo = vmlsl_n_s16(v_t3_lo, vget_low_s16(v_x2), (int16_t)cospi_8_64);
    157    v_t3_hi = vmlsl_n_s16(v_t3_hi, vget_high_s16(v_x2), (int16_t)cospi_8_64);
    158    v_t0_lo = vmulq_n_s32(v_t0_lo, (int32_t)cospi_16_64);
    159    v_t0_hi = vmulq_n_s32(v_t0_hi, (int32_t)cospi_16_64);
    160    v_t1_lo = vmulq_n_s32(v_t1_lo, (int32_t)cospi_16_64);
    161    v_t1_hi = vmulq_n_s32(v_t1_hi, (int32_t)cospi_16_64);
    162    {
    163      const int16x4_t a = vrshrn_n_s32(v_t0_lo, DCT_CONST_BITS);
    164      const int16x4_t b = vrshrn_n_s32(v_t0_hi, DCT_CONST_BITS);
    165      const int16x4_t c = vrshrn_n_s32(v_t1_lo, DCT_CONST_BITS);
    166      const int16x4_t d = vrshrn_n_s32(v_t1_hi, DCT_CONST_BITS);
    167      const int16x4_t e = vrshrn_n_s32(v_t2_lo, DCT_CONST_BITS);
    168      const int16x4_t f = vrshrn_n_s32(v_t2_hi, DCT_CONST_BITS);
    169      const int16x4_t g = vrshrn_n_s32(v_t3_lo, DCT_CONST_BITS);
    170      const int16x4_t h = vrshrn_n_s32(v_t3_hi, DCT_CONST_BITS);
    171      out_0 = vcombine_s16(a, c);  // 00 01 02 03 40 41 42 43
    172      out_2 = vcombine_s16(e, g);  // 20 21 22 23 60 61 62 63
    173      out_4 = vcombine_s16(b, d);  // 04 05 06 07 44 45 46 47
    174      out_6 = vcombine_s16(f, h);  // 24 25 26 27 64 65 66 67
    175    }
    176    // Stage 2
    177    v_x0 = vsubq_s16(v_s6, v_s5);
    178    v_x1 = vaddq_s16(v_s6, v_s5);
    179    v_t0_lo = vmull_n_s16(vget_low_s16(v_x0), (int16_t)cospi_16_64);
    180    v_t0_hi = vmull_n_s16(vget_high_s16(v_x0), (int16_t)cospi_16_64);
    181    v_t1_lo = vmull_n_s16(vget_low_s16(v_x1), (int16_t)cospi_16_64);
    182    v_t1_hi = vmull_n_s16(vget_high_s16(v_x1), (int16_t)cospi_16_64);
    183    {
    184      const int16x4_t a = vrshrn_n_s32(v_t0_lo, DCT_CONST_BITS);
    185      const int16x4_t b = vrshrn_n_s32(v_t0_hi, DCT_CONST_BITS);
    186      const int16x4_t c = vrshrn_n_s32(v_t1_lo, DCT_CONST_BITS);
    187      const int16x4_t d = vrshrn_n_s32(v_t1_hi, DCT_CONST_BITS);
    188      const int16x8_t ab = vcombine_s16(a, b);
    189      const int16x8_t cd = vcombine_s16(c, d);
    190      // Stage 3
    191      v_x0 = vaddq_s16(v_s4, ab);
    192      v_x1 = vsubq_s16(v_s4, ab);
    193      v_x2 = vsubq_s16(v_s7, cd);
    194      v_x3 = vaddq_s16(v_s7, cd);
    195    }
    196    // Stage 4
    197    v_t0_lo = vmull_n_s16(vget_low_s16(v_x3), (int16_t)cospi_4_64);
    198    v_t0_hi = vmull_n_s16(vget_high_s16(v_x3), (int16_t)cospi_4_64);
    199    v_t0_lo = vmlal_n_s16(v_t0_lo, vget_low_s16(v_x0), (int16_t)cospi_28_64);
    200    v_t0_hi = vmlal_n_s16(v_t0_hi, vget_high_s16(v_x0), (int16_t)cospi_28_64);
    201    v_t1_lo = vmull_n_s16(vget_low_s16(v_x1), (int16_t)cospi_12_64);
    202    v_t1_hi = vmull_n_s16(vget_high_s16(v_x1), (int16_t)cospi_12_64);
    203    v_t1_lo = vmlal_n_s16(v_t1_lo, vget_low_s16(v_x2), (int16_t)cospi_20_64);
    204    v_t1_hi = vmlal_n_s16(v_t1_hi, vget_high_s16(v_x2), (int16_t)cospi_20_64);
    205    v_t2_lo = vmull_n_s16(vget_low_s16(v_x2), (int16_t)cospi_12_64);
    206    v_t2_hi = vmull_n_s16(vget_high_s16(v_x2), (int16_t)cospi_12_64);
    207    v_t2_lo = vmlsl_n_s16(v_t2_lo, vget_low_s16(v_x1), (int16_t)cospi_20_64);
    208    v_t2_hi = vmlsl_n_s16(v_t2_hi, vget_high_s16(v_x1), (int16_t)cospi_20_64);
    209    v_t3_lo = vmull_n_s16(vget_low_s16(v_x3), (int16_t)cospi_28_64);
    210    v_t3_hi = vmull_n_s16(vget_high_s16(v_x3), (int16_t)cospi_28_64);
    211    v_t3_lo = vmlsl_n_s16(v_t3_lo, vget_low_s16(v_x0), (int16_t)cospi_4_64);
    212    v_t3_hi = vmlsl_n_s16(v_t3_hi, vget_high_s16(v_x0), (int16_t)cospi_4_64);
    213    {
    214      const int16x4_t a = vrshrn_n_s32(v_t0_lo, DCT_CONST_BITS);
    215      const int16x4_t b = vrshrn_n_s32(v_t0_hi, DCT_CONST_BITS);
    216      const int16x4_t c = vrshrn_n_s32(v_t1_lo, DCT_CONST_BITS);
    217      const int16x4_t d = vrshrn_n_s32(v_t1_hi, DCT_CONST_BITS);
    218      const int16x4_t e = vrshrn_n_s32(v_t2_lo, DCT_CONST_BITS);
    219      const int16x4_t f = vrshrn_n_s32(v_t2_hi, DCT_CONST_BITS);
    220      const int16x4_t g = vrshrn_n_s32(v_t3_lo, DCT_CONST_BITS);
    221      const int16x4_t h = vrshrn_n_s32(v_t3_hi, DCT_CONST_BITS);
    222      out_1 = vcombine_s16(a, c);  // 10 11 12 13 50 51 52 53
    223      out_3 = vcombine_s16(e, g);  // 30 31 32 33 70 71 72 73
    224      out_5 = vcombine_s16(b, d);  // 14 15 16 17 54 55 56 57
    225      out_7 = vcombine_s16(f, h);  // 34 35 36 37 74 75 76 77
    226    }
    227    // transpose 8x8
    228    {
    229      // 00 01 02 03 40 41 42 43
    230      // 10 11 12 13 50 51 52 53
    231      // 20 21 22 23 60 61 62 63
    232      // 30 31 32 33 70 71 72 73
    233      // 04 05 06 07 44 45 46 47
    234      // 14 15 16 17 54 55 56 57
    235      // 24 25 26 27 64 65 66 67
    236      // 34 35 36 37 74 75 76 77
    237      const int32x4x2_t r02_s32 =
    238          vtrnq_s32(vreinterpretq_s32_s16(out_0), vreinterpretq_s32_s16(out_2));
    239      const int32x4x2_t r13_s32 =
    240          vtrnq_s32(vreinterpretq_s32_s16(out_1), vreinterpretq_s32_s16(out_3));
    241      const int32x4x2_t r46_s32 =
    242          vtrnq_s32(vreinterpretq_s32_s16(out_4), vreinterpretq_s32_s16(out_6));
    243      const int32x4x2_t r57_s32 =
    244          vtrnq_s32(vreinterpretq_s32_s16(out_5), vreinterpretq_s32_s16(out_7));
    245      const int16x8x2_t r01_s16 =
    246          vtrnq_s16(vreinterpretq_s16_s32(r02_s32.val[0]),
    247                    vreinterpretq_s16_s32(r13_s32.val[0]));
    248      const int16x8x2_t r23_s16 =
    249          vtrnq_s16(vreinterpretq_s16_s32(r02_s32.val[1]),
    250                    vreinterpretq_s16_s32(r13_s32.val[1]));
    251      const int16x8x2_t r45_s16 =
    252          vtrnq_s16(vreinterpretq_s16_s32(r46_s32.val[0]),
    253                    vreinterpretq_s16_s32(r57_s32.val[0]));
    254      const int16x8x2_t r67_s16 =
    255          vtrnq_s16(vreinterpretq_s16_s32(r46_s32.val[1]),
    256                    vreinterpretq_s16_s32(r57_s32.val[1]));
    257      input_0 = r01_s16.val[0];
    258      input_1 = r01_s16.val[1];
    259      input_2 = r23_s16.val[0];
    260      input_3 = r23_s16.val[1];
    261      input_4 = r45_s16.val[0];
    262      input_5 = r45_s16.val[1];
    263      input_6 = r67_s16.val[0];
    264      input_7 = r67_s16.val[1];
    265      // 00 10 20 30 40 50 60 70
    266      // 01 11 21 31 41 51 61 71
    267      // 02 12 22 32 42 52 62 72
    268      // 03 13 23 33 43 53 63 73
    269      // 04 14 24 34 44 54 64 74
    270      // 05 15 25 35 45 55 65 75
    271      // 06 16 26 36 46 56 66 76
    272      // 07 17 27 37 47 57 67 77
    273    }
    274  }  // for
    275  {
    276    // from aom_dct_sse2.c
    277    // Post-condition (division by two)
    278    //    division of two 16 bits signed numbers using shifts
    279    //    n / 2 = (n - (n >> 15)) >> 1
    280    const int16x8_t sign_in0 = vshrq_n_s16(input_0, 15);
    281    const int16x8_t sign_in1 = vshrq_n_s16(input_1, 15);
    282    const int16x8_t sign_in2 = vshrq_n_s16(input_2, 15);
    283    const int16x8_t sign_in3 = vshrq_n_s16(input_3, 15);
    284    const int16x8_t sign_in4 = vshrq_n_s16(input_4, 15);
    285    const int16x8_t sign_in5 = vshrq_n_s16(input_5, 15);
    286    const int16x8_t sign_in6 = vshrq_n_s16(input_6, 15);
    287    const int16x8_t sign_in7 = vshrq_n_s16(input_7, 15);
    288    input_0 = vhsubq_s16(input_0, sign_in0);
    289    input_1 = vhsubq_s16(input_1, sign_in1);
    290    input_2 = vhsubq_s16(input_2, sign_in2);
    291    input_3 = vhsubq_s16(input_3, sign_in3);
    292    input_4 = vhsubq_s16(input_4, sign_in4);
    293    input_5 = vhsubq_s16(input_5, sign_in5);
    294    input_6 = vhsubq_s16(input_6, sign_in6);
    295    input_7 = vhsubq_s16(input_7, sign_in7);
    296    // store results
    297    vst1q_s16(&final_output[0 * 8], input_0);
    298    vst1q_s16(&final_output[1 * 8], input_1);
    299    vst1q_s16(&final_output[2 * 8], input_2);
    300    vst1q_s16(&final_output[3 * 8], input_3);
    301    vst1q_s16(&final_output[4 * 8], input_4);
    302    vst1q_s16(&final_output[5 * 8], input_5);
    303    vst1q_s16(&final_output[6 * 8], input_6);
    304    vst1q_s16(&final_output[7 * 8], input_7);
    305  }
    306 }
    307 #endif  // CONFIG_INTERNAL_STATS