• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
ITransformOne(const uint8_t * ref,const int16_t * in,uint8_t * dst)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 
ITransform(const uint8_t * ref,const int16_t * in,uint8_t * dst,int do_two)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
ITransformWHT(const int16_t * in,int16_t * out)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 
FTransform(const uint8_t * src,const uint8_t * ref,int16_t * out)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 
FTransformWHT(const int16_t * in,int16_t * out)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
Disto4x4(const uint8_t * const a,const uint8_t * const b,const uint16_t * const w)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 
Disto16x16(const uint8_t * const a,const uint8_t * const b,const uint16_t * const w)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 
VP8EncDspInitNEON(void)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