Home | History | Annotate | Download | only in dsp
      1 // Copyright 2012 Google Inc. All Rights Reserved.
      2 //
      3 // Use of this source code is governed by a BSD-style license
      4 // that can be found in the COPYING file in the root of the source
      5 // tree. An additional intellectual property rights grant can be found
      6 // in the file PATENTS. All contributing project authors may
      7 // be found in the AUTHORS file in the root of the source tree.
      8 // -----------------------------------------------------------------------------
      9 //
     10 // ARM NEON version of speed-critical encoding functions.
     11 //
     12 // adapted from libvpx (http://www.webmproject.org/code/)
     13 
     14 #include "./dsp.h"
     15 
     16 #if defined(__cplusplus) || defined(c_plusplus)
     17 extern "C" {
     18 #endif
     19 
     20 #if defined(WEBP_USE_NEON)
     21 
     22 #include "../enc/vp8enci.h"
     23 
     24 //------------------------------------------------------------------------------
     25 // Transforms (Paragraph 14.4)
     26 
     27 // Inverse transform.
     28 // This code is pretty much the same as TransformOneNEON in the decoder, except
     29 // for subtraction to *ref. See the comments there for algorithmic explanations.
     30 static void ITransformOne(const uint8_t* ref,
     31                           const int16_t* in, uint8_t* dst) {
     32   const int kBPS = BPS;
     33   const int16_t kC1C2[] = { 20091, 17734, 0, 0 };  // kC1 / (kC2 >> 1) / 0 / 0
     34 
     35   __asm__ volatile (
     36     "vld1.16         {q1, q2}, [%[in]]           \n"
     37     "vld1.16         {d0}, [%[kC1C2]]            \n"
     38 
     39     // d2: in[0]
     40     // d3: in[8]
     41     // d4: in[4]
     42     // d5: in[12]
     43     "vswp            d3, d4                      \n"
     44 
     45     // q8 = {in[4], in[12]} * kC1 * 2 >> 16
     46     // q9 = {in[4], in[12]} * kC2 >> 16
     47     "vqdmulh.s16     q8, q2, d0[0]               \n"
     48     "vqdmulh.s16     q9, q2, d0[1]               \n"
     49 
     50     // d22 = a = in[0] + in[8]
     51     // d23 = b = in[0] - in[8]
     52     "vqadd.s16       d22, d2, d3                 \n"
     53     "vqsub.s16       d23, d2, d3                 \n"
     54 
     55     //  q8 = in[4]/[12] * kC1 >> 16
     56     "vshr.s16        q8, q8, #1                  \n"
     57 
     58     // Add {in[4], in[12]} back after the multiplication.
     59     "vqadd.s16       q8, q2, q8                  \n"
     60 
     61     // d20 = c = in[4]*kC2 - in[12]*kC1
     62     // d21 = d = in[4]*kC1 + in[12]*kC2
     63     "vqsub.s16       d20, d18, d17               \n"
     64     "vqadd.s16       d21, d19, d16               \n"
     65 
     66     // d2 = tmp[0] = a + d
     67     // d3 = tmp[1] = b + c
     68     // d4 = tmp[2] = b - c
     69     // d5 = tmp[3] = a - d
     70     "vqadd.s16       d2, d22, d21                \n"
     71     "vqadd.s16       d3, d23, d20                \n"
     72     "vqsub.s16       d4, d23, d20                \n"
     73     "vqsub.s16       d5, d22, d21                \n"
     74 
     75     "vzip.16         q1, q2                      \n"
     76     "vzip.16         q1, q2                      \n"
     77 
     78     "vswp            d3, d4                      \n"
     79 
     80     // q8 = {tmp[4], tmp[12]} * kC1 * 2 >> 16
     81     // q9 = {tmp[4], tmp[12]} * kC2 >> 16
     82     "vqdmulh.s16     q8, q2, d0[0]               \n"
     83     "vqdmulh.s16     q9, q2, d0[1]               \n"
     84 
     85     // d22 = a = tmp[0] + tmp[8]
     86     // d23 = b = tmp[0] - tmp[8]
     87     "vqadd.s16       d22, d2, d3                 \n"
     88     "vqsub.s16       d23, d2, d3                 \n"
     89 
     90     "vshr.s16        q8, q8, #1                  \n"
     91     "vqadd.s16       q8, q2, q8                  \n"
     92 
     93     // d20 = c = in[4]*kC2 - in[12]*kC1
     94     // d21 = d = in[4]*kC1 + in[12]*kC2
     95     "vqsub.s16       d20, d18, d17               \n"
     96     "vqadd.s16       d21, d19, d16               \n"
     97 
     98     // d2 = tmp[0] = a + d
     99     // d3 = tmp[1] = b + c
    100     // d4 = tmp[2] = b - c
    101     // d5 = tmp[3] = a - d
    102     "vqadd.s16       d2, d22, d21                \n"
    103     "vqadd.s16       d3, d23, d20                \n"
    104     "vqsub.s16       d4, d23, d20                \n"
    105     "vqsub.s16       d5, d22, d21                \n"
    106 
    107     "vld1.32         d6[0], [%[ref]], %[kBPS]    \n"
    108     "vld1.32         d6[1], [%[ref]], %[kBPS]    \n"
    109     "vld1.32         d7[0], [%[ref]], %[kBPS]    \n"
    110     "vld1.32         d7[1], [%[ref]], %[kBPS]    \n"
    111 
    112     "sub         %[ref], %[ref], %[kBPS], lsl #2 \n"
    113 
    114     // (val) + 4 >> 3
    115     "vrshr.s16       d2, d2, #3                  \n"
    116     "vrshr.s16       d3, d3, #3                  \n"
    117     "vrshr.s16       d4, d4, #3                  \n"
    118     "vrshr.s16       d5, d5, #3                  \n"
    119 
    120     "vzip.16         q1, q2                      \n"
    121     "vzip.16         q1, q2                      \n"
    122 
    123     // Must accumulate before saturating
    124     "vmovl.u8        q8, d6                      \n"
    125     "vmovl.u8        q9, d7                      \n"
    126 
    127     "vqadd.s16       q1, q1, q8                  \n"
    128     "vqadd.s16       q2, q2, q9                  \n"
    129 
    130     "vqmovun.s16     d0, q1                      \n"
    131     "vqmovun.s16     d1, q2                      \n"
    132 
    133     "vst1.32         d0[0], [%[dst]], %[kBPS]    \n"
    134     "vst1.32         d0[1], [%[dst]], %[kBPS]    \n"
    135     "vst1.32         d1[0], [%[dst]], %[kBPS]    \n"
    136     "vst1.32         d1[1], [%[dst]]             \n"
    137 
    138     : [in] "+r"(in), [dst] "+r"(dst)               // modified registers
    139     : [kBPS] "r"(kBPS), [kC1C2] "r"(kC1C2), [ref] "r"(ref)  // constants
    140     : "memory", "q0", "q1", "q2", "q8", "q9", "q10", "q11"  // clobbered
    141   );
    142 }
    143 
    144 static void ITransform(const uint8_t* ref,
    145                        const int16_t* in, uint8_t* dst, int do_two) {
    146   ITransformOne(ref, in, dst);
    147   if (do_two) {
    148     ITransformOne(ref + 4, in + 16, dst + 4);
    149   }
    150 }
    151 
    152 // Same code as dec_neon.c
    153 static void ITransformWHT(const int16_t* in, int16_t* out) {
    154   const int kStep = 32;  // The store is only incrementing the pointer as if we
    155                          // had stored a single byte.
    156   __asm__ volatile (
    157     // part 1
    158     // load data into q0, q1
    159     "vld1.16         {q0, q1}, [%[in]]           \n"
    160 
    161     "vaddl.s16       q2, d0, d3                  \n" // a0 = in[0] + in[12]
    162     "vaddl.s16       q3, d1, d2                  \n" // a1 = in[4] + in[8]
    163     "vsubl.s16       q4, d1, d2                  \n" // a2 = in[4] - in[8]
    164     "vsubl.s16       q5, d0, d3                  \n" // a3 = in[0] - in[12]
    165 
    166     "vadd.s32        q0, q2, q3                  \n" // tmp[0] = a0 + a1
    167     "vsub.s32        q2, q2, q3                  \n" // tmp[8] = a0 - a1
    168     "vadd.s32        q1, q5, q4                  \n" // tmp[4] = a3 + a2
    169     "vsub.s32        q3, q5, q4                  \n" // tmp[12] = a3 - a2
    170 
    171     // Transpose
    172     // q0 = tmp[0, 4, 8, 12], q1 = tmp[2, 6, 10, 14]
    173     // q2 = tmp[1, 5, 9, 13], q3 = tmp[3, 7, 11, 15]
    174     "vswp            d1, d4                      \n" // vtrn.64 q0, q2
    175     "vswp            d3, d6                      \n" // vtrn.64 q1, q3
    176     "vtrn.32         q0, q1                      \n"
    177     "vtrn.32         q2, q3                      \n"
    178 
    179     "vmov.s32        q4, #3                      \n" // dc = 3
    180     "vadd.s32        q0, q0, q4                  \n" // dc = tmp[0] + 3
    181     "vadd.s32        q6, q0, q3                  \n" // a0 = dc + tmp[3]
    182     "vadd.s32        q7, q1, q2                  \n" // a1 = tmp[1] + tmp[2]
    183     "vsub.s32        q8, q1, q2                  \n" // a2 = tmp[1] - tmp[2]
    184     "vsub.s32        q9, q0, q3                  \n" // a3 = dc - tmp[3]
    185 
    186     "vadd.s32        q0, q6, q7                  \n"
    187     "vshrn.s32       d0, q0, #3                  \n" // (a0 + a1) >> 3
    188     "vadd.s32        q1, q9, q8                  \n"
    189     "vshrn.s32       d1, q1, #3                  \n" // (a3 + a2) >> 3
    190     "vsub.s32        q2, q6, q7                  \n"
    191     "vshrn.s32       d2, q2, #3                  \n" // (a0 - a1) >> 3
    192     "vsub.s32        q3, q9, q8                  \n"
    193     "vshrn.s32       d3, q3, #3                  \n" // (a3 - a2) >> 3
    194 
    195     // set the results to output
    196     "vst1.16         d0[0], [%[out]], %[kStep]      \n"
    197     "vst1.16         d1[0], [%[out]], %[kStep]      \n"
    198     "vst1.16         d2[0], [%[out]], %[kStep]      \n"
    199     "vst1.16         d3[0], [%[out]], %[kStep]      \n"
    200     "vst1.16         d0[1], [%[out]], %[kStep]      \n"
    201     "vst1.16         d1[1], [%[out]], %[kStep]      \n"
    202     "vst1.16         d2[1], [%[out]], %[kStep]      \n"
    203     "vst1.16         d3[1], [%[out]], %[kStep]      \n"
    204     "vst1.16         d0[2], [%[out]], %[kStep]      \n"
    205     "vst1.16         d1[2], [%[out]], %[kStep]      \n"
    206     "vst1.16         d2[2], [%[out]], %[kStep]      \n"
    207     "vst1.16         d3[2], [%[out]], %[kStep]      \n"
    208     "vst1.16         d0[3], [%[out]], %[kStep]      \n"
    209     "vst1.16         d1[3], [%[out]], %[kStep]      \n"
    210     "vst1.16         d2[3], [%[out]], %[kStep]      \n"
    211     "vst1.16         d3[3], [%[out]], %[kStep]      \n"
    212 
    213     : [out] "+r"(out)  // modified registers
    214     : [in] "r"(in), [kStep] "r"(kStep)  // constants
    215     : "memory", "q0", "q1", "q2", "q3", "q4",
    216       "q5", "q6", "q7", "q8", "q9" // clobbered
    217   );
    218 }
    219 
    220 // Forward transform.
    221 
    222 // adapted from vp8/encoder/arm/neon/shortfdct_neon.asm
    223 static const int16_t kCoeff16[] = {
    224   5352,  5352,  5352, 5352, 2217,  2217,  2217, 2217
    225 };
    226 static const int32_t kCoeff32[] = {
    227    1812,  1812,  1812,  1812,
    228     937,   937,   937,   937,
    229   12000, 12000, 12000, 12000,
    230   51000, 51000, 51000, 51000
    231 };
    232 
    233 static void FTransform(const uint8_t* src, const uint8_t* ref,
    234                        int16_t* out) {
    235   const int kBPS = BPS;
    236   const uint8_t* src_ptr = src;
    237   const uint8_t* ref_ptr = ref;
    238   const int16_t* coeff16 = kCoeff16;
    239   const int32_t* coeff32 = kCoeff32;
    240 
    241   __asm__ volatile (
    242     // load src into q4, q5 in high half
    243     "vld1.8 {d8},  [%[src_ptr]], %[kBPS]      \n"
    244     "vld1.8 {d10}, [%[src_ptr]], %[kBPS]      \n"
    245     "vld1.8 {d9},  [%[src_ptr]], %[kBPS]      \n"
    246     "vld1.8 {d11}, [%[src_ptr]]               \n"
    247 
    248     // load ref into q6, q7 in high half
    249     "vld1.8 {d12}, [%[ref_ptr]], %[kBPS]      \n"
    250     "vld1.8 {d14}, [%[ref_ptr]], %[kBPS]      \n"
    251     "vld1.8 {d13}, [%[ref_ptr]], %[kBPS]      \n"
    252     "vld1.8 {d15}, [%[ref_ptr]]               \n"
    253 
    254     // Pack the high values in to q4 and q6
    255     "vtrn.32     q4, q5                       \n"
    256     "vtrn.32     q6, q7                       \n"
    257 
    258     // d[0-3] = src - ref
    259     "vsubl.u8    q0, d8, d12                  \n"
    260     "vsubl.u8    q1, d9, d13                  \n"
    261 
    262     // load coeff16 into q8(d16=5352, d17=2217)
    263     "vld1.16     {q8}, [%[coeff16]]           \n"
    264 
    265     // load coeff32 high half into q9 = 1812, q10 = 937
    266     "vld1.32     {q9, q10}, [%[coeff32]]!     \n"
    267 
    268     // load coeff32 low half into q11=12000, q12=51000
    269     "vld1.32     {q11,q12}, [%[coeff32]]      \n"
    270 
    271     // part 1
    272     // Transpose. Register dN is the same as dN in C
    273     "vtrn.32         d0, d2                   \n"
    274     "vtrn.32         d1, d3                   \n"
    275     "vtrn.16         d0, d1                   \n"
    276     "vtrn.16         d2, d3                   \n"
    277 
    278     "vadd.s16        d4, d0, d3               \n" // a0 = d0 + d3
    279     "vadd.s16        d5, d1, d2               \n" // a1 = d1 + d2
    280     "vsub.s16        d6, d1, d2               \n" // a2 = d1 - d2
    281     "vsub.s16        d7, d0, d3               \n" // a3 = d0 - d3
    282 
    283     "vadd.s16        d0, d4, d5               \n" // a0 + a1
    284     "vshl.s16        d0, d0, #3               \n" // temp[0+i*4] = (a0+a1) << 3
    285     "vsub.s16        d2, d4, d5               \n" // a0 - a1
    286     "vshl.s16        d2, d2, #3               \n" // (temp[2+i*4] = (a0-a1) << 3
    287 
    288     "vmlal.s16       q9, d7, d16              \n" // a3*5352 + 1812
    289     "vmlal.s16       q10, d7, d17             \n" // a3*2217 + 937
    290     "vmlal.s16       q9, d6, d17              \n" // a2*2217 + a3*5352 + 1812
    291     "vmlsl.s16       q10, d6, d16             \n" // a3*2217 + 937 - a2*5352
    292 
    293     // temp[1+i*4] = (d2*2217 + d3*5352 + 1812) >> 9
    294     // temp[3+i*4] = (d3*2217 + 937 - d2*5352) >> 9
    295     "vshrn.s32       d1, q9, #9               \n"
    296     "vshrn.s32       d3, q10, #9              \n"
    297 
    298     // part 2
    299     // transpose d0=ip[0], d1=ip[4], d2=ip[8], d3=ip[12]
    300     "vtrn.32         d0, d2                   \n"
    301     "vtrn.32         d1, d3                   \n"
    302     "vtrn.16         d0, d1                   \n"
    303     "vtrn.16         d2, d3                   \n"
    304 
    305     "vmov.s16        d26, #7                  \n"
    306 
    307     "vadd.s16        d4, d0, d3               \n" // a1 = ip[0] + ip[12]
    308     "vadd.s16        d5, d1, d2               \n" // b1 = ip[4] + ip[8]
    309     "vsub.s16        d6, d1, d2               \n" // c1 = ip[4] - ip[8]
    310     "vadd.s16        d4, d4, d26              \n" // a1 + 7
    311     "vsub.s16        d7, d0, d3               \n" // d1 = ip[0] - ip[12]
    312 
    313     "vadd.s16        d0, d4, d5               \n" // op[0] = a1 + b1 + 7
    314     "vsub.s16        d2, d4, d5               \n" // op[8] = a1 - b1 + 7
    315 
    316     "vmlal.s16       q11, d7, d16             \n" // d1*5352 + 12000
    317     "vmlal.s16       q12, d7, d17             \n" // d1*2217 + 51000
    318 
    319     "vceq.s16        d4, d7, #0               \n"
    320 
    321     "vshr.s16        d0, d0, #4               \n"
    322     "vshr.s16        d2, d2, #4               \n"
    323 
    324     "vmlal.s16       q11, d6, d17             \n" // c1*2217 + d1*5352 + 12000
    325     "vmlsl.s16       q12, d6, d16             \n" // d1*2217 - c1*5352 + 51000
    326 
    327     "vmvn            d4, d4                   \n" // !(d1 == 0)
    328     // op[4] = (c1*2217 + d1*5352 + 12000)>>16
    329     "vshrn.s32       d1, q11, #16             \n"
    330     // op[4] += (d1!=0)
    331     "vsub.s16        d1, d1, d4               \n"
    332     // op[12]= (d1*2217 - c1*5352 + 51000)>>16
    333     "vshrn.s32       d3, q12, #16             \n"
    334 
    335     // set result to out array
    336     "vst1.16         {q0, q1}, [%[out]]   \n"
    337     : [src_ptr] "+r"(src_ptr), [ref_ptr] "+r"(ref_ptr),
    338       [coeff32] "+r"(coeff32)          // modified registers
    339     : [kBPS] "r"(kBPS), [coeff16] "r"(coeff16),
    340       [out] "r"(out)                   // constants
    341     : "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", "q8", "q9",
    342       "q10", "q11", "q12", "q13"       // clobbered
    343   );
    344 }
    345 
    346 static void FTransformWHT(const int16_t* in, int16_t* out) {
    347   const int kStep = 32;
    348   __asm__ volatile (
    349     // d0 = in[0 * 16] , d1 = in[1 * 16]
    350     // d2 = in[2 * 16] , d3 = in[3 * 16]
    351     "vld1.16         d0[0], [%[in]], %[kStep]   \n"
    352     "vld1.16         d1[0], [%[in]], %[kStep]   \n"
    353     "vld1.16         d2[0], [%[in]], %[kStep]   \n"
    354     "vld1.16         d3[0], [%[in]], %[kStep]   \n"
    355     "vld1.16         d0[1], [%[in]], %[kStep]   \n"
    356     "vld1.16         d1[1], [%[in]], %[kStep]   \n"
    357     "vld1.16         d2[1], [%[in]], %[kStep]   \n"
    358     "vld1.16         d3[1], [%[in]], %[kStep]   \n"
    359     "vld1.16         d0[2], [%[in]], %[kStep]   \n"
    360     "vld1.16         d1[2], [%[in]], %[kStep]   \n"
    361     "vld1.16         d2[2], [%[in]], %[kStep]   \n"
    362     "vld1.16         d3[2], [%[in]], %[kStep]   \n"
    363     "vld1.16         d0[3], [%[in]], %[kStep]   \n"
    364     "vld1.16         d1[3], [%[in]], %[kStep]   \n"
    365     "vld1.16         d2[3], [%[in]], %[kStep]   \n"
    366     "vld1.16         d3[3], [%[in]], %[kStep]   \n"
    367 
    368     "vaddl.s16       q2, d0, d2                 \n" // a0=(in[0*16]+in[2*16])
    369     "vaddl.s16       q3, d1, d3                 \n" // a1=(in[1*16]+in[3*16])
    370     "vsubl.s16       q4, d1, d3                 \n" // a2=(in[1*16]-in[3*16])
    371     "vsubl.s16       q5, d0, d2                 \n" // a3=(in[0*16]-in[2*16])
    372 
    373     "vqadd.s32       q6, q2, q3                 \n" // a0 + a1
    374     "vqadd.s32       q7, q5, q4                 \n" // a3 + a2
    375     "vqsub.s32       q8, q5, q4                 \n" // a3 - a2
    376     "vqsub.s32       q9, q2, q3                 \n" // a0 - a1
    377 
    378     // Transpose
    379     // q6 = tmp[0, 1,  2,  3] ; q7 = tmp[ 4,  5,  6,  7]
    380     // q8 = tmp[8, 9, 10, 11] ; q9 = tmp[12, 13, 14, 15]
    381     "vswp            d13, d16                   \n" // vtrn.64 q0, q2
    382     "vswp            d15, d18                   \n" // vtrn.64 q1, q3
    383     "vtrn.32         q6, q7                     \n"
    384     "vtrn.32         q8, q9                     \n"
    385 
    386     "vqadd.s32       q0, q6, q8                 \n" // a0 = tmp[0] + tmp[8]
    387     "vqadd.s32       q1, q7, q9                 \n" // a1 = tmp[4] + tmp[12]
    388     "vqsub.s32       q2, q7, q9                 \n" // a2 = tmp[4] - tmp[12]
    389     "vqsub.s32       q3, q6, q8                 \n" // a3 = tmp[0] - tmp[8]
    390 
    391     "vqadd.s32       q4, q0, q1                 \n" // b0 = a0 + a1
    392     "vqadd.s32       q5, q3, q2                 \n" // b1 = a3 + a2
    393     "vqsub.s32       q6, q3, q2                 \n" // b2 = a3 - a2
    394     "vqsub.s32       q7, q0, q1                 \n" // b3 = a0 - a1
    395 
    396     "vshrn.s32       d18, q4, #1                \n" // b0 >> 1
    397     "vshrn.s32       d19, q5, #1                \n" // b1 >> 1
    398     "vshrn.s32       d20, q6, #1                \n" // b2 >> 1
    399     "vshrn.s32       d21, q7, #1                \n" // b3 >> 1
    400 
    401     "vst1.16         {q9, q10}, [%[out]]        \n"
    402 
    403     : [in] "+r"(in)
    404     : [kStep] "r"(kStep), [out] "r"(out)
    405     : "memory", "q0", "q1", "q2", "q3", "q4", "q5",
    406       "q6", "q7", "q8", "q9", "q10"       // clobbered
    407   ) ;
    408 }
    409 
    410 //------------------------------------------------------------------------------
    411 // Texture distortion
    412 //
    413 // We try to match the spectral content (weighted) between source and
    414 // reconstructed samples.
    415 
    416 // Hadamard transform
    417 // Returns the weighted sum of the absolute value of transformed coefficients.
    418 // This uses a TTransform helper function in C
    419 static int Disto4x4(const uint8_t* const a, const uint8_t* const b,
    420                     const uint16_t* const w) {
    421   const int kBPS = BPS;
    422   const uint8_t* A = a;
    423   const uint8_t* B = b;
    424   const uint16_t* W = w;
    425   int sum;
    426   __asm__ volatile (
    427     "vld1.32         d0[0], [%[a]], %[kBPS]   \n"
    428     "vld1.32         d0[1], [%[a]], %[kBPS]   \n"
    429     "vld1.32         d2[0], [%[a]], %[kBPS]   \n"
    430     "vld1.32         d2[1], [%[a]]            \n"
    431 
    432     "vld1.32         d1[0], [%[b]], %[kBPS]   \n"
    433     "vld1.32         d1[1], [%[b]], %[kBPS]   \n"
    434     "vld1.32         d3[0], [%[b]], %[kBPS]   \n"
    435     "vld1.32         d3[1], [%[b]]            \n"
    436 
    437     // a d0/d2, b d1/d3
    438     // d0/d1: 01 01 01 01
    439     // d2/d3: 23 23 23 23
    440     // But: it goes 01 45 23 67
    441     // Notice the middle values are transposed
    442     "vtrn.16         q0, q1                   \n"
    443 
    444     // {a0, a1} = {in[0] + in[2], in[1] + in[3]}
    445     "vaddl.u8        q2, d0, d2               \n"
    446     "vaddl.u8        q10, d1, d3              \n"
    447     // {a3, a2} = {in[0] - in[2], in[1] - in[3]}
    448     "vsubl.u8        q3, d0, d2               \n"
    449     "vsubl.u8        q11, d1, d3              \n"
    450 
    451     // tmp[0] = a0 + a1
    452     "vpaddl.s16      q0, q2                   \n"
    453     "vpaddl.s16      q8, q10                  \n"
    454 
    455     // tmp[1] = a3 + a2
    456     "vpaddl.s16      q1, q3                   \n"
    457     "vpaddl.s16      q9, q11                  \n"
    458 
    459     // No pair subtract
    460     // q2 = {a0, a3}
    461     // q3 = {a1, a2}
    462     "vtrn.16         q2, q3                   \n"
    463     "vtrn.16         q10, q11                 \n"
    464 
    465     // {tmp[3], tmp[2]} = {a0 - a1, a3 - a2}
    466     "vsubl.s16       q12, d4, d6              \n"
    467     "vsubl.s16       q13, d5, d7              \n"
    468     "vsubl.s16       q14, d20, d22            \n"
    469     "vsubl.s16       q15, d21, d23            \n"
    470 
    471     // separate tmp[3] and tmp[2]
    472     // q12 = tmp[3]
    473     // q13 = tmp[2]
    474     "vtrn.32         q12, q13                 \n"
    475     "vtrn.32         q14, q15                 \n"
    476 
    477     // Transpose tmp for a
    478     "vswp            d1, d26                  \n" // vtrn.64
    479     "vswp            d3, d24                  \n" // vtrn.64
    480     "vtrn.32         q0, q1                   \n"
    481     "vtrn.32         q13, q12                 \n"
    482 
    483     // Transpose tmp for b
    484     "vswp            d17, d30                 \n" // vtrn.64
    485     "vswp            d19, d28                 \n" // vtrn.64
    486     "vtrn.32         q8, q9                   \n"
    487     "vtrn.32         q15, q14                 \n"
    488 
    489     // The first Q register is a, the second b.
    490     // q0/8 tmp[0-3]
    491     // q13/15 tmp[4-7]
    492     // q1/9 tmp[8-11]
    493     // q12/14 tmp[12-15]
    494 
    495     // These are still in 01 45 23 67 order. We fix it easily in the addition
    496     // case but the subtraction propegates them.
    497     "vswp            d3, d27                  \n"
    498     "vswp            d19, d31                 \n"
    499 
    500     // a0 = tmp[0] + tmp[8]
    501     "vadd.s32        q2, q0, q1               \n"
    502     "vadd.s32        q3, q8, q9               \n"
    503 
    504     // a1 = tmp[4] + tmp[12]
    505     "vadd.s32        q10, q13, q12            \n"
    506     "vadd.s32        q11, q15, q14            \n"
    507 
    508     // a2 = tmp[4] - tmp[12]
    509     "vsub.s32        q13, q13, q12            \n"
    510     "vsub.s32        q15, q15, q14            \n"
    511 
    512     // a3 = tmp[0] - tmp[8]
    513     "vsub.s32        q0, q0, q1               \n"
    514     "vsub.s32        q8, q8, q9               \n"
    515 
    516     // b0 = a0 + a1
    517     "vadd.s32        q1, q2, q10              \n"
    518     "vadd.s32        q9, q3, q11              \n"
    519 
    520     // b1 = a3 + a2
    521     "vadd.s32        q12, q0, q13             \n"
    522     "vadd.s32        q14, q8, q15             \n"
    523 
    524     // b2 = a3 - a2
    525     "vsub.s32        q0, q0, q13              \n"
    526     "vsub.s32        q8, q8, q15              \n"
    527 
    528     // b3 = a0 - a1
    529     "vsub.s32        q2, q2, q10              \n"
    530     "vsub.s32        q3, q3, q11              \n"
    531 
    532     "vld1.64         {q10, q11}, [%[w]]       \n"
    533 
    534     // abs(b0)
    535     "vabs.s32        q1, q1                   \n"
    536     "vabs.s32        q9, q9                   \n"
    537     // abs(b1)
    538     "vabs.s32        q12, q12                 \n"
    539     "vabs.s32        q14, q14                 \n"
    540     // abs(b2)
    541     "vabs.s32        q0, q0                   \n"
    542     "vabs.s32        q8, q8                   \n"
    543     // abs(b3)
    544     "vabs.s32        q2, q2                   \n"
    545     "vabs.s32        q3, q3                   \n"
    546 
    547     // expand w before using.
    548     "vmovl.u16       q13, d20                 \n"
    549     "vmovl.u16       q15, d21                 \n"
    550 
    551     // w[0] * abs(b0)
    552     "vmul.u32        q1, q1, q13              \n"
    553     "vmul.u32        q9, q9, q13              \n"
    554 
    555     // w[4] * abs(b1)
    556     "vmla.u32        q1, q12, q15             \n"
    557     "vmla.u32        q9, q14, q15             \n"
    558 
    559     // expand w before using.
    560     "vmovl.u16       q13, d22                 \n"
    561     "vmovl.u16       q15, d23                 \n"
    562 
    563     // w[8] * abs(b1)
    564     "vmla.u32        q1, q0, q13              \n"
    565     "vmla.u32        q9, q8, q13              \n"
    566 
    567     // w[12] * abs(b1)
    568     "vmla.u32        q1, q2, q15              \n"
    569     "vmla.u32        q9, q3, q15              \n"
    570 
    571     // Sum the arrays
    572     "vpaddl.u32      q1, q1                   \n"
    573     "vpaddl.u32      q9, q9                   \n"
    574     "vadd.u64        d2, d3                   \n"
    575     "vadd.u64        d18, d19                 \n"
    576 
    577     // Hadamard transform needs 4 bits of extra precision (2 bits in each
    578     // direction) for dynamic raw. Weights w[] are 16bits at max, so the maximum
    579     // precision for coeff is 8bit of input + 4bits of Hadamard transform +
    580     // 16bits for w[] + 2 bits of abs() summation.
    581     //
    582     // This uses a maximum of 31 bits (signed). Discarding the top 32 bits is
    583     // A-OK.
    584 
    585     // sum2 - sum1
    586     "vsub.u32        d0, d2, d18              \n"
    587     // abs(sum2 - sum1)
    588     "vabs.s32        d0, d0                   \n"
    589     // abs(sum2 - sum1) >> 5
    590     "vshr.u32        d0, #5                   \n"
    591 
    592     // It would be better to move the value straight into r0 but I'm not
    593     // entirely sure how this works with inline assembly.
    594     "vmov.32         %[sum], d0[0]            \n"
    595 
    596     : [sum] "=r"(sum), [a] "+r"(A), [b] "+r"(B), [w] "+r"(W)
    597     : [kBPS] "r"(kBPS)
    598     : "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", "q8", "q9",
    599       "q10", "q11", "q12", "q13", "q14", "q15"  // clobbered
    600   ) ;
    601 
    602   return sum;
    603 }
    604 
    605 static int Disto16x16(const uint8_t* const a, const uint8_t* const b,
    606                       const uint16_t* const w) {
    607   int D = 0;
    608   int x, y;
    609   for (y = 0; y < 16 * BPS; y += 4 * BPS) {
    610     for (x = 0; x < 16; x += 4) {
    611       D += Disto4x4(a + x + y, b + x + y, w);
    612     }
    613   }
    614   return D;
    615 }
    616 
    617 #endif   // WEBP_USE_NEON
    618 
    619 //------------------------------------------------------------------------------
    620 // Entry point
    621 
    622 extern void VP8EncDspInitNEON(void);
    623 
    624 void VP8EncDspInitNEON(void) {
    625 #if defined(WEBP_USE_NEON)
    626   VP8ITransform = ITransform;
    627   VP8FTransform = FTransform;
    628 
    629   VP8ITransformWHT = ITransformWHT;
    630   VP8FTransformWHT = FTransformWHT;
    631 
    632   VP8TDisto4x4 = Disto4x4;
    633   VP8TDisto16x16 = Disto16x16;
    634 #endif   // WEBP_USE_NEON
    635 }
    636 
    637 #if defined(__cplusplus) || defined(c_plusplus)
    638 }    // extern "C"
    639 #endif
    640