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 |vp9_loop_filter_horizontal_edge_neon| 12 EXPORT |vp9_loop_filter_vertical_edge_neon| 13 EXPORT |vp9_mbloop_filter_horizontal_edge_neon| 14 EXPORT |vp9_mbloop_filter_vertical_edge_neon| 15 ARM 16 17 AREA ||.text||, CODE, READONLY, ALIGN=2 18 19; Currently vp9 only works on iterations 8 at a time. The vp8 loop filter 20; works on 16 iterations at a time. 21; TODO(fgalligan): See about removing the count code as this function is only 22; called with a count of 1. 23; 24; void vp9_loop_filter_horizontal_edge_neon(uint8_t *s, 25; int p /* pitch */, 26; const uint8_t *blimit, 27; const uint8_t *limit, 28; const uint8_t *thresh, 29; int count) 30; 31; r0 uint8_t *s, 32; r1 int p, /* pitch */ 33; r2 const uint8_t *blimit, 34; r3 const uint8_t *limit, 35; sp const uint8_t *thresh, 36; sp+4 int count 37|vp9_loop_filter_horizontal_edge_neon| PROC 38 push {lr} 39 40 vld1.8 {d0[]}, [r2] ; duplicate *blimit 41 ldr r12, [sp, #8] ; load count 42 ldr r2, [sp, #4] ; load thresh 43 add r1, r1, r1 ; double pitch 44 45 cmp r12, #0 46 beq end_vp9_lf_h_edge 47 48 vld1.8 {d1[]}, [r3] ; duplicate *limit 49 vld1.8 {d2[]}, [r2] ; duplicate *thresh 50 51count_lf_h_loop 52 sub r2, r0, r1, lsl #1 ; move src pointer down by 4 lines 53 add r3, r2, r1, lsr #1 ; set to 3 lines down 54 55 vld1.u8 {d3}, [r2@64], r1 ; p3 56 vld1.u8 {d4}, [r3@64], r1 ; p2 57 vld1.u8 {d5}, [r2@64], r1 ; p1 58 vld1.u8 {d6}, [r3@64], r1 ; p0 59 vld1.u8 {d7}, [r2@64], r1 ; q0 60 vld1.u8 {d16}, [r3@64], r1 ; q1 61 vld1.u8 {d17}, [r2@64] ; q2 62 vld1.u8 {d18}, [r3@64] ; q3 63 64 sub r2, r2, r1, lsl #1 65 sub r3, r3, r1, lsl #1 66 67 bl vp9_loop_filter_neon 68 69 vst1.u8 {d4}, [r2@64], r1 ; store op1 70 vst1.u8 {d5}, [r3@64], r1 ; store op0 71 vst1.u8 {d6}, [r2@64], r1 ; store oq0 72 vst1.u8 {d7}, [r3@64], r1 ; store oq1 73 74 add r0, r0, #8 75 subs r12, r12, #1 76 bne count_lf_h_loop 77 78end_vp9_lf_h_edge 79 pop {pc} 80 ENDP ; |vp9_loop_filter_horizontal_edge_neon| 81 82; Currently vp9 only works on iterations 8 at a time. The vp8 loop filter 83; works on 16 iterations at a time. 84; TODO(fgalligan): See about removing the count code as this function is only 85; called with a count of 1. 86; 87; void vp9_loop_filter_vertical_edge_neon(uint8_t *s, 88; int p /* pitch */, 89; const uint8_t *blimit, 90; const uint8_t *limit, 91; const uint8_t *thresh, 92; int count) 93; 94; r0 uint8_t *s, 95; r1 int p, /* pitch */ 96; r2 const uint8_t *blimit, 97; r3 const uint8_t *limit, 98; sp const uint8_t *thresh, 99; sp+4 int count 100|vp9_loop_filter_vertical_edge_neon| PROC 101 push {lr} 102 103 vld1.8 {d0[]}, [r2] ; duplicate *blimit 104 ldr r12, [sp, #8] ; load count 105 vld1.8 {d1[]}, [r3] ; duplicate *limit 106 107 ldr r3, [sp, #4] ; load thresh 108 sub r2, r0, #4 ; move s pointer down by 4 columns 109 cmp r12, #0 110 beq end_vp9_lf_v_edge 111 112 vld1.8 {d2[]}, [r3] ; duplicate *thresh 113 114count_lf_v_loop 115 vld1.u8 {d3}, [r2], r1 ; load s data 116 vld1.u8 {d4}, [r2], r1 117 vld1.u8 {d5}, [r2], r1 118 vld1.u8 {d6}, [r2], r1 119 vld1.u8 {d7}, [r2], r1 120 vld1.u8 {d16}, [r2], r1 121 vld1.u8 {d17}, [r2], r1 122 vld1.u8 {d18}, [r2] 123 124 ;transpose to 8x16 matrix 125 vtrn.32 d3, d7 126 vtrn.32 d4, d16 127 vtrn.32 d5, d17 128 vtrn.32 d6, d18 129 130 vtrn.16 d3, d5 131 vtrn.16 d4, d6 132 vtrn.16 d7, d17 133 vtrn.16 d16, d18 134 135 vtrn.8 d3, d4 136 vtrn.8 d5, d6 137 vtrn.8 d7, d16 138 vtrn.8 d17, d18 139 140 bl vp9_loop_filter_neon 141 142 sub r0, r0, #2 143 144 ;store op1, op0, oq0, oq1 145 vst4.8 {d4[0], d5[0], d6[0], d7[0]}, [r0], r1 146 vst4.8 {d4[1], d5[1], d6[1], d7[1]}, [r0], r1 147 vst4.8 {d4[2], d5[2], d6[2], d7[2]}, [r0], r1 148 vst4.8 {d4[3], d5[3], d6[3], d7[3]}, [r0], r1 149 vst4.8 {d4[4], d5[4], d6[4], d7[4]}, [r0], r1 150 vst4.8 {d4[5], d5[5], d6[5], d7[5]}, [r0], r1 151 vst4.8 {d4[6], d5[6], d6[6], d7[6]}, [r0], r1 152 vst4.8 {d4[7], d5[7], d6[7], d7[7]}, [r0] 153 154 add r0, r0, r1, lsl #3 ; s += pitch * 8 155 subs r12, r12, #1 156 subne r2, r0, #4 ; move s pointer down by 4 columns 157 bne count_lf_v_loop 158 159end_vp9_lf_v_edge 160 pop {pc} 161 ENDP ; |vp9_loop_filter_vertical_edge_neon| 162 163; void vp9_loop_filter_neon(); 164; This is a helper function for the loopfilters. The invidual functions do the 165; necessary load, transpose (if necessary) and store. The function does not use 166; registers d8-d15. 167; 168; Inputs: 169; r0-r3, r12 PRESERVE 170; d0 blimit 171; d1 limit 172; d2 thresh 173; d3 p3 174; d4 p2 175; d5 p1 176; d6 p0 177; d7 q0 178; d16 q1 179; d17 q2 180; d18 q3 181; 182; Outputs: 183; d4 op1 184; d5 op0 185; d6 oq0 186; d7 oq1 187|vp9_loop_filter_neon| PROC 188 ; filter_mask 189 vabd.u8 d19, d3, d4 ; m1 = abs(p3 - p2) 190 vabd.u8 d20, d4, d5 ; m2 = abs(p2 - p1) 191 vabd.u8 d21, d5, d6 ; m3 = abs(p1 - p0) 192 vabd.u8 d22, d16, d7 ; m4 = abs(q1 - q0) 193 vabd.u8 d3, d17, d16 ; m5 = abs(q2 - q1) 194 vabd.u8 d4, d18, d17 ; m6 = abs(q3 - q2) 195 196 ; only compare the largest value to limit 197 vmax.u8 d19, d19, d20 ; m1 = max(m1, m2) 198 vmax.u8 d20, d21, d22 ; m2 = max(m3, m4) 199 200 vabd.u8 d17, d6, d7 ; abs(p0 - q0) 201 202 vmax.u8 d3, d3, d4 ; m3 = max(m5, m6) 203 204 vmov.u8 d18, #0x80 205 206 vmax.u8 d23, d19, d20 ; m1 = max(m1, m2) 207 208 ; hevmask 209 vcgt.u8 d21, d21, d2 ; (abs(p1 - p0) > thresh)*-1 210 vcgt.u8 d22, d22, d2 ; (abs(q1 - q0) > thresh)*-1 211 vmax.u8 d23, d23, d3 ; m1 = max(m1, m3) 212 213 vabd.u8 d28, d5, d16 ; a = abs(p1 - q1) 214 vqadd.u8 d17, d17, d17 ; b = abs(p0 - q0) * 2 215 216 veor d7, d7, d18 ; qs0 217 218 vcge.u8 d23, d1, d23 ; abs(m1) > limit 219 220 ; filter() function 221 ; convert to signed 222 223 vshr.u8 d28, d28, #1 ; a = a / 2 224 veor d6, d6, d18 ; ps0 225 226 veor d5, d5, d18 ; ps1 227 vqadd.u8 d17, d17, d28 ; a = b + a 228 229 veor d16, d16, d18 ; qs1 230 231 vmov.u8 d19, #3 232 233 vsub.s8 d28, d7, d6 ; ( qs0 - ps0) 234 235 vcge.u8 d17, d0, d17 ; a > blimit 236 237 vqsub.s8 d27, d5, d16 ; filter = clamp(ps1-qs1) 238 vorr d22, d21, d22 ; hevmask 239 240 vmull.s8 q12, d28, d19 ; 3 * ( qs0 - ps0) 241 242 vand d27, d27, d22 ; filter &= hev 243 vand d23, d23, d17 ; filter_mask 244 245 vaddw.s8 q12, q12, d27 ; filter + 3 * (qs0 - ps0) 246 247 vmov.u8 d17, #4 248 249 ; filter = clamp(filter + 3 * ( qs0 - ps0)) 250 vqmovn.s16 d27, q12 251 252 vand d27, d27, d23 ; filter &= mask 253 254 vqadd.s8 d28, d27, d19 ; filter2 = clamp(filter+3) 255 vqadd.s8 d27, d27, d17 ; filter1 = clamp(filter+4) 256 vshr.s8 d28, d28, #3 ; filter2 >>= 3 257 vshr.s8 d27, d27, #3 ; filter1 >>= 3 258 259 vqadd.s8 d19, d6, d28 ; u = clamp(ps0 + filter2) 260 vqsub.s8 d26, d7, d27 ; u = clamp(qs0 - filter1) 261 262 ; outer tap adjustments 263 vrshr.s8 d27, d27, #1 ; filter = ++filter1 >> 1 264 265 veor d6, d26, d18 ; *oq0 = u^0x80 266 267 vbic d27, d27, d22 ; filter &= ~hev 268 269 vqadd.s8 d21, d5, d27 ; u = clamp(ps1 + filter) 270 vqsub.s8 d20, d16, d27 ; u = clamp(qs1 - filter) 271 272 veor d5, d19, d18 ; *op0 = u^0x80 273 veor d4, d21, d18 ; *op1 = u^0x80 274 veor d7, d20, d18 ; *oq1 = u^0x80 275 276 bx lr 277 ENDP ; |vp9_loop_filter_neon| 278 279; void vp9_mbloop_filter_horizontal_edge_neon(uint8_t *s, int p, 280; const uint8_t *blimit, 281; const uint8_t *limit, 282; const uint8_t *thresh, 283; int count) 284; r0 uint8_t *s, 285; r1 int p, /* pitch */ 286; r2 const uint8_t *blimit, 287; r3 const uint8_t *limit, 288; sp const uint8_t *thresh, 289; sp+4 int count 290|vp9_mbloop_filter_horizontal_edge_neon| PROC 291 push {r4-r5, lr} 292 293 vld1.8 {d0[]}, [r2] ; duplicate *blimit 294 ldr r12, [sp, #16] ; load count 295 ldr r2, [sp, #12] ; load thresh 296 add r1, r1, r1 ; double pitch 297 298 cmp r12, #0 299 beq end_vp9_mblf_h_edge 300 301 vld1.8 {d1[]}, [r3] ; duplicate *limit 302 vld1.8 {d2[]}, [r2] ; duplicate *thresh 303 304count_mblf_h_loop 305 sub r3, r0, r1, lsl #1 ; move src pointer down by 4 lines 306 add r2, r3, r1, lsr #1 ; set to 3 lines down 307 308 vld1.u8 {d3}, [r3@64], r1 ; p3 309 vld1.u8 {d4}, [r2@64], r1 ; p2 310 vld1.u8 {d5}, [r3@64], r1 ; p1 311 vld1.u8 {d6}, [r2@64], r1 ; p0 312 vld1.u8 {d7}, [r3@64], r1 ; q0 313 vld1.u8 {d16}, [r2@64], r1 ; q1 314 vld1.u8 {d17}, [r3@64] ; q2 315 vld1.u8 {d18}, [r2@64], r1 ; q3 316 317 sub r3, r3, r1, lsl #1 318 sub r2, r2, r1, lsl #2 319 320 bl vp9_mbloop_filter_neon 321 322 vst1.u8 {d0}, [r2@64], r1 ; store op2 323 vst1.u8 {d1}, [r3@64], r1 ; store op1 324 vst1.u8 {d2}, [r2@64], r1 ; store op0 325 vst1.u8 {d3}, [r3@64], r1 ; store oq0 326 vst1.u8 {d4}, [r2@64], r1 ; store oq1 327 vst1.u8 {d5}, [r3@64], r1 ; store oq2 328 329 add r0, r0, #8 330 subs r12, r12, #1 331 bne count_mblf_h_loop 332 333end_vp9_mblf_h_edge 334 pop {r4-r5, pc} 335 336 ENDP ; |vp9_mbloop_filter_horizontal_edge_neon| 337 338; void vp9_mbloop_filter_vertical_edge_neon(uint8_t *s, 339; int pitch, 340; const uint8_t *blimit, 341; const uint8_t *limit, 342; const uint8_t *thresh, 343; int count) 344; 345; r0 uint8_t *s, 346; r1 int pitch, 347; r2 const uint8_t *blimit, 348; r3 const uint8_t *limit, 349; sp const uint8_t *thresh, 350; sp+4 int count 351|vp9_mbloop_filter_vertical_edge_neon| PROC 352 push {r4-r5, lr} 353 354 vld1.8 {d0[]}, [r2] ; duplicate *blimit 355 ldr r12, [sp, #16] ; load count 356 vld1.8 {d1[]}, [r3] ; duplicate *limit 357 358 ldr r3, [sp, #12] ; load thresh 359 sub r2, r0, #4 ; move s pointer down by 4 columns 360 cmp r12, #0 361 beq end_vp9_mblf_v_edge 362 363 vld1.8 {d2[]}, [r3] ; duplicate *thresh 364 365count_mblf_v_loop 366 vld1.u8 {d3}, [r2], r1 ; load s data 367 vld1.u8 {d4}, [r2], r1 368 vld1.u8 {d5}, [r2], r1 369 vld1.u8 {d6}, [r2], r1 370 vld1.u8 {d7}, [r2], r1 371 vld1.u8 {d16}, [r2], r1 372 vld1.u8 {d17}, [r2], r1 373 vld1.u8 {d18}, [r2] 374 375 ;transpose to 8x16 matrix 376 vtrn.32 d3, d7 377 vtrn.32 d4, d16 378 vtrn.32 d5, d17 379 vtrn.32 d6, d18 380 381 vtrn.16 d3, d5 382 vtrn.16 d4, d6 383 vtrn.16 d7, d17 384 vtrn.16 d16, d18 385 386 vtrn.8 d3, d4 387 vtrn.8 d5, d6 388 vtrn.8 d7, d16 389 vtrn.8 d17, d18 390 391 sub r2, r0, #3 392 add r3, r0, #1 393 394 bl vp9_mbloop_filter_neon 395 396 ;store op2, op1, op0, oq0 397 vst4.8 {d0[0], d1[0], d2[0], d3[0]}, [r2], r1 398 vst4.8 {d0[1], d1[1], d2[1], d3[1]}, [r2], r1 399 vst4.8 {d0[2], d1[2], d2[2], d3[2]}, [r2], r1 400 vst4.8 {d0[3], d1[3], d2[3], d3[3]}, [r2], r1 401 vst4.8 {d0[4], d1[4], d2[4], d3[4]}, [r2], r1 402 vst4.8 {d0[5], d1[5], d2[5], d3[5]}, [r2], r1 403 vst4.8 {d0[6], d1[6], d2[6], d3[6]}, [r2], r1 404 vst4.8 {d0[7], d1[7], d2[7], d3[7]}, [r2] 405 406 ;store oq1, oq2 407 vst2.8 {d4[0], d5[0]}, [r3], r1 408 vst2.8 {d4[1], d5[1]}, [r3], r1 409 vst2.8 {d4[2], d5[2]}, [r3], r1 410 vst2.8 {d4[3], d5[3]}, [r3], r1 411 vst2.8 {d4[4], d5[4]}, [r3], r1 412 vst2.8 {d4[5], d5[5]}, [r3], r1 413 vst2.8 {d4[6], d5[6]}, [r3], r1 414 vst2.8 {d4[7], d5[7]}, [r3] 415 416 add r0, r0, r1, lsl #3 ; s += pitch * 8 417 subs r12, r12, #1 418 subne r2, r0, #4 ; move s pointer down by 4 columns 419 bne count_mblf_v_loop 420 421end_vp9_mblf_v_edge 422 pop {r4-r5, pc} 423 ENDP ; |vp9_mbloop_filter_vertical_edge_neon| 424 425; void vp9_mbloop_filter_neon(); 426; This is a helper function for the loopfilters. The invidual functions do the 427; necessary load, transpose (if necessary) and store. The function does not use 428; registers d8-d15. 429; 430; Inputs: 431; r0-r3, r12 PRESERVE 432; d0 blimit 433; d1 limit 434; d2 thresh 435; d3 p3 436; d4 p2 437; d5 p1 438; d6 p0 439; d7 q0 440; d16 q1 441; d17 q2 442; d18 q3 443; 444; Outputs: 445; d0 op2 446; d1 op1 447; d2 op0 448; d3 oq0 449; d4 oq1 450; d5 oq2 451|vp9_mbloop_filter_neon| PROC 452 ; filter_mask 453 vabd.u8 d19, d3, d4 ; m1 = abs(p3 - p2) 454 vabd.u8 d20, d4, d5 ; m2 = abs(p2 - p1) 455 vabd.u8 d21, d5, d6 ; m3 = abs(p1 - p0) 456 vabd.u8 d22, d16, d7 ; m4 = abs(q1 - q0) 457 vabd.u8 d23, d17, d16 ; m5 = abs(q2 - q1) 458 vabd.u8 d24, d18, d17 ; m6 = abs(q3 - q2) 459 460 ; only compare the largest value to limit 461 vmax.u8 d19, d19, d20 ; m1 = max(m1, m2) 462 vmax.u8 d20, d21, d22 ; m2 = max(m3, m4) 463 464 vabd.u8 d25, d6, d4 ; m7 = abs(p0 - p2) 465 466 vmax.u8 d23, d23, d24 ; m3 = max(m5, m6) 467 468 vabd.u8 d26, d7, d17 ; m8 = abs(q0 - q2) 469 470 vmax.u8 d19, d19, d20 471 472 vabd.u8 d24, d6, d7 ; m9 = abs(p0 - q0) 473 vabd.u8 d27, d3, d6 ; m10 = abs(p3 - p0) 474 vabd.u8 d28, d18, d7 ; m11 = abs(q3 - q0) 475 476 vmax.u8 d19, d19, d23 477 478 vabd.u8 d23, d5, d16 ; a = abs(p1 - q1) 479 vqadd.u8 d24, d24, d24 ; b = abs(p0 - q0) * 2 480 481 ; abs () > limit 482 vcge.u8 d19, d1, d19 483 484 ; only compare the largest value to thresh 485 vmax.u8 d25, d25, d26 ; m4 = max(m7, m8) 486 vmax.u8 d26, d27, d28 ; m5 = max(m10, m11) 487 488 vshr.u8 d23, d23, #1 ; a = a / 2 489 490 vmax.u8 d25, d25, d26 ; m4 = max(m4, m5) 491 492 vqadd.u8 d24, d24, d23 ; a = b + a 493 494 vmax.u8 d20, d20, d25 ; m2 = max(m2, m4) 495 496 vmov.u8 d23, #1 497 vcge.u8 d24, d0, d24 ; a > blimit 498 499 vcgt.u8 d21, d21, d2 ; (abs(p1 - p0) > thresh)*-1 500 501 vcge.u8 d20, d23, d20 ; flat 502 503 vand d19, d19, d24 ; mask 504 505 vcgt.u8 d23, d22, d2 ; (abs(q1 - q0) > thresh)*-1 506 507 vand d20, d20, d19 ; flat & mask 508 509 vmov.u8 d22, #0x80 510 511 vorr d23, d21, d23 ; hev 512 513 ; This instruction will truncate the "flat & mask" masks down to 4 bits 514 ; each to fit into one 32 bit arm register. The values are stored in 515 ; q10.64[0]. 516 vshrn.u16 d30, q10, #4 517 vmov.u32 r4, d30[0] ; flat & mask 4bits 518 519 adds r5, r4, #1 ; Check for all 1's 520 521 ; If mask and flat are 1's for all vectors, then we only need to execute 522 ; the power branch for all vectors. 523 beq power_branch_only 524 525 cmp r4, #0 ; Check for 0, set flag for later 526 527 ; mbfilter() function 528 ; filter() function 529 ; convert to signed 530 veor d21, d7, d22 ; qs0 531 veor d24, d6, d22 ; ps0 532 veor d25, d5, d22 ; ps1 533 veor d26, d16, d22 ; qs1 534 535 vmov.u8 d27, #3 536 537 vsub.s8 d28, d21, d24 ; ( qs0 - ps0) 538 539 vqsub.s8 d29, d25, d26 ; filter = clamp(ps1-qs1) 540 541 vmull.s8 q15, d28, d27 ; 3 * ( qs0 - ps0) 542 543 vand d29, d29, d23 ; filter &= hev 544 545 vaddw.s8 q15, q15, d29 ; filter + 3 * (qs0 - ps0) 546 547 vmov.u8 d29, #4 548 549 ; filter = clamp(filter + 3 * ( qs0 - ps0)) 550 vqmovn.s16 d28, q15 551 552 vand d28, d28, d19 ; filter &= mask 553 554 vqadd.s8 d30, d28, d27 ; filter2 = clamp(filter+3) 555 vqadd.s8 d29, d28, d29 ; filter1 = clamp(filter+4) 556 vshr.s8 d30, d30, #3 ; filter2 >>= 3 557 vshr.s8 d29, d29, #3 ; filter1 >>= 3 558 559 vqadd.s8 d24, d24, d30 ; op0 = clamp(ps0 + filter2) 560 vqsub.s8 d21, d21, d29 ; oq0 = clamp(qs0 - filter1) 561 562 ; outer tap adjustments: ++filter1 >> 1 563 vrshr.s8 d29, d29, #1 564 vbic d29, d29, d23 ; filter &= ~hev 565 566 vqadd.s8 d25, d25, d29 ; op1 = clamp(ps1 + filter) 567 vqsub.s8 d26, d26, d29 ; oq1 = clamp(qs1 - filter) 568 569 ; If mask and flat are 0's for all vectors, then we only need to execute 570 ; the filter branch for all vectors. 571 beq filter_branch_only 572 573 ; If mask and flat are mixed then we must perform both branches and 574 ; combine the data. 575 veor d24, d24, d22 ; *f_op0 = u^0x80 576 veor d21, d21, d22 ; *f_oq0 = u^0x80 577 veor d25, d25, d22 ; *f_op1 = u^0x80 578 veor d26, d26, d22 ; *f_oq1 = u^0x80 579 580 ; At this point we have already executed the filter branch. The filter 581 ; branch does not set op2 or oq2, so use p2 and q2. Execute the power 582 ; branch and combine the data. 583 vmov.u8 d23, #2 584 vaddl.u8 q14, d6, d7 ; r_op2 = p0 + q0 585 vmlal.u8 q14, d3, d27 ; r_op2 += p3 * 3 586 vmlal.u8 q14, d4, d23 ; r_op2 += p2 * 2 587 588 vbif d0, d4, d20 ; op2 |= p2 & ~(flat & mask) 589 590 vaddw.u8 q14, d5 ; r_op2 += p1 591 592 vbif d1, d25, d20 ; op1 |= f_op1 & ~(flat & mask) 593 594 vqrshrn.u16 d30, q14, #3 ; r_op2 595 596 vsubw.u8 q14, d3 ; r_op1 = r_op2 - p3 597 vsubw.u8 q14, d4 ; r_op1 -= p2 598 vaddw.u8 q14, d5 ; r_op1 += p1 599 vaddw.u8 q14, d16 ; r_op1 += q1 600 601 vbif d2, d24, d20 ; op0 |= f_op0 & ~(flat & mask) 602 603 vqrshrn.u16 d31, q14, #3 ; r_op1 604 605 vsubw.u8 q14, d3 ; r_op0 = r_op1 - p3 606 vsubw.u8 q14, d5 ; r_op0 -= p1 607 vaddw.u8 q14, d6 ; r_op0 += p0 608 vaddw.u8 q14, d17 ; r_op0 += q2 609 610 vbit d0, d30, d20 ; op2 |= r_op2 & (flat & mask) 611 612 vqrshrn.u16 d23, q14, #3 ; r_op0 613 614 vsubw.u8 q14, d3 ; r_oq0 = r_op0 - p3 615 vsubw.u8 q14, d6 ; r_oq0 -= p0 616 vaddw.u8 q14, d7 ; r_oq0 += q0 617 618 vbit d1, d31, d20 ; op1 |= r_op1 & (flat & mask) 619 620 vaddw.u8 q14, d18 ; oq0 += q3 621 622 vbit d2, d23, d20 ; op0 |= r_op0 & (flat & mask) 623 624 vqrshrn.u16 d22, q14, #3 ; r_oq0 625 626 vsubw.u8 q14, d4 ; r_oq1 = r_oq0 - p2 627 vsubw.u8 q14, d7 ; r_oq1 -= q0 628 vaddw.u8 q14, d16 ; r_oq1 += q1 629 630 vbif d3, d21, d20 ; oq0 |= f_oq0 & ~(flat & mask) 631 632 vaddw.u8 q14, d18 ; r_oq1 += q3 633 634 vbif d4, d26, d20 ; oq1 |= f_oq1 & ~(flat & mask) 635 636 vqrshrn.u16 d6, q14, #3 ; r_oq1 637 638 vsubw.u8 q14, d5 ; r_oq2 = r_oq1 - p1 639 vsubw.u8 q14, d16 ; r_oq2 -= q1 640 vaddw.u8 q14, d17 ; r_oq2 += q2 641 vaddw.u8 q14, d18 ; r_oq2 += q3 642 643 vbif d5, d17, d20 ; oq2 |= q2 & ~(flat & mask) 644 645 vqrshrn.u16 d7, q14, #3 ; r_oq2 646 647 vbit d3, d22, d20 ; oq0 |= r_oq0 & (flat & mask) 648 vbit d4, d6, d20 ; oq1 |= r_oq1 & (flat & mask) 649 vbit d5, d7, d20 ; oq2 |= r_oq2 & (flat & mask) 650 651 bx lr 652 653power_branch_only 654 vmov.u8 d27, #3 655 vmov.u8 d21, #2 656 vaddl.u8 q14, d6, d7 ; op2 = p0 + q0 657 vmlal.u8 q14, d3, d27 ; op2 += p3 * 3 658 vmlal.u8 q14, d4, d21 ; op2 += p2 * 2 659 vaddw.u8 q14, d5 ; op2 += p1 660 vqrshrn.u16 d0, q14, #3 ; op2 661 662 vsubw.u8 q14, d3 ; op1 = op2 - p3 663 vsubw.u8 q14, d4 ; op1 -= p2 664 vaddw.u8 q14, d5 ; op1 += p1 665 vaddw.u8 q14, d16 ; op1 += q1 666 vqrshrn.u16 d1, q14, #3 ; op1 667 668 vsubw.u8 q14, d3 ; op0 = op1 - p3 669 vsubw.u8 q14, d5 ; op0 -= p1 670 vaddw.u8 q14, d6 ; op0 += p0 671 vaddw.u8 q14, d17 ; op0 += q2 672 vqrshrn.u16 d2, q14, #3 ; op0 673 674 vsubw.u8 q14, d3 ; oq0 = op0 - p3 675 vsubw.u8 q14, d6 ; oq0 -= p0 676 vaddw.u8 q14, d7 ; oq0 += q0 677 vaddw.u8 q14, d18 ; oq0 += q3 678 vqrshrn.u16 d3, q14, #3 ; oq0 679 680 vsubw.u8 q14, d4 ; oq1 = oq0 - p2 681 vsubw.u8 q14, d7 ; oq1 -= q0 682 vaddw.u8 q14, d16 ; oq1 += q1 683 vaddw.u8 q14, d18 ; oq1 += q3 684 vqrshrn.u16 d4, q14, #3 ; oq1 685 686 vsubw.u8 q14, d5 ; oq2 = oq1 - p1 687 vsubw.u8 q14, d16 ; oq2 -= q1 688 vaddw.u8 q14, d17 ; oq2 += q2 689 vaddw.u8 q14, d18 ; oq2 += q3 690 vqrshrn.u16 d5, q14, #3 ; oq2 691 692 bx lr 693 694filter_branch_only 695 ; TODO(fgalligan): See if we can rearange registers so we do not need to 696 ; do the 2 vswp. 697 vswp d0, d4 ; op2 698 vswp d5, d17 ; oq2 699 veor d2, d24, d22 ; *op0 = u^0x80 700 veor d3, d21, d22 ; *oq0 = u^0x80 701 veor d1, d25, d22 ; *op1 = u^0x80 702 veor d4, d26, d22 ; *oq1 = u^0x80 703 704 bx lr 705 706 ENDP ; |vp9_mbloop_filter_neon| 707 708 END 709