1 ; 2 ; Copyright (c) 2013 The WebM project authors. All Rights Reserved. 3 ; 4 ; Use of this source code is governed by a BSD-style license 5 ; that can be found in the LICENSE file in the root of the source 6 ; tree. An additional intellectual property rights grant can be found 7 ; in the file PATENTS. All contributing project authors may 8 ; be found in the AUTHORS file in the root of the source tree. 9 ; 10 11 EXPORT |vpx_idct8x8_64_add_neon| 12 EXPORT |vpx_idct8x8_12_add_neon| 13 ARM 14 REQUIRE8 15 PRESERVE8 16 17 AREA ||.text||, CODE, READONLY, ALIGN=2 18 19 ; Parallel 1D IDCT on all the columns of a 8x8 16bit data matrix which are 20 ; loaded in q8-q15. The output will be stored back into q8-q15 registers. 21 ; This macro will touch q0-q7 registers and use them as buffer during 22 ; calculation. 23 MACRO 24 IDCT8x8_1D 25 ; stage 1 26 vdup.16 d0, r3 ; duplicate cospi_28_64 27 vdup.16 d1, r4 ; duplicate cospi_4_64 28 vdup.16 d2, r5 ; duplicate cospi_12_64 29 vdup.16 d3, r6 ; duplicate cospi_20_64 30 31 ; input[1] * cospi_28_64 32 vmull.s16 q2, d18, d0 33 vmull.s16 q3, d19, d0 34 35 ; input[5] * cospi_12_64 36 vmull.s16 q5, d26, d2 37 vmull.s16 q6, d27, d2 38 39 ; input[1]*cospi_28_64-input[7]*cospi_4_64 40 vmlsl.s16 q2, d30, d1 41 vmlsl.s16 q3, d31, d1 42 43 ; input[5] * cospi_12_64 - input[3] * cospi_20_64 44 vmlsl.s16 q5, d22, d3 45 vmlsl.s16 q6, d23, d3 46 47 ; dct_const_round_shift(input_dc * cospi_16_64) 48 vqrshrn.s32 d8, q2, #14 ; >> 14 49 vqrshrn.s32 d9, q3, #14 ; >> 14 50 51 ; dct_const_round_shift(input_dc * cospi_16_64) 52 vqrshrn.s32 d10, q5, #14 ; >> 14 53 vqrshrn.s32 d11, q6, #14 ; >> 14 54 55 ; input[1] * cospi_4_64 56 vmull.s16 q2, d18, d1 57 vmull.s16 q3, d19, d1 58 59 ; input[5] * cospi_20_64 60 vmull.s16 q9, d26, d3 61 vmull.s16 q13, d27, d3 62 63 ; input[1]*cospi_4_64+input[7]*cospi_28_64 64 vmlal.s16 q2, d30, d0 65 vmlal.s16 q3, d31, d0 66 67 ; input[5] * cospi_20_64 + input[3] * cospi_12_64 68 vmlal.s16 q9, d22, d2 69 vmlal.s16 q13, d23, d2 70 71 ; dct_const_round_shift(input_dc * cospi_16_64) 72 vqrshrn.s32 d14, q2, #14 ; >> 14 73 vqrshrn.s32 d15, q3, #14 ; >> 14 74 75 ; stage 2 & stage 3 - even half 76 vdup.16 d0, r7 ; duplicate cospi_16_64 77 78 ; dct_const_round_shift(input_dc * cospi_16_64) 79 vqrshrn.s32 d12, q9, #14 ; >> 14 80 vqrshrn.s32 d13, q13, #14 ; >> 14 81 82 ; input[0] * cospi_16_64 83 vmull.s16 q2, d16, d0 84 vmull.s16 q3, d17, d0 85 86 ; input[0] * cospi_16_64 87 vmull.s16 q13, d16, d0 88 vmull.s16 q15, d17, d0 89 90 ; (input[0] + input[2]) * cospi_16_64 91 vmlal.s16 q2, d24, d0 92 vmlal.s16 q3, d25, d0 93 94 ; (input[0] - input[2]) * cospi_16_64 95 vmlsl.s16 q13, d24, d0 96 vmlsl.s16 q15, d25, d0 97 98 vdup.16 d0, r8 ; duplicate cospi_24_64 99 vdup.16 d1, r9 ; duplicate cospi_8_64 100 101 ; dct_const_round_shift(input_dc * cospi_16_64) 102 vqrshrn.s32 d18, q2, #14 ; >> 14 103 vqrshrn.s32 d19, q3, #14 ; >> 14 104 105 ; dct_const_round_shift(input_dc * cospi_16_64) 106 vqrshrn.s32 d22, q13, #14 ; >> 14 107 vqrshrn.s32 d23, q15, #14 ; >> 14 108 109 ; input[1] * cospi_24_64 - input[3] * cospi_8_64 110 ; input[1] * cospi_24_64 111 vmull.s16 q2, d20, d0 112 vmull.s16 q3, d21, d0 113 114 ; input[1] * cospi_8_64 115 vmull.s16 q8, d20, d1 116 vmull.s16 q12, d21, d1 117 118 ; input[1] * cospi_24_64 - input[3] * cospi_8_64 119 vmlsl.s16 q2, d28, d1 120 vmlsl.s16 q3, d29, d1 121 122 ; input[1] * cospi_8_64 + input[3] * cospi_24_64 123 vmlal.s16 q8, d28, d0 124 vmlal.s16 q12, d29, d0 125 126 ; dct_const_round_shift(input_dc * cospi_16_64) 127 vqrshrn.s32 d26, q2, #14 ; >> 14 128 vqrshrn.s32 d27, q3, #14 ; >> 14 129 130 ; dct_const_round_shift(input_dc * cospi_16_64) 131 vqrshrn.s32 d30, q8, #14 ; >> 14 132 vqrshrn.s32 d31, q12, #14 ; >> 14 133 134 vadd.s16 q0, q9, q15 ; output[0] = step[0] + step[3] 135 vadd.s16 q1, q11, q13 ; output[1] = step[1] + step[2] 136 vsub.s16 q2, q11, q13 ; output[2] = step[1] - step[2] 137 vsub.s16 q3, q9, q15 ; output[3] = step[0] - step[3] 138 139 ; stage 3 -odd half 140 vdup.16 d16, r7 ; duplicate cospi_16_64 141 142 ; stage 2 - odd half 143 vsub.s16 q13, q4, q5 ; step2[5] = step1[4] - step1[5] 144 vadd.s16 q4, q4, q5 ; step2[4] = step1[4] + step1[5] 145 vsub.s16 q14, q7, q6 ; step2[6] = -step1[6] + step1[7] 146 vadd.s16 q7, q7, q6 ; step2[7] = step1[6] + step1[7] 147 148 ; step2[6] * cospi_16_64 149 vmull.s16 q9, d28, d16 150 vmull.s16 q10, d29, d16 151 152 ; step2[6] * cospi_16_64 153 vmull.s16 q11, d28, d16 154 vmull.s16 q12, d29, d16 155 156 ; (step2[6] - step2[5]) * cospi_16_64 157 vmlsl.s16 q9, d26, d16 158 vmlsl.s16 q10, d27, d16 159 160 ; (step2[5] + step2[6]) * cospi_16_64 161 vmlal.s16 q11, d26, d16 162 vmlal.s16 q12, d27, d16 163 164 ; dct_const_round_shift(input_dc * cospi_16_64) 165 vqrshrn.s32 d10, q9, #14 ; >> 14 166 vqrshrn.s32 d11, q10, #14 ; >> 14 167 168 ; dct_const_round_shift(input_dc * cospi_16_64) 169 vqrshrn.s32 d12, q11, #14 ; >> 14 170 vqrshrn.s32 d13, q12, #14 ; >> 14 171 172 ; stage 4 173 vadd.s16 q8, q0, q7 ; output[0] = step1[0] + step1[7]; 174 vadd.s16 q9, q1, q6 ; output[1] = step1[1] + step1[6]; 175 vadd.s16 q10, q2, q5 ; output[2] = step1[2] + step1[5]; 176 vadd.s16 q11, q3, q4 ; output[3] = step1[3] + step1[4]; 177 vsub.s16 q12, q3, q4 ; output[4] = step1[3] - step1[4]; 178 vsub.s16 q13, q2, q5 ; output[5] = step1[2] - step1[5]; 179 vsub.s16 q14, q1, q6 ; output[6] = step1[1] - step1[6]; 180 vsub.s16 q15, q0, q7 ; output[7] = step1[0] - step1[7]; 181 MEND 182 183 ; Transpose a 8x8 16bit data matrix. Datas are loaded in q8-q15. 184 MACRO 185 TRANSPOSE8X8 186 vswp d17, d24 187 vswp d23, d30 188 vswp d21, d28 189 vswp d19, d26 190 vtrn.32 q8, q10 191 vtrn.32 q9, q11 192 vtrn.32 q12, q14 193 vtrn.32 q13, q15 194 vtrn.16 q8, q9 195 vtrn.16 q10, q11 196 vtrn.16 q12, q13 197 vtrn.16 q14, q15 198 MEND 199 200 AREA Block, CODE, READONLY ; name this block of code 201 ;void vpx_idct8x8_64_add_neon(int16_t *input, uint8_t *dest, int dest_stride) 202 ; 203 ; r0 int16_t input 204 ; r1 uint8_t *dest 205 ; r2 int dest_stride) 206 207 |vpx_idct8x8_64_add_neon| PROC 208 push {r4-r9} 209 vpush {d8-d15} 210 vld1.s16 {q8,q9}, [r0]! 211 vld1.s16 {q10,q11}, [r0]! 212 vld1.s16 {q12,q13}, [r0]! 213 vld1.s16 {q14,q15}, [r0]! 214 215 ; transpose the input data 216 TRANSPOSE8X8 217 218 ; generate cospi_28_64 = 3196 219 mov r3, #0x0c00 220 add r3, #0x7c 221 222 ; generate cospi_4_64 = 16069 223 mov r4, #0x3e00 224 add r4, #0xc5 225 226 ; generate cospi_12_64 = 13623 227 mov r5, #0x3500 228 add r5, #0x37 229 230 ; generate cospi_20_64 = 9102 231 mov r6, #0x2300 232 add r6, #0x8e 233 234 ; generate cospi_16_64 = 11585 235 mov r7, #0x2d00 236 add r7, #0x41 237 238 ; generate cospi_24_64 = 6270 239 mov r8, #0x1800 240 add r8, #0x7e 241 242 ; generate cospi_8_64 = 15137 243 mov r9, #0x3b00 244 add r9, #0x21 245 246 ; First transform rows 247 IDCT8x8_1D 248 249 ; Transpose the matrix 250 TRANSPOSE8X8 251 252 ; Then transform columns 253 IDCT8x8_1D 254 255 ; ROUND_POWER_OF_TWO(temp_out[j], 5) 256 vrshr.s16 q8, q8, #5 257 vrshr.s16 q9, q9, #5 258 vrshr.s16 q10, q10, #5 259 vrshr.s16 q11, q11, #5 260 vrshr.s16 q12, q12, #5 261 vrshr.s16 q13, q13, #5 262 vrshr.s16 q14, q14, #5 263 vrshr.s16 q15, q15, #5 264 265 ; save dest pointer 266 mov r0, r1 267 268 ; load destination data 269 vld1.64 {d0}, [r1], r2 270 vld1.64 {d1}, [r1], r2 271 vld1.64 {d2}, [r1], r2 272 vld1.64 {d3}, [r1], r2 273 vld1.64 {d4}, [r1], r2 274 vld1.64 {d5}, [r1], r2 275 vld1.64 {d6}, [r1], r2 276 vld1.64 {d7}, [r1] 277 278 ; ROUND_POWER_OF_TWO(temp_out[j], 5) + dest[j * dest_stride + i] 279 vaddw.u8 q8, q8, d0 280 vaddw.u8 q9, q9, d1 281 vaddw.u8 q10, q10, d2 282 vaddw.u8 q11, q11, d3 283 vaddw.u8 q12, q12, d4 284 vaddw.u8 q13, q13, d5 285 vaddw.u8 q14, q14, d6 286 vaddw.u8 q15, q15, d7 287 288 ; clip_pixel 289 vqmovun.s16 d0, q8 290 vqmovun.s16 d1, q9 291 vqmovun.s16 d2, q10 292 vqmovun.s16 d3, q11 293 vqmovun.s16 d4, q12 294 vqmovun.s16 d5, q13 295 vqmovun.s16 d6, q14 296 vqmovun.s16 d7, q15 297 298 ; store the data 299 vst1.64 {d0}, [r0], r2 300 vst1.64 {d1}, [r0], r2 301 vst1.64 {d2}, [r0], r2 302 vst1.64 {d3}, [r0], r2 303 vst1.64 {d4}, [r0], r2 304 vst1.64 {d5}, [r0], r2 305 vst1.64 {d6}, [r0], r2 306 vst1.64 {d7}, [r0], r2 307 308 vpop {d8-d15} 309 pop {r4-r9} 310 bx lr 311 ENDP ; |vpx_idct8x8_64_add_neon| 312 313 ;void vpx_idct8x8_12_add_neon(int16_t *input, uint8_t *dest, int dest_stride) 314 ; 315 ; r0 int16_t input 316 ; r1 uint8_t *dest 317 ; r2 int dest_stride) 318 319 |vpx_idct8x8_12_add_neon| PROC 320 push {r4-r9} 321 vpush {d8-d15} 322 vld1.s16 {q8,q9}, [r0]! 323 vld1.s16 {q10,q11}, [r0]! 324 vld1.s16 {q12,q13}, [r0]! 325 vld1.s16 {q14,q15}, [r0]! 326 327 ; transpose the input data 328 TRANSPOSE8X8 329 330 ; generate cospi_28_64 = 3196 331 mov r3, #0x0c00 332 add r3, #0x7c 333 334 ; generate cospi_4_64 = 16069 335 mov r4, #0x3e00 336 add r4, #0xc5 337 338 ; generate cospi_12_64 = 13623 339 mov r5, #0x3500 340 add r5, #0x37 341 342 ; generate cospi_20_64 = 9102 343 mov r6, #0x2300 344 add r6, #0x8e 345 346 ; generate cospi_16_64 = 11585 347 mov r7, #0x2d00 348 add r7, #0x41 349 350 ; generate cospi_24_64 = 6270 351 mov r8, #0x1800 352 add r8, #0x7e 353 354 ; generate cospi_8_64 = 15137 355 mov r9, #0x3b00 356 add r9, #0x21 357 358 ; First transform rows 359 ; stage 1 360 ; The following instructions use vqrdmulh to do the 361 ; dct_const_round_shift(input[1] * cospi_28_64). vqrdmulh will do doubling 362 ; multiply and shift the result by 16 bits instead of 14 bits. So we need 363 ; to double the constants before multiplying to compensate this. 364 mov r12, r3, lsl #1 365 vdup.16 q0, r12 ; duplicate cospi_28_64*2 366 mov r12, r4, lsl #1 367 vdup.16 q1, r12 ; duplicate cospi_4_64*2 368 369 ; dct_const_round_shift(input[1] * cospi_28_64) 370 vqrdmulh.s16 q4, q9, q0 371 372 mov r12, r6, lsl #1 373 rsb r12, #0 374 vdup.16 q0, r12 ; duplicate -cospi_20_64*2 375 376 ; dct_const_round_shift(input[1] * cospi_4_64) 377 vqrdmulh.s16 q7, q9, q1 378 379 mov r12, r5, lsl #1 380 vdup.16 q1, r12 ; duplicate cospi_12_64*2 381 382 ; dct_const_round_shift(- input[3] * cospi_20_64) 383 vqrdmulh.s16 q5, q11, q0 384 385 mov r12, r7, lsl #1 386 vdup.16 q0, r12 ; duplicate cospi_16_64*2 387 388 ; dct_const_round_shift(input[3] * cospi_12_64) 389 vqrdmulh.s16 q6, q11, q1 390 391 ; stage 2 & stage 3 - even half 392 mov r12, r8, lsl #1 393 vdup.16 q1, r12 ; duplicate cospi_24_64*2 394 395 ; dct_const_round_shift(input_dc * cospi_16_64) 396 vqrdmulh.s16 q9, q8, q0 397 398 mov r12, r9, lsl #1 399 vdup.16 q0, r12 ; duplicate cospi_8_64*2 400 401 ; dct_const_round_shift(input[1] * cospi_24_64) 402 vqrdmulh.s16 q13, q10, q1 403 404 ; dct_const_round_shift(input[1] * cospi_8_64) 405 vqrdmulh.s16 q15, q10, q0 406 407 ; stage 3 -odd half 408 vdup.16 d16, r7 ; duplicate cospi_16_64 409 410 vadd.s16 q0, q9, q15 ; output[0] = step[0] + step[3] 411 vadd.s16 q1, q9, q13 ; output[1] = step[1] + step[2] 412 vsub.s16 q2, q9, q13 ; output[2] = step[1] - step[2] 413 vsub.s16 q3, q9, q15 ; output[3] = step[0] - step[3] 414 415 ; stage 2 - odd half 416 vsub.s16 q13, q4, q5 ; step2[5] = step1[4] - step1[5] 417 vadd.s16 q4, q4, q5 ; step2[4] = step1[4] + step1[5] 418 vsub.s16 q14, q7, q6 ; step2[6] = -step1[6] + step1[7] 419 vadd.s16 q7, q7, q6 ; step2[7] = step1[6] + step1[7] 420 421 ; step2[6] * cospi_16_64 422 vmull.s16 q9, d28, d16 423 vmull.s16 q10, d29, d16 424 425 ; step2[6] * cospi_16_64 426 vmull.s16 q11, d28, d16 427 vmull.s16 q12, d29, d16 428 429 ; (step2[6] - step2[5]) * cospi_16_64 430 vmlsl.s16 q9, d26, d16 431 vmlsl.s16 q10, d27, d16 432 433 ; (step2[5] + step2[6]) * cospi_16_64 434 vmlal.s16 q11, d26, d16 435 vmlal.s16 q12, d27, d16 436 437 ; dct_const_round_shift(input_dc * cospi_16_64) 438 vqrshrn.s32 d10, q9, #14 ; >> 14 439 vqrshrn.s32 d11, q10, #14 ; >> 14 440 441 ; dct_const_round_shift(input_dc * cospi_16_64) 442 vqrshrn.s32 d12, q11, #14 ; >> 14 443 vqrshrn.s32 d13, q12, #14 ; >> 14 444 445 ; stage 4 446 vadd.s16 q8, q0, q7 ; output[0] = step1[0] + step1[7]; 447 vadd.s16 q9, q1, q6 ; output[1] = step1[1] + step1[6]; 448 vadd.s16 q10, q2, q5 ; output[2] = step1[2] + step1[5]; 449 vadd.s16 q11, q3, q4 ; output[3] = step1[3] + step1[4]; 450 vsub.s16 q12, q3, q4 ; output[4] = step1[3] - step1[4]; 451 vsub.s16 q13, q2, q5 ; output[5] = step1[2] - step1[5]; 452 vsub.s16 q14, q1, q6 ; output[6] = step1[1] - step1[6]; 453 vsub.s16 q15, q0, q7 ; output[7] = step1[0] - step1[7]; 454 455 ; Transpose the matrix 456 TRANSPOSE8X8 457 458 ; Then transform columns 459 IDCT8x8_1D 460 461 ; ROUND_POWER_OF_TWO(temp_out[j], 5) 462 vrshr.s16 q8, q8, #5 463 vrshr.s16 q9, q9, #5 464 vrshr.s16 q10, q10, #5 465 vrshr.s16 q11, q11, #5 466 vrshr.s16 q12, q12, #5 467 vrshr.s16 q13, q13, #5 468 vrshr.s16 q14, q14, #5 469 vrshr.s16 q15, q15, #5 470 471 ; save dest pointer 472 mov r0, r1 473 474 ; load destination data 475 vld1.64 {d0}, [r1], r2 476 vld1.64 {d1}, [r1], r2 477 vld1.64 {d2}, [r1], r2 478 vld1.64 {d3}, [r1], r2 479 vld1.64 {d4}, [r1], r2 480 vld1.64 {d5}, [r1], r2 481 vld1.64 {d6}, [r1], r2 482 vld1.64 {d7}, [r1] 483 484 ; ROUND_POWER_OF_TWO(temp_out[j], 5) + dest[j * dest_stride + i] 485 vaddw.u8 q8, q8, d0 486 vaddw.u8 q9, q9, d1 487 vaddw.u8 q10, q10, d2 488 vaddw.u8 q11, q11, d3 489 vaddw.u8 q12, q12, d4 490 vaddw.u8 q13, q13, d5 491 vaddw.u8 q14, q14, d6 492 vaddw.u8 q15, q15, d7 493 494 ; clip_pixel 495 vqmovun.s16 d0, q8 496 vqmovun.s16 d1, q9 497 vqmovun.s16 d2, q10 498 vqmovun.s16 d3, q11 499 vqmovun.s16 d4, q12 500 vqmovun.s16 d5, q13 501 vqmovun.s16 d6, q14 502 vqmovun.s16 d7, q15 503 504 ; store the data 505 vst1.64 {d0}, [r0], r2 506 vst1.64 {d1}, [r0], r2 507 vst1.64 {d2}, [r0], r2 508 vst1.64 {d3}, [r0], r2 509 vst1.64 {d4}, [r0], r2 510 vst1.64 {d5}, [r0], r2 511 vst1.64 {d6}, [r0], r2 512 vst1.64 {d7}, [r0], r2 513 514 vpop {d8-d15} 515 pop {r4-r9} 516 bx lr 517 ENDP ; |vpx_idct8x8_12_add_neon| 518 519 END 520