jsimd_arm_neon.S revision 98a44fe07b2f9694f4f74c320744613b9624f323
1/*
2 * ARM NEON optimizations for libjpeg-turbo
3 *
4 * Copyright (C) 2009-2011 Nokia Corporation and/or its subsidiary(-ies).
5 * All rights reserved.
6 * Contact: Alexander Bokovoy <alexander.bokovoy@nokia.com>
7 *
8 * This software is provided 'as-is', without any express or implied
9 * warranty.  In no event will the authors be held liable for any damages
10 * arising from the use of this software.
11 *
12 * Permission is granted to anyone to use this software for any purpose,
13 * including commercial applications, and to alter it and redistribute it
14 * freely, subject to the following restrictions:
15 *
16 * 1. The origin of this software must not be misrepresented; you must not
17 *    claim that you wrote the original software. If you use this software
18 *    in a product, an acknowledgment in the product documentation would be
19 *    appreciated but is not required.
20 * 2. Altered source versions must be plainly marked as such, and must not be
21 *    misrepresented as being the original software.
22 * 3. This notice may not be removed or altered from any source distribution.
23 */
24
25#if defined(__linux__) && defined(__ELF__)
26.section .note.GNU-stack,"",%progbits /* mark stack as non-executable */
27#endif
28
29.text
30.fpu neon
31.arch armv7a
32.object_arch armv4
33.arm
34
35
36#define RESPECT_STRICT_ALIGNMENT 1
37
38/*****************************************************************************/
39
40/* Supplementary macro for setting function attributes */
41.macro asm_function fname
42#ifdef __APPLE__
43    .func _\fname
44    .globl _\fname
45_\fname:
46#else
47    .func \fname
48    .global \fname
49#ifdef __ELF__
50    .hidden \fname
51    .type \fname, %function
52#endif
53\fname:
54#endif
55.endm
56
57/* Transpose a block of 4x4 coefficients in four 64-bit registers */
58.macro transpose_4x4 x0, x1, x2, x3
59    vtrn.16 \x0, \x1
60    vtrn.16 \x2, \x3
61    vtrn.32 \x0, \x2
62    vtrn.32 \x1, \x3
63.endm
64
65#define CENTERJSAMPLE 128
66
67/*****************************************************************************/
68
69/*
70 * Perform dequantization and inverse DCT on one block of coefficients.
71 *
72 * GLOBAL(void)
73 * jsimd_idct_islow_neon (void * dct_table, JCOEFPTR coef_block,
74 *                        JSAMPARRAY output_buf, JDIMENSION output_col)
75 */
76
77#define FIX_0_298631336  (2446)
78#define FIX_0_390180644  (3196)
79#define FIX_0_541196100  (4433)
80#define FIX_0_765366865  (6270)
81#define FIX_0_899976223  (7373)
82#define FIX_1_175875602  (9633)
83#define FIX_1_501321110  (12299)
84#define FIX_1_847759065  (15137)
85#define FIX_1_961570560  (16069)
86#define FIX_2_053119869  (16819)
87#define FIX_2_562915447  (20995)
88#define FIX_3_072711026  (25172)
89
90#define FIX_1_175875602_MINUS_1_961570560 (FIX_1_175875602 - FIX_1_961570560)
91#define FIX_1_175875602_MINUS_0_390180644 (FIX_1_175875602 - FIX_0_390180644)
92#define FIX_0_541196100_MINUS_1_847759065 (FIX_0_541196100 - FIX_1_847759065)
93#define FIX_3_072711026_MINUS_2_562915447 (FIX_3_072711026 - FIX_2_562915447)
94#define FIX_0_298631336_MINUS_0_899976223 (FIX_0_298631336 - FIX_0_899976223)
95#define FIX_1_501321110_MINUS_0_899976223 (FIX_1_501321110 - FIX_0_899976223)
96#define FIX_2_053119869_MINUS_2_562915447 (FIX_2_053119869 - FIX_2_562915447)
97#define FIX_0_541196100_PLUS_0_765366865  (FIX_0_541196100 + FIX_0_765366865)
98
99/*
100 * Reference SIMD-friendly 1-D ISLOW iDCT C implementation.
101 * Uses some ideas from the comments in 'simd/jiss2int-64.asm'
102 */
103#define REF_1D_IDCT(xrow0, xrow1, xrow2, xrow3, xrow4, xrow5, xrow6, xrow7)   \
104{                                                                             \
105    DCTELEM row0, row1, row2, row3, row4, row5, row6, row7;                   \
106    INT32   q1, q2, q3, q4, q5, q6, q7;                                       \
107    INT32   tmp11_plus_tmp2, tmp11_minus_tmp2;                                \
108                                                                              \
109    /* 1-D iDCT input data */                                                 \
110    row0 = xrow0;                                                             \
111    row1 = xrow1;                                                             \
112    row2 = xrow2;                                                             \
113    row3 = xrow3;                                                             \
114    row4 = xrow4;                                                             \
115    row5 = xrow5;                                                             \
116    row6 = xrow6;                                                             \
117    row7 = xrow7;                                                             \
118                                                                              \
119    q5 = row7 + row3;                                                         \
120    q4 = row5 + row1;                                                         \
121    q6 = MULTIPLY(q5, FIX_1_175875602_MINUS_1_961570560) +                    \
122         MULTIPLY(q4, FIX_1_175875602);                                       \
123    q7 = MULTIPLY(q5, FIX_1_175875602) +                                      \
124         MULTIPLY(q4, FIX_1_175875602_MINUS_0_390180644);                     \
125    q2 = MULTIPLY(row2, FIX_0_541196100) +                                    \
126         MULTIPLY(row6, FIX_0_541196100_MINUS_1_847759065);                   \
127    q4 = q6;                                                                  \
128    q3 = ((INT32) row0 - (INT32) row4) << 13;                                 \
129    q6 += MULTIPLY(row5, -FIX_2_562915447) +                                  \
130          MULTIPLY(row3, FIX_3_072711026_MINUS_2_562915447);                  \
131    /* now we can use q1 (reloadable constants have been used up) */          \
132    q1 = q3 + q2;                                                             \
133    q4 += MULTIPLY(row7, FIX_0_298631336_MINUS_0_899976223) +                 \
134          MULTIPLY(row1, -FIX_0_899976223);                                   \
135    q5 = q7;                                                                  \
136    q1 = q1 + q6;                                                             \
137    q7 += MULTIPLY(row7, -FIX_0_899976223) +                                  \
138          MULTIPLY(row1, FIX_1_501321110_MINUS_0_899976223);                  \
139                                                                              \
140    /* (tmp11 + tmp2) has been calculated (out_row1 before descale) */        \
141    tmp11_plus_tmp2 = q1;                                                     \
142    row1 = 0;                                                                 \
143                                                                              \
144    q1 = q1 - q6;                                                             \
145    q5 += MULTIPLY(row5, FIX_2_053119869_MINUS_2_562915447) +                 \
146          MULTIPLY(row3, -FIX_2_562915447);                                   \
147    q1 = q1 - q6;                                                             \
148    q6 = MULTIPLY(row2, FIX_0_541196100_PLUS_0_765366865) +                   \
149         MULTIPLY(row6, FIX_0_541196100);                                     \
150    q3 = q3 - q2;                                                             \
151                                                                              \
152    /* (tmp11 - tmp2) has been calculated (out_row6 before descale) */        \
153    tmp11_minus_tmp2 = q1;                                                    \
154                                                                              \
155    q1 = ((INT32) row0 + (INT32) row4) << 13;                                 \
156    q2 = q1 + q6;                                                             \
157    q1 = q1 - q6;                                                             \
158                                                                              \
159    /* pick up the results */                                                 \
160    tmp0  = q4;                                                               \
161    tmp1  = q5;                                                               \
162    tmp2  = (tmp11_plus_tmp2 - tmp11_minus_tmp2) / 2;                         \
163    tmp3  = q7;                                                               \
164    tmp10 = q2;                                                               \
165    tmp11 = (tmp11_plus_tmp2 + tmp11_minus_tmp2) / 2;                         \
166    tmp12 = q3;                                                               \
167    tmp13 = q1;                                                               \
168}
169
170#define XFIX_0_899976223                    d0[0]
171#define XFIX_0_541196100                    d0[1]
172#define XFIX_2_562915447                    d0[2]
173#define XFIX_0_298631336_MINUS_0_899976223  d0[3]
174#define XFIX_1_501321110_MINUS_0_899976223  d1[0]
175#define XFIX_2_053119869_MINUS_2_562915447  d1[1]
176#define XFIX_0_541196100_PLUS_0_765366865   d1[2]
177#define XFIX_1_175875602                    d1[3]
178#define XFIX_1_175875602_MINUS_0_390180644  d2[0]
179#define XFIX_0_541196100_MINUS_1_847759065  d2[1]
180#define XFIX_3_072711026_MINUS_2_562915447  d2[2]
181#define XFIX_1_175875602_MINUS_1_961570560  d2[3]
182
183.balign 16
184jsimd_idct_islow_neon_consts:
185    .short FIX_0_899976223                    /* d0[0] */
186    .short FIX_0_541196100                    /* d0[1] */
187    .short FIX_2_562915447                    /* d0[2] */
188    .short FIX_0_298631336_MINUS_0_899976223  /* d0[3] */
189    .short FIX_1_501321110_MINUS_0_899976223  /* d1[0] */
190    .short FIX_2_053119869_MINUS_2_562915447  /* d1[1] */
191    .short FIX_0_541196100_PLUS_0_765366865   /* d1[2] */
192    .short FIX_1_175875602                    /* d1[3] */
193    /* reloadable constants */
194    .short FIX_1_175875602_MINUS_0_390180644  /* d2[0] */
195    .short FIX_0_541196100_MINUS_1_847759065  /* d2[1] */
196    .short FIX_3_072711026_MINUS_2_562915447  /* d2[2] */
197    .short FIX_1_175875602_MINUS_1_961570560  /* d2[3] */
198
199asm_function jsimd_idct_islow_neon
200
201    DCT_TABLE       .req r0
202    COEF_BLOCK      .req r1
203    OUTPUT_BUF      .req r2
204    OUTPUT_COL      .req r3
205    TMP1            .req r0
206    TMP2            .req r1
207    TMP3            .req r2
208    TMP4            .req ip
209
210    ROW0L           .req d16
211    ROW0R           .req d17
212    ROW1L           .req d18
213    ROW1R           .req d19
214    ROW2L           .req d20
215    ROW2R           .req d21
216    ROW3L           .req d22
217    ROW3R           .req d23
218    ROW4L           .req d24
219    ROW4R           .req d25
220    ROW5L           .req d26
221    ROW5R           .req d27
222    ROW6L           .req d28
223    ROW6R           .req d29
224    ROW7L           .req d30
225    ROW7R           .req d31
226
227    /* Load and dequantize coefficients into NEON registers
228     * with the following allocation:
229     *       0 1 2 3 | 4 5 6 7
230     *      ---------+--------
231     *   0 | d16     | d17     ( q8  )
232     *   1 | d18     | d19     ( q9  )
233     *   2 | d20     | d21     ( q10 )
234     *   3 | d22     | d23     ( q11 )
235     *   4 | d24     | d25     ( q12 )
236     *   5 | d26     | d27     ( q13 )
237     *   6 | d28     | d29     ( q14 )
238     *   7 | d30     | d31     ( q15 )
239     */
240    adr             ip, jsimd_idct_islow_neon_consts
241    vld1.16         {d16, d17, d18, d19}, [COEF_BLOCK, :128]!
242    vld1.16         {d0, d1, d2, d3}, [DCT_TABLE, :128]!
243    vld1.16         {d20, d21, d22, d23}, [COEF_BLOCK, :128]!
244    vmul.s16        q8, q8, q0
245    vld1.16         {d4, d5, d6, d7}, [DCT_TABLE, :128]!
246    vmul.s16        q9, q9, q1
247    vld1.16         {d24, d25, d26, d27}, [COEF_BLOCK, :128]!
248    vmul.s16        q10, q10, q2
249    vld1.16         {d0, d1, d2, d3}, [DCT_TABLE, :128]!
250    vmul.s16        q11, q11, q3
251    vld1.16         {d28, d29, d30, d31}, [COEF_BLOCK, :128]
252    vmul.s16        q12, q12, q0
253    vld1.16         {d4, d5, d6, d7}, [DCT_TABLE, :128]!
254    vmul.s16        q14, q14, q2
255    vmul.s16        q13, q13, q1
256    vld1.16         {d0, d1, d2, d3}, [ip, :128] /* load constants */
257    add             ip, ip, #16
258    vmul.s16        q15, q15, q3
259    vpush           {d8-d15} /* save NEON registers */
260    /* 1-D IDCT, pass 1, left 4x8 half */
261    vadd.s16        d4,    ROW7L, ROW3L
262    vadd.s16        d5,    ROW5L, ROW1L
263    vmull.s16       q6,    d4,    XFIX_1_175875602_MINUS_1_961570560
264    vmlal.s16       q6,    d5,    XFIX_1_175875602
265    vmull.s16       q7,    d4,    XFIX_1_175875602
266    vmlal.s16       q7,    d5,    XFIX_1_175875602_MINUS_0_390180644
267    vsubl.s16       q3,    ROW0L, ROW4L
268    vmull.s16       q2,    ROW2L, XFIX_0_541196100
269    vmlal.s16       q2,    ROW6L, XFIX_0_541196100_MINUS_1_847759065
270    vmov            q4,    q6
271    vmlsl.s16       q6,    ROW5L, XFIX_2_562915447
272    vmlal.s16       q6,    ROW3L, XFIX_3_072711026_MINUS_2_562915447
273    vshl.s32        q3,    q3,    #13
274    vmlsl.s16       q4,    ROW1L, XFIX_0_899976223
275    vadd.s32        q1,    q3,    q2
276    vmov            q5,    q7
277    vadd.s32        q1,    q1,    q6
278    vmlsl.s16       q7,    ROW7L, XFIX_0_899976223
279    vmlal.s16       q7,    ROW1L, XFIX_1_501321110_MINUS_0_899976223
280    vrshrn.s32      ROW1L, q1,    #11
281    vsub.s32        q1,    q1,    q6
282    vmlal.s16       q5,    ROW5L, XFIX_2_053119869_MINUS_2_562915447
283    vmlsl.s16       q5,    ROW3L, XFIX_2_562915447
284    vsub.s32        q1,    q1,    q6
285    vmull.s16       q6,    ROW2L, XFIX_0_541196100_PLUS_0_765366865
286    vmlal.s16       q6,    ROW6L, XFIX_0_541196100
287    vsub.s32        q3,    q3,    q2
288    vrshrn.s32      ROW6L, q1,    #11
289    vadd.s32        q1,    q3,    q5
290    vsub.s32        q3,    q3,    q5
291    vaddl.s16       q5,    ROW0L, ROW4L
292    vrshrn.s32      ROW2L, q1,    #11
293    vrshrn.s32      ROW5L, q3,    #11
294    vshl.s32        q5,    q5,    #13
295    vmlal.s16       q4,    ROW7L, XFIX_0_298631336_MINUS_0_899976223
296    vadd.s32        q2,    q5,    q6
297    vsub.s32        q1,    q5,    q6
298    vadd.s32        q6,    q2,    q7
299    vsub.s32        q2,    q2,    q7
300    vadd.s32        q5,    q1,    q4
301    vsub.s32        q3,    q1,    q4
302    vrshrn.s32      ROW7L, q2,    #11
303    vrshrn.s32      ROW3L, q5,    #11
304    vrshrn.s32      ROW0L, q6,    #11
305    vrshrn.s32      ROW4L, q3,    #11
306    /* 1-D IDCT, pass 1, right 4x8 half */
307    vld1.s16        {d2},  [ip, :64]    /* reload constants */
308    vadd.s16        d10,   ROW7R, ROW3R
309    vadd.s16        d8,    ROW5R, ROW1R
310      /* Transpose left 4x8 half */
311      vtrn.16         ROW6L, ROW7L
312    vmull.s16       q6,    d10,   XFIX_1_175875602_MINUS_1_961570560
313    vmlal.s16       q6,    d8,    XFIX_1_175875602
314      vtrn.16         ROW2L, ROW3L
315    vmull.s16       q7,    d10,   XFIX_1_175875602
316    vmlal.s16       q7,    d8,    XFIX_1_175875602_MINUS_0_390180644
317      vtrn.16         ROW0L, ROW1L
318    vsubl.s16       q3,    ROW0R, ROW4R
319    vmull.s16       q2,    ROW2R, XFIX_0_541196100
320    vmlal.s16       q2,    ROW6R, XFIX_0_541196100_MINUS_1_847759065
321      vtrn.16         ROW4L, ROW5L
322    vmov            q4,    q6
323    vmlsl.s16       q6,    ROW5R, XFIX_2_562915447
324    vmlal.s16       q6,    ROW3R, XFIX_3_072711026_MINUS_2_562915447
325      vtrn.32         ROW1L, ROW3L
326    vshl.s32        q3,    q3,    #13
327    vmlsl.s16       q4,    ROW1R, XFIX_0_899976223
328      vtrn.32         ROW4L, ROW6L
329    vadd.s32        q1,    q3,    q2
330    vmov            q5,    q7
331    vadd.s32        q1,    q1,    q6
332      vtrn.32         ROW0L, ROW2L
333    vmlsl.s16       q7,    ROW7R, XFIX_0_899976223
334    vmlal.s16       q7,    ROW1R, XFIX_1_501321110_MINUS_0_899976223
335    vrshrn.s32      ROW1R, q1,    #11
336      vtrn.32         ROW5L, ROW7L
337    vsub.s32        q1,    q1,    q6
338    vmlal.s16       q5,    ROW5R, XFIX_2_053119869_MINUS_2_562915447
339    vmlsl.s16       q5,    ROW3R, XFIX_2_562915447
340    vsub.s32        q1,    q1,    q6
341    vmull.s16       q6,    ROW2R, XFIX_0_541196100_PLUS_0_765366865
342    vmlal.s16       q6,    ROW6R, XFIX_0_541196100
343    vsub.s32        q3,    q3,    q2
344    vrshrn.s32      ROW6R, q1,    #11
345    vadd.s32        q1,    q3,    q5
346    vsub.s32        q3,    q3,    q5
347    vaddl.s16       q5,    ROW0R, ROW4R
348    vrshrn.s32      ROW2R, q1,    #11
349    vrshrn.s32      ROW5R, q3,    #11
350    vshl.s32        q5,    q5,    #13
351    vmlal.s16       q4,    ROW7R, XFIX_0_298631336_MINUS_0_899976223
352    vadd.s32        q2,    q5,    q6
353    vsub.s32        q1,    q5,    q6
354    vadd.s32        q6,    q2,    q7
355    vsub.s32        q2,    q2,    q7
356    vadd.s32        q5,    q1,    q4
357    vsub.s32        q3,    q1,    q4
358    vrshrn.s32      ROW7R, q2,    #11
359    vrshrn.s32      ROW3R, q5,    #11
360    vrshrn.s32      ROW0R, q6,    #11
361    vrshrn.s32      ROW4R, q3,    #11
362    vld1.s16        {d2},  [ip, :64]    /* reload constants */
363      /* Transpose right 4x8 half */
364      vtrn.16         ROW6R, ROW7R
365      vtrn.16         ROW2R, ROW3R
366      vtrn.16         ROW0R, ROW1R
367      vtrn.16         ROW4R, ROW5R
368    vmov.s16        q7,  #(CENTERJSAMPLE << 5)
369      vtrn.32         ROW1R, ROW3R
370      vtrn.32         ROW4R, ROW6R
371      vtrn.32         ROW0R, ROW2R
372      vtrn.32         ROW5R, ROW7R
373    /* 1-D IDCT, pass 2, left 4x8 half */
374      vswp            ROW7L, ROW3R
375    vadd.s16        d10,   ROW7L, ROW3L
376      vswp            ROW5L, ROW1R
377    vadd.s16        d8,    ROW5L, ROW1L
378    vmull.s16       q6,    d10,   XFIX_1_175875602_MINUS_1_961570560
379    vmlal.s16       q6,    d8,    XFIX_1_175875602
380      vswp            ROW4L, ROW0R
381    vadd.s16        q8,    q8,    q7
382    vmull.s16       q7,    d10,   XFIX_1_175875602
383    vmlal.s16       q7,    d8,    XFIX_1_175875602_MINUS_0_390180644
384    vsubl.s16       q3,    ROW0L, ROW4L
385      vswp            ROW6L, ROW2R
386    vmull.s16       q2,    ROW2L, XFIX_0_541196100
387    vmlal.s16       q2,    ROW6L, XFIX_0_541196100_MINUS_1_847759065
388    vmov            q4,    q6
389    vmlsl.s16       q6,    ROW5L, XFIX_2_562915447
390    vmlal.s16       q6,    ROW3L, XFIX_3_072711026_MINUS_2_562915447
391    vshl.s32        q3,    q3,    #13
392    vmlsl.s16       q4,    ROW1L, XFIX_0_899976223
393    vadd.s32        q1,    q3,    q2
394    vmov            q5,    q7
395    vadd.s32        q1,    q1,    q6
396    vmlsl.s16       q7,    ROW7L, XFIX_0_899976223
397    vmlal.s16       q7,    ROW1L, XFIX_1_501321110_MINUS_0_899976223
398    vshrn.s32       ROW1L, q1,    #16
399    vsub.s32        q1,    q1,    q6
400    vmlal.s16       q5,    ROW5L, XFIX_2_053119869_MINUS_2_562915447
401    vmlsl.s16       q5,    ROW3L, XFIX_2_562915447
402    vsub.s32        q1,    q1,    q6
403    vmull.s16       q6,    ROW2L, XFIX_0_541196100_PLUS_0_765366865
404    vmlal.s16       q6,    ROW6L, XFIX_0_541196100
405    vsub.s32        q3,    q3,    q2
406    vshrn.s32       ROW6L, q1,    #16
407    vadd.s32        q1,    q3,    q5
408    vsub.s32        q3,    q3,    q5
409    vaddl.s16       q5,    ROW0L, ROW4L
410    vshrn.s32       ROW2L, q1,    #16
411    vshrn.s32       ROW5L, q3,    #16
412    vshl.s32        q5,    q5,    #13
413    vmlal.s16       q4,    ROW7L, XFIX_0_298631336_MINUS_0_899976223
414    vadd.s32        q2,    q5,    q6
415    vsub.s32        q1,    q5,    q6
416    vadd.s32        q6,    q2,    q7
417    vsub.s32        q2,    q2,    q7
418    vadd.s32        q5,    q1,    q4
419    vsub.s32        q3,    q1,    q4
420    vshrn.s32       ROW7L, q2,    #16
421    vshrn.s32       ROW3L, q5,    #16
422    vshrn.s32       ROW0L, q6,    #16
423    vshrn.s32       ROW4L, q3,    #16
424    /* 1-D IDCT, pass 2, right 4x8 half */
425    vld1.s16        {d2},  [ip, :64]    /* reload constants */
426    vadd.s16        d10,   ROW7R, ROW3R
427    vadd.s16        d8,    ROW5R, ROW1R
428    vmull.s16       q6,    d10,   XFIX_1_175875602_MINUS_1_961570560
429    vmlal.s16       q6,    d8,    XFIX_1_175875602
430    vmull.s16       q7,    d10,   XFIX_1_175875602
431    vmlal.s16       q7,    d8,    XFIX_1_175875602_MINUS_0_390180644
432    vsubl.s16       q3,    ROW0R, ROW4R
433    vmull.s16       q2,    ROW2R, XFIX_0_541196100
434    vmlal.s16       q2,    ROW6R, XFIX_0_541196100_MINUS_1_847759065
435    vmov            q4,    q6
436    vmlsl.s16       q6,    ROW5R, XFIX_2_562915447
437    vmlal.s16       q6,    ROW3R, XFIX_3_072711026_MINUS_2_562915447
438    vshl.s32        q3,    q3,    #13
439    vmlsl.s16       q4,    ROW1R, XFIX_0_899976223
440    vadd.s32        q1,    q3,    q2
441    vmov            q5,    q7
442    vadd.s32        q1,    q1,    q6
443    vmlsl.s16       q7,    ROW7R, XFIX_0_899976223
444    vmlal.s16       q7,    ROW1R, XFIX_1_501321110_MINUS_0_899976223
445    vshrn.s32       ROW1R, q1,    #16
446    vsub.s32        q1,    q1,    q6
447    vmlal.s16       q5,    ROW5R, XFIX_2_053119869_MINUS_2_562915447
448    vmlsl.s16       q5,    ROW3R, XFIX_2_562915447
449    vsub.s32        q1,    q1,    q6
450    vmull.s16       q6,    ROW2R, XFIX_0_541196100_PLUS_0_765366865
451    vmlal.s16       q6,    ROW6R, XFIX_0_541196100
452    vsub.s32        q3,    q3,    q2
453    vshrn.s32       ROW6R, q1,    #16
454    vadd.s32        q1,    q3,    q5
455    vsub.s32        q3,    q3,    q5
456    vaddl.s16       q5,    ROW0R, ROW4R
457    vshrn.s32       ROW2R, q1,    #16
458    vshrn.s32       ROW5R, q3,    #16
459    vshl.s32        q5,    q5,    #13
460    vmlal.s16       q4,    ROW7R, XFIX_0_298631336_MINUS_0_899976223
461    vadd.s32        q2,    q5,    q6
462    vsub.s32        q1,    q5,    q6
463    vadd.s32        q6,    q2,    q7
464    vsub.s32        q2,    q2,    q7
465    vadd.s32        q5,    q1,    q4
466    vsub.s32        q3,    q1,    q4
467    vshrn.s32       ROW7R, q2,    #16
468    vshrn.s32       ROW3R, q5,    #16
469    vshrn.s32       ROW0R, q6,    #16
470    vshrn.s32       ROW4R, q3,    #16
471    /* Descale to 8-bit and range limit */
472    vqrshrun.s16    d16,   q8,    #2
473    vqrshrun.s16    d17,   q9,    #2
474    vqrshrun.s16    d18,   q10,   #2
475    vqrshrun.s16    d19,   q11,   #2
476    vpop            {d8-d15} /* restore NEON registers */
477    vqrshrun.s16    d20,   q12,   #2
478    vqrshrun.s16    d21,   q13,   #2
479    vqrshrun.s16    d22,   q14,   #2
480    vqrshrun.s16    d23,   q15,   #2
481    /* Transpose the final 8-bit samples */
482    vtrn.16         q8,    q9
483    vtrn.16         q10,   q11
484    vtrn.32         q8,    q10
485    vtrn.32         q9,    q11
486    vtrn.8          d16,   d17
487    vtrn.8          d18,   d19
488      /* Store results to the output buffer */
489      ldmia           OUTPUT_BUF!, {TMP1, TMP2}
490      add             TMP1, TMP1, OUTPUT_COL
491      add             TMP2, TMP2, OUTPUT_COL
492      vst1.8          {d16}, [TMP1]
493      vst1.8          {d17}, [TMP2]
494      ldmia           OUTPUT_BUF!, {TMP1, TMP2}
495      add             TMP1, TMP1, OUTPUT_COL
496      add             TMP2, TMP2, OUTPUT_COL
497      vst1.8          {d18}, [TMP1]
498    vtrn.8          d20, d21
499      vst1.8          {d19}, [TMP2]
500      ldmia           OUTPUT_BUF, {TMP1, TMP2, TMP3, TMP4}
501      add             TMP1, TMP1, OUTPUT_COL
502      add             TMP2, TMP2, OUTPUT_COL
503      add             TMP3, TMP3, OUTPUT_COL
504      add             TMP4, TMP4, OUTPUT_COL
505      vst1.8          {d20}, [TMP1]
506    vtrn.8          d22, d23
507      vst1.8          {d21}, [TMP2]
508      vst1.8          {d22}, [TMP3]
509      vst1.8          {d23}, [TMP4]
510    bx              lr
511
512    .unreq          DCT_TABLE
513    .unreq          COEF_BLOCK
514    .unreq          OUTPUT_BUF
515    .unreq          OUTPUT_COL
516    .unreq          TMP1
517    .unreq          TMP2
518    .unreq          TMP3
519    .unreq          TMP4
520
521    .unreq          ROW0L
522    .unreq          ROW0R
523    .unreq          ROW1L
524    .unreq          ROW1R
525    .unreq          ROW2L
526    .unreq          ROW2R
527    .unreq          ROW3L
528    .unreq          ROW3R
529    .unreq          ROW4L
530    .unreq          ROW4R
531    .unreq          ROW5L
532    .unreq          ROW5R
533    .unreq          ROW6L
534    .unreq          ROW6R
535    .unreq          ROW7L
536    .unreq          ROW7R
537.endfunc
538
539/*****************************************************************************/
540
541/*
542 * jsimd_idct_ifast_neon
543 *
544 * This function contains a fast, not so accurate integer implementation of
545 * the inverse DCT (Discrete Cosine Transform). It uses the same calculations
546 * and produces exactly the same output as IJG's original 'jpeg_idct_ifast'
547 * function from jidctfst.c
548 *
549 * Normally 1-D AAN DCT needs 5 multiplications and 29 additions.
550 * But in ARM NEON case some extra additions are required because VQDMULH
551 * instruction can't handle the constants larger than 1. So the expressions
552 * like "x * 1.082392200" have to be converted to "x * 0.082392200 + x",
553 * which introduces an extra addition. Overall, there are 6 extra additions
554 * per 1-D IDCT pass, totalling to 5 VQDMULH and 35 VADD/VSUB instructions.
555 */
556
557#define XFIX_1_082392200 d0[0]
558#define XFIX_1_414213562 d0[1]
559#define XFIX_1_847759065 d0[2]
560#define XFIX_2_613125930 d0[3]
561
562.balign 16
563jsimd_idct_ifast_neon_consts:
564    .short (277 * 128 - 256 * 128) /* XFIX_1_082392200 */
565    .short (362 * 128 - 256 * 128) /* XFIX_1_414213562 */
566    .short (473 * 128 - 256 * 128) /* XFIX_1_847759065 */
567    .short (669 * 128 - 512 * 128) /* XFIX_2_613125930 */
568
569asm_function jsimd_idct_ifast_neon
570
571    DCT_TABLE       .req r0
572    COEF_BLOCK      .req r1
573    OUTPUT_BUF      .req r2
574    OUTPUT_COL      .req r3
575    TMP1            .req r0
576    TMP2            .req r1
577    TMP3            .req r2
578    TMP4            .req ip
579
580    /* Load and dequantize coefficients into NEON registers
581     * with the following allocation:
582     *       0 1 2 3 | 4 5 6 7
583     *      ---------+--------
584     *   0 | d16     | d17     ( q8  )
585     *   1 | d18     | d19     ( q9  )
586     *   2 | d20     | d21     ( q10 )
587     *   3 | d22     | d23     ( q11 )
588     *   4 | d24     | d25     ( q12 )
589     *   5 | d26     | d27     ( q13 )
590     *   6 | d28     | d29     ( q14 )
591     *   7 | d30     | d31     ( q15 )
592     */
593    adr             ip, jsimd_idct_ifast_neon_consts
594    vld1.16         {d16, d17, d18, d19}, [COEF_BLOCK, :128]!
595    vld1.16         {d0, d1, d2, d3}, [DCT_TABLE, :128]!
596    vld1.16         {d20, d21, d22, d23}, [COEF_BLOCK, :128]!
597    vmul.s16        q8,  q8,  q0
598    vld1.16         {d4, d5, d6, d7}, [DCT_TABLE, :128]!
599    vmul.s16        q9,  q9,  q1
600    vld1.16         {d24, d25, d26, d27}, [COEF_BLOCK, :128]!
601    vmul.s16        q10, q10, q2
602    vld1.16         {d0, d1, d2, d3}, [DCT_TABLE, :128]!
603    vmul.s16        q11, q11, q3
604    vld1.16         {d28, d29, d30, d31}, [COEF_BLOCK, :128]
605    vmul.s16        q12, q12, q0
606    vld1.16         {d4, d5, d6, d7}, [DCT_TABLE, :128]!
607    vmul.s16        q14, q14, q2
608    vmul.s16        q13, q13, q1
609    vld1.16         {d0}, [ip, :64] /* load constants */
610    vmul.s16        q15, q15, q3
611    vpush           {d8-d13}        /* save NEON registers */
612    /* 1-D IDCT, pass 1 */
613    vsub.s16        q2,  q10, q14
614    vadd.s16        q14, q10, q14
615    vsub.s16        q1,  q11, q13
616    vadd.s16        q13, q11, q13
617    vsub.s16        q5,  q9,  q15
618    vadd.s16        q15, q9,  q15
619    vqdmulh.s16     q4,  q2,  XFIX_1_414213562
620    vqdmulh.s16     q6,  q1,  XFIX_2_613125930
621    vadd.s16        q3,  q1,  q1
622    vsub.s16        q1,  q5,  q1
623    vadd.s16        q10, q2,  q4
624    vqdmulh.s16     q4,  q1,  XFIX_1_847759065
625    vsub.s16        q2,  q15, q13
626    vadd.s16        q3,  q3,  q6
627    vqdmulh.s16     q6,  q2,  XFIX_1_414213562
628    vadd.s16        q1,  q1,  q4
629    vqdmulh.s16     q4,  q5,  XFIX_1_082392200
630    vsub.s16        q10, q10, q14
631    vadd.s16        q2,  q2,  q6
632    vsub.s16        q6,  q8,  q12
633    vadd.s16        q12, q8,  q12
634    vadd.s16        q9,  q5,  q4
635    vadd.s16        q5,  q6,  q10
636    vsub.s16        q10, q6,  q10
637    vadd.s16        q6,  q15, q13
638    vadd.s16        q8,  q12, q14
639    vsub.s16        q3,  q6,  q3
640    vsub.s16        q12, q12, q14
641    vsub.s16        q3,  q3,  q1
642    vsub.s16        q1,  q9,  q1
643    vadd.s16        q2,  q3,  q2
644    vsub.s16        q15, q8,  q6
645    vadd.s16        q1,  q1,  q2
646    vadd.s16        q8,  q8,  q6
647    vadd.s16        q14, q5,  q3
648    vsub.s16        q9,  q5,  q3
649    vsub.s16        q13, q10, q2
650    vadd.s16        q10, q10, q2
651      /* Transpose */
652      vtrn.16         q8,  q9
653    vsub.s16        q11, q12, q1
654      vtrn.16         q14, q15
655    vadd.s16        q12, q12, q1
656      vtrn.16         q10, q11
657      vtrn.16         q12, q13
658      vtrn.32         q9,  q11
659      vtrn.32         q12, q14
660      vtrn.32         q8,  q10
661      vtrn.32         q13, q15
662      vswp            d28, d21
663      vswp            d26, d19
664    /* 1-D IDCT, pass 2 */
665    vsub.s16        q2,  q10, q14
666      vswp            d30, d23
667    vadd.s16        q14, q10, q14
668      vswp            d24, d17
669    vsub.s16        q1,  q11, q13
670    vadd.s16        q13, q11, q13
671    vsub.s16        q5,  q9,  q15
672    vadd.s16        q15, q9,  q15
673    vqdmulh.s16     q4,  q2,  XFIX_1_414213562
674    vqdmulh.s16     q6,  q1,  XFIX_2_613125930
675    vadd.s16        q3,  q1,  q1
676    vsub.s16        q1,  q5,  q1
677    vadd.s16        q10, q2,  q4
678    vqdmulh.s16     q4,  q1,  XFIX_1_847759065
679    vsub.s16        q2,  q15, q13
680    vadd.s16        q3,  q3,  q6
681    vqdmulh.s16     q6,  q2,  XFIX_1_414213562
682    vadd.s16        q1,  q1,  q4
683    vqdmulh.s16     q4,  q5,  XFIX_1_082392200
684    vsub.s16        q10, q10, q14
685    vadd.s16        q2,  q2,  q6
686    vsub.s16        q6,  q8,  q12
687    vadd.s16        q12, q8,  q12
688    vadd.s16        q9,  q5,  q4
689    vadd.s16        q5,  q6,  q10
690    vsub.s16        q10, q6,  q10
691    vadd.s16        q6,  q15, q13
692    vadd.s16        q8,  q12, q14
693    vsub.s16        q3,  q6,  q3
694    vsub.s16        q12, q12, q14
695    vsub.s16        q3,  q3,  q1
696    vsub.s16        q1,  q9,  q1
697    vadd.s16        q2,  q3,  q2
698    vsub.s16        q15, q8,  q6
699    vadd.s16        q1,  q1,  q2
700    vadd.s16        q8,  q8,  q6
701    vadd.s16        q14, q5,  q3
702    vsub.s16        q9,  q5,  q3
703    vsub.s16        q13, q10, q2
704    vpop            {d8-d13}        /* restore NEON registers */
705    vadd.s16        q10, q10, q2
706      /* Transpose */
707      vtrn.16         q8,  q9
708    vsub.s16        q11, q12, q1
709      vtrn.16         q14, q15
710    vadd.s16        q12, q12, q1
711      vtrn.16         q10, q11
712      vtrn.16         q12, q13
713    /* Descale and range limit */
714    vmov.s16        q0,  #(0x80 << 5)
715      vtrn.32         q9,  q11
716      vtrn.32         q12, q14
717      vtrn.32         q8,  q10
718      vtrn.32         q13, q15
719      vswp            d24, d17
720      vswp            d26, d19
721    vqadd.s16       q8,  q8,  q0
722      vswp            d28, d21
723    vqadd.s16       q9,  q9,  q0
724      vswp            d30, d23
725    vqadd.s16       q10, q10, q0
726    vqadd.s16       q11, q11, q0
727      /* Store results to the output buffer */
728      ldmia           OUTPUT_BUF!, {TMP1, TMP2}
729      add             TMP1, TMP1, OUTPUT_COL
730      add             TMP2, TMP2, OUTPUT_COL
731    vqshrun.s16     d16, q8,  #5
732    vqshrun.s16     d17, q9,  #5
733    vqshrun.s16     d18, q10, #5
734    vqshrun.s16     d19, q11, #5
735      vst1.8          {d16}, [TMP1]
736    vqadd.s16       q12, q12, q0
737    vqadd.s16       q13, q13, q0
738      vst1.8          {d17}, [TMP2]
739    vqadd.s16       q14, q14, q0
740    vqadd.s16       q15, q15, q0
741      ldmia           OUTPUT_BUF!, {TMP1, TMP2}
742      add             TMP1, TMP1, OUTPUT_COL
743      add             TMP2, TMP2, OUTPUT_COL
744      vst1.8          {d18}, [TMP1]
745    vqshrun.s16     d20, q12, #5
746    vqshrun.s16     d21, q13, #5
747      vst1.8          {d19}, [TMP2]
748    vqshrun.s16     d22, q14, #5
749      ldmia           OUTPUT_BUF, {TMP1, TMP2, TMP3, TMP4}
750      add             TMP1, TMP1, OUTPUT_COL
751      add             TMP2, TMP2, OUTPUT_COL
752      add             TMP3, TMP3, OUTPUT_COL
753      add             TMP4, TMP4, OUTPUT_COL
754      vst1.8          {d20}, [TMP1]
755    vqshrun.s16     d23, q15, #5
756      vst1.8          {d21}, [TMP2]
757      vst1.8          {d22}, [TMP3]
758      vst1.8          {d23}, [TMP4]
759    bx              lr
760
761    .unreq          DCT_TABLE
762    .unreq          COEF_BLOCK
763    .unreq          OUTPUT_BUF
764    .unreq          OUTPUT_COL
765    .unreq          TMP1
766    .unreq          TMP2
767    .unreq          TMP3
768    .unreq          TMP4
769.endfunc
770
771/*****************************************************************************/
772
773/*
774 * jsimd_idct_4x4_neon
775 *
776 * This function contains inverse-DCT code for getting reduced-size
777 * 4x4 pixels output from an 8x8 DCT block. It uses the same  calculations
778 * and produces exactly the same output as IJG's original 'jpeg_idct_4x4'
779 * function from jpeg-6b (jidctred.c).
780 *
781 * NOTE: jpeg-8 has an improved implementation of 4x4 inverse-DCT, which
782 *       requires much less arithmetic operations and hence should be faster.
783 *       The primary purpose of this particular NEON optimized function is
784 *       bit exact compatibility with jpeg-6b.
785 *
786 * TODO: a bit better instructions scheduling can be achieved by expanding
787 *       idct_helper/transpose_4x4 macros and reordering instructions,
788 *       but readability will suffer somewhat.
789 */
790
791#define CONST_BITS  13
792
793#define FIX_0_211164243  (1730)  /* FIX(0.211164243) */
794#define FIX_0_509795579  (4176)  /* FIX(0.509795579) */
795#define FIX_0_601344887  (4926)  /* FIX(0.601344887) */
796#define FIX_0_720959822  (5906)  /* FIX(0.720959822) */
797#define FIX_0_765366865  (6270)  /* FIX(0.765366865) */
798#define FIX_0_850430095  (6967)  /* FIX(0.850430095) */
799#define FIX_0_899976223  (7373)  /* FIX(0.899976223) */
800#define FIX_1_061594337  (8697)  /* FIX(1.061594337) */
801#define FIX_1_272758580  (10426) /* FIX(1.272758580) */
802#define FIX_1_451774981  (11893) /* FIX(1.451774981) */
803#define FIX_1_847759065  (15137) /* FIX(1.847759065) */
804#define FIX_2_172734803  (17799) /* FIX(2.172734803) */
805#define FIX_2_562915447  (20995) /* FIX(2.562915447) */
806#define FIX_3_624509785  (29692) /* FIX(3.624509785) */
807
808.balign 16
809jsimd_idct_4x4_neon_consts:
810    .short     FIX_1_847759065     /* d0[0] */
811    .short     -FIX_0_765366865    /* d0[1] */
812    .short     -FIX_0_211164243    /* d0[2] */
813    .short     FIX_1_451774981     /* d0[3] */
814    .short     -FIX_2_172734803    /* d1[0] */
815    .short     FIX_1_061594337     /* d1[1] */
816    .short     -FIX_0_509795579    /* d1[2] */
817    .short     -FIX_0_601344887    /* d1[3] */
818    .short     FIX_0_899976223     /* d2[0] */
819    .short     FIX_2_562915447     /* d2[1] */
820    .short     1 << (CONST_BITS+1) /* d2[2] */
821    .short     0                   /* d2[3] */
822
823.macro idct_helper x4, x6, x8, x10, x12, x14, x16, shift, y26, y27, y28, y29
824    vmull.s16       q14, \x4,  d2[2]
825    vmlal.s16       q14, \x8,  d0[0]
826    vmlal.s16       q14, \x14, d0[1]
827
828    vmull.s16       q13, \x16, d1[2]
829    vmlal.s16       q13, \x12, d1[3]
830    vmlal.s16       q13, \x10, d2[0]
831    vmlal.s16       q13, \x6,  d2[1]
832
833    vmull.s16       q15, \x4,  d2[2]
834    vmlsl.s16       q15, \x8,  d0[0]
835    vmlsl.s16       q15, \x14, d0[1]
836
837    vmull.s16       q12, \x16, d0[2]
838    vmlal.s16       q12, \x12, d0[3]
839    vmlal.s16       q12, \x10, d1[0]
840    vmlal.s16       q12, \x6,  d1[1]
841
842    vadd.s32        q10, q14, q13
843    vsub.s32        q14, q14, q13
844
845.if \shift > 16
846    vrshr.s32       q10,  q10, #\shift
847    vrshr.s32       q14,  q14, #\shift
848    vmovn.s32       \y26, q10
849    vmovn.s32       \y29, q14
850.else
851    vrshrn.s32      \y26, q10, #\shift
852    vrshrn.s32      \y29, q14, #\shift
853.endif
854
855    vadd.s32        q10, q15, q12
856    vsub.s32        q15, q15, q12
857
858.if \shift > 16
859    vrshr.s32       q10,  q10, #\shift
860    vrshr.s32       q15,  q15, #\shift
861    vmovn.s32       \y27, q10
862    vmovn.s32       \y28, q15
863.else
864    vrshrn.s32      \y27, q10, #\shift
865    vrshrn.s32      \y28, q15, #\shift
866.endif
867
868.endm
869
870asm_function jsimd_idct_4x4_neon
871
872    DCT_TABLE       .req r0
873    COEF_BLOCK      .req r1
874    OUTPUT_BUF      .req r2
875    OUTPUT_COL      .req r3
876    TMP1            .req r0
877    TMP2            .req r1
878    TMP3            .req r2
879    TMP4            .req ip
880
881    vpush           {d8-d15}
882
883    /* Load constants (d3 is just used for padding) */
884    adr             TMP4, jsimd_idct_4x4_neon_consts
885    vld1.16         {d0, d1, d2, d3}, [TMP4, :128]
886
887    /* Load all COEF_BLOCK into NEON registers with the following allocation:
888     *       0 1 2 3 | 4 5 6 7
889     *      ---------+--------
890     *   0 | d4      | d5
891     *   1 | d6      | d7
892     *   2 | d8      | d9
893     *   3 | d10     | d11
894     *   4 | -       | -
895     *   5 | d12     | d13
896     *   6 | d14     | d15
897     *   7 | d16     | d17
898     */
899    vld1.16         {d4, d5, d6, d7}, [COEF_BLOCK, :128]!
900    vld1.16         {d8, d9, d10, d11}, [COEF_BLOCK, :128]!
901    add COEF_BLOCK, COEF_BLOCK, #16
902    vld1.16         {d12, d13, d14, d15}, [COEF_BLOCK, :128]!
903    vld1.16         {d16, d17}, [COEF_BLOCK, :128]!
904    /* dequantize */
905    vld1.16         {d18, d19, d20, d21}, [DCT_TABLE, :128]!
906    vmul.s16        q2, q2, q9
907    vld1.16         {d22, d23, d24, d25}, [DCT_TABLE, :128]!
908    vmul.s16        q3, q3, q10
909    vmul.s16        q4, q4, q11
910    add             DCT_TABLE, DCT_TABLE, #16
911    vld1.16         {d26, d27, d28, d29}, [DCT_TABLE, :128]!
912    vmul.s16        q5, q5, q12
913    vmul.s16        q6, q6, q13
914    vld1.16         {d30, d31}, [DCT_TABLE, :128]!
915    vmul.s16        q7, q7, q14
916    vmul.s16        q8, q8, q15
917
918    /* Pass 1 */
919    idct_helper     d4, d6, d8, d10, d12, d14, d16, 12, d4, d6, d8, d10
920    transpose_4x4   d4, d6, d8, d10
921    idct_helper     d5, d7, d9, d11, d13, d15, d17, 12, d5, d7, d9, d11
922    transpose_4x4   d5, d7, d9, d11
923
924    /* Pass 2 */
925    idct_helper     d4, d6, d8, d10, d7, d9, d11, 19, d26, d27, d28, d29
926    transpose_4x4   d26, d27, d28, d29
927
928    /* Range limit */
929    vmov.u16        q15, #0x80
930    vadd.s16        q13, q13, q15
931    vadd.s16        q14, q14, q15
932    vqmovun.s16     d26, q13
933    vqmovun.s16     d27, q14
934
935    /* Store results to the output buffer */
936    ldmia           OUTPUT_BUF, {TMP1, TMP2, TMP3, TMP4}
937    add             TMP1, TMP1, OUTPUT_COL
938    add             TMP2, TMP2, OUTPUT_COL
939    add             TMP3, TMP3, OUTPUT_COL
940    add             TMP4, TMP4, OUTPUT_COL
941
942#if defined(__ARMEL__) && !RESPECT_STRICT_ALIGNMENT
943    /* We can use much less instructions on little endian systems if the
944     * OS kernel is not configured to trap unaligned memory accesses
945     */
946    vst1.32         {d26[0]}, [TMP1]!
947    vst1.32         {d27[0]}, [TMP3]!
948    vst1.32         {d26[1]}, [TMP2]!
949    vst1.32         {d27[1]}, [TMP4]!
950#else
951    vst1.8          {d26[0]}, [TMP1]!
952    vst1.8          {d27[0]}, [TMP3]!
953    vst1.8          {d26[1]}, [TMP1]!
954    vst1.8          {d27[1]}, [TMP3]!
955    vst1.8          {d26[2]}, [TMP1]!
956    vst1.8          {d27[2]}, [TMP3]!
957    vst1.8          {d26[3]}, [TMP1]!
958    vst1.8          {d27[3]}, [TMP3]!
959
960    vst1.8          {d26[4]}, [TMP2]!
961    vst1.8          {d27[4]}, [TMP4]!
962    vst1.8          {d26[5]}, [TMP2]!
963    vst1.8          {d27[5]}, [TMP4]!
964    vst1.8          {d26[6]}, [TMP2]!
965    vst1.8          {d27[6]}, [TMP4]!
966    vst1.8          {d26[7]}, [TMP2]!
967    vst1.8          {d27[7]}, [TMP4]!
968#endif
969
970    vpop            {d8-d15}
971    bx              lr
972
973    .unreq          DCT_TABLE
974    .unreq          COEF_BLOCK
975    .unreq          OUTPUT_BUF
976    .unreq          OUTPUT_COL
977    .unreq          TMP1
978    .unreq          TMP2
979    .unreq          TMP3
980    .unreq          TMP4
981.endfunc
982
983.purgem idct_helper
984
985/*****************************************************************************/
986
987/*
988 * jsimd_idct_2x2_neon
989 *
990 * This function contains inverse-DCT code for getting reduced-size
991 * 2x2 pixels output from an 8x8 DCT block. It uses the same  calculations
992 * and produces exactly the same output as IJG's original 'jpeg_idct_2x2'
993 * function from jpeg-6b (jidctred.c).
994 *
995 * NOTE: jpeg-8 has an improved implementation of 2x2 inverse-DCT, which
996 *       requires much less arithmetic operations and hence should be faster.
997 *       The primary purpose of this particular NEON optimized function is
998 *       bit exact compatibility with jpeg-6b.
999 */
1000
1001.balign 8
1002jsimd_idct_2x2_neon_consts:
1003    .short     -FIX_0_720959822    /* d0[0] */
1004    .short     FIX_0_850430095     /* d0[1] */
1005    .short     -FIX_1_272758580    /* d0[2] */
1006    .short     FIX_3_624509785     /* d0[3] */
1007
1008.macro idct_helper x4, x6, x10, x12, x16, shift, y26, y27
1009    vshll.s16  q14,  \x4,  #15
1010    vmull.s16  q13,  \x6,  d0[3]
1011    vmlal.s16  q13,  \x10, d0[2]
1012    vmlal.s16  q13,  \x12, d0[1]
1013    vmlal.s16  q13,  \x16, d0[0]
1014
1015    vadd.s32   q10,  q14,  q13
1016    vsub.s32   q14,  q14,  q13
1017
1018.if \shift > 16
1019    vrshr.s32  q10,  q10,  #\shift
1020    vrshr.s32  q14,  q14,  #\shift
1021    vmovn.s32  \y26, q10
1022    vmovn.s32  \y27, q14
1023.else
1024    vrshrn.s32 \y26, q10,  #\shift
1025    vrshrn.s32 \y27, q14,  #\shift
1026.endif
1027
1028.endm
1029
1030asm_function jsimd_idct_2x2_neon
1031
1032    DCT_TABLE       .req r0
1033    COEF_BLOCK      .req r1
1034    OUTPUT_BUF      .req r2
1035    OUTPUT_COL      .req r3
1036    TMP1            .req r0
1037    TMP2            .req ip
1038
1039    vpush           {d8-d15}
1040
1041    /* Load constants */
1042    adr             TMP2, jsimd_idct_2x2_neon_consts
1043    vld1.16         {d0}, [TMP2, :64]
1044
1045    /* Load all COEF_BLOCK into NEON registers with the following allocation:
1046     *       0 1 2 3 | 4 5 6 7
1047     *      ---------+--------
1048     *   0 | d4      | d5
1049     *   1 | d6      | d7
1050     *   2 | -       | -
1051     *   3 | d10     | d11
1052     *   4 | -       | -
1053     *   5 | d12     | d13
1054     *   6 | -       | -
1055     *   7 | d16     | d17
1056     */
1057    vld1.16         {d4, d5, d6, d7}, [COEF_BLOCK, :128]!
1058    add             COEF_BLOCK, COEF_BLOCK, #16
1059    vld1.16         {d10, d11}, [COEF_BLOCK, :128]!
1060    add             COEF_BLOCK, COEF_BLOCK, #16
1061    vld1.16         {d12, d13}, [COEF_BLOCK, :128]!
1062    add             COEF_BLOCK, COEF_BLOCK, #16
1063    vld1.16         {d16, d17}, [COEF_BLOCK, :128]!
1064    /* Dequantize */
1065    vld1.16         {d18, d19, d20, d21}, [DCT_TABLE, :128]!
1066    vmul.s16        q2, q2, q9
1067    vmul.s16        q3, q3, q10
1068    add             DCT_TABLE, DCT_TABLE, #16
1069    vld1.16         {d24, d25}, [DCT_TABLE, :128]!
1070    vmul.s16        q5, q5, q12
1071    add             DCT_TABLE, DCT_TABLE, #16
1072    vld1.16         {d26, d27}, [DCT_TABLE, :128]!
1073    vmul.s16        q6, q6, q13
1074    add             DCT_TABLE, DCT_TABLE, #16
1075    vld1.16         {d30, d31}, [DCT_TABLE, :128]!
1076    vmul.s16        q8, q8, q15
1077
1078    /* Pass 1 */
1079#if 0
1080    idct_helper     d4, d6, d10, d12, d16, 13, d4, d6
1081    transpose_4x4   d4, d6, d8,  d10
1082    idct_helper     d5, d7, d11, d13, d17, 13, d5, d7
1083    transpose_4x4   d5, d7, d9,  d11
1084#else
1085    vmull.s16       q13, d6,  d0[3]
1086    vmlal.s16       q13, d10, d0[2]
1087    vmlal.s16       q13, d12, d0[1]
1088    vmlal.s16       q13, d16, d0[0]
1089    vmull.s16       q12, d7,  d0[3]
1090    vmlal.s16       q12, d11, d0[2]
1091    vmlal.s16       q12, d13, d0[1]
1092    vmlal.s16       q12, d17, d0[0]
1093    vshll.s16       q14, d4,  #15
1094    vshll.s16       q15, d5,  #15
1095    vadd.s32        q10, q14, q13
1096    vsub.s32        q14, q14, q13
1097    vrshrn.s32      d4,  q10, #13
1098    vrshrn.s32      d6,  q14, #13
1099    vadd.s32        q10, q15, q12
1100    vsub.s32        q14, q15, q12
1101    vrshrn.s32      d5,  q10, #13
1102    vrshrn.s32      d7,  q14, #13
1103    vtrn.16         q2,  q3
1104    vtrn.32         q3,  q5
1105#endif
1106
1107    /* Pass 2 */
1108    idct_helper     d4, d6, d10, d7, d11, 20, d26, d27
1109
1110    /* Range limit */
1111    vmov.u16        q15, #0x80
1112    vadd.s16        q13, q13, q15
1113    vqmovun.s16     d26, q13
1114    vqmovun.s16     d27, q13
1115
1116    /* Store results to the output buffer */
1117    ldmia           OUTPUT_BUF, {TMP1, TMP2}
1118    add             TMP1, TMP1, OUTPUT_COL
1119    add             TMP2, TMP2, OUTPUT_COL
1120
1121    vst1.8          {d26[0]}, [TMP1]!
1122    vst1.8          {d27[4]}, [TMP1]!
1123    vst1.8          {d26[1]}, [TMP2]!
1124    vst1.8          {d27[5]}, [TMP2]!
1125
1126    vpop            {d8-d15}
1127    bx              lr
1128
1129    .unreq          DCT_TABLE
1130    .unreq          COEF_BLOCK
1131    .unreq          OUTPUT_BUF
1132    .unreq          OUTPUT_COL
1133    .unreq          TMP1
1134    .unreq          TMP2
1135.endfunc
1136
1137.purgem idct_helper
1138
1139/*****************************************************************************/
1140
1141/*
1142 * jsimd_ycc_extrgb_convert_neon
1143 * jsimd_ycc_extbgr_convert_neon
1144 * jsimd_ycc_extrgbx_convert_neon
1145 * jsimd_ycc_extbgrx_convert_neon
1146 * jsimd_ycc_extxbgr_convert_neon
1147 * jsimd_ycc_extxrgb_convert_neon
1148 *
1149 * Colorspace conversion YCbCr -> RGB
1150 */
1151
1152
1153.macro do_load size
1154    .if \size == 8
1155        vld1.8  {d4}, [U, :64]!
1156        vld1.8  {d5}, [V, :64]!
1157        vld1.8  {d0}, [Y, :64]!
1158        pld     [U, #64]
1159        pld     [V, #64]
1160        pld     [Y, #64]
1161    .elseif \size == 4
1162        vld1.8  {d4[0]}, [U]!
1163        vld1.8  {d4[1]}, [U]!
1164        vld1.8  {d4[2]}, [U]!
1165        vld1.8  {d4[3]}, [U]!
1166        vld1.8  {d5[0]}, [V]!
1167        vld1.8  {d5[1]}, [V]!
1168        vld1.8  {d5[2]}, [V]!
1169        vld1.8  {d5[3]}, [V]!
1170        vld1.8  {d0[0]}, [Y]!
1171        vld1.8  {d0[1]}, [Y]!
1172        vld1.8  {d0[2]}, [Y]!
1173        vld1.8  {d0[3]}, [Y]!
1174    .elseif \size == 2
1175        vld1.8  {d4[4]}, [U]!
1176        vld1.8  {d4[5]}, [U]!
1177        vld1.8  {d5[4]}, [V]!
1178        vld1.8  {d5[5]}, [V]!
1179        vld1.8  {d0[4]}, [Y]!
1180        vld1.8  {d0[5]}, [Y]!
1181    .elseif \size == 1
1182        vld1.8  {d4[6]}, [U]!
1183        vld1.8  {d5[6]}, [V]!
1184        vld1.8  {d0[6]}, [Y]!
1185    .else
1186        .error unsupported macroblock size
1187    .endif
1188.endm
1189
1190.macro do_store bpp, size
1191    .if \bpp == 24
1192        .if \size == 8
1193            vst3.8  {d10, d11, d12}, [RGB]!
1194        .elseif \size == 4
1195            vst3.8  {d10[0], d11[0], d12[0]}, [RGB]!
1196            vst3.8  {d10[1], d11[1], d12[1]}, [RGB]!
1197            vst3.8  {d10[2], d11[2], d12[2]}, [RGB]!
1198            vst3.8  {d10[3], d11[3], d12[3]}, [RGB]!
1199        .elseif \size == 2
1200            vst3.8  {d10[4], d11[4], d12[4]}, [RGB]!
1201            vst3.8  {d10[5], d11[5], d12[5]}, [RGB]!
1202        .elseif \size == 1
1203            vst3.8  {d10[6], d11[6], d12[6]}, [RGB]!
1204        .else
1205            .error unsupported macroblock size
1206        .endif
1207    .elseif \bpp == 32
1208        .if \size == 8
1209            vst4.8  {d10, d11, d12, d13}, [RGB]!
1210        .elseif \size == 4
1211            vst4.8  {d10[0], d11[0], d12[0], d13[0]}, [RGB]!
1212            vst4.8  {d10[1], d11[1], d12[1], d13[1]}, [RGB]!
1213            vst4.8  {d10[2], d11[2], d12[2], d13[2]}, [RGB]!
1214            vst4.8  {d10[3], d11[3], d12[3], d13[3]}, [RGB]!
1215        .elseif \size == 2
1216            vst4.8  {d10[4], d11[4], d12[4], d13[4]}, [RGB]!
1217            vst4.8  {d10[5], d11[5], d12[5], d13[5]}, [RGB]!
1218        .elseif \size == 1
1219            vst4.8  {d10[6], d11[6], d12[6], d13[6]}, [RGB]!
1220        .else
1221            .error unsupported macroblock size
1222        .endif
1223    .else
1224        .error unsupported bpp
1225    .endif
1226.endm
1227
1228.macro generate_jsimd_ycc_rgb_convert_neon colorid, bpp, r_offs, g_offs, b_offs
1229
1230/*
1231 * 2 stage pipelined YCbCr->RGB conversion
1232 */
1233
1234.macro do_yuv_to_rgb_stage1
1235    vaddw.u8        q3, q1, d4     /* q3 = u - 128 */
1236    vaddw.u8        q4, q1, d5     /* q2 = v - 128 */
1237    vmull.s16       q10, d6, d1[1] /* multiply by -11277 */
1238    vmlal.s16       q10, d8, d1[2] /* multiply by -23401 */
1239    vmull.s16       q11, d7, d1[1] /* multiply by -11277 */
1240    vmlal.s16       q11, d9, d1[2] /* multiply by -23401 */
1241    vmull.s16       q12, d8, d1[0] /* multiply by 22971 */
1242    vmull.s16       q13, d9, d1[0] /* multiply by 22971 */
1243    vmull.s16       q14, d6, d1[3] /* multiply by 29033 */
1244    vmull.s16       q15, d7, d1[3] /* multiply by 29033 */
1245.endm
1246
1247.macro do_yuv_to_rgb_stage2
1248    vrshrn.s32      d20, q10, #15
1249    vrshrn.s32      d21, q11, #15
1250    vrshrn.s32      d24, q12, #14
1251    vrshrn.s32      d25, q13, #14
1252    vrshrn.s32      d28, q14, #14
1253    vrshrn.s32      d29, q15, #14
1254    vaddw.u8        q10, q10, d0
1255    vaddw.u8        q12, q12, d0
1256    vaddw.u8        q14, q14, d0
1257    vqmovun.s16     d1\g_offs, q10
1258    vqmovun.s16     d1\r_offs, q12
1259    vqmovun.s16     d1\b_offs, q14
1260.endm
1261
1262.macro do_yuv_to_rgb_stage2_store_load_stage1
1263    vld1.8          {d4}, [U, :64]!
1264      vrshrn.s32      d20, q10, #15
1265      vrshrn.s32      d21, q11, #15
1266      vrshrn.s32      d24, q12, #14
1267      vrshrn.s32      d25, q13, #14
1268      vrshrn.s32      d28, q14, #14
1269    vld1.8          {d5}, [V, :64]!
1270      vrshrn.s32      d29, q15, #14
1271      vaddw.u8        q10, q10, d0
1272      vaddw.u8        q12, q12, d0
1273      vaddw.u8        q14, q14, d0
1274      vqmovun.s16     d1\g_offs, q10
1275    vld1.8          {d0}, [Y, :64]!
1276      vqmovun.s16     d1\r_offs, q12
1277    pld             [U, #64]
1278    pld             [V, #64]
1279    pld             [Y, #64]
1280      vqmovun.s16     d1\b_offs, q14
1281    vaddw.u8        q3, q1, d4     /* q3 = u - 128 */
1282    vaddw.u8        q4, q1, d5     /* q2 = v - 128 */
1283      do_store        \bpp, 8
1284    vmull.s16       q10, d6, d1[1] /* multiply by -11277 */
1285    vmlal.s16       q10, d8, d1[2] /* multiply by -23401 */
1286    vmull.s16       q11, d7, d1[1] /* multiply by -11277 */
1287    vmlal.s16       q11, d9, d1[2] /* multiply by -23401 */
1288    vmull.s16       q12, d8, d1[0] /* multiply by 22971 */
1289    vmull.s16       q13, d9, d1[0] /* multiply by 22971 */
1290    vmull.s16       q14, d6, d1[3] /* multiply by 29033 */
1291    vmull.s16       q15, d7, d1[3] /* multiply by 29033 */
1292.endm
1293
1294.macro do_yuv_to_rgb
1295    do_yuv_to_rgb_stage1
1296    do_yuv_to_rgb_stage2
1297.endm
1298
1299/* Apple gas crashes on adrl, work around that by using adr.
1300 * But this requires a copy of these constants for each function.
1301 */
1302
1303.balign 16
1304jsimd_ycc_\colorid\()_neon_consts:
1305    .short          0,      0,     0,      0
1306    .short          22971, -11277, -23401, 29033
1307    .short          -128,  -128,   -128,   -128
1308    .short          -128,  -128,   -128,   -128
1309
1310asm_function jsimd_ycc_\colorid\()_convert_neon
1311    OUTPUT_WIDTH    .req r0
1312    INPUT_BUF       .req r1
1313    INPUT_ROW       .req r2
1314    OUTPUT_BUF      .req r3
1315    NUM_ROWS        .req r4
1316
1317    INPUT_BUF0      .req r5
1318    INPUT_BUF1      .req r6
1319    INPUT_BUF2      .req INPUT_BUF
1320
1321    RGB             .req r7
1322    Y               .req r8
1323    U               .req r9
1324    V               .req r10
1325    N               .req ip
1326
1327    /* Load constants to d1, d2, d3 (d0 is just used for padding) */
1328    adr             ip, jsimd_ycc_\colorid\()_neon_consts
1329    vld1.16         {d0, d1, d2, d3}, [ip, :128]
1330
1331    /* Save ARM registers and handle input arguments */
1332    push            {r4, r5, r6, r7, r8, r9, r10, lr}
1333    ldr             NUM_ROWS, [sp, #(4 * 8)]
1334    ldr             INPUT_BUF0, [INPUT_BUF]
1335    ldr             INPUT_BUF1, [INPUT_BUF, #4]
1336    ldr             INPUT_BUF2, [INPUT_BUF, #8]
1337    .unreq          INPUT_BUF
1338
1339    /* Save NEON registers */
1340    vpush           {d8-d15}
1341
1342    /* Initially set d10, d11, d12, d13 to 0xFF */
1343    vmov.u8         q5, #255
1344    vmov.u8         q6, #255
1345
1346    /* Outer loop over scanlines */
1347    cmp             NUM_ROWS, #1
1348    blt             9f
13490:
1350    ldr             Y, [INPUT_BUF0, INPUT_ROW, lsl #2]
1351    ldr             U, [INPUT_BUF1, INPUT_ROW, lsl #2]
1352    mov             N, OUTPUT_WIDTH
1353    ldr             V, [INPUT_BUF2, INPUT_ROW, lsl #2]
1354    add             INPUT_ROW, INPUT_ROW, #1
1355    ldr             RGB, [OUTPUT_BUF], #4
1356
1357    /* Inner loop over pixels */
1358    subs            N, N, #8
1359    blt             3f
1360    do_load         8
1361    do_yuv_to_rgb_stage1
1362    subs            N, N, #8
1363    blt             2f
13641:
1365    do_yuv_to_rgb_stage2_store_load_stage1
1366    subs            N, N, #8
1367    bge             1b
13682:
1369    do_yuv_to_rgb_stage2
1370    do_store        \bpp, 8
1371    tst             N, #7
1372    beq             8f
13733:
1374    tst             N, #4
1375    beq             3f
1376    do_load         4
13773:
1378    tst             N, #2
1379    beq             4f
1380    do_load         2
13814:
1382    tst             N, #1
1383    beq             5f
1384    do_load         1
13855:
1386    do_yuv_to_rgb
1387    tst             N, #4
1388    beq             6f
1389    do_store        \bpp, 4
13906:
1391    tst             N, #2
1392    beq             7f
1393    do_store        \bpp, 2
13947:
1395    tst             N, #1
1396    beq             8f
1397    do_store        \bpp, 1
13988:
1399    subs            NUM_ROWS, NUM_ROWS, #1
1400    bgt             0b
14019:
1402    /* Restore all registers and return */
1403    vpop            {d8-d15}
1404    pop             {r4, r5, r6, r7, r8, r9, r10, pc}
1405
1406    .unreq          OUTPUT_WIDTH
1407    .unreq          INPUT_ROW
1408    .unreq          OUTPUT_BUF
1409    .unreq          NUM_ROWS
1410    .unreq          INPUT_BUF0
1411    .unreq          INPUT_BUF1
1412    .unreq          INPUT_BUF2
1413    .unreq          RGB
1414    .unreq          Y
1415    .unreq          U
1416    .unreq          V
1417    .unreq          N
1418.endfunc
1419
1420.purgem do_yuv_to_rgb
1421.purgem do_yuv_to_rgb_stage1
1422.purgem do_yuv_to_rgb_stage2
1423.purgem do_yuv_to_rgb_stage2_store_load_stage1
1424
1425.endm
1426
1427/*--------------------------------- id ----- bpp R  G  B */
1428generate_jsimd_ycc_rgb_convert_neon extrgb,  24, 0, 1, 2
1429generate_jsimd_ycc_rgb_convert_neon extbgr,  24, 2, 1, 0
1430generate_jsimd_ycc_rgb_convert_neon extrgbx, 32, 0, 1, 2
1431generate_jsimd_ycc_rgb_convert_neon extbgrx, 32, 2, 1, 0
1432generate_jsimd_ycc_rgb_convert_neon extxbgr, 32, 3, 2, 1
1433generate_jsimd_ycc_rgb_convert_neon extxrgb, 32, 1, 2, 3
1434
1435.purgem do_load
1436.purgem do_store
1437
1438/*****************************************************************************/
1439
1440/*
1441 * jsimd_extrgb_ycc_convert_neon
1442 * jsimd_extbgr_ycc_convert_neon
1443 * jsimd_extrgbx_ycc_convert_neon
1444 * jsimd_extbgrx_ycc_convert_neon
1445 * jsimd_extxbgr_ycc_convert_neon
1446 * jsimd_extxrgb_ycc_convert_neon
1447 *
1448 * Colorspace conversion RGB -> YCbCr
1449 */
1450
1451.macro do_store size
1452    .if \size == 8
1453        vst1.8  {d20}, [Y]!
1454        vst1.8  {d21}, [U]!
1455        vst1.8  {d22}, [V]!
1456    .elseif \size == 4
1457        vst1.8  {d20[0]}, [Y]!
1458        vst1.8  {d20[1]}, [Y]!
1459        vst1.8  {d20[2]}, [Y]!
1460        vst1.8  {d20[3]}, [Y]!
1461        vst1.8  {d21[0]}, [U]!
1462        vst1.8  {d21[1]}, [U]!
1463        vst1.8  {d21[2]}, [U]!
1464        vst1.8  {d21[3]}, [U]!
1465        vst1.8  {d22[0]}, [V]!
1466        vst1.8  {d22[1]}, [V]!
1467        vst1.8  {d22[2]}, [V]!
1468        vst1.8  {d22[3]}, [V]!
1469    .elseif \size == 2
1470        vst1.8  {d20[4]}, [Y]!
1471        vst1.8  {d20[5]}, [Y]!
1472        vst1.8  {d21[4]}, [U]!
1473        vst1.8  {d21[5]}, [U]!
1474        vst1.8  {d22[4]}, [V]!
1475        vst1.8  {d22[5]}, [V]!
1476    .elseif \size == 1
1477        vst1.8  {d20[6]}, [Y]!
1478        vst1.8  {d21[6]}, [U]!
1479        vst1.8  {d22[6]}, [V]!
1480    .else
1481        .error unsupported macroblock size
1482    .endif
1483.endm
1484
1485.macro do_load bpp, size
1486    .if \bpp == 24
1487        .if \size == 8
1488            vld3.8  {d10, d11, d12}, [RGB]!
1489            pld     [RGB, #128]
1490        .elseif \size == 4
1491            vld3.8  {d10[0], d11[0], d12[0]}, [RGB]!
1492            vld3.8  {d10[1], d11[1], d12[1]}, [RGB]!
1493            vld3.8  {d10[2], d11[2], d12[2]}, [RGB]!
1494            vld3.8  {d10[3], d11[3], d12[3]}, [RGB]!
1495        .elseif \size == 2
1496            vld3.8  {d10[4], d11[4], d12[4]}, [RGB]!
1497            vld3.8  {d10[5], d11[5], d12[5]}, [RGB]!
1498        .elseif \size == 1
1499            vld3.8  {d10[6], d11[6], d12[6]}, [RGB]!
1500        .else
1501            .error unsupported macroblock size
1502        .endif
1503    .elseif \bpp == 32
1504        .if \size == 8
1505            vld4.8  {d10, d11, d12, d13}, [RGB]!
1506            pld     [RGB, #128]
1507        .elseif \size == 4
1508            vld4.8  {d10[0], d11[0], d12[0], d13[0]}, [RGB]!
1509            vld4.8  {d10[1], d11[1], d12[1], d13[1]}, [RGB]!
1510            vld4.8  {d10[2], d11[2], d12[2], d13[2]}, [RGB]!
1511            vld4.8  {d10[3], d11[3], d12[3], d13[3]}, [RGB]!
1512        .elseif \size == 2
1513            vld4.8  {d10[4], d11[4], d12[4], d13[4]}, [RGB]!
1514            vld4.8  {d10[5], d11[5], d12[5], d13[5]}, [RGB]!
1515        .elseif \size == 1
1516            vld4.8  {d10[6], d11[6], d12[6], d13[6]}, [RGB]!
1517        .else
1518            .error unsupported macroblock size
1519        .endif
1520    .else
1521        .error unsupported bpp
1522    .endif
1523.endm
1524
1525.macro generate_jsimd_rgb_ycc_convert_neon colorid, bpp, r_offs, g_offs, b_offs
1526
1527/*
1528 * 2 stage pipelined RGB->YCbCr conversion
1529 */
1530
1531.macro do_rgb_to_yuv_stage1
1532    vmovl.u8    q2, d1\r_offs /* r = { d4, d5 } */
1533    vmovl.u8    q3, d1\g_offs /* g = { d6, d7 } */
1534    vmovl.u8    q4, d1\b_offs /* b = { d8, d9 } */
1535    vmull.u16   q7, d4, d0[0]
1536    vmlal.u16   q7, d6, d0[1]
1537    vmlal.u16   q7, d8, d0[2]
1538    vmull.u16   q8, d5, d0[0]
1539    vmlal.u16   q8, d7, d0[1]
1540    vmlal.u16   q8, d9, d0[2]
1541    vrev64.32   q9,  q1
1542    vrev64.32   q13, q1
1543    vmlsl.u16   q9,  d4, d0[3]
1544    vmlsl.u16   q9,  d6, d1[0]
1545    vmlal.u16   q9,  d8, d1[1]
1546    vmlsl.u16   q13, d5, d0[3]
1547    vmlsl.u16   q13, d7, d1[0]
1548    vmlal.u16   q13, d9, d1[1]
1549    vrev64.32   q14, q1
1550    vrev64.32   q15, q1
1551    vmlal.u16   q14, d4, d1[1]
1552    vmlsl.u16   q14, d6, d1[2]
1553    vmlsl.u16   q14, d8, d1[3]
1554    vmlal.u16   q15, d5, d1[1]
1555    vmlsl.u16   q15, d7, d1[2]
1556    vmlsl.u16   q15, d9, d1[3]
1557.endm
1558
1559.macro do_rgb_to_yuv_stage2
1560    vrshrn.u32  d20, q7,  #16
1561    vrshrn.u32  d21, q8,  #16
1562    vshrn.u32   d22, q9,  #16
1563    vshrn.u32   d23, q13, #16
1564    vshrn.u32   d24, q14, #16
1565    vshrn.u32   d25, q15, #16
1566    vmovn.u16   d20, q10      /* d20 = y */
1567    vmovn.u16   d21, q11      /* d21 = u */
1568    vmovn.u16   d22, q12      /* d22 = v */
1569.endm
1570
1571.macro do_rgb_to_yuv
1572    do_rgb_to_yuv_stage1
1573    do_rgb_to_yuv_stage2
1574.endm
1575
1576.macro do_rgb_to_yuv_stage2_store_load_stage1
1577      vrshrn.u32  d20, q7,  #16
1578      vrshrn.u32  d21, q8,  #16
1579      vshrn.u32   d22, q9,  #16
1580    vrev64.32   q9,  q1
1581      vshrn.u32   d23, q13, #16
1582    vrev64.32   q13, q1
1583      vshrn.u32   d24, q14, #16
1584      vshrn.u32   d25, q15, #16
1585    do_load     \bpp, 8
1586      vmovn.u16   d20, q10      /* d20 = y */
1587    vmovl.u8    q2, d1\r_offs   /* r = { d4, d5 } */
1588      vmovn.u16   d21, q11      /* d21 = u */
1589    vmovl.u8    q3, d1\g_offs   /* g = { d6, d7 } */
1590      vmovn.u16   d22, q12      /* d22 = v */
1591    vmovl.u8    q4, d1\b_offs   /* b = { d8, d9 } */
1592    vmull.u16   q7, d4, d0[0]
1593    vmlal.u16   q7, d6, d0[1]
1594    vmlal.u16   q7, d8, d0[2]
1595      vst1.8      {d20}, [Y]!
1596    vmull.u16   q8, d5, d0[0]
1597    vmlal.u16   q8, d7, d0[1]
1598    vmlal.u16   q8, d9, d0[2]
1599    vmlsl.u16   q9,  d4, d0[3]
1600    vmlsl.u16   q9,  d6, d1[0]
1601    vmlal.u16   q9,  d8, d1[1]
1602      vst1.8      {d21}, [U]!
1603    vmlsl.u16   q13, d5, d0[3]
1604    vmlsl.u16   q13, d7, d1[0]
1605    vmlal.u16   q13, d9, d1[1]
1606    vrev64.32   q14, q1
1607    vrev64.32   q15, q1
1608    vmlal.u16   q14, d4, d1[1]
1609    vmlsl.u16   q14, d6, d1[2]
1610    vmlsl.u16   q14, d8, d1[3]
1611      vst1.8      {d22}, [V]!
1612    vmlal.u16   q15, d5, d1[1]
1613    vmlsl.u16   q15, d7, d1[2]
1614    vmlsl.u16   q15, d9, d1[3]
1615.endm
1616
1617.balign 16
1618jsimd_\colorid\()_ycc_neon_consts:
1619    .short          19595, 38470, 7471,  11059
1620    .short          21709, 32768, 27439, 5329
1621    .short          32767, 128,   32767, 128
1622    .short          32767, 128,   32767, 128
1623
1624asm_function jsimd_\colorid\()_ycc_convert_neon
1625    OUTPUT_WIDTH    .req r0
1626    INPUT_BUF       .req r1
1627    OUTPUT_BUF      .req r2
1628    OUTPUT_ROW      .req r3
1629    NUM_ROWS        .req r4
1630
1631    OUTPUT_BUF0     .req r5
1632    OUTPUT_BUF1     .req r6
1633    OUTPUT_BUF2     .req OUTPUT_BUF
1634
1635    RGB             .req r7
1636    Y               .req r8
1637    U               .req r9
1638    V               .req r10
1639    N               .req ip
1640
1641    /* Load constants to d0, d1, d2, d3 */
1642    adr             ip, jsimd_\colorid\()_ycc_neon_consts
1643    vld1.16         {d0, d1, d2, d3}, [ip, :128]
1644
1645    /* Save ARM registers and handle input arguments */
1646    push            {r4, r5, r6, r7, r8, r9, r10, lr}
1647    ldr             NUM_ROWS, [sp, #(4 * 8)]
1648    ldr             OUTPUT_BUF0, [OUTPUT_BUF]
1649    ldr             OUTPUT_BUF1, [OUTPUT_BUF, #4]
1650    ldr             OUTPUT_BUF2, [OUTPUT_BUF, #8]
1651    .unreq          OUTPUT_BUF
1652
1653    /* Save NEON registers */
1654    vpush           {d8-d15}
1655
1656    /* Outer loop over scanlines */
1657    cmp             NUM_ROWS, #1
1658    blt             9f
16590:
1660    ldr             Y, [OUTPUT_BUF0, OUTPUT_ROW, lsl #2]
1661    ldr             U, [OUTPUT_BUF1, OUTPUT_ROW, lsl #2]
1662    mov             N, OUTPUT_WIDTH
1663    ldr             V, [OUTPUT_BUF2, OUTPUT_ROW, lsl #2]
1664    add             OUTPUT_ROW, OUTPUT_ROW, #1
1665    ldr             RGB, [INPUT_BUF], #4
1666
1667    /* Inner loop over pixels */
1668    subs            N, N, #8
1669    blt             3f
1670    do_load         \bpp, 8
1671    do_rgb_to_yuv_stage1
1672    subs            N, N, #8
1673    blt             2f
16741:
1675    do_rgb_to_yuv_stage2_store_load_stage1
1676    subs            N, N, #8
1677    bge             1b
16782:
1679    do_rgb_to_yuv_stage2
1680    do_store        8
1681    tst             N, #7
1682    beq             8f
16833:
1684    tst             N, #4
1685    beq             3f
1686    do_load         \bpp, 4
16873:
1688    tst             N, #2
1689    beq             4f
1690    do_load         \bpp, 2
16914:
1692    tst             N, #1
1693    beq             5f
1694    do_load         \bpp, 1
16955:
1696    do_rgb_to_yuv
1697    tst             N, #4
1698    beq             6f
1699    do_store        4
17006:
1701    tst             N, #2
1702    beq             7f
1703    do_store        2
17047:
1705    tst             N, #1
1706    beq             8f
1707    do_store        1
17088:
1709    subs            NUM_ROWS, NUM_ROWS, #1
1710    bgt             0b
17119:
1712    /* Restore all registers and return */
1713    vpop            {d8-d15}
1714    pop             {r4, r5, r6, r7, r8, r9, r10, pc}
1715
1716    .unreq          OUTPUT_WIDTH
1717    .unreq          OUTPUT_ROW
1718    .unreq          INPUT_BUF
1719    .unreq          NUM_ROWS
1720    .unreq          OUTPUT_BUF0
1721    .unreq          OUTPUT_BUF1
1722    .unreq          OUTPUT_BUF2
1723    .unreq          RGB
1724    .unreq          Y
1725    .unreq          U
1726    .unreq          V
1727    .unreq          N
1728.endfunc
1729
1730.purgem do_rgb_to_yuv
1731.purgem do_rgb_to_yuv_stage1
1732.purgem do_rgb_to_yuv_stage2
1733.purgem do_rgb_to_yuv_stage2_store_load_stage1
1734
1735.endm
1736
1737/*--------------------------------- id ----- bpp R  G  B */
1738generate_jsimd_rgb_ycc_convert_neon extrgb,  24, 0, 1, 2
1739generate_jsimd_rgb_ycc_convert_neon extbgr,  24, 2, 1, 0
1740generate_jsimd_rgb_ycc_convert_neon extrgbx, 32, 0, 1, 2
1741generate_jsimd_rgb_ycc_convert_neon extbgrx, 32, 2, 1, 0
1742generate_jsimd_rgb_ycc_convert_neon extxbgr, 32, 3, 2, 1
1743generate_jsimd_rgb_ycc_convert_neon extxrgb, 32, 1, 2, 3
1744
1745.purgem do_load
1746.purgem do_store
1747
1748/*****************************************************************************/
1749
1750/*
1751 * Load data into workspace, applying unsigned->signed conversion
1752 *
1753 * TODO: can be combined with 'jsimd_fdct_ifast_neon' to get
1754 *       rid of VST1.16 instructions
1755 */
1756
1757asm_function jsimd_convsamp_neon
1758    SAMPLE_DATA     .req r0
1759    START_COL       .req r1
1760    WORKSPACE       .req r2
1761    TMP1            .req r3
1762    TMP2            .req r4
1763    TMP3            .req r5
1764    TMP4            .req ip
1765
1766    push            {r4, r5}
1767    vmov.u8         d0, #128
1768
1769    ldmia           SAMPLE_DATA!, {TMP1, TMP2, TMP3, TMP4}
1770    add             TMP1, TMP1, START_COL
1771    add             TMP2, TMP2, START_COL
1772    add             TMP3, TMP3, START_COL
1773    add             TMP4, TMP4, START_COL
1774    vld1.8          {d16}, [TMP1]
1775    vsubl.u8        q8, d16, d0
1776    vld1.8          {d18}, [TMP2]
1777    vsubl.u8        q9, d18, d0
1778    vld1.8          {d20}, [TMP3]
1779    vsubl.u8        q10, d20, d0
1780    vld1.8          {d22}, [TMP4]
1781    ldmia           SAMPLE_DATA!, {TMP1, TMP2, TMP3, TMP4}
1782    vsubl.u8        q11, d22, d0
1783    vst1.16         {d16, d17, d18, d19}, [WORKSPACE, :128]!
1784    add             TMP1, TMP1, START_COL
1785    add             TMP2, TMP2, START_COL
1786    vst1.16         {d20, d21, d22, d23}, [WORKSPACE, :128]!
1787    add             TMP3, TMP3, START_COL
1788    add             TMP4, TMP4, START_COL
1789    vld1.8          {d24}, [TMP1]
1790    vsubl.u8        q12, d24, d0
1791    vld1.8          {d26}, [TMP2]
1792    vsubl.u8        q13, d26, d0
1793    vld1.8          {d28}, [TMP3]
1794    vsubl.u8        q14, d28, d0
1795    vld1.8          {d30}, [TMP4]
1796    vsubl.u8        q15, d30, d0
1797    vst1.16         {d24, d25, d26, d27}, [WORKSPACE, :128]!
1798    vst1.16         {d28, d29, d30, d31}, [WORKSPACE, :128]!
1799    pop             {r4, r5}
1800    bx              lr
1801
1802    .unreq          SAMPLE_DATA
1803    .unreq          START_COL
1804    .unreq          WORKSPACE
1805    .unreq          TMP1
1806    .unreq          TMP2
1807    .unreq          TMP3
1808    .unreq          TMP4
1809.endfunc
1810
1811/*****************************************************************************/
1812
1813/*
1814 * jsimd_fdct_ifast_neon
1815 *
1816 * This function contains a fast, not so accurate integer implementation of
1817 * the forward DCT (Discrete Cosine Transform). It uses the same calculations
1818 * and produces exactly the same output as IJG's original 'jpeg_fdct_ifast'
1819 * function from jfdctfst.c
1820 *
1821 * TODO: can be combined with 'jsimd_convsamp_neon' to get
1822 *       rid of a bunch of VLD1.16 instructions
1823 */
1824
1825#define XFIX_0_382683433 d0[0]
1826#define XFIX_0_541196100 d0[1]
1827#define XFIX_0_707106781 d0[2]
1828#define XFIX_1_306562965 d0[3]
1829
1830.balign 16
1831jsimd_fdct_ifast_neon_consts:
1832    .short (98 * 128)              /* XFIX_0_382683433 */
1833    .short (139 * 128)             /* XFIX_0_541196100 */
1834    .short (181 * 128)             /* XFIX_0_707106781 */
1835    .short (334 * 128 - 256 * 128) /* XFIX_1_306562965 */
1836
1837asm_function jsimd_fdct_ifast_neon
1838
1839    DATA            .req r0
1840    TMP             .req ip
1841
1842    vpush           {d8-d15}
1843
1844    /* Load constants */
1845    adr             TMP, jsimd_fdct_ifast_neon_consts
1846    vld1.16         {d0}, [TMP, :64]
1847
1848    /* Load all DATA into NEON registers with the following allocation:
1849     *       0 1 2 3 | 4 5 6 7
1850     *      ---------+--------
1851     *   0 | d16     | d17    | q8
1852     *   1 | d18     | d19    | q9
1853     *   2 | d20     | d21    | q10
1854     *   3 | d22     | d23    | q11
1855     *   4 | d24     | d25    | q12
1856     *   5 | d26     | d27    | q13
1857     *   6 | d28     | d29    | q14
1858     *   7 | d30     | d31    | q15
1859     */
1860
1861    vld1.16         {d16, d17, d18, d19}, [DATA, :128]!
1862    vld1.16         {d20, d21, d22, d23}, [DATA, :128]!
1863    vld1.16         {d24, d25, d26, d27}, [DATA, :128]!
1864    vld1.16         {d28, d29, d30, d31}, [DATA, :128]
1865    sub             DATA, DATA, #(128 - 32)
1866
1867    mov             TMP, #2
18681:
1869    /* Transpose */
1870    vtrn.16         q12, q13
1871    vtrn.16         q10, q11
1872    vtrn.16         q8,  q9
1873    vtrn.16         q14, q15
1874    vtrn.32         q9,  q11
1875    vtrn.32         q13, q15
1876    vtrn.32         q8,  q10
1877    vtrn.32         q12, q14
1878    vswp            d30, d23
1879    vswp            d24, d17
1880    vswp            d26, d19
1881      /* 1-D FDCT */
1882      vadd.s16        q2,  q11, q12
1883    vswp            d28, d21
1884      vsub.s16        q12, q11, q12
1885      vsub.s16        q6,  q10, q13
1886      vadd.s16        q10, q10, q13
1887      vsub.s16        q7,  q9,  q14
1888      vadd.s16        q9,  q9,  q14
1889      vsub.s16        q1,  q8,  q15
1890      vadd.s16        q8,  q8,  q15
1891      vsub.s16        q4,  q9,  q10
1892      vsub.s16        q5,  q8,  q2
1893      vadd.s16        q3,  q9,  q10
1894      vadd.s16        q4,  q4,  q5
1895      vadd.s16        q2,  q8,  q2
1896      vqdmulh.s16     q4,  q4,  XFIX_0_707106781
1897      vadd.s16        q11, q12, q6
1898      vadd.s16        q8,  q2,  q3
1899      vsub.s16        q12, q2,  q3
1900      vadd.s16        q3,  q6,  q7
1901      vadd.s16        q7,  q7,  q1
1902      vqdmulh.s16     q3,  q3,  XFIX_0_707106781
1903      vsub.s16        q6,  q11, q7
1904      vadd.s16        q10, q5,  q4
1905      vqdmulh.s16     q6,  q6,  XFIX_0_382683433
1906      vsub.s16        q14, q5,  q4
1907      vqdmulh.s16     q11, q11, XFIX_0_541196100
1908      vqdmulh.s16     q5,  q7,  XFIX_1_306562965
1909      vadd.s16        q4,  q1,  q3
1910      vsub.s16        q3,  q1,  q3
1911      vadd.s16        q7,  q7,  q6
1912      vadd.s16        q11, q11, q6
1913      vadd.s16        q7,  q7,  q5
1914      vadd.s16        q13, q3,  q11
1915      vsub.s16        q11, q3,  q11
1916      vadd.s16        q9,  q4,  q7
1917      vsub.s16        q15, q4,  q7
1918    subs            TMP, TMP, #1
1919    bne             1b
1920
1921    /* store results */
1922    vst1.16         {d16, d17, d18, d19}, [DATA, :128]!
1923    vst1.16         {d20, d21, d22, d23}, [DATA, :128]!
1924    vst1.16         {d24, d25, d26, d27}, [DATA, :128]!
1925    vst1.16         {d28, d29, d30, d31}, [DATA, :128]
1926
1927    vpop            {d8-d15}
1928    bx              lr
1929
1930    .unreq          DATA
1931    .unreq          TMP
1932.endfunc
1933
1934/*****************************************************************************/
1935
1936/*
1937 * GLOBAL(void)
1938 * jsimd_quantize_neon (JCOEFPTR coef_block, DCTELEM * divisors,
1939 *                      DCTELEM * workspace);
1940 *
1941 * Note: the code uses 2 stage pipelining in order to improve instructions
1942 *       scheduling and eliminate stalls (this provides ~15% better
1943 *       performance for this function on both ARM Cortex-A8 and
1944 *       ARM Cortex-A9 when compared to the non-pipelined variant).
1945 *       The instructions which belong to the second stage use different
1946 *       indentation for better readiability.
1947 */
1948asm_function jsimd_quantize_neon
1949
1950    COEF_BLOCK      .req r0
1951    DIVISORS        .req r1
1952    WORKSPACE       .req r2
1953
1954    RECIPROCAL      .req DIVISORS
1955    CORRECTION      .req r3
1956    SHIFT           .req ip
1957    LOOP_COUNT      .req r4
1958
1959    vld1.16         {d0, d1, d2, d3}, [WORKSPACE, :128]!
1960    vabs.s16        q12, q0
1961    add             CORRECTION, DIVISORS, #(64 * 2)
1962    add             SHIFT, DIVISORS, #(64 * 6)
1963    vld1.16         {d20, d21, d22, d23}, [CORRECTION, :128]!
1964    vabs.s16        q13, q1
1965    vld1.16         {d16, d17, d18, d19}, [RECIPROCAL, :128]!
1966    vadd.u16        q12, q12, q10 /* add correction */
1967    vadd.u16        q13, q13, q11
1968    vmull.u16       q10, d24, d16 /* multiply by reciprocal */
1969    vmull.u16       q11, d25, d17
1970    vmull.u16       q8,  d26, d18
1971    vmull.u16       q9,  d27, d19
1972    vld1.16         {d24, d25, d26, d27}, [SHIFT, :128]!
1973    vshrn.u32       d20, q10, #16
1974    vshrn.u32       d21, q11, #16
1975    vshrn.u32       d22, q8,  #16
1976    vshrn.u32       d23, q9,  #16
1977    vneg.s16        q12, q12
1978    vneg.s16        q13, q13
1979    vshr.s16        q2,  q0,  #15 /* extract sign */
1980    vshr.s16        q3,  q1,  #15
1981    vshl.u16        q14, q10, q12 /* shift */
1982    vshl.u16        q15, q11, q13
1983
1984    push            {r4, r5}
1985    mov             LOOP_COUNT, #3
19861:
1987    vld1.16         {d0, d1, d2, d3}, [WORKSPACE, :128]!
1988      veor.u16        q14, q14, q2  /* restore sign */
1989    vabs.s16        q12, q0
1990    vld1.16         {d20, d21, d22, d23}, [CORRECTION, :128]!
1991    vabs.s16        q13, q1
1992      veor.u16        q15, q15, q3
1993    vld1.16         {d16, d17, d18, d19}, [RECIPROCAL, :128]!
1994    vadd.u16        q12, q12, q10 /* add correction */
1995    vadd.u16        q13, q13, q11
1996    vmull.u16       q10, d24, d16 /* multiply by reciprocal */
1997    vmull.u16       q11, d25, d17
1998    vmull.u16       q8,  d26, d18
1999    vmull.u16       q9,  d27, d19
2000      vsub.u16        q14, q14, q2
2001    vld1.16         {d24, d25, d26, d27}, [SHIFT, :128]!
2002      vsub.u16        q15, q15, q3
2003    vshrn.u32       d20, q10, #16
2004    vshrn.u32       d21, q11, #16
2005      vst1.16         {d28, d29, d30, d31}, [COEF_BLOCK, :128]!
2006    vshrn.u32       d22, q8,  #16
2007    vshrn.u32       d23, q9,  #16
2008    vneg.s16        q12, q12
2009    vneg.s16        q13, q13
2010    vshr.s16        q2,  q0,  #15 /* extract sign */
2011    vshr.s16        q3,  q1,  #15
2012    vshl.u16        q14, q10, q12 /* shift */
2013    vshl.u16        q15, q11, q13
2014    subs            LOOP_COUNT, LOOP_COUNT, #1
2015    bne             1b
2016    pop             {r4, r5}
2017
2018      veor.u16        q14, q14, q2  /* restore sign */
2019      veor.u16        q15, q15, q3
2020      vsub.u16        q14, q14, q2
2021      vsub.u16        q15, q15, q3
2022      vst1.16         {d28, d29, d30, d31}, [COEF_BLOCK, :128]!
2023
2024    bx              lr /* return */
2025
2026    .unreq          COEF_BLOCK
2027    .unreq          DIVISORS
2028    .unreq          WORKSPACE
2029    .unreq          RECIPROCAL
2030    .unreq          CORRECTION
2031    .unreq          SHIFT
2032    .unreq          LOOP_COUNT
2033.endfunc
2034