binop-divrem-with-constant-arm64-ion-codegen.js (19931B)
1 // |jit-test| skip-if: !hasDisassembler() || wasmCompileMode() != "ion" || !getBuildConfiguration("arm64"); include:codegen-arm64-test.js 2 3 const WasmTrapIns = `dcps0 \\{#0x0\\} \\(Wasm Trap\\)`; 4 5 // Signed 32-bit division with constants. 6 const i32_div_s = [ 7 // Division by zero. 8 { 9 divisor: 0, 10 expected: `mov w2, w0 11 mov w1, w2 12 ${WasmTrapIns}`, 13 }, 14 15 // Power of two divisor 16 { 17 divisor: 1, 18 expected: `mov w2, w0 19 mov w1, w2 20 mov w0, w1`, 21 }, 22 { 23 divisor: 2, 24 expected: `mov w2, w0 25 mov w1, w2 26 lsr w0, w1, #31 27 add w0, w0, w1 28 asr w0, w0, #1`, 29 }, 30 { 31 divisor: 4, 32 expected: `mov w2, w0 33 mov w1, w2 34 asr w0, w1, #31 35 lsr w0, w0, #30 36 add w0, w0, w1 37 asr w0, w0, #2`, 38 }, 39 40 // Division by -1 needs an overflow check. 41 { 42 divisor: -1, 43 expected: `mov w2, w0 44 mov w1, w2 45 negs w0, w1 46 b.vc #\\+0x8 \\(addr 0x${HEX}+\\) 47 ${WasmTrapIns}`, 48 }, 49 50 // Other divisors. 51 { 52 divisor: 3, 53 expected: `mov w2, w0 54 mov w1, w2 55 mov w16, #0x5556 56 movk w16, #0x5555, lsl #16 57 smull x0, w16, w1 58 asr x0, x0, #32 59 sub w0, w0, w1, asr #31`, 60 }, 61 { 62 divisor: 5, 63 expected: `mov w2, w0 64 mov w1, w2 65 mov w16, #0x6667 66 movk w16, #0x6666, lsl #16 67 smull x0, w16, w1 68 asr x0, x0, #33 69 sub w0, w0, w1, asr #31`, 70 }, 71 { 72 divisor: 7, 73 expected: `mov w2, w0 74 mov w1, w2 75 mov w16, #0x2493 76 movk w16, #0x9249, lsl #16 77 lsl x0, x1, #32 78 smaddl x0, w16, w1, x0 79 asr x0, x0, #34 80 sub w0, w0, w1, asr #31`, 81 }, 82 { 83 divisor: 9, 84 expected: `mov w2, w0 85 mov w1, w2 86 mov w16, #0x8e39 87 movk w16, #0x38e3, lsl #16 88 smull x0, w16, w1 89 asr x0, x0, #33 90 sub w0, w0, w1, asr #31`, 91 }, 92 ]; 93 94 for (let {divisor, expected} of i32_div_s) { 95 let divs32 = 96 `(module 97 (func (export "f") (param i32) (result i32) 98 (i32.div_s (local.get 0) (i32.const ${divisor}))))` 99 codegenTestARM64_adhoc(divs32, 'f', expected); 100 101 // Test negative divisors, too. 102 if (divisor > 1) { 103 let divs32 = 104 `(module 105 (func (export "f") (param i32) (result i32) 106 (i32.div_s (local.get 0) (i32.const -${divisor}))))` 107 codegenTestARM64_adhoc(divs32, 'f', expected + ` 108 neg w0, w0` 109 ); 110 } 111 } 112 113 // Unsigned 32-bit division with constants. 114 const i32_div_u = [ 115 // Division by zero. 116 { 117 divisor: 0, 118 expected: `mov w2, w0 119 mov w1, w2 120 ${WasmTrapIns}`, 121 }, 122 123 // Power of two divisor 124 { 125 divisor: 1, 126 expected: `mov w2, w0 127 mov w1, w2 128 mov w0, w1`, 129 }, 130 { 131 divisor: 2, 132 expected: `mov w2, w0 133 mov w1, w2 134 lsr w0, w1, #1`, 135 }, 136 { 137 divisor: 4, 138 expected: `mov w2, w0 139 mov w1, w2 140 lsr w0, w1, #2`, 141 }, 142 143 // Other divisors. 144 { 145 divisor: 3, 146 expected: `mov w2, w0 147 mov w1, w2 148 mov w16, #0xaaab 149 movk w16, #0xaaaa, lsl #16 150 umull x0, w16, w1 151 lsr x0, x0, #33`, 152 }, 153 { 154 divisor: 5, 155 expected: `mov w2, w0 156 mov w1, w2 157 mov w16, #0xcccd 158 movk w16, #0xcccc, lsl #16 159 umull x0, w16, w1 160 lsr x0, x0, #34`, 161 }, 162 { 163 divisor: 7, 164 expected: `mov w2, w0 165 mov w1, w2 166 mov w16, #0x4925 167 movk w16, #0x2492, lsl #16 168 umull x0, w16, w1 169 add x0, x1, x0, lsr #32 170 lsr x0, x0, #3`, 171 }, 172 { 173 divisor: 9, 174 expected: `mov w2, w0 175 mov w1, w2 176 mov w16, #0x8e39 177 movk w16, #0x38e3, lsl #16 178 umull x0, w16, w1 179 lsr x0, x0, #33`, 180 }, 181 182 // Special case: Zero (additional) shift amount. 183 { 184 divisor: 641, 185 expected: `mov w2, w0 186 mov w1, w2 187 mov w16, #0x3d81 188 movk w16, #0x66, lsl #16 189 umull x0, w16, w1 190 lsr x0, x0, #32`, 191 }, 192 ]; 193 194 for (let {divisor, expected} of i32_div_u) { 195 let divu32 = 196 `(module 197 (func (export "f") (param i32) (result i32) 198 (i32.div_u (local.get 0) (i32.const ${divisor}))))` 199 codegenTestARM64_adhoc(divu32, 'f', expected); 200 } 201 202 // Signed 64-bit division with constants. 203 const i64_div_s = [ 204 // Division by zero. 205 { 206 divisor: 0, 207 expected: `mov x2, x0 208 mov x1, x2 209 ${WasmTrapIns}`, 210 }, 211 212 // Power of two divisor 213 { 214 divisor: 1, 215 expected: `mov x2, x0 216 mov x1, x2 217 mov x0, x1`, 218 }, 219 { 220 divisor: 2, 221 expected: `mov x2, x0 222 mov x1, x2 223 lsr x0, x1, #63 224 add x0, x0, x1 225 asr x0, x0, #1`, 226 }, 227 { 228 divisor: 4, 229 expected: `mov x2, x0 230 mov x1, x2 231 asr x0, x1, #63 232 lsr x0, x0, #62 233 add x0, x0, x1 234 asr x0, x0, #2`, 235 }, 236 { 237 divisor: 0x1_0000_0000, 238 expected: `mov x2, x0 239 mov x1, x2 240 asr x0, x1, #63 241 lsr x0, x0, #32 242 add x0, x0, x1 243 asr x0, x0, #32`, 244 }, 245 246 // Division by -1 needs an overflow check. 247 { 248 divisor: -1, 249 expected: `mov x2, x0 250 mov x1, x2 251 negs x0, x1 252 b.vc #\\+0x8 \\(addr 0x${HEX}+\\) 253 ${WasmTrapIns}`, 254 }, 255 256 // Other divisors. 257 { 258 divisor: 3, 259 expected: `mov x2, x0 260 mov x1, x2 261 mov x16, #0x5556 262 movk x16, #0x5555, lsl #16 263 movk x16, #0x5555, lsl #32 264 movk x16, #0x5555, lsl #48 265 smulh x0, x1, x16 266 sbfx x0, x0, #0, #64 267 sub x0, x0, x1, asr #63`, 268 }, 269 { 270 divisor: 5, 271 expected: `mov x2, x0 272 mov x1, x2 273 mov x16, #0x6667 274 movk x16, #0x6666, lsl #16 275 movk x16, #0x6666, lsl #32 276 movk x16, #0x6666, lsl #48 277 smulh x0, x1, x16 278 asr x0, x0, #1 279 sub x0, x0, x1, asr #63`, 280 }, 281 { 282 divisor: 7, 283 expected: `mov x2, x0 284 mov x1, x2 285 mov x16, #0x4925 286 movk x16, #0x2492, lsl #16 287 movk x16, #0x9249, lsl #32 288 movk x16, #0x4924, lsl #48 289 smulh x0, x1, x16 290 asr x0, x0, #1 291 sub x0, x0, x1, asr #63`, 292 }, 293 { 294 divisor: 9, 295 expected: `mov x2, x0 296 mov x1, x2 297 mov x16, #0x1c72 298 movk x16, #0x71c7, lsl #16 299 movk x16, #0xc71c, lsl #32 300 movk x16, #0x1c71, lsl #48 301 smulh x0, x1, x16 302 sbfx x0, x0, #0, #64 303 sub x0, x0, x1, asr #63`, 304 }, 305 ]; 306 307 for (let {divisor, expected} of i64_div_s) { 308 let divs64 = 309 `(module 310 (func (export "f") (param i64) (result i64) 311 (i64.div_s (local.get 0) (i64.const ${divisor}))))` 312 codegenTestARM64_adhoc(divs64, 'f', expected); 313 314 // Test negative divisors, too. 315 if (divisor > 1) { 316 let divs64 = 317 `(module 318 (func (export "f") (param i64) (result i64) 319 (i64.div_s (local.get 0) (i64.const -${divisor}))))` 320 codegenTestARM64_adhoc(divs64, 'f', expected + ` 321 neg x0, x0`); 322 } 323 } 324 325 // Unsigned 64-bit division with constants. 326 const i64_div_u = [ 327 // Division by zero. 328 { 329 divisor: 0, 330 expected: `mov x2, x0 331 mov x1, x2 332 ${WasmTrapIns}`, 333 }, 334 335 // Power of two divisor 336 { 337 divisor: 1, 338 expected: `mov x2, x0 339 mov x1, x2 340 mov x0, x1`, 341 }, 342 { 343 divisor: 2, 344 expected: `mov x2, x0 345 mov x1, x2 346 lsr x0, x1, #1`, 347 }, 348 { 349 divisor: 4, 350 expected: `mov x2, x0 351 mov x1, x2 352 lsr x0, x1, #2`, 353 }, 354 { 355 divisor: 0x1_0000_0000, 356 expected: `mov x2, x0 357 mov x1, x2 358 lsr x0, x1, #32`, 359 }, 360 361 // Other divisors. 362 { 363 divisor: 3, 364 expected: `mov x2, x0 365 mov x1, x2 366 mov x16, #0xaaab 367 movk x16, #0xaaaa, lsl #16 368 movk x16, #0xaaaa, lsl #32 369 movk x16, #0xaaaa, lsl #48 370 umulh x0, x1, x16 371 lsr x0, x0, #1`, 372 }, 373 { 374 divisor: 5, 375 expected: `mov x2, x0 376 mov x1, x2 377 mov x16, #0xcccd 378 movk x16, #0xcccc, lsl #16 379 movk x16, #0xcccc, lsl #32 380 movk x16, #0xcccc, lsl #48 381 umulh x0, x1, x16 382 lsr x0, x0, #2`, 383 }, 384 { 385 divisor: 7, 386 expected: `mov x2, x0 387 mov x1, x2 388 mov x16, #0x2493 389 movk x16, #0x9249, lsl #16 390 movk x16, #0x4924, lsl #32 391 movk x16, #0x2492, lsl #48 392 umulh x0, x1, x16 393 sub x16, x1, x0 394 add x0, x0, x16, lsr #1 395 lsr x0, x0, #2`, 396 }, 397 { 398 divisor: 9, 399 expected: `mov x2, x0 400 mov x1, x2 401 mov x16, #0xe38f 402 movk x16, #0x8e38, lsl #16 403 movk x16, #0x38e3, lsl #32 404 movk x16, #0xe38e, lsl #48 405 umulh x0, x1, x16 406 lsr x0, x0, #3`, 407 }, 408 409 // Special case: Zero shift amount. 410 { 411 divisor: 274177, 412 expected: `mov x2, x0 413 mov x1, x2 414 mov x16, #0xd101 415 movk x16, #0xf19c, lsl #16 416 movk x16, #0x3d30, lsl #32 417 umulh x0, x1, x16 418 lsr x0, x0, #0`, 419 }, 420 ]; 421 422 for (let {divisor, expected} of i64_div_u) { 423 let divu64 = 424 `(module 425 (func (export "f") (param i64) (result i64) 426 (i64.div_u (local.get 0) (i64.const ${divisor}))))` 427 codegenTestARM64_adhoc(divu64, 'f', expected); 428 } 429 430 ////////////// 431 432 433 434 // Signed 32-bit remainder with constants. 435 const i32_rem_s = [ 436 // Division by zero. 437 { 438 divisor: 0, 439 expected: `mov w2, w0 440 mov w1, w2 441 ${WasmTrapIns}`, 442 }, 443 444 // Power of two divisor 445 { 446 divisor: 1, 447 expected: `mov w2, w0 448 mov w1, w2 449 mov w0, wzr`, 450 }, 451 { 452 divisor: 2, 453 expected: `mov w2, w0 454 mov w1, w2 455 tst w1, w1 456 b.mi #\\+0xc \\(addr 0x${HEX}+\\) 457 and w0, w1, #0x1 458 b #\\+0x10 \\(addr 0x${HEX}+\\) 459 neg w0, w1 460 and w0, w0, #0x1 461 neg w0, w0`, 462 }, 463 { 464 divisor: 4, 465 expected: `mov w2, w0 466 mov w1, w2 467 tst w1, w1 468 b.mi #\\+0xc \\(addr 0x${HEX}+\\) 469 and w0, w1, #0x3 470 b #\\+0x10 \\(addr 0x${HEX}+\\) 471 neg w0, w1 472 and w0, w0, #0x3 473 neg w0, w0`, 474 }, 475 { 476 divisor: 0x100, 477 expected: `mov w2, w0 478 mov w1, w2 479 tst w1, w1 480 b.mi #\\+0xc \\(addr 0x${HEX}+\\) 481 and w0, w1, #0xff 482 b #\\+0x10 \\(addr 0x${HEX}+\\) 483 neg w0, w1 484 and w0, w0, #0xff 485 neg w0, w0`, 486 }, 487 { 488 divisor: 0x10000, 489 expected: `mov w2, w0 490 mov w1, w2 491 tst w1, w1 492 b.mi #\\+0xc \\(addr 0x${HEX}+\\) 493 and w0, w1, #0xffff 494 b #\\+0x10 \\(addr 0x${HEX}+\\) 495 neg w0, w1 496 and w0, w0, #0xffff 497 neg w0, w0`, 498 }, 499 { 500 divisor: 0x8000_0000, 501 expected: `mov w2, w0 502 mov w1, w2 503 tst w1, w1 504 b.mi #\\+0xc \\(addr 0x${HEX}+\\) 505 and w0, w1, #0x7fffffff 506 b #\\+0x10 \\(addr 0x${HEX}+\\) 507 neg w0, w1 508 and w0, w0, #0x7fffffff 509 neg w0, w0`, 510 }, 511 ]; 512 513 for (let {divisor, expected} of i32_rem_s) { 514 let rems32 = 515 `(module 516 (func (export "f") (param i32) (result i32) 517 (i32.rem_s (local.get 0) (i32.const ${divisor}))))` 518 codegenTestARM64_adhoc(rems32, 'f', expected); 519 520 // Test negative divisors, too. 521 if (divisor > 0) { 522 let rems32 = 523 `(module 524 (func (export "f") (param i32) (result i32) 525 (i32.rem_s (local.get 0) (i32.const -${divisor}))))` 526 codegenTestARM64_adhoc(rems32, 'f', expected); 527 } 528 } 529 530 // Unigned 32-bit remainder with constants. 531 const u32_rem_s = [ 532 // Division by zero. 533 { 534 divisor: 0, 535 expected: `mov w2, w0 536 mov w1, w2 537 ${WasmTrapIns}`, 538 }, 539 540 // Power of two divisor 541 { 542 divisor: 1, 543 expected: `mov w2, w0 544 mov w1, w2 545 mov w0, wzr`, 546 }, 547 { 548 divisor: 2, 549 expected: `mov w2, w0 550 mov w1, w2 551 and w0, w1, #0x1`, 552 }, 553 { 554 divisor: 4, 555 expected: `mov w2, w0 556 mov w1, w2 557 and w0, w1, #0x3`, 558 }, 559 { 560 divisor: 0x100, 561 expected: `mov w2, w0 562 mov w1, w2 563 and w0, w1, #0xff`, 564 }, 565 { 566 divisor: 0x10000, 567 expected: `mov w2, w0 568 mov w1, w2 569 and w0, w1, #0xffff`, 570 }, 571 { 572 divisor: 0x8000_0000, 573 expected: `mov w2, w0 574 mov w1, w2 575 and w0, w1, #0x7fffffff`, 576 }, 577 ]; 578 579 for (let {divisor, expected} of u32_rem_s) { 580 let remu32 = 581 `(module 582 (func (export "f") (param i32) (result i32) 583 (i32.rem_u (local.get 0) (i32.const ${divisor}))))` 584 codegenTestARM64_adhoc(remu32, 'f', expected); 585 } 586 587 // Signed 64-bit remainder with constants. 588 const i64_rem_s = [ 589 // Division by zero. 590 { 591 divisor: 0, 592 expected: `mov x2, x0 593 mov x1, x2 594 ${WasmTrapIns}`, 595 }, 596 597 // Power of two divisor 598 { 599 divisor: 1, 600 expected: `mov x2, x0 601 mov x1, x2 602 mov x0, xzr`, 603 }, 604 { 605 divisor: 2, 606 expected: `mov x2, x0 607 mov x1, x2 608 tst x1, x1 609 b.mi #\\+0xc \\(addr 0x${HEX}+\\) 610 and x0, x1, #0x1 611 b #\\+0x10 \\(addr 0x${HEX}+\\) 612 neg x0, x1 613 and x0, x0, #0x1 614 neg x0, x0`, 615 }, 616 { 617 divisor: 4, 618 expected: `mov x2, x0 619 mov x1, x2 620 tst x1, x1 621 b.mi #\\+0xc \\(addr 0x${HEX}+\\) 622 and x0, x1, #0x3 623 b #\\+0x10 \\(addr 0x${HEX}+\\) 624 neg x0, x1 625 and x0, x0, #0x3 626 neg x0, x0`, 627 }, 628 { 629 divisor: 0x100, 630 expected: `mov x2, x0 631 mov x1, x2 632 tst x1, x1 633 b.mi #\\+0xc \\(addr 0x${HEX}+\\) 634 and x0, x1, #0xff 635 b #\\+0x10 \\(addr 0x${HEX}+\\) 636 neg x0, x1 637 and x0, x0, #0xff 638 neg x0, x0`, 639 }, 640 { 641 divisor: 0x10000, 642 expected: `mov x2, x0 643 mov x1, x2 644 tst x1, x1 645 b.mi #\\+0xc \\(addr 0x${HEX}+\\) 646 and x0, x1, #0xffff 647 b #\\+0x10 \\(addr 0x${HEX}+\\) 648 neg x0, x1 649 and x0, x0, #0xffff 650 neg x0, x0`, 651 }, 652 { 653 divisor: 0x8000_0000, 654 expected: `mov x2, x0 655 mov x1, x2 656 tst x1, x1 657 b.mi #\\+0xc \\(addr 0x${HEX}+\\) 658 and x0, x1, #0x7fffffff 659 b #\\+0x10 \\(addr 0x${HEX}+\\) 660 neg x0, x1 661 and x0, x0, #0x7fffffff 662 neg x0, x0`, 663 }, 664 { 665 divisor: 0x1_0000_0000, 666 expected: `mov x2, x0 667 mov x1, x2 668 tst x1, x1 669 b.mi #\\+0xc \\(addr 0x${HEX}+\\) 670 mov w0, w1 671 b #\\+0x10 \\(addr 0x${HEX}+\\) 672 neg x0, x1 673 mov w0, w0 674 neg x0, x0`, 675 }, 676 { 677 divisor: 0x8000_0000_0000_0000n, 678 expected: `mov x2, x0 679 mov x1, x2 680 tst x1, x1 681 b.mi #\\+0xc \\(addr 0x${HEX}+\\) 682 and x0, x1, #0x7fffffffffffffff 683 b #\\+0x10 \\(addr 0x${HEX}+\\) 684 neg x0, x1 685 and x0, x0, #0x7fffffffffffffff 686 neg x0, x0`, 687 }, 688 ]; 689 690 for (let {divisor, expected} of i64_rem_s) { 691 let rems64 = 692 `(module 693 (func (export "f") (param i64) (result i64) 694 (i64.rem_s (local.get 0) (i64.const ${divisor}))))` 695 codegenTestARM64_adhoc(rems64, 'f', expected); 696 697 // Test negative divisors, too. 698 if (divisor > 0) { 699 let rems64 = 700 `(module 701 (func (export "f") (param i64) (result i64) 702 (i64.rem_s (local.get 0) (i64.const -${divisor}))))` 703 codegenTestARM64_adhoc(rems64, 'f', expected); 704 } 705 } 706 707 // Unsigned 64-bit remainder with constants. 708 const i64_rem_u = [ 709 // Division by zero. 710 { 711 divisor: 0, 712 expected: `mov x2, x0 713 mov x1, x2 714 ${WasmTrapIns}`, 715 }, 716 717 // Power of two divisor 718 { 719 divisor: 1, 720 expected: `mov x2, x0 721 mov x1, x2 722 mov x0, xzr`, 723 }, 724 { 725 divisor: 2, 726 expected: `mov x2, x0 727 mov x1, x2 728 and x0, x1, #0x1`, 729 }, 730 { 731 divisor: 4, 732 expected: `mov x2, x0 733 mov x1, x2 734 and x0, x1, #0x3`, 735 }, 736 { 737 divisor: 0x100, 738 expected: `mov x2, x0 739 mov x1, x2 740 and x0, x1, #0xff`, 741 }, 742 { 743 divisor: 0x10000, 744 expected: `mov x2, x0 745 mov x1, x2 746 and x0, x1, #0xffff`, 747 }, 748 { 749 divisor: 0x8000_0000, 750 expected: `mov x2, x0 751 mov x1, x2 752 and x0, x1, #0x7fffffff`, 753 }, 754 { 755 divisor: 0x1_0000_0000, 756 expected: `mov x2, x0 757 mov x1, x2 758 mov w0, w1`, 759 }, 760 { 761 divisor: 0x8000_0000_0000_0000n, 762 expected: `mov x2, x0 763 mov x1, x2 764 and x0, x1, #0x7fffffffffffffff`, 765 }, 766 ]; 767 768 for (let {divisor, expected} of i64_rem_u) { 769 let remu64 = 770 `(module 771 (func (export "f") (param i64) (result i64) 772 (i64.rem_u (local.get 0) (i64.const ${divisor}))))` 773 codegenTestARM64_adhoc(remu64, 'f', expected); 774 }