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