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