media/libjpeg/simd/jsimd_arm_neon.S

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:8df8d593edb1
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 * Author: Siarhei Siamashka <siarhei.siamashka@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
184 jsimd_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
199 asm_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 /* Check for the zero coefficients in the right 4x8 half */
267 push {r4, r5}
268 vmlal.s16 q7, d5, XFIX_1_175875602_MINUS_0_390180644
269 vsubl.s16 q3, ROW0L, ROW4L
270 ldrd r4, [COEF_BLOCK, #(-96 + 2 * (4 + 1 * 8))]
271 vmull.s16 q2, ROW2L, XFIX_0_541196100
272 vmlal.s16 q2, ROW6L, XFIX_0_541196100_MINUS_1_847759065
273 orr r0, r4, r5
274 vmov q4, q6
275 vmlsl.s16 q6, ROW5L, XFIX_2_562915447
276 ldrd r4, [COEF_BLOCK, #(-96 + 2 * (4 + 2 * 8))]
277 vmlal.s16 q6, ROW3L, XFIX_3_072711026_MINUS_2_562915447
278 vshl.s32 q3, q3, #13
279 orr r0, r0, r4
280 vmlsl.s16 q4, ROW1L, XFIX_0_899976223
281 orr r0, r0, r5
282 vadd.s32 q1, q3, q2
283 ldrd r4, [COEF_BLOCK, #(-96 + 2 * (4 + 3 * 8))]
284 vmov q5, q7
285 vadd.s32 q1, q1, q6
286 orr r0, r0, r4
287 vmlsl.s16 q7, ROW7L, XFIX_0_899976223
288 orr r0, r0, r5
289 vmlal.s16 q7, ROW1L, XFIX_1_501321110_MINUS_0_899976223
290 vrshrn.s32 ROW1L, q1, #11
291 ldrd r4, [COEF_BLOCK, #(-96 + 2 * (4 + 4 * 8))]
292 vsub.s32 q1, q1, q6
293 vmlal.s16 q5, ROW5L, XFIX_2_053119869_MINUS_2_562915447
294 orr r0, r0, r4
295 vmlsl.s16 q5, ROW3L, XFIX_2_562915447
296 orr r0, r0, r5
297 vsub.s32 q1, q1, q6
298 vmull.s16 q6, ROW2L, XFIX_0_541196100_PLUS_0_765366865
299 ldrd r4, [COEF_BLOCK, #(-96 + 2 * (4 + 5 * 8))]
300 vmlal.s16 q6, ROW6L, XFIX_0_541196100
301 vsub.s32 q3, q3, q2
302 orr r0, r0, r4
303 vrshrn.s32 ROW6L, q1, #11
304 orr r0, r0, r5
305 vadd.s32 q1, q3, q5
306 ldrd r4, [COEF_BLOCK, #(-96 + 2 * (4 + 6 * 8))]
307 vsub.s32 q3, q3, q5
308 vaddl.s16 q5, ROW0L, ROW4L
309 orr r0, r0, r4
310 vrshrn.s32 ROW2L, q1, #11
311 orr r0, r0, r5
312 vrshrn.s32 ROW5L, q3, #11
313 ldrd r4, [COEF_BLOCK, #(-96 + 2 * (4 + 7 * 8))]
314 vshl.s32 q5, q5, #13
315 vmlal.s16 q4, ROW7L, XFIX_0_298631336_MINUS_0_899976223
316 orr r0, r0, r4
317 vadd.s32 q2, q5, q6
318 orrs r0, r0, r5
319 vsub.s32 q1, q5, q6
320 vadd.s32 q6, q2, q7
321 ldrd r4, [COEF_BLOCK, #(-96 + 2 * (4 + 0 * 8))]
322 vsub.s32 q2, q2, q7
323 vadd.s32 q5, q1, q4
324 orr r0, r4, r5
325 vsub.s32 q3, q1, q4
326 pop {r4, r5}
327 vrshrn.s32 ROW7L, q2, #11
328 vrshrn.s32 ROW3L, q5, #11
329 vrshrn.s32 ROW0L, q6, #11
330 vrshrn.s32 ROW4L, q3, #11
331
332 beq 3f /* Go to do some special handling for the sparse right 4x8 half */
333
334 /* 1-D IDCT, pass 1, right 4x8 half */
335 vld1.s16 {d2}, [ip, :64] /* reload constants */
336 vadd.s16 d10, ROW7R, ROW3R
337 vadd.s16 d8, ROW5R, ROW1R
338 /* Transpose left 4x8 half */
339 vtrn.16 ROW6L, ROW7L
340 vmull.s16 q6, d10, XFIX_1_175875602_MINUS_1_961570560
341 vmlal.s16 q6, d8, XFIX_1_175875602
342 vtrn.16 ROW2L, ROW3L
343 vmull.s16 q7, d10, XFIX_1_175875602
344 vmlal.s16 q7, d8, XFIX_1_175875602_MINUS_0_390180644
345 vtrn.16 ROW0L, ROW1L
346 vsubl.s16 q3, ROW0R, ROW4R
347 vmull.s16 q2, ROW2R, XFIX_0_541196100
348 vmlal.s16 q2, ROW6R, XFIX_0_541196100_MINUS_1_847759065
349 vtrn.16 ROW4L, ROW5L
350 vmov q4, q6
351 vmlsl.s16 q6, ROW5R, XFIX_2_562915447
352 vmlal.s16 q6, ROW3R, XFIX_3_072711026_MINUS_2_562915447
353 vtrn.32 ROW1L, ROW3L
354 vshl.s32 q3, q3, #13
355 vmlsl.s16 q4, ROW1R, XFIX_0_899976223
356 vtrn.32 ROW4L, ROW6L
357 vadd.s32 q1, q3, q2
358 vmov q5, q7
359 vadd.s32 q1, q1, q6
360 vtrn.32 ROW0L, ROW2L
361 vmlsl.s16 q7, ROW7R, XFIX_0_899976223
362 vmlal.s16 q7, ROW1R, XFIX_1_501321110_MINUS_0_899976223
363 vrshrn.s32 ROW1R, q1, #11
364 vtrn.32 ROW5L, ROW7L
365 vsub.s32 q1, q1, q6
366 vmlal.s16 q5, ROW5R, XFIX_2_053119869_MINUS_2_562915447
367 vmlsl.s16 q5, ROW3R, XFIX_2_562915447
368 vsub.s32 q1, q1, q6
369 vmull.s16 q6, ROW2R, XFIX_0_541196100_PLUS_0_765366865
370 vmlal.s16 q6, ROW6R, XFIX_0_541196100
371 vsub.s32 q3, q3, q2
372 vrshrn.s32 ROW6R, q1, #11
373 vadd.s32 q1, q3, q5
374 vsub.s32 q3, q3, q5
375 vaddl.s16 q5, ROW0R, ROW4R
376 vrshrn.s32 ROW2R, q1, #11
377 vrshrn.s32 ROW5R, q3, #11
378 vshl.s32 q5, q5, #13
379 vmlal.s16 q4, ROW7R, XFIX_0_298631336_MINUS_0_899976223
380 vadd.s32 q2, q5, q6
381 vsub.s32 q1, q5, q6
382 vadd.s32 q6, q2, q7
383 vsub.s32 q2, q2, q7
384 vadd.s32 q5, q1, q4
385 vsub.s32 q3, q1, q4
386 vrshrn.s32 ROW7R, q2, #11
387 vrshrn.s32 ROW3R, q5, #11
388 vrshrn.s32 ROW0R, q6, #11
389 vrshrn.s32 ROW4R, q3, #11
390 /* Transpose right 4x8 half */
391 vtrn.16 ROW6R, ROW7R
392 vtrn.16 ROW2R, ROW3R
393 vtrn.16 ROW0R, ROW1R
394 vtrn.16 ROW4R, ROW5R
395 vtrn.32 ROW1R, ROW3R
396 vtrn.32 ROW4R, ROW6R
397 vtrn.32 ROW0R, ROW2R
398 vtrn.32 ROW5R, ROW7R
399
400 1: /* 1-D IDCT, pass 2 (normal variant), left 4x8 half */
401 vld1.s16 {d2}, [ip, :64] /* reload constants */
402 vmull.s16 q6, ROW1R, XFIX_1_175875602 /* ROW5L <-> ROW1R */
403 vmlal.s16 q6, ROW1L, XFIX_1_175875602
404 vmlal.s16 q6, ROW3R, XFIX_1_175875602_MINUS_1_961570560 /* ROW7L <-> ROW3R */
405 vmlal.s16 q6, ROW3L, XFIX_1_175875602_MINUS_1_961570560
406 vmull.s16 q7, ROW3R, XFIX_1_175875602 /* ROW7L <-> ROW3R */
407 vmlal.s16 q7, ROW3L, XFIX_1_175875602
408 vmlal.s16 q7, ROW1R, XFIX_1_175875602_MINUS_0_390180644 /* ROW5L <-> ROW1R */
409 vmlal.s16 q7, ROW1L, XFIX_1_175875602_MINUS_0_390180644
410 vsubl.s16 q3, ROW0L, ROW0R /* ROW4L <-> ROW0R */
411 vmull.s16 q2, ROW2L, XFIX_0_541196100
412 vmlal.s16 q2, ROW2R, XFIX_0_541196100_MINUS_1_847759065 /* ROW6L <-> ROW2R */
413 vmov q4, q6
414 vmlsl.s16 q6, ROW1R, XFIX_2_562915447 /* ROW5L <-> ROW1R */
415 vmlal.s16 q6, ROW3L, XFIX_3_072711026_MINUS_2_562915447
416 vshl.s32 q3, q3, #13
417 vmlsl.s16 q4, ROW1L, XFIX_0_899976223
418 vadd.s32 q1, q3, q2
419 vmov q5, q7
420 vadd.s32 q1, q1, q6
421 vmlsl.s16 q7, ROW3R, XFIX_0_899976223 /* ROW7L <-> ROW3R */
422 vmlal.s16 q7, ROW1L, XFIX_1_501321110_MINUS_0_899976223
423 vshrn.s32 ROW1L, q1, #16
424 vsub.s32 q1, q1, q6
425 vmlal.s16 q5, ROW1R, XFIX_2_053119869_MINUS_2_562915447 /* ROW5L <-> ROW1R */
426 vmlsl.s16 q5, ROW3L, XFIX_2_562915447
427 vsub.s32 q1, q1, q6
428 vmull.s16 q6, ROW2L, XFIX_0_541196100_PLUS_0_765366865
429 vmlal.s16 q6, ROW2R, XFIX_0_541196100 /* ROW6L <-> ROW2R */
430 vsub.s32 q3, q3, q2
431 vshrn.s32 ROW2R, q1, #16 /* ROW6L <-> ROW2R */
432 vadd.s32 q1, q3, q5
433 vsub.s32 q3, q3, q5
434 vaddl.s16 q5, ROW0L, ROW0R /* ROW4L <-> ROW0R */
435 vshrn.s32 ROW2L, q1, #16
436 vshrn.s32 ROW1R, q3, #16 /* ROW5L <-> ROW1R */
437 vshl.s32 q5, q5, #13
438 vmlal.s16 q4, ROW3R, XFIX_0_298631336_MINUS_0_899976223 /* ROW7L <-> ROW3R */
439 vadd.s32 q2, q5, q6
440 vsub.s32 q1, q5, q6
441 vadd.s32 q6, q2, q7
442 vsub.s32 q2, q2, q7
443 vadd.s32 q5, q1, q4
444 vsub.s32 q3, q1, q4
445 vshrn.s32 ROW3R, q2, #16 /* ROW7L <-> ROW3R */
446 vshrn.s32 ROW3L, q5, #16
447 vshrn.s32 ROW0L, q6, #16
448 vshrn.s32 ROW0R, q3, #16 /* ROW4L <-> ROW0R */
449 /* 1-D IDCT, pass 2, right 4x8 half */
450 vld1.s16 {d2}, [ip, :64] /* reload constants */
451 vmull.s16 q6, ROW5R, XFIX_1_175875602
452 vmlal.s16 q6, ROW5L, XFIX_1_175875602 /* ROW5L <-> ROW1R */
453 vmlal.s16 q6, ROW7R, XFIX_1_175875602_MINUS_1_961570560
454 vmlal.s16 q6, ROW7L, XFIX_1_175875602_MINUS_1_961570560 /* ROW7L <-> ROW3R */
455 vmull.s16 q7, ROW7R, XFIX_1_175875602
456 vmlal.s16 q7, ROW7L, XFIX_1_175875602 /* ROW7L <-> ROW3R */
457 vmlal.s16 q7, ROW5R, XFIX_1_175875602_MINUS_0_390180644
458 vmlal.s16 q7, ROW5L, XFIX_1_175875602_MINUS_0_390180644 /* ROW5L <-> ROW1R */
459 vsubl.s16 q3, ROW4L, ROW4R /* ROW4L <-> ROW0R */
460 vmull.s16 q2, ROW6L, XFIX_0_541196100 /* ROW6L <-> ROW2R */
461 vmlal.s16 q2, ROW6R, XFIX_0_541196100_MINUS_1_847759065
462 vmov q4, q6
463 vmlsl.s16 q6, ROW5R, XFIX_2_562915447
464 vmlal.s16 q6, ROW7L, XFIX_3_072711026_MINUS_2_562915447 /* ROW7L <-> ROW3R */
465 vshl.s32 q3, q3, #13
466 vmlsl.s16 q4, ROW5L, XFIX_0_899976223 /* ROW5L <-> ROW1R */
467 vadd.s32 q1, q3, q2
468 vmov q5, q7
469 vadd.s32 q1, q1, q6
470 vmlsl.s16 q7, ROW7R, XFIX_0_899976223
471 vmlal.s16 q7, ROW5L, XFIX_1_501321110_MINUS_0_899976223 /* ROW5L <-> ROW1R */
472 vshrn.s32 ROW5L, q1, #16 /* ROW5L <-> ROW1R */
473 vsub.s32 q1, q1, q6
474 vmlal.s16 q5, ROW5R, XFIX_2_053119869_MINUS_2_562915447
475 vmlsl.s16 q5, ROW7L, XFIX_2_562915447 /* ROW7L <-> ROW3R */
476 vsub.s32 q1, q1, q6
477 vmull.s16 q6, ROW6L, XFIX_0_541196100_PLUS_0_765366865 /* ROW6L <-> ROW2R */
478 vmlal.s16 q6, ROW6R, XFIX_0_541196100
479 vsub.s32 q3, q3, q2
480 vshrn.s32 ROW6R, q1, #16
481 vadd.s32 q1, q3, q5
482 vsub.s32 q3, q3, q5
483 vaddl.s16 q5, ROW4L, ROW4R /* ROW4L <-> ROW0R */
484 vshrn.s32 ROW6L, q1, #16 /* ROW6L <-> ROW2R */
485 vshrn.s32 ROW5R, q3, #16
486 vshl.s32 q5, q5, #13
487 vmlal.s16 q4, ROW7R, XFIX_0_298631336_MINUS_0_899976223
488 vadd.s32 q2, q5, q6
489 vsub.s32 q1, q5, q6
490 vadd.s32 q6, q2, q7
491 vsub.s32 q2, q2, q7
492 vadd.s32 q5, q1, q4
493 vsub.s32 q3, q1, q4
494 vshrn.s32 ROW7R, q2, #16
495 vshrn.s32 ROW7L, q5, #16 /* ROW7L <-> ROW3R */
496 vshrn.s32 ROW4L, q6, #16 /* ROW4L <-> ROW0R */
497 vshrn.s32 ROW4R, q3, #16
498
499 2: /* Descale to 8-bit and range limit */
500 vqrshrn.s16 d16, q8, #2
501 vqrshrn.s16 d17, q9, #2
502 vqrshrn.s16 d18, q10, #2
503 vqrshrn.s16 d19, q11, #2
504 vpop {d8-d15} /* restore NEON registers */
505 vqrshrn.s16 d20, q12, #2
506 /* Transpose the final 8-bit samples and do signed->unsigned conversion */
507 vtrn.16 q8, q9
508 vqrshrn.s16 d21, q13, #2
509 vqrshrn.s16 d22, q14, #2
510 vmov.u8 q0, #(CENTERJSAMPLE)
511 vqrshrn.s16 d23, q15, #2
512 vtrn.8 d16, d17
513 vtrn.8 d18, d19
514 vadd.u8 q8, q8, q0
515 vadd.u8 q9, q9, q0
516 vtrn.16 q10, q11
517 /* Store results to the output buffer */
518 ldmia OUTPUT_BUF!, {TMP1, TMP2}
519 add TMP1, TMP1, OUTPUT_COL
520 add TMP2, TMP2, OUTPUT_COL
521 vst1.8 {d16}, [TMP1]
522 vtrn.8 d20, d21
523 vst1.8 {d17}, [TMP2]
524 ldmia OUTPUT_BUF!, {TMP1, TMP2}
525 add TMP1, TMP1, OUTPUT_COL
526 add TMP2, TMP2, OUTPUT_COL
527 vst1.8 {d18}, [TMP1]
528 vadd.u8 q10, q10, q0
529 vst1.8 {d19}, [TMP2]
530 ldmia OUTPUT_BUF, {TMP1, TMP2, TMP3, TMP4}
531 add TMP1, TMP1, OUTPUT_COL
532 add TMP2, TMP2, OUTPUT_COL
533 add TMP3, TMP3, OUTPUT_COL
534 add TMP4, TMP4, OUTPUT_COL
535 vtrn.8 d22, d23
536 vst1.8 {d20}, [TMP1]
537 vadd.u8 q11, q11, q0
538 vst1.8 {d21}, [TMP2]
539 vst1.8 {d22}, [TMP3]
540 vst1.8 {d23}, [TMP4]
541 bx lr
542
543 3: /* Left 4x8 half is done, right 4x8 half contains mostly zeros */
544
545 /* Transpose left 4x8 half */
546 vtrn.16 ROW6L, ROW7L
547 vtrn.16 ROW2L, ROW3L
548 vtrn.16 ROW0L, ROW1L
549 vtrn.16 ROW4L, ROW5L
550 vshl.s16 ROW0R, ROW0R, #2 /* PASS1_BITS */
551 vtrn.32 ROW1L, ROW3L
552 vtrn.32 ROW4L, ROW6L
553 vtrn.32 ROW0L, ROW2L
554 vtrn.32 ROW5L, ROW7L
555
556 cmp r0, #0
557 beq 4f /* Right 4x8 half has all zeros, go to 'sparse' second pass */
558
559 /* Only row 0 is non-zero for the right 4x8 half */
560 vdup.s16 ROW1R, ROW0R[1]
561 vdup.s16 ROW2R, ROW0R[2]
562 vdup.s16 ROW3R, ROW0R[3]
563 vdup.s16 ROW4R, ROW0R[0]
564 vdup.s16 ROW5R, ROW0R[1]
565 vdup.s16 ROW6R, ROW0R[2]
566 vdup.s16 ROW7R, ROW0R[3]
567 vdup.s16 ROW0R, ROW0R[0]
568 b 1b /* Go to 'normal' second pass */
569
570 4: /* 1-D IDCT, pass 2 (sparse variant with zero rows 4-7), left 4x8 half */
571 vld1.s16 {d2}, [ip, :64] /* reload constants */
572 vmull.s16 q6, ROW1L, XFIX_1_175875602
573 vmlal.s16 q6, ROW3L, XFIX_1_175875602_MINUS_1_961570560
574 vmull.s16 q7, ROW3L, XFIX_1_175875602
575 vmlal.s16 q7, ROW1L, XFIX_1_175875602_MINUS_0_390180644
576 vmull.s16 q2, ROW2L, XFIX_0_541196100
577 vshll.s16 q3, ROW0L, #13
578 vmov q4, q6
579 vmlal.s16 q6, ROW3L, XFIX_3_072711026_MINUS_2_562915447
580 vmlsl.s16 q4, ROW1L, XFIX_0_899976223
581 vadd.s32 q1, q3, q2
582 vmov q5, q7
583 vmlal.s16 q7, ROW1L, XFIX_1_501321110_MINUS_0_899976223
584 vadd.s32 q1, q1, q6
585 vadd.s32 q6, q6, q6
586 vmlsl.s16 q5, ROW3L, XFIX_2_562915447
587 vshrn.s32 ROW1L, q1, #16
588 vsub.s32 q1, q1, q6
589 vmull.s16 q6, ROW2L, XFIX_0_541196100_PLUS_0_765366865
590 vsub.s32 q3, q3, q2
591 vshrn.s32 ROW2R, q1, #16 /* ROW6L <-> ROW2R */
592 vadd.s32 q1, q3, q5
593 vsub.s32 q3, q3, q5
594 vshll.s16 q5, ROW0L, #13
595 vshrn.s32 ROW2L, q1, #16
596 vshrn.s32 ROW1R, q3, #16 /* ROW5L <-> ROW1R */
597 vadd.s32 q2, q5, q6
598 vsub.s32 q1, q5, q6
599 vadd.s32 q6, q2, q7
600 vsub.s32 q2, q2, q7
601 vadd.s32 q5, q1, q4
602 vsub.s32 q3, q1, q4
603 vshrn.s32 ROW3R, q2, #16 /* ROW7L <-> ROW3R */
604 vshrn.s32 ROW3L, q5, #16
605 vshrn.s32 ROW0L, q6, #16
606 vshrn.s32 ROW0R, q3, #16 /* ROW4L <-> ROW0R */
607 /* 1-D IDCT, pass 2 (sparse variant with zero rows 4-7), right 4x8 half */
608 vld1.s16 {d2}, [ip, :64] /* reload constants */
609 vmull.s16 q6, ROW5L, XFIX_1_175875602
610 vmlal.s16 q6, ROW7L, XFIX_1_175875602_MINUS_1_961570560
611 vmull.s16 q7, ROW7L, XFIX_1_175875602
612 vmlal.s16 q7, ROW5L, XFIX_1_175875602_MINUS_0_390180644
613 vmull.s16 q2, ROW6L, XFIX_0_541196100
614 vshll.s16 q3, ROW4L, #13
615 vmov q4, q6
616 vmlal.s16 q6, ROW7L, XFIX_3_072711026_MINUS_2_562915447
617 vmlsl.s16 q4, ROW5L, XFIX_0_899976223
618 vadd.s32 q1, q3, q2
619 vmov q5, q7
620 vmlal.s16 q7, ROW5L, XFIX_1_501321110_MINUS_0_899976223
621 vadd.s32 q1, q1, q6
622 vadd.s32 q6, q6, q6
623 vmlsl.s16 q5, ROW7L, XFIX_2_562915447
624 vshrn.s32 ROW5L, q1, #16 /* ROW5L <-> ROW1R */
625 vsub.s32 q1, q1, q6
626 vmull.s16 q6, ROW6L, XFIX_0_541196100_PLUS_0_765366865
627 vsub.s32 q3, q3, q2
628 vshrn.s32 ROW6R, q1, #16
629 vadd.s32 q1, q3, q5
630 vsub.s32 q3, q3, q5
631 vshll.s16 q5, ROW4L, #13
632 vshrn.s32 ROW6L, q1, #16 /* ROW6L <-> ROW2R */
633 vshrn.s32 ROW5R, q3, #16
634 vadd.s32 q2, q5, q6
635 vsub.s32 q1, q5, q6
636 vadd.s32 q6, q2, q7
637 vsub.s32 q2, q2, q7
638 vadd.s32 q5, q1, q4
639 vsub.s32 q3, q1, q4
640 vshrn.s32 ROW7R, q2, #16
641 vshrn.s32 ROW7L, q5, #16 /* ROW7L <-> ROW3R */
642 vshrn.s32 ROW4L, q6, #16 /* ROW4L <-> ROW0R */
643 vshrn.s32 ROW4R, q3, #16
644 b 2b /* Go to epilogue */
645
646 .unreq DCT_TABLE
647 .unreq COEF_BLOCK
648 .unreq OUTPUT_BUF
649 .unreq OUTPUT_COL
650 .unreq TMP1
651 .unreq TMP2
652 .unreq TMP3
653 .unreq TMP4
654
655 .unreq ROW0L
656 .unreq ROW0R
657 .unreq ROW1L
658 .unreq ROW1R
659 .unreq ROW2L
660 .unreq ROW2R
661 .unreq ROW3L
662 .unreq ROW3R
663 .unreq ROW4L
664 .unreq ROW4R
665 .unreq ROW5L
666 .unreq ROW5R
667 .unreq ROW6L
668 .unreq ROW6R
669 .unreq ROW7L
670 .unreq ROW7R
671 .endfunc
672
673 /*****************************************************************************/
674
675 /*
676 * jsimd_idct_ifast_neon
677 *
678 * This function contains a fast, not so accurate integer implementation of
679 * the inverse DCT (Discrete Cosine Transform). It uses the same calculations
680 * and produces exactly the same output as IJG's original 'jpeg_idct_ifast'
681 * function from jidctfst.c
682 *
683 * Normally 1-D AAN DCT needs 5 multiplications and 29 additions.
684 * But in ARM NEON case some extra additions are required because VQDMULH
685 * instruction can't handle the constants larger than 1. So the expressions
686 * like "x * 1.082392200" have to be converted to "x * 0.082392200 + x",
687 * which introduces an extra addition. Overall, there are 6 extra additions
688 * per 1-D IDCT pass, totalling to 5 VQDMULH and 35 VADD/VSUB instructions.
689 */
690
691 #define XFIX_1_082392200 d0[0]
692 #define XFIX_1_414213562 d0[1]
693 #define XFIX_1_847759065 d0[2]
694 #define XFIX_2_613125930 d0[3]
695
696 .balign 16
697 jsimd_idct_ifast_neon_consts:
698 .short (277 * 128 - 256 * 128) /* XFIX_1_082392200 */
699 .short (362 * 128 - 256 * 128) /* XFIX_1_414213562 */
700 .short (473 * 128 - 256 * 128) /* XFIX_1_847759065 */
701 .short (669 * 128 - 512 * 128) /* XFIX_2_613125930 */
702
703 asm_function jsimd_idct_ifast_neon
704
705 DCT_TABLE .req r0
706 COEF_BLOCK .req r1
707 OUTPUT_BUF .req r2
708 OUTPUT_COL .req r3
709 TMP1 .req r0
710 TMP2 .req r1
711 TMP3 .req r2
712 TMP4 .req ip
713
714 /* Load and dequantize coefficients into NEON registers
715 * with the following allocation:
716 * 0 1 2 3 | 4 5 6 7
717 * ---------+--------
718 * 0 | d16 | d17 ( q8 )
719 * 1 | d18 | d19 ( q9 )
720 * 2 | d20 | d21 ( q10 )
721 * 3 | d22 | d23 ( q11 )
722 * 4 | d24 | d25 ( q12 )
723 * 5 | d26 | d27 ( q13 )
724 * 6 | d28 | d29 ( q14 )
725 * 7 | d30 | d31 ( q15 )
726 */
727 adr ip, jsimd_idct_ifast_neon_consts
728 vld1.16 {d16, d17, d18, d19}, [COEF_BLOCK, :128]!
729 vld1.16 {d0, d1, d2, d3}, [DCT_TABLE, :128]!
730 vld1.16 {d20, d21, d22, d23}, [COEF_BLOCK, :128]!
731 vmul.s16 q8, q8, q0
732 vld1.16 {d4, d5, d6, d7}, [DCT_TABLE, :128]!
733 vmul.s16 q9, q9, q1
734 vld1.16 {d24, d25, d26, d27}, [COEF_BLOCK, :128]!
735 vmul.s16 q10, q10, q2
736 vld1.16 {d0, d1, d2, d3}, [DCT_TABLE, :128]!
737 vmul.s16 q11, q11, q3
738 vld1.16 {d28, d29, d30, d31}, [COEF_BLOCK, :128]
739 vmul.s16 q12, q12, q0
740 vld1.16 {d4, d5, d6, d7}, [DCT_TABLE, :128]!
741 vmul.s16 q14, q14, q2
742 vmul.s16 q13, q13, q1
743 vld1.16 {d0}, [ip, :64] /* load constants */
744 vmul.s16 q15, q15, q3
745 vpush {d8-d13} /* save NEON registers */
746 /* 1-D IDCT, pass 1 */
747 vsub.s16 q2, q10, q14
748 vadd.s16 q14, q10, q14
749 vsub.s16 q1, q11, q13
750 vadd.s16 q13, q11, q13
751 vsub.s16 q5, q9, q15
752 vadd.s16 q15, q9, q15
753 vqdmulh.s16 q4, q2, XFIX_1_414213562
754 vqdmulh.s16 q6, q1, XFIX_2_613125930
755 vadd.s16 q3, q1, q1
756 vsub.s16 q1, q5, q1
757 vadd.s16 q10, q2, q4
758 vqdmulh.s16 q4, q1, XFIX_1_847759065
759 vsub.s16 q2, q15, q13
760 vadd.s16 q3, q3, q6
761 vqdmulh.s16 q6, q2, XFIX_1_414213562
762 vadd.s16 q1, q1, q4
763 vqdmulh.s16 q4, q5, XFIX_1_082392200
764 vsub.s16 q10, q10, q14
765 vadd.s16 q2, q2, q6
766 vsub.s16 q6, q8, q12
767 vadd.s16 q12, q8, q12
768 vadd.s16 q9, q5, q4
769 vadd.s16 q5, q6, q10
770 vsub.s16 q10, q6, q10
771 vadd.s16 q6, q15, q13
772 vadd.s16 q8, q12, q14
773 vsub.s16 q3, q6, q3
774 vsub.s16 q12, q12, q14
775 vsub.s16 q3, q3, q1
776 vsub.s16 q1, q9, q1
777 vadd.s16 q2, q3, q2
778 vsub.s16 q15, q8, q6
779 vadd.s16 q1, q1, q2
780 vadd.s16 q8, q8, q6
781 vadd.s16 q14, q5, q3
782 vsub.s16 q9, q5, q3
783 vsub.s16 q13, q10, q2
784 vadd.s16 q10, q10, q2
785 /* Transpose */
786 vtrn.16 q8, q9
787 vsub.s16 q11, q12, q1
788 vtrn.16 q14, q15
789 vadd.s16 q12, q12, q1
790 vtrn.16 q10, q11
791 vtrn.16 q12, q13
792 vtrn.32 q9, q11
793 vtrn.32 q12, q14
794 vtrn.32 q8, q10
795 vtrn.32 q13, q15
796 vswp d28, d21
797 vswp d26, d19
798 /* 1-D IDCT, pass 2 */
799 vsub.s16 q2, q10, q14
800 vswp d30, d23
801 vadd.s16 q14, q10, q14
802 vswp d24, d17
803 vsub.s16 q1, q11, q13
804 vadd.s16 q13, q11, q13
805 vsub.s16 q5, q9, q15
806 vadd.s16 q15, q9, q15
807 vqdmulh.s16 q4, q2, XFIX_1_414213562
808 vqdmulh.s16 q6, q1, XFIX_2_613125930
809 vadd.s16 q3, q1, q1
810 vsub.s16 q1, q5, q1
811 vadd.s16 q10, q2, q4
812 vqdmulh.s16 q4, q1, XFIX_1_847759065
813 vsub.s16 q2, q15, q13
814 vadd.s16 q3, q3, q6
815 vqdmulh.s16 q6, q2, XFIX_1_414213562
816 vadd.s16 q1, q1, q4
817 vqdmulh.s16 q4, q5, XFIX_1_082392200
818 vsub.s16 q10, q10, q14
819 vadd.s16 q2, q2, q6
820 vsub.s16 q6, q8, q12
821 vadd.s16 q12, q8, q12
822 vadd.s16 q9, q5, q4
823 vadd.s16 q5, q6, q10
824 vsub.s16 q10, q6, q10
825 vadd.s16 q6, q15, q13
826 vadd.s16 q8, q12, q14
827 vsub.s16 q3, q6, q3
828 vsub.s16 q12, q12, q14
829 vsub.s16 q3, q3, q1
830 vsub.s16 q1, q9, q1
831 vadd.s16 q2, q3, q2
832 vsub.s16 q15, q8, q6
833 vadd.s16 q1, q1, q2
834 vadd.s16 q8, q8, q6
835 vadd.s16 q14, q5, q3
836 vsub.s16 q9, q5, q3
837 vsub.s16 q13, q10, q2
838 vpop {d8-d13} /* restore NEON registers */
839 vadd.s16 q10, q10, q2
840 vsub.s16 q11, q12, q1
841 vadd.s16 q12, q12, q1
842 /* Descale to 8-bit and range limit */
843 vmov.u8 q0, #0x80
844 vqshrn.s16 d16, q8, #5
845 vqshrn.s16 d17, q9, #5
846 vqshrn.s16 d18, q10, #5
847 vqshrn.s16 d19, q11, #5
848 vqshrn.s16 d20, q12, #5
849 vqshrn.s16 d21, q13, #5
850 vqshrn.s16 d22, q14, #5
851 vqshrn.s16 d23, q15, #5
852 vadd.u8 q8, q8, q0
853 vadd.u8 q9, q9, q0
854 vadd.u8 q10, q10, q0
855 vadd.u8 q11, q11, q0
856 /* Transpose the final 8-bit samples */
857 vtrn.16 q8, q9
858 vtrn.16 q10, q11
859 vtrn.32 q8, q10
860 vtrn.32 q9, q11
861 vtrn.8 d16, d17
862 vtrn.8 d18, d19
863 /* Store results to the output buffer */
864 ldmia OUTPUT_BUF!, {TMP1, TMP2}
865 add TMP1, TMP1, OUTPUT_COL
866 add TMP2, TMP2, OUTPUT_COL
867 vst1.8 {d16}, [TMP1]
868 vst1.8 {d17}, [TMP2]
869 ldmia OUTPUT_BUF!, {TMP1, TMP2}
870 add TMP1, TMP1, OUTPUT_COL
871 add TMP2, TMP2, OUTPUT_COL
872 vst1.8 {d18}, [TMP1]
873 vtrn.8 d20, d21
874 vst1.8 {d19}, [TMP2]
875 ldmia OUTPUT_BUF, {TMP1, TMP2, TMP3, TMP4}
876 add TMP1, TMP1, OUTPUT_COL
877 add TMP2, TMP2, OUTPUT_COL
878 add TMP3, TMP3, OUTPUT_COL
879 add TMP4, TMP4, OUTPUT_COL
880 vst1.8 {d20}, [TMP1]
881 vtrn.8 d22, d23
882 vst1.8 {d21}, [TMP2]
883 vst1.8 {d22}, [TMP3]
884 vst1.8 {d23}, [TMP4]
885 bx lr
886
887 .unreq DCT_TABLE
888 .unreq COEF_BLOCK
889 .unreq OUTPUT_BUF
890 .unreq OUTPUT_COL
891 .unreq TMP1
892 .unreq TMP2
893 .unreq TMP3
894 .unreq TMP4
895 .endfunc
896
897 /*****************************************************************************/
898
899 /*
900 * jsimd_idct_4x4_neon
901 *
902 * This function contains inverse-DCT code for getting reduced-size
903 * 4x4 pixels output from an 8x8 DCT block. It uses the same calculations
904 * and produces exactly the same output as IJG's original 'jpeg_idct_4x4'
905 * function from jpeg-6b (jidctred.c).
906 *
907 * NOTE: jpeg-8 has an improved implementation of 4x4 inverse-DCT, which
908 * requires much less arithmetic operations and hence should be faster.
909 * The primary purpose of this particular NEON optimized function is
910 * bit exact compatibility with jpeg-6b.
911 *
912 * TODO: a bit better instructions scheduling can be achieved by expanding
913 * idct_helper/transpose_4x4 macros and reordering instructions,
914 * but readability will suffer somewhat.
915 */
916
917 #define CONST_BITS 13
918
919 #define FIX_0_211164243 (1730) /* FIX(0.211164243) */
920 #define FIX_0_509795579 (4176) /* FIX(0.509795579) */
921 #define FIX_0_601344887 (4926) /* FIX(0.601344887) */
922 #define FIX_0_720959822 (5906) /* FIX(0.720959822) */
923 #define FIX_0_765366865 (6270) /* FIX(0.765366865) */
924 #define FIX_0_850430095 (6967) /* FIX(0.850430095) */
925 #define FIX_0_899976223 (7373) /* FIX(0.899976223) */
926 #define FIX_1_061594337 (8697) /* FIX(1.061594337) */
927 #define FIX_1_272758580 (10426) /* FIX(1.272758580) */
928 #define FIX_1_451774981 (11893) /* FIX(1.451774981) */
929 #define FIX_1_847759065 (15137) /* FIX(1.847759065) */
930 #define FIX_2_172734803 (17799) /* FIX(2.172734803) */
931 #define FIX_2_562915447 (20995) /* FIX(2.562915447) */
932 #define FIX_3_624509785 (29692) /* FIX(3.624509785) */
933
934 .balign 16
935 jsimd_idct_4x4_neon_consts:
936 .short FIX_1_847759065 /* d0[0] */
937 .short -FIX_0_765366865 /* d0[1] */
938 .short -FIX_0_211164243 /* d0[2] */
939 .short FIX_1_451774981 /* d0[3] */
940 .short -FIX_2_172734803 /* d1[0] */
941 .short FIX_1_061594337 /* d1[1] */
942 .short -FIX_0_509795579 /* d1[2] */
943 .short -FIX_0_601344887 /* d1[3] */
944 .short FIX_0_899976223 /* d2[0] */
945 .short FIX_2_562915447 /* d2[1] */
946 .short 1 << (CONST_BITS+1) /* d2[2] */
947 .short 0 /* d2[3] */
948
949 .macro idct_helper x4, x6, x8, x10, x12, x14, x16, shift, y26, y27, y28, y29
950 vmull.s16 q14, \x4, d2[2]
951 vmlal.s16 q14, \x8, d0[0]
952 vmlal.s16 q14, \x14, d0[1]
953
954 vmull.s16 q13, \x16, d1[2]
955 vmlal.s16 q13, \x12, d1[3]
956 vmlal.s16 q13, \x10, d2[0]
957 vmlal.s16 q13, \x6, d2[1]
958
959 vmull.s16 q15, \x4, d2[2]
960 vmlsl.s16 q15, \x8, d0[0]
961 vmlsl.s16 q15, \x14, d0[1]
962
963 vmull.s16 q12, \x16, d0[2]
964 vmlal.s16 q12, \x12, d0[3]
965 vmlal.s16 q12, \x10, d1[0]
966 vmlal.s16 q12, \x6, d1[1]
967
968 vadd.s32 q10, q14, q13
969 vsub.s32 q14, q14, q13
970
971 .if \shift > 16
972 vrshr.s32 q10, q10, #\shift
973 vrshr.s32 q14, q14, #\shift
974 vmovn.s32 \y26, q10
975 vmovn.s32 \y29, q14
976 .else
977 vrshrn.s32 \y26, q10, #\shift
978 vrshrn.s32 \y29, q14, #\shift
979 .endif
980
981 vadd.s32 q10, q15, q12
982 vsub.s32 q15, q15, q12
983
984 .if \shift > 16
985 vrshr.s32 q10, q10, #\shift
986 vrshr.s32 q15, q15, #\shift
987 vmovn.s32 \y27, q10
988 vmovn.s32 \y28, q15
989 .else
990 vrshrn.s32 \y27, q10, #\shift
991 vrshrn.s32 \y28, q15, #\shift
992 .endif
993
994 .endm
995
996 asm_function jsimd_idct_4x4_neon
997
998 DCT_TABLE .req r0
999 COEF_BLOCK .req r1
1000 OUTPUT_BUF .req r2
1001 OUTPUT_COL .req r3
1002 TMP1 .req r0
1003 TMP2 .req r1
1004 TMP3 .req r2
1005 TMP4 .req ip
1006
1007 vpush {d8-d15}
1008
1009 /* Load constants (d3 is just used for padding) */
1010 adr TMP4, jsimd_idct_4x4_neon_consts
1011 vld1.16 {d0, d1, d2, d3}, [TMP4, :128]
1012
1013 /* Load all COEF_BLOCK into NEON registers with the following allocation:
1014 * 0 1 2 3 | 4 5 6 7
1015 * ---------+--------
1016 * 0 | d4 | d5
1017 * 1 | d6 | d7
1018 * 2 | d8 | d9
1019 * 3 | d10 | d11
1020 * 4 | - | -
1021 * 5 | d12 | d13
1022 * 6 | d14 | d15
1023 * 7 | d16 | d17
1024 */
1025 vld1.16 {d4, d5, d6, d7}, [COEF_BLOCK, :128]!
1026 vld1.16 {d8, d9, d10, d11}, [COEF_BLOCK, :128]!
1027 add COEF_BLOCK, COEF_BLOCK, #16
1028 vld1.16 {d12, d13, d14, d15}, [COEF_BLOCK, :128]!
1029 vld1.16 {d16, d17}, [COEF_BLOCK, :128]!
1030 /* dequantize */
1031 vld1.16 {d18, d19, d20, d21}, [DCT_TABLE, :128]!
1032 vmul.s16 q2, q2, q9
1033 vld1.16 {d22, d23, d24, d25}, [DCT_TABLE, :128]!
1034 vmul.s16 q3, q3, q10
1035 vmul.s16 q4, q4, q11
1036 add DCT_TABLE, DCT_TABLE, #16
1037 vld1.16 {d26, d27, d28, d29}, [DCT_TABLE, :128]!
1038 vmul.s16 q5, q5, q12
1039 vmul.s16 q6, q6, q13
1040 vld1.16 {d30, d31}, [DCT_TABLE, :128]!
1041 vmul.s16 q7, q7, q14
1042 vmul.s16 q8, q8, q15
1043
1044 /* Pass 1 */
1045 idct_helper d4, d6, d8, d10, d12, d14, d16, 12, d4, d6, d8, d10
1046 transpose_4x4 d4, d6, d8, d10
1047 idct_helper d5, d7, d9, d11, d13, d15, d17, 12, d5, d7, d9, d11
1048 transpose_4x4 d5, d7, d9, d11
1049
1050 /* Pass 2 */
1051 idct_helper d4, d6, d8, d10, d7, d9, d11, 19, d26, d27, d28, d29
1052 transpose_4x4 d26, d27, d28, d29
1053
1054 /* Range limit */
1055 vmov.u16 q15, #0x80
1056 vadd.s16 q13, q13, q15
1057 vadd.s16 q14, q14, q15
1058 vqmovun.s16 d26, q13
1059 vqmovun.s16 d27, q14
1060
1061 /* Store results to the output buffer */
1062 ldmia OUTPUT_BUF, {TMP1, TMP2, TMP3, TMP4}
1063 add TMP1, TMP1, OUTPUT_COL
1064 add TMP2, TMP2, OUTPUT_COL
1065 add TMP3, TMP3, OUTPUT_COL
1066 add TMP4, TMP4, OUTPUT_COL
1067
1068 #if defined(__ARMEL__) && !RESPECT_STRICT_ALIGNMENT
1069 /* We can use much less instructions on little endian systems if the
1070 * OS kernel is not configured to trap unaligned memory accesses
1071 */
1072 vst1.32 {d26[0]}, [TMP1]!
1073 vst1.32 {d27[0]}, [TMP3]!
1074 vst1.32 {d26[1]}, [TMP2]!
1075 vst1.32 {d27[1]}, [TMP4]!
1076 #else
1077 vst1.8 {d26[0]}, [TMP1]!
1078 vst1.8 {d27[0]}, [TMP3]!
1079 vst1.8 {d26[1]}, [TMP1]!
1080 vst1.8 {d27[1]}, [TMP3]!
1081 vst1.8 {d26[2]}, [TMP1]!
1082 vst1.8 {d27[2]}, [TMP3]!
1083 vst1.8 {d26[3]}, [TMP1]!
1084 vst1.8 {d27[3]}, [TMP3]!
1085
1086 vst1.8 {d26[4]}, [TMP2]!
1087 vst1.8 {d27[4]}, [TMP4]!
1088 vst1.8 {d26[5]}, [TMP2]!
1089 vst1.8 {d27[5]}, [TMP4]!
1090 vst1.8 {d26[6]}, [TMP2]!
1091 vst1.8 {d27[6]}, [TMP4]!
1092 vst1.8 {d26[7]}, [TMP2]!
1093 vst1.8 {d27[7]}, [TMP4]!
1094 #endif
1095
1096 vpop {d8-d15}
1097 bx lr
1098
1099 .unreq DCT_TABLE
1100 .unreq COEF_BLOCK
1101 .unreq OUTPUT_BUF
1102 .unreq OUTPUT_COL
1103 .unreq TMP1
1104 .unreq TMP2
1105 .unreq TMP3
1106 .unreq TMP4
1107 .endfunc
1108
1109 .purgem idct_helper
1110
1111 /*****************************************************************************/
1112
1113 /*
1114 * jsimd_idct_2x2_neon
1115 *
1116 * This function contains inverse-DCT code for getting reduced-size
1117 * 2x2 pixels output from an 8x8 DCT block. It uses the same calculations
1118 * and produces exactly the same output as IJG's original 'jpeg_idct_2x2'
1119 * function from jpeg-6b (jidctred.c).
1120 *
1121 * NOTE: jpeg-8 has an improved implementation of 2x2 inverse-DCT, which
1122 * requires much less arithmetic operations and hence should be faster.
1123 * The primary purpose of this particular NEON optimized function is
1124 * bit exact compatibility with jpeg-6b.
1125 */
1126
1127 .balign 8
1128 jsimd_idct_2x2_neon_consts:
1129 .short -FIX_0_720959822 /* d0[0] */
1130 .short FIX_0_850430095 /* d0[1] */
1131 .short -FIX_1_272758580 /* d0[2] */
1132 .short FIX_3_624509785 /* d0[3] */
1133
1134 .macro idct_helper x4, x6, x10, x12, x16, shift, y26, y27
1135 vshll.s16 q14, \x4, #15
1136 vmull.s16 q13, \x6, d0[3]
1137 vmlal.s16 q13, \x10, d0[2]
1138 vmlal.s16 q13, \x12, d0[1]
1139 vmlal.s16 q13, \x16, d0[0]
1140
1141 vadd.s32 q10, q14, q13
1142 vsub.s32 q14, q14, q13
1143
1144 .if \shift > 16
1145 vrshr.s32 q10, q10, #\shift
1146 vrshr.s32 q14, q14, #\shift
1147 vmovn.s32 \y26, q10
1148 vmovn.s32 \y27, q14
1149 .else
1150 vrshrn.s32 \y26, q10, #\shift
1151 vrshrn.s32 \y27, q14, #\shift
1152 .endif
1153
1154 .endm
1155
1156 asm_function jsimd_idct_2x2_neon
1157
1158 DCT_TABLE .req r0
1159 COEF_BLOCK .req r1
1160 OUTPUT_BUF .req r2
1161 OUTPUT_COL .req r3
1162 TMP1 .req r0
1163 TMP2 .req ip
1164
1165 vpush {d8-d15}
1166
1167 /* Load constants */
1168 adr TMP2, jsimd_idct_2x2_neon_consts
1169 vld1.16 {d0}, [TMP2, :64]
1170
1171 /* Load all COEF_BLOCK into NEON registers with the following allocation:
1172 * 0 1 2 3 | 4 5 6 7
1173 * ---------+--------
1174 * 0 | d4 | d5
1175 * 1 | d6 | d7
1176 * 2 | - | -
1177 * 3 | d10 | d11
1178 * 4 | - | -
1179 * 5 | d12 | d13
1180 * 6 | - | -
1181 * 7 | d16 | d17
1182 */
1183 vld1.16 {d4, d5, d6, d7}, [COEF_BLOCK, :128]!
1184 add COEF_BLOCK, COEF_BLOCK, #16
1185 vld1.16 {d10, d11}, [COEF_BLOCK, :128]!
1186 add COEF_BLOCK, COEF_BLOCK, #16
1187 vld1.16 {d12, d13}, [COEF_BLOCK, :128]!
1188 add COEF_BLOCK, COEF_BLOCK, #16
1189 vld1.16 {d16, d17}, [COEF_BLOCK, :128]!
1190 /* Dequantize */
1191 vld1.16 {d18, d19, d20, d21}, [DCT_TABLE, :128]!
1192 vmul.s16 q2, q2, q9
1193 vmul.s16 q3, q3, q10
1194 add DCT_TABLE, DCT_TABLE, #16
1195 vld1.16 {d24, d25}, [DCT_TABLE, :128]!
1196 vmul.s16 q5, q5, q12
1197 add DCT_TABLE, DCT_TABLE, #16
1198 vld1.16 {d26, d27}, [DCT_TABLE, :128]!
1199 vmul.s16 q6, q6, q13
1200 add DCT_TABLE, DCT_TABLE, #16
1201 vld1.16 {d30, d31}, [DCT_TABLE, :128]!
1202 vmul.s16 q8, q8, q15
1203
1204 /* Pass 1 */
1205 #if 0
1206 idct_helper d4, d6, d10, d12, d16, 13, d4, d6
1207 transpose_4x4 d4, d6, d8, d10
1208 idct_helper d5, d7, d11, d13, d17, 13, d5, d7
1209 transpose_4x4 d5, d7, d9, d11
1210 #else
1211 vmull.s16 q13, d6, d0[3]
1212 vmlal.s16 q13, d10, d0[2]
1213 vmlal.s16 q13, d12, d0[1]
1214 vmlal.s16 q13, d16, d0[0]
1215 vmull.s16 q12, d7, d0[3]
1216 vmlal.s16 q12, d11, d0[2]
1217 vmlal.s16 q12, d13, d0[1]
1218 vmlal.s16 q12, d17, d0[0]
1219 vshll.s16 q14, d4, #15
1220 vshll.s16 q15, d5, #15
1221 vadd.s32 q10, q14, q13
1222 vsub.s32 q14, q14, q13
1223 vrshrn.s32 d4, q10, #13
1224 vrshrn.s32 d6, q14, #13
1225 vadd.s32 q10, q15, q12
1226 vsub.s32 q14, q15, q12
1227 vrshrn.s32 d5, q10, #13
1228 vrshrn.s32 d7, q14, #13
1229 vtrn.16 q2, q3
1230 vtrn.32 q3, q5
1231 #endif
1232
1233 /* Pass 2 */
1234 idct_helper d4, d6, d10, d7, d11, 20, d26, d27
1235
1236 /* Range limit */
1237 vmov.u16 q15, #0x80
1238 vadd.s16 q13, q13, q15
1239 vqmovun.s16 d26, q13
1240 vqmovun.s16 d27, q13
1241
1242 /* Store results to the output buffer */
1243 ldmia OUTPUT_BUF, {TMP1, TMP2}
1244 add TMP1, TMP1, OUTPUT_COL
1245 add TMP2, TMP2, OUTPUT_COL
1246
1247 vst1.8 {d26[0]}, [TMP1]!
1248 vst1.8 {d27[4]}, [TMP1]!
1249 vst1.8 {d26[1]}, [TMP2]!
1250 vst1.8 {d27[5]}, [TMP2]!
1251
1252 vpop {d8-d15}
1253 bx lr
1254
1255 .unreq DCT_TABLE
1256 .unreq COEF_BLOCK
1257 .unreq OUTPUT_BUF
1258 .unreq OUTPUT_COL
1259 .unreq TMP1
1260 .unreq TMP2
1261 .endfunc
1262
1263 .purgem idct_helper
1264
1265 /*****************************************************************************/
1266
1267 /*
1268 * jsimd_ycc_extrgb_convert_neon
1269 * jsimd_ycc_extbgr_convert_neon
1270 * jsimd_ycc_extrgbx_convert_neon
1271 * jsimd_ycc_extbgrx_convert_neon
1272 * jsimd_ycc_extxbgr_convert_neon
1273 * jsimd_ycc_extxrgb_convert_neon
1274 *
1275 * Colorspace conversion YCbCr -> RGB
1276 */
1277
1278
1279 .macro do_load size
1280 .if \size == 8
1281 vld1.8 {d4}, [U, :64]!
1282 vld1.8 {d5}, [V, :64]!
1283 vld1.8 {d0}, [Y, :64]!
1284 pld [U, #64]
1285 pld [V, #64]
1286 pld [Y, #64]
1287 .elseif \size == 4
1288 vld1.8 {d4[0]}, [U]!
1289 vld1.8 {d4[1]}, [U]!
1290 vld1.8 {d4[2]}, [U]!
1291 vld1.8 {d4[3]}, [U]!
1292 vld1.8 {d5[0]}, [V]!
1293 vld1.8 {d5[1]}, [V]!
1294 vld1.8 {d5[2]}, [V]!
1295 vld1.8 {d5[3]}, [V]!
1296 vld1.8 {d0[0]}, [Y]!
1297 vld1.8 {d0[1]}, [Y]!
1298 vld1.8 {d0[2]}, [Y]!
1299 vld1.8 {d0[3]}, [Y]!
1300 .elseif \size == 2
1301 vld1.8 {d4[4]}, [U]!
1302 vld1.8 {d4[5]}, [U]!
1303 vld1.8 {d5[4]}, [V]!
1304 vld1.8 {d5[5]}, [V]!
1305 vld1.8 {d0[4]}, [Y]!
1306 vld1.8 {d0[5]}, [Y]!
1307 .elseif \size == 1
1308 vld1.8 {d4[6]}, [U]!
1309 vld1.8 {d5[6]}, [V]!
1310 vld1.8 {d0[6]}, [Y]!
1311 .else
1312 .error unsupported macroblock size
1313 .endif
1314 .endm
1315
1316 .macro do_store bpp, size
1317 .if \bpp == 24
1318 .if \size == 8
1319 vst3.8 {d10, d11, d12}, [RGB]!
1320 .elseif \size == 4
1321 vst3.8 {d10[0], d11[0], d12[0]}, [RGB]!
1322 vst3.8 {d10[1], d11[1], d12[1]}, [RGB]!
1323 vst3.8 {d10[2], d11[2], d12[2]}, [RGB]!
1324 vst3.8 {d10[3], d11[3], d12[3]}, [RGB]!
1325 .elseif \size == 2
1326 vst3.8 {d10[4], d11[4], d12[4]}, [RGB]!
1327 vst3.8 {d10[5], d11[5], d12[5]}, [RGB]!
1328 .elseif \size == 1
1329 vst3.8 {d10[6], d11[6], d12[6]}, [RGB]!
1330 .else
1331 .error unsupported macroblock size
1332 .endif
1333 .elseif \bpp == 32
1334 .if \size == 8
1335 vst4.8 {d10, d11, d12, d13}, [RGB]!
1336 .elseif \size == 4
1337 vst4.8 {d10[0], d11[0], d12[0], d13[0]}, [RGB]!
1338 vst4.8 {d10[1], d11[1], d12[1], d13[1]}, [RGB]!
1339 vst4.8 {d10[2], d11[2], d12[2], d13[2]}, [RGB]!
1340 vst4.8 {d10[3], d11[3], d12[3], d13[3]}, [RGB]!
1341 .elseif \size == 2
1342 vst4.8 {d10[4], d11[4], d12[4], d13[4]}, [RGB]!
1343 vst4.8 {d10[5], d11[5], d12[5], d13[5]}, [RGB]!
1344 .elseif \size == 1
1345 vst4.8 {d10[6], d11[6], d12[6], d13[6]}, [RGB]!
1346 .else
1347 .error unsupported macroblock size
1348 .endif
1349 .else
1350 .error unsupported bpp
1351 .endif
1352 .endm
1353
1354 .macro generate_jsimd_ycc_rgb_convert_neon colorid, bpp, r_offs, g_offs, b_offs
1355
1356 /*
1357 * 2 stage pipelined YCbCr->RGB conversion
1358 */
1359
1360 .macro do_yuv_to_rgb_stage1
1361 vaddw.u8 q3, q1, d4 /* q3 = u - 128 */
1362 vaddw.u8 q4, q1, d5 /* q2 = v - 128 */
1363 vmull.s16 q10, d6, d1[1] /* multiply by -11277 */
1364 vmlal.s16 q10, d8, d1[2] /* multiply by -23401 */
1365 vmull.s16 q11, d7, d1[1] /* multiply by -11277 */
1366 vmlal.s16 q11, d9, d1[2] /* multiply by -23401 */
1367 vmull.s16 q12, d8, d1[0] /* multiply by 22971 */
1368 vmull.s16 q13, d9, d1[0] /* multiply by 22971 */
1369 vmull.s16 q14, d6, d1[3] /* multiply by 29033 */
1370 vmull.s16 q15, d7, d1[3] /* multiply by 29033 */
1371 .endm
1372
1373 .macro do_yuv_to_rgb_stage2
1374 vrshrn.s32 d20, q10, #15
1375 vrshrn.s32 d21, q11, #15
1376 vrshrn.s32 d24, q12, #14
1377 vrshrn.s32 d25, q13, #14
1378 vrshrn.s32 d28, q14, #14
1379 vrshrn.s32 d29, q15, #14
1380 vaddw.u8 q10, q10, d0
1381 vaddw.u8 q12, q12, d0
1382 vaddw.u8 q14, q14, d0
1383 vqmovun.s16 d1\g_offs, q10
1384 vqmovun.s16 d1\r_offs, q12
1385 vqmovun.s16 d1\b_offs, q14
1386 .endm
1387
1388 .macro do_yuv_to_rgb_stage2_store_load_stage1
1389 vld1.8 {d4}, [U, :64]!
1390 vrshrn.s32 d20, q10, #15
1391 vrshrn.s32 d21, q11, #15
1392 vrshrn.s32 d24, q12, #14
1393 vrshrn.s32 d25, q13, #14
1394 vrshrn.s32 d28, q14, #14
1395 vld1.8 {d5}, [V, :64]!
1396 vrshrn.s32 d29, q15, #14
1397 vaddw.u8 q10, q10, d0
1398 vaddw.u8 q12, q12, d0
1399 vaddw.u8 q14, q14, d0
1400 vqmovun.s16 d1\g_offs, q10
1401 vld1.8 {d0}, [Y, :64]!
1402 vqmovun.s16 d1\r_offs, q12
1403 pld [U, #64]
1404 pld [V, #64]
1405 pld [Y, #64]
1406 vqmovun.s16 d1\b_offs, q14
1407 vaddw.u8 q3, q1, d4 /* q3 = u - 128 */
1408 vaddw.u8 q4, q1, d5 /* q2 = v - 128 */
1409 do_store \bpp, 8
1410 vmull.s16 q10, d6, d1[1] /* multiply by -11277 */
1411 vmlal.s16 q10, d8, d1[2] /* multiply by -23401 */
1412 vmull.s16 q11, d7, d1[1] /* multiply by -11277 */
1413 vmlal.s16 q11, d9, d1[2] /* multiply by -23401 */
1414 vmull.s16 q12, d8, d1[0] /* multiply by 22971 */
1415 vmull.s16 q13, d9, d1[0] /* multiply by 22971 */
1416 vmull.s16 q14, d6, d1[3] /* multiply by 29033 */
1417 vmull.s16 q15, d7, d1[3] /* multiply by 29033 */
1418 .endm
1419
1420 .macro do_yuv_to_rgb
1421 do_yuv_to_rgb_stage1
1422 do_yuv_to_rgb_stage2
1423 .endm
1424
1425 /* Apple gas crashes on adrl, work around that by using adr.
1426 * But this requires a copy of these constants for each function.
1427 */
1428
1429 .balign 16
1430 jsimd_ycc_\colorid\()_neon_consts:
1431 .short 0, 0, 0, 0
1432 .short 22971, -11277, -23401, 29033
1433 .short -128, -128, -128, -128
1434 .short -128, -128, -128, -128
1435
1436 asm_function jsimd_ycc_\colorid\()_convert_neon
1437 OUTPUT_WIDTH .req r0
1438 INPUT_BUF .req r1
1439 INPUT_ROW .req r2
1440 OUTPUT_BUF .req r3
1441 NUM_ROWS .req r4
1442
1443 INPUT_BUF0 .req r5
1444 INPUT_BUF1 .req r6
1445 INPUT_BUF2 .req INPUT_BUF
1446
1447 RGB .req r7
1448 Y .req r8
1449 U .req r9
1450 V .req r10
1451 N .req ip
1452
1453 /* Load constants to d1, d2, d3 (d0 is just used for padding) */
1454 adr ip, jsimd_ycc_\colorid\()_neon_consts
1455 vld1.16 {d0, d1, d2, d3}, [ip, :128]
1456
1457 /* Save ARM registers and handle input arguments */
1458 push {r4, r5, r6, r7, r8, r9, r10, lr}
1459 ldr NUM_ROWS, [sp, #(4 * 8)]
1460 ldr INPUT_BUF0, [INPUT_BUF]
1461 ldr INPUT_BUF1, [INPUT_BUF, #4]
1462 ldr INPUT_BUF2, [INPUT_BUF, #8]
1463 .unreq INPUT_BUF
1464
1465 /* Save NEON registers */
1466 vpush {d8-d15}
1467
1468 /* Initially set d10, d11, d12, d13 to 0xFF */
1469 vmov.u8 q5, #255
1470 vmov.u8 q6, #255
1471
1472 /* Outer loop over scanlines */
1473 cmp NUM_ROWS, #1
1474 blt 9f
1475 0:
1476 ldr Y, [INPUT_BUF0, INPUT_ROW, lsl #2]
1477 ldr U, [INPUT_BUF1, INPUT_ROW, lsl #2]
1478 mov N, OUTPUT_WIDTH
1479 ldr V, [INPUT_BUF2, INPUT_ROW, lsl #2]
1480 add INPUT_ROW, INPUT_ROW, #1
1481 ldr RGB, [OUTPUT_BUF], #4
1482
1483 /* Inner loop over pixels */
1484 subs N, N, #8
1485 blt 3f
1486 do_load 8
1487 do_yuv_to_rgb_stage1
1488 subs N, N, #8
1489 blt 2f
1490 1:
1491 do_yuv_to_rgb_stage2_store_load_stage1
1492 subs N, N, #8
1493 bge 1b
1494 2:
1495 do_yuv_to_rgb_stage2
1496 do_store \bpp, 8
1497 tst N, #7
1498 beq 8f
1499 3:
1500 tst N, #4
1501 beq 3f
1502 do_load 4
1503 3:
1504 tst N, #2
1505 beq 4f
1506 do_load 2
1507 4:
1508 tst N, #1
1509 beq 5f
1510 do_load 1
1511 5:
1512 do_yuv_to_rgb
1513 tst N, #4
1514 beq 6f
1515 do_store \bpp, 4
1516 6:
1517 tst N, #2
1518 beq 7f
1519 do_store \bpp, 2
1520 7:
1521 tst N, #1
1522 beq 8f
1523 do_store \bpp, 1
1524 8:
1525 subs NUM_ROWS, NUM_ROWS, #1
1526 bgt 0b
1527 9:
1528 /* Restore all registers and return */
1529 vpop {d8-d15}
1530 pop {r4, r5, r6, r7, r8, r9, r10, pc}
1531
1532 .unreq OUTPUT_WIDTH
1533 .unreq INPUT_ROW
1534 .unreq OUTPUT_BUF
1535 .unreq NUM_ROWS
1536 .unreq INPUT_BUF0
1537 .unreq INPUT_BUF1
1538 .unreq INPUT_BUF2
1539 .unreq RGB
1540 .unreq Y
1541 .unreq U
1542 .unreq V
1543 .unreq N
1544 .endfunc
1545
1546 .purgem do_yuv_to_rgb
1547 .purgem do_yuv_to_rgb_stage1
1548 .purgem do_yuv_to_rgb_stage2
1549 .purgem do_yuv_to_rgb_stage2_store_load_stage1
1550
1551 .endm
1552
1553 /*--------------------------------- id ----- bpp R G B */
1554 generate_jsimd_ycc_rgb_convert_neon extrgb, 24, 0, 1, 2
1555 generate_jsimd_ycc_rgb_convert_neon extbgr, 24, 2, 1, 0
1556 generate_jsimd_ycc_rgb_convert_neon extrgbx, 32, 0, 1, 2
1557 generate_jsimd_ycc_rgb_convert_neon extbgrx, 32, 2, 1, 0
1558 generate_jsimd_ycc_rgb_convert_neon extxbgr, 32, 3, 2, 1
1559 generate_jsimd_ycc_rgb_convert_neon extxrgb, 32, 1, 2, 3
1560
1561 .purgem do_load
1562 .purgem do_store
1563
1564 /*****************************************************************************/
1565
1566 /*
1567 * jsimd_extrgb_ycc_convert_neon
1568 * jsimd_extbgr_ycc_convert_neon
1569 * jsimd_extrgbx_ycc_convert_neon
1570 * jsimd_extbgrx_ycc_convert_neon
1571 * jsimd_extxbgr_ycc_convert_neon
1572 * jsimd_extxrgb_ycc_convert_neon
1573 *
1574 * Colorspace conversion RGB -> YCbCr
1575 */
1576
1577 .macro do_store size
1578 .if \size == 8
1579 vst1.8 {d20}, [Y]!
1580 vst1.8 {d21}, [U]!
1581 vst1.8 {d22}, [V]!
1582 .elseif \size == 4
1583 vst1.8 {d20[0]}, [Y]!
1584 vst1.8 {d20[1]}, [Y]!
1585 vst1.8 {d20[2]}, [Y]!
1586 vst1.8 {d20[3]}, [Y]!
1587 vst1.8 {d21[0]}, [U]!
1588 vst1.8 {d21[1]}, [U]!
1589 vst1.8 {d21[2]}, [U]!
1590 vst1.8 {d21[3]}, [U]!
1591 vst1.8 {d22[0]}, [V]!
1592 vst1.8 {d22[1]}, [V]!
1593 vst1.8 {d22[2]}, [V]!
1594 vst1.8 {d22[3]}, [V]!
1595 .elseif \size == 2
1596 vst1.8 {d20[4]}, [Y]!
1597 vst1.8 {d20[5]}, [Y]!
1598 vst1.8 {d21[4]}, [U]!
1599 vst1.8 {d21[5]}, [U]!
1600 vst1.8 {d22[4]}, [V]!
1601 vst1.8 {d22[5]}, [V]!
1602 .elseif \size == 1
1603 vst1.8 {d20[6]}, [Y]!
1604 vst1.8 {d21[6]}, [U]!
1605 vst1.8 {d22[6]}, [V]!
1606 .else
1607 .error unsupported macroblock size
1608 .endif
1609 .endm
1610
1611 .macro do_load bpp, size
1612 .if \bpp == 24
1613 .if \size == 8
1614 vld3.8 {d10, d11, d12}, [RGB]!
1615 pld [RGB, #128]
1616 .elseif \size == 4
1617 vld3.8 {d10[0], d11[0], d12[0]}, [RGB]!
1618 vld3.8 {d10[1], d11[1], d12[1]}, [RGB]!
1619 vld3.8 {d10[2], d11[2], d12[2]}, [RGB]!
1620 vld3.8 {d10[3], d11[3], d12[3]}, [RGB]!
1621 .elseif \size == 2
1622 vld3.8 {d10[4], d11[4], d12[4]}, [RGB]!
1623 vld3.8 {d10[5], d11[5], d12[5]}, [RGB]!
1624 .elseif \size == 1
1625 vld3.8 {d10[6], d11[6], d12[6]}, [RGB]!
1626 .else
1627 .error unsupported macroblock size
1628 .endif
1629 .elseif \bpp == 32
1630 .if \size == 8
1631 vld4.8 {d10, d11, d12, d13}, [RGB]!
1632 pld [RGB, #128]
1633 .elseif \size == 4
1634 vld4.8 {d10[0], d11[0], d12[0], d13[0]}, [RGB]!
1635 vld4.8 {d10[1], d11[1], d12[1], d13[1]}, [RGB]!
1636 vld4.8 {d10[2], d11[2], d12[2], d13[2]}, [RGB]!
1637 vld4.8 {d10[3], d11[3], d12[3], d13[3]}, [RGB]!
1638 .elseif \size == 2
1639 vld4.8 {d10[4], d11[4], d12[4], d13[4]}, [RGB]!
1640 vld4.8 {d10[5], d11[5], d12[5], d13[5]}, [RGB]!
1641 .elseif \size == 1
1642 vld4.8 {d10[6], d11[6], d12[6], d13[6]}, [RGB]!
1643 .else
1644 .error unsupported macroblock size
1645 .endif
1646 .else
1647 .error unsupported bpp
1648 .endif
1649 .endm
1650
1651 .macro generate_jsimd_rgb_ycc_convert_neon colorid, bpp, r_offs, g_offs, b_offs
1652
1653 /*
1654 * 2 stage pipelined RGB->YCbCr conversion
1655 */
1656
1657 .macro do_rgb_to_yuv_stage1
1658 vmovl.u8 q2, d1\r_offs /* r = { d4, d5 } */
1659 vmovl.u8 q3, d1\g_offs /* g = { d6, d7 } */
1660 vmovl.u8 q4, d1\b_offs /* b = { d8, d9 } */
1661 vmull.u16 q7, d4, d0[0]
1662 vmlal.u16 q7, d6, d0[1]
1663 vmlal.u16 q7, d8, d0[2]
1664 vmull.u16 q8, d5, d0[0]
1665 vmlal.u16 q8, d7, d0[1]
1666 vmlal.u16 q8, d9, d0[2]
1667 vrev64.32 q9, q1
1668 vrev64.32 q13, q1
1669 vmlsl.u16 q9, d4, d0[3]
1670 vmlsl.u16 q9, d6, d1[0]
1671 vmlal.u16 q9, d8, d1[1]
1672 vmlsl.u16 q13, d5, d0[3]
1673 vmlsl.u16 q13, d7, d1[0]
1674 vmlal.u16 q13, d9, d1[1]
1675 vrev64.32 q14, q1
1676 vrev64.32 q15, q1
1677 vmlal.u16 q14, d4, d1[1]
1678 vmlsl.u16 q14, d6, d1[2]
1679 vmlsl.u16 q14, d8, d1[3]
1680 vmlal.u16 q15, d5, d1[1]
1681 vmlsl.u16 q15, d7, d1[2]
1682 vmlsl.u16 q15, d9, d1[3]
1683 .endm
1684
1685 .macro do_rgb_to_yuv_stage2
1686 vrshrn.u32 d20, q7, #16
1687 vrshrn.u32 d21, q8, #16
1688 vshrn.u32 d22, q9, #16
1689 vshrn.u32 d23, q13, #16
1690 vshrn.u32 d24, q14, #16
1691 vshrn.u32 d25, q15, #16
1692 vmovn.u16 d20, q10 /* d20 = y */
1693 vmovn.u16 d21, q11 /* d21 = u */
1694 vmovn.u16 d22, q12 /* d22 = v */
1695 .endm
1696
1697 .macro do_rgb_to_yuv
1698 do_rgb_to_yuv_stage1
1699 do_rgb_to_yuv_stage2
1700 .endm
1701
1702 .macro do_rgb_to_yuv_stage2_store_load_stage1
1703 vrshrn.u32 d20, q7, #16
1704 vrshrn.u32 d21, q8, #16
1705 vshrn.u32 d22, q9, #16
1706 vrev64.32 q9, q1
1707 vshrn.u32 d23, q13, #16
1708 vrev64.32 q13, q1
1709 vshrn.u32 d24, q14, #16
1710 vshrn.u32 d25, q15, #16
1711 do_load \bpp, 8
1712 vmovn.u16 d20, q10 /* d20 = y */
1713 vmovl.u8 q2, d1\r_offs /* r = { d4, d5 } */
1714 vmovn.u16 d21, q11 /* d21 = u */
1715 vmovl.u8 q3, d1\g_offs /* g = { d6, d7 } */
1716 vmovn.u16 d22, q12 /* d22 = v */
1717 vmovl.u8 q4, d1\b_offs /* b = { d8, d9 } */
1718 vmull.u16 q7, d4, d0[0]
1719 vmlal.u16 q7, d6, d0[1]
1720 vmlal.u16 q7, d8, d0[2]
1721 vst1.8 {d20}, [Y]!
1722 vmull.u16 q8, d5, d0[0]
1723 vmlal.u16 q8, d7, d0[1]
1724 vmlal.u16 q8, d9, d0[2]
1725 vmlsl.u16 q9, d4, d0[3]
1726 vmlsl.u16 q9, d6, d1[0]
1727 vmlal.u16 q9, d8, d1[1]
1728 vst1.8 {d21}, [U]!
1729 vmlsl.u16 q13, d5, d0[3]
1730 vmlsl.u16 q13, d7, d1[0]
1731 vmlal.u16 q13, d9, d1[1]
1732 vrev64.32 q14, q1
1733 vrev64.32 q15, q1
1734 vmlal.u16 q14, d4, d1[1]
1735 vmlsl.u16 q14, d6, d1[2]
1736 vmlsl.u16 q14, d8, d1[3]
1737 vst1.8 {d22}, [V]!
1738 vmlal.u16 q15, d5, d1[1]
1739 vmlsl.u16 q15, d7, d1[2]
1740 vmlsl.u16 q15, d9, d1[3]
1741 .endm
1742
1743 .balign 16
1744 jsimd_\colorid\()_ycc_neon_consts:
1745 .short 19595, 38470, 7471, 11059
1746 .short 21709, 32768, 27439, 5329
1747 .short 32767, 128, 32767, 128
1748 .short 32767, 128, 32767, 128
1749
1750 asm_function jsimd_\colorid\()_ycc_convert_neon
1751 OUTPUT_WIDTH .req r0
1752 INPUT_BUF .req r1
1753 OUTPUT_BUF .req r2
1754 OUTPUT_ROW .req r3
1755 NUM_ROWS .req r4
1756
1757 OUTPUT_BUF0 .req r5
1758 OUTPUT_BUF1 .req r6
1759 OUTPUT_BUF2 .req OUTPUT_BUF
1760
1761 RGB .req r7
1762 Y .req r8
1763 U .req r9
1764 V .req r10
1765 N .req ip
1766
1767 /* Load constants to d0, d1, d2, d3 */
1768 adr ip, jsimd_\colorid\()_ycc_neon_consts
1769 vld1.16 {d0, d1, d2, d3}, [ip, :128]
1770
1771 /* Save ARM registers and handle input arguments */
1772 push {r4, r5, r6, r7, r8, r9, r10, lr}
1773 ldr NUM_ROWS, [sp, #(4 * 8)]
1774 ldr OUTPUT_BUF0, [OUTPUT_BUF]
1775 ldr OUTPUT_BUF1, [OUTPUT_BUF, #4]
1776 ldr OUTPUT_BUF2, [OUTPUT_BUF, #8]
1777 .unreq OUTPUT_BUF
1778
1779 /* Save NEON registers */
1780 vpush {d8-d15}
1781
1782 /* Outer loop over scanlines */
1783 cmp NUM_ROWS, #1
1784 blt 9f
1785 0:
1786 ldr Y, [OUTPUT_BUF0, OUTPUT_ROW, lsl #2]
1787 ldr U, [OUTPUT_BUF1, OUTPUT_ROW, lsl #2]
1788 mov N, OUTPUT_WIDTH
1789 ldr V, [OUTPUT_BUF2, OUTPUT_ROW, lsl #2]
1790 add OUTPUT_ROW, OUTPUT_ROW, #1
1791 ldr RGB, [INPUT_BUF], #4
1792
1793 /* Inner loop over pixels */
1794 subs N, N, #8
1795 blt 3f
1796 do_load \bpp, 8
1797 do_rgb_to_yuv_stage1
1798 subs N, N, #8
1799 blt 2f
1800 1:
1801 do_rgb_to_yuv_stage2_store_load_stage1
1802 subs N, N, #8
1803 bge 1b
1804 2:
1805 do_rgb_to_yuv_stage2
1806 do_store 8
1807 tst N, #7
1808 beq 8f
1809 3:
1810 tst N, #4
1811 beq 3f
1812 do_load \bpp, 4
1813 3:
1814 tst N, #2
1815 beq 4f
1816 do_load \bpp, 2
1817 4:
1818 tst N, #1
1819 beq 5f
1820 do_load \bpp, 1
1821 5:
1822 do_rgb_to_yuv
1823 tst N, #4
1824 beq 6f
1825 do_store 4
1826 6:
1827 tst N, #2
1828 beq 7f
1829 do_store 2
1830 7:
1831 tst N, #1
1832 beq 8f
1833 do_store 1
1834 8:
1835 subs NUM_ROWS, NUM_ROWS, #1
1836 bgt 0b
1837 9:
1838 /* Restore all registers and return */
1839 vpop {d8-d15}
1840 pop {r4, r5, r6, r7, r8, r9, r10, pc}
1841
1842 .unreq OUTPUT_WIDTH
1843 .unreq OUTPUT_ROW
1844 .unreq INPUT_BUF
1845 .unreq NUM_ROWS
1846 .unreq OUTPUT_BUF0
1847 .unreq OUTPUT_BUF1
1848 .unreq OUTPUT_BUF2
1849 .unreq RGB
1850 .unreq Y
1851 .unreq U
1852 .unreq V
1853 .unreq N
1854 .endfunc
1855
1856 .purgem do_rgb_to_yuv
1857 .purgem do_rgb_to_yuv_stage1
1858 .purgem do_rgb_to_yuv_stage2
1859 .purgem do_rgb_to_yuv_stage2_store_load_stage1
1860
1861 .endm
1862
1863 /*--------------------------------- id ----- bpp R G B */
1864 generate_jsimd_rgb_ycc_convert_neon extrgb, 24, 0, 1, 2
1865 generate_jsimd_rgb_ycc_convert_neon extbgr, 24, 2, 1, 0
1866 generate_jsimd_rgb_ycc_convert_neon extrgbx, 32, 0, 1, 2
1867 generate_jsimd_rgb_ycc_convert_neon extbgrx, 32, 2, 1, 0
1868 generate_jsimd_rgb_ycc_convert_neon extxbgr, 32, 3, 2, 1
1869 generate_jsimd_rgb_ycc_convert_neon extxrgb, 32, 1, 2, 3
1870
1871 .purgem do_load
1872 .purgem do_store
1873
1874 /*****************************************************************************/
1875
1876 /*
1877 * Load data into workspace, applying unsigned->signed conversion
1878 *
1879 * TODO: can be combined with 'jsimd_fdct_ifast_neon' to get
1880 * rid of VST1.16 instructions
1881 */
1882
1883 asm_function jsimd_convsamp_neon
1884 SAMPLE_DATA .req r0
1885 START_COL .req r1
1886 WORKSPACE .req r2
1887 TMP1 .req r3
1888 TMP2 .req r4
1889 TMP3 .req r5
1890 TMP4 .req ip
1891
1892 push {r4, r5}
1893 vmov.u8 d0, #128
1894
1895 ldmia SAMPLE_DATA!, {TMP1, TMP2, TMP3, TMP4}
1896 add TMP1, TMP1, START_COL
1897 add TMP2, TMP2, START_COL
1898 add TMP3, TMP3, START_COL
1899 add TMP4, TMP4, START_COL
1900 vld1.8 {d16}, [TMP1]
1901 vsubl.u8 q8, d16, d0
1902 vld1.8 {d18}, [TMP2]
1903 vsubl.u8 q9, d18, d0
1904 vld1.8 {d20}, [TMP3]
1905 vsubl.u8 q10, d20, d0
1906 vld1.8 {d22}, [TMP4]
1907 ldmia SAMPLE_DATA!, {TMP1, TMP2, TMP3, TMP4}
1908 vsubl.u8 q11, d22, d0
1909 vst1.16 {d16, d17, d18, d19}, [WORKSPACE, :128]!
1910 add TMP1, TMP1, START_COL
1911 add TMP2, TMP2, START_COL
1912 vst1.16 {d20, d21, d22, d23}, [WORKSPACE, :128]!
1913 add TMP3, TMP3, START_COL
1914 add TMP4, TMP4, START_COL
1915 vld1.8 {d24}, [TMP1]
1916 vsubl.u8 q12, d24, d0
1917 vld1.8 {d26}, [TMP2]
1918 vsubl.u8 q13, d26, d0
1919 vld1.8 {d28}, [TMP3]
1920 vsubl.u8 q14, d28, d0
1921 vld1.8 {d30}, [TMP4]
1922 vsubl.u8 q15, d30, d0
1923 vst1.16 {d24, d25, d26, d27}, [WORKSPACE, :128]!
1924 vst1.16 {d28, d29, d30, d31}, [WORKSPACE, :128]!
1925 pop {r4, r5}
1926 bx lr
1927
1928 .unreq SAMPLE_DATA
1929 .unreq START_COL
1930 .unreq WORKSPACE
1931 .unreq TMP1
1932 .unreq TMP2
1933 .unreq TMP3
1934 .unreq TMP4
1935 .endfunc
1936
1937 /*****************************************************************************/
1938
1939 /*
1940 * jsimd_fdct_ifast_neon
1941 *
1942 * This function contains a fast, not so accurate integer implementation of
1943 * the forward DCT (Discrete Cosine Transform). It uses the same calculations
1944 * and produces exactly the same output as IJG's original 'jpeg_fdct_ifast'
1945 * function from jfdctfst.c
1946 *
1947 * TODO: can be combined with 'jsimd_convsamp_neon' to get
1948 * rid of a bunch of VLD1.16 instructions
1949 */
1950
1951 #define XFIX_0_382683433 d0[0]
1952 #define XFIX_0_541196100 d0[1]
1953 #define XFIX_0_707106781 d0[2]
1954 #define XFIX_1_306562965 d0[3]
1955
1956 .balign 16
1957 jsimd_fdct_ifast_neon_consts:
1958 .short (98 * 128) /* XFIX_0_382683433 */
1959 .short (139 * 128) /* XFIX_0_541196100 */
1960 .short (181 * 128) /* XFIX_0_707106781 */
1961 .short (334 * 128 - 256 * 128) /* XFIX_1_306562965 */
1962
1963 asm_function jsimd_fdct_ifast_neon
1964
1965 DATA .req r0
1966 TMP .req ip
1967
1968 vpush {d8-d15}
1969
1970 /* Load constants */
1971 adr TMP, jsimd_fdct_ifast_neon_consts
1972 vld1.16 {d0}, [TMP, :64]
1973
1974 /* Load all DATA into NEON registers with the following allocation:
1975 * 0 1 2 3 | 4 5 6 7
1976 * ---------+--------
1977 * 0 | d16 | d17 | q8
1978 * 1 | d18 | d19 | q9
1979 * 2 | d20 | d21 | q10
1980 * 3 | d22 | d23 | q11
1981 * 4 | d24 | d25 | q12
1982 * 5 | d26 | d27 | q13
1983 * 6 | d28 | d29 | q14
1984 * 7 | d30 | d31 | q15
1985 */
1986
1987 vld1.16 {d16, d17, d18, d19}, [DATA, :128]!
1988 vld1.16 {d20, d21, d22, d23}, [DATA, :128]!
1989 vld1.16 {d24, d25, d26, d27}, [DATA, :128]!
1990 vld1.16 {d28, d29, d30, d31}, [DATA, :128]
1991 sub DATA, DATA, #(128 - 32)
1992
1993 mov TMP, #2
1994 1:
1995 /* Transpose */
1996 vtrn.16 q12, q13
1997 vtrn.16 q10, q11
1998 vtrn.16 q8, q9
1999 vtrn.16 q14, q15
2000 vtrn.32 q9, q11
2001 vtrn.32 q13, q15
2002 vtrn.32 q8, q10
2003 vtrn.32 q12, q14
2004 vswp d30, d23
2005 vswp d24, d17
2006 vswp d26, d19
2007 /* 1-D FDCT */
2008 vadd.s16 q2, q11, q12
2009 vswp d28, d21
2010 vsub.s16 q12, q11, q12
2011 vsub.s16 q6, q10, q13
2012 vadd.s16 q10, q10, q13
2013 vsub.s16 q7, q9, q14
2014 vadd.s16 q9, q9, q14
2015 vsub.s16 q1, q8, q15
2016 vadd.s16 q8, q8, q15
2017 vsub.s16 q4, q9, q10
2018 vsub.s16 q5, q8, q2
2019 vadd.s16 q3, q9, q10
2020 vadd.s16 q4, q4, q5
2021 vadd.s16 q2, q8, q2
2022 vqdmulh.s16 q4, q4, XFIX_0_707106781
2023 vadd.s16 q11, q12, q6
2024 vadd.s16 q8, q2, q3
2025 vsub.s16 q12, q2, q3
2026 vadd.s16 q3, q6, q7
2027 vadd.s16 q7, q7, q1
2028 vqdmulh.s16 q3, q3, XFIX_0_707106781
2029 vsub.s16 q6, q11, q7
2030 vadd.s16 q10, q5, q4
2031 vqdmulh.s16 q6, q6, XFIX_0_382683433
2032 vsub.s16 q14, q5, q4
2033 vqdmulh.s16 q11, q11, XFIX_0_541196100
2034 vqdmulh.s16 q5, q7, XFIX_1_306562965
2035 vadd.s16 q4, q1, q3
2036 vsub.s16 q3, q1, q3
2037 vadd.s16 q7, q7, q6
2038 vadd.s16 q11, q11, q6
2039 vadd.s16 q7, q7, q5
2040 vadd.s16 q13, q3, q11
2041 vsub.s16 q11, q3, q11
2042 vadd.s16 q9, q4, q7
2043 vsub.s16 q15, q4, q7
2044 subs TMP, TMP, #1
2045 bne 1b
2046
2047 /* store results */
2048 vst1.16 {d16, d17, d18, d19}, [DATA, :128]!
2049 vst1.16 {d20, d21, d22, d23}, [DATA, :128]!
2050 vst1.16 {d24, d25, d26, d27}, [DATA, :128]!
2051 vst1.16 {d28, d29, d30, d31}, [DATA, :128]
2052
2053 vpop {d8-d15}
2054 bx lr
2055
2056 .unreq DATA
2057 .unreq TMP
2058 .endfunc
2059
2060 /*****************************************************************************/
2061
2062 /*
2063 * GLOBAL(void)
2064 * jsimd_quantize_neon (JCOEFPTR coef_block, DCTELEM * divisors,
2065 * DCTELEM * workspace);
2066 *
2067 * Note: the code uses 2 stage pipelining in order to improve instructions
2068 * scheduling and eliminate stalls (this provides ~15% better
2069 * performance for this function on both ARM Cortex-A8 and
2070 * ARM Cortex-A9 when compared to the non-pipelined variant).
2071 * The instructions which belong to the second stage use different
2072 * indentation for better readiability.
2073 */
2074 asm_function jsimd_quantize_neon
2075
2076 COEF_BLOCK .req r0
2077 DIVISORS .req r1
2078 WORKSPACE .req r2
2079
2080 RECIPROCAL .req DIVISORS
2081 CORRECTION .req r3
2082 SHIFT .req ip
2083 LOOP_COUNT .req r4
2084
2085 vld1.16 {d0, d1, d2, d3}, [WORKSPACE, :128]!
2086 vabs.s16 q12, q0
2087 add CORRECTION, DIVISORS, #(64 * 2)
2088 add SHIFT, DIVISORS, #(64 * 6)
2089 vld1.16 {d20, d21, d22, d23}, [CORRECTION, :128]!
2090 vabs.s16 q13, q1
2091 vld1.16 {d16, d17, d18, d19}, [RECIPROCAL, :128]!
2092 vadd.u16 q12, q12, q10 /* add correction */
2093 vadd.u16 q13, q13, q11
2094 vmull.u16 q10, d24, d16 /* multiply by reciprocal */
2095 vmull.u16 q11, d25, d17
2096 vmull.u16 q8, d26, d18
2097 vmull.u16 q9, d27, d19
2098 vld1.16 {d24, d25, d26, d27}, [SHIFT, :128]!
2099 vshrn.u32 d20, q10, #16
2100 vshrn.u32 d21, q11, #16
2101 vshrn.u32 d22, q8, #16
2102 vshrn.u32 d23, q9, #16
2103 vneg.s16 q12, q12
2104 vneg.s16 q13, q13
2105 vshr.s16 q2, q0, #15 /* extract sign */
2106 vshr.s16 q3, q1, #15
2107 vshl.u16 q14, q10, q12 /* shift */
2108 vshl.u16 q15, q11, q13
2109
2110 push {r4, r5}
2111 mov LOOP_COUNT, #3
2112 1:
2113 vld1.16 {d0, d1, d2, d3}, [WORKSPACE, :128]!
2114 veor.u16 q14, q14, q2 /* restore sign */
2115 vabs.s16 q12, q0
2116 vld1.16 {d20, d21, d22, d23}, [CORRECTION, :128]!
2117 vabs.s16 q13, q1
2118 veor.u16 q15, q15, q3
2119 vld1.16 {d16, d17, d18, d19}, [RECIPROCAL, :128]!
2120 vadd.u16 q12, q12, q10 /* add correction */
2121 vadd.u16 q13, q13, q11
2122 vmull.u16 q10, d24, d16 /* multiply by reciprocal */
2123 vmull.u16 q11, d25, d17
2124 vmull.u16 q8, d26, d18
2125 vmull.u16 q9, d27, d19
2126 vsub.u16 q14, q14, q2
2127 vld1.16 {d24, d25, d26, d27}, [SHIFT, :128]!
2128 vsub.u16 q15, q15, q3
2129 vshrn.u32 d20, q10, #16
2130 vshrn.u32 d21, q11, #16
2131 vst1.16 {d28, d29, d30, d31}, [COEF_BLOCK, :128]!
2132 vshrn.u32 d22, q8, #16
2133 vshrn.u32 d23, q9, #16
2134 vneg.s16 q12, q12
2135 vneg.s16 q13, q13
2136 vshr.s16 q2, q0, #15 /* extract sign */
2137 vshr.s16 q3, q1, #15
2138 vshl.u16 q14, q10, q12 /* shift */
2139 vshl.u16 q15, q11, q13
2140 subs LOOP_COUNT, LOOP_COUNT, #1
2141 bne 1b
2142 pop {r4, r5}
2143
2144 veor.u16 q14, q14, q2 /* restore sign */
2145 veor.u16 q15, q15, q3
2146 vsub.u16 q14, q14, q2
2147 vsub.u16 q15, q15, q3
2148 vst1.16 {d28, d29, d30, d31}, [COEF_BLOCK, :128]!
2149
2150 bx lr /* return */
2151
2152 .unreq COEF_BLOCK
2153 .unreq DIVISORS
2154 .unreq WORKSPACE
2155 .unreq RECIPROCAL
2156 .unreq CORRECTION
2157 .unreq SHIFT
2158 .unreq LOOP_COUNT
2159 .endfunc
2160
2161 /*****************************************************************************/
2162
2163 /*
2164 * GLOBAL(void)
2165 * jsimd_h2v1_fancy_upsample_neon (int max_v_samp_factor,
2166 * JDIMENSION downsampled_width,
2167 * JSAMPARRAY input_data,
2168 * JSAMPARRAY * output_data_ptr);
2169 *
2170 * Note: the use of unaligned writes is the main remaining bottleneck in
2171 * this code, which can be potentially solved to get up to tens
2172 * of percents performance improvement on Cortex-A8/Cortex-A9.
2173 */
2174
2175 /*
2176 * Upsample 16 source pixels to 32 destination pixels. The new 16 source
2177 * pixels are loaded to q0. The previous 16 source pixels are in q1. The
2178 * shifted-by-one source pixels are constructed in q2 by using q0 and q1.
2179 * Register d28 is used for multiplication by 3. Register q15 is used
2180 * for adding +1 bias.
2181 */
2182 .macro upsample16 OUTPTR, INPTR
2183 vld1.8 {q0}, [\INPTR]!
2184 vmovl.u8 q8, d0
2185 vext.8 q2, q1, q0, #15
2186 vmovl.u8 q9, d1
2187 vaddw.u8 q10, q15, d4
2188 vaddw.u8 q11, q15, d5
2189 vmlal.u8 q8, d4, d28
2190 vmlal.u8 q9, d5, d28
2191 vmlal.u8 q10, d0, d28
2192 vmlal.u8 q11, d1, d28
2193 vmov q1, q0 /* backup source pixels to q1 */
2194 vrshrn.u16 d6, q8, #2
2195 vrshrn.u16 d7, q9, #2
2196 vshrn.u16 d8, q10, #2
2197 vshrn.u16 d9, q11, #2
2198 vst2.8 {d6, d7, d8, d9}, [\OUTPTR]!
2199 .endm
2200
2201 /*
2202 * Upsample 32 source pixels to 64 destination pixels. Compared to 'usample16'
2203 * macro, the roles of q0 and q1 registers are reversed for even and odd
2204 * groups of 16 pixels, that's why "vmov q1, q0" instructions are not needed.
2205 * Also this unrolling allows to reorder loads and stores to compensate
2206 * multiplication latency and reduce stalls.
2207 */
2208 .macro upsample32 OUTPTR, INPTR
2209 /* even 16 pixels group */
2210 vld1.8 {q0}, [\INPTR]!
2211 vmovl.u8 q8, d0
2212 vext.8 q2, q1, q0, #15
2213 vmovl.u8 q9, d1
2214 vaddw.u8 q10, q15, d4
2215 vaddw.u8 q11, q15, d5
2216 vmlal.u8 q8, d4, d28
2217 vmlal.u8 q9, d5, d28
2218 vmlal.u8 q10, d0, d28
2219 vmlal.u8 q11, d1, d28
2220 /* odd 16 pixels group */
2221 vld1.8 {q1}, [\INPTR]!
2222 vrshrn.u16 d6, q8, #2
2223 vrshrn.u16 d7, q9, #2
2224 vshrn.u16 d8, q10, #2
2225 vshrn.u16 d9, q11, #2
2226 vmovl.u8 q8, d2
2227 vext.8 q2, q0, q1, #15
2228 vmovl.u8 q9, d3
2229 vaddw.u8 q10, q15, d4
2230 vaddw.u8 q11, q15, d5
2231 vmlal.u8 q8, d4, d28
2232 vmlal.u8 q9, d5, d28
2233 vmlal.u8 q10, d2, d28
2234 vmlal.u8 q11, d3, d28
2235 vst2.8 {d6, d7, d8, d9}, [\OUTPTR]!
2236 vrshrn.u16 d6, q8, #2
2237 vrshrn.u16 d7, q9, #2
2238 vshrn.u16 d8, q10, #2
2239 vshrn.u16 d9, q11, #2
2240 vst2.8 {d6, d7, d8, d9}, [\OUTPTR]!
2241 .endm
2242
2243 /*
2244 * Upsample a row of WIDTH pixels from INPTR to OUTPTR.
2245 */
2246 .macro upsample_row OUTPTR, INPTR, WIDTH, TMP1
2247 /* special case for the first and last pixels */
2248 sub \WIDTH, \WIDTH, #1
2249 add \OUTPTR, \OUTPTR, #1
2250 ldrb \TMP1, [\INPTR, \WIDTH]
2251 strb \TMP1, [\OUTPTR, \WIDTH, asl #1]
2252 ldrb \TMP1, [\INPTR], #1
2253 strb \TMP1, [\OUTPTR, #-1]
2254 vmov.8 d3[7], \TMP1
2255
2256 subs \WIDTH, \WIDTH, #32
2257 blt 5f
2258 0: /* process 32 pixels per iteration */
2259 upsample32 \OUTPTR, \INPTR
2260 subs \WIDTH, \WIDTH, #32
2261 bge 0b
2262 5:
2263 adds \WIDTH, \WIDTH, #16
2264 blt 1f
2265 0: /* process 16 pixels if needed */
2266 upsample16 \OUTPTR, \INPTR
2267 subs \WIDTH, \WIDTH, #16
2268 1:
2269 adds \WIDTH, \WIDTH, #16
2270 beq 9f
2271
2272 /* load the remaining 1-15 pixels */
2273 add \INPTR, \INPTR, \WIDTH
2274 tst \WIDTH, #1
2275 beq 2f
2276 sub \INPTR, \INPTR, #1
2277 vld1.8 {d0[0]}, [\INPTR]
2278 2:
2279 tst \WIDTH, #2
2280 beq 2f
2281 vext.8 d0, d0, d0, #6
2282 sub \INPTR, \INPTR, #1
2283 vld1.8 {d0[1]}, [\INPTR]
2284 sub \INPTR, \INPTR, #1
2285 vld1.8 {d0[0]}, [\INPTR]
2286 2:
2287 tst \WIDTH, #4
2288 beq 2f
2289 vrev64.32 d0, d0
2290 sub \INPTR, \INPTR, #1
2291 vld1.8 {d0[3]}, [\INPTR]
2292 sub \INPTR, \INPTR, #1
2293 vld1.8 {d0[2]}, [\INPTR]
2294 sub \INPTR, \INPTR, #1
2295 vld1.8 {d0[1]}, [\INPTR]
2296 sub \INPTR, \INPTR, #1
2297 vld1.8 {d0[0]}, [\INPTR]
2298 2:
2299 tst \WIDTH, #8
2300 beq 2f
2301 vmov d1, d0
2302 sub \INPTR, \INPTR, #8
2303 vld1.8 {d0}, [\INPTR]
2304 2: /* upsample the remaining pixels */
2305 vmovl.u8 q8, d0
2306 vext.8 q2, q1, q0, #15
2307 vmovl.u8 q9, d1
2308 vaddw.u8 q10, q15, d4
2309 vaddw.u8 q11, q15, d5
2310 vmlal.u8 q8, d4, d28
2311 vmlal.u8 q9, d5, d28
2312 vmlal.u8 q10, d0, d28
2313 vmlal.u8 q11, d1, d28
2314 vrshrn.u16 d10, q8, #2
2315 vrshrn.u16 d12, q9, #2
2316 vshrn.u16 d11, q10, #2
2317 vshrn.u16 d13, q11, #2
2318 vzip.8 d10, d11
2319 vzip.8 d12, d13
2320 /* store the remaining pixels */
2321 tst \WIDTH, #8
2322 beq 2f
2323 vst1.8 {d10, d11}, [\OUTPTR]!
2324 vmov q5, q6
2325 2:
2326 tst \WIDTH, #4
2327 beq 2f
2328 vst1.8 {d10}, [\OUTPTR]!
2329 vmov d10, d11
2330 2:
2331 tst \WIDTH, #2
2332 beq 2f
2333 vst1.8 {d10[0]}, [\OUTPTR]!
2334 vst1.8 {d10[1]}, [\OUTPTR]!
2335 vst1.8 {d10[2]}, [\OUTPTR]!
2336 vst1.8 {d10[3]}, [\OUTPTR]!
2337 vext.8 d10, d10, d10, #4
2338 2:
2339 tst \WIDTH, #1
2340 beq 2f
2341 vst1.8 {d10[0]}, [\OUTPTR]!
2342 vst1.8 {d10[1]}, [\OUTPTR]!
2343 2:
2344 9:
2345 .endm
2346
2347 asm_function jsimd_h2v1_fancy_upsample_neon
2348
2349 MAX_V_SAMP_FACTOR .req r0
2350 DOWNSAMPLED_WIDTH .req r1
2351 INPUT_DATA .req r2
2352 OUTPUT_DATA_PTR .req r3
2353 OUTPUT_DATA .req OUTPUT_DATA_PTR
2354
2355 OUTPTR .req r4
2356 INPTR .req r5
2357 WIDTH .req ip
2358 TMP .req lr
2359
2360 push {r4, r5, r6, lr}
2361 vpush {d8-d15}
2362
2363 ldr OUTPUT_DATA, [OUTPUT_DATA_PTR]
2364 cmp MAX_V_SAMP_FACTOR, #0
2365 ble 99f
2366
2367 /* initialize constants */
2368 vmov.u8 d28, #3
2369 vmov.u16 q15, #1
2370 11:
2371 ldr INPTR, [INPUT_DATA], #4
2372 ldr OUTPTR, [OUTPUT_DATA], #4
2373 mov WIDTH, DOWNSAMPLED_WIDTH
2374 upsample_row OUTPTR, INPTR, WIDTH, TMP
2375 subs MAX_V_SAMP_FACTOR, MAX_V_SAMP_FACTOR, #1
2376 bgt 11b
2377
2378 99:
2379 vpop {d8-d15}
2380 pop {r4, r5, r6, pc}
2381
2382 .unreq MAX_V_SAMP_FACTOR
2383 .unreq DOWNSAMPLED_WIDTH
2384 .unreq INPUT_DATA
2385 .unreq OUTPUT_DATA_PTR
2386 .unreq OUTPUT_DATA
2387
2388 .unreq OUTPTR
2389 .unreq INPTR
2390 .unreq WIDTH
2391 .unreq TMP
2392
2393 .endfunc
2394
2395 .purgem upsample16
2396 .purgem upsample32
2397 .purgem upsample_row

mercurial