Source/JavaScriptCore/ChangeLog

 12021-07-30 Yijia Huang <yijia_huang@apple.com>
 2
 3 Add new patternes to instruction selector to utilize AND/EOR/ORR-with-shift and UMULL supported by ARM64
 4 https://bugs.webkit.org/show_bug.cgi?id=228675
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 * assembler/MacroAssemblerARM64.h:
 9 (JSC::MacroAssemblerARM64::andLeftShift32):
 10 (JSC::MacroAssemblerARM64::andRightShift32):
 11 (JSC::MacroAssemblerARM64::andUnsignedRightShift32):
 12 (JSC::MacroAssemblerARM64::andLeftShift64):
 13 (JSC::MacroAssemblerARM64::andRightShift64):
 14 (JSC::MacroAssemblerARM64::andUnsignedRightShift64):
 15 (JSC::MacroAssemblerARM64::xorLeftShift32):
 16 (JSC::MacroAssemblerARM64::xorRightShift32):
 17 (JSC::MacroAssemblerARM64::xorUnsignedRightShift32):
 18 (JSC::MacroAssemblerARM64::xorLeftShift64):
 19 (JSC::MacroAssemblerARM64::xorRightShift64):
 20 (JSC::MacroAssemblerARM64::xorUnsignedRightShift64):
 21 (JSC::MacroAssemblerARM64::orLeftShift32):
 22 (JSC::MacroAssemblerARM64::orRightShift32):
 23 (JSC::MacroAssemblerARM64::orUnsignedRightShift32):
 24 (JSC::MacroAssemblerARM64::orLeftShift64):
 25 (JSC::MacroAssemblerARM64::orRightShift64):
 26 (JSC::MacroAssemblerARM64::orUnsignedRightShift64):
 27 (JSC::MacroAssemblerARM64::multiplyZeroExtend32):
 28 * assembler/testmasm.cpp:
 29 (JSC::testMultiplyZeroExtend32):
 30 (JSC::testAndLeftShift32):
 31 (JSC::testAndRightShift32):
 32 (JSC::testAndUnsignedRightShift32):
 33 (JSC::testAndLeftShift64):
 34 (JSC::testAndRightShift64):
 35 (JSC::testAndUnsignedRightShift64):
 36 (JSC::testXorLeftShift32):
 37 (JSC::testXorRightShift32):
 38 (JSC::testXorUnsignedRightShift32):
 39 (JSC::testXorLeftShift64):
 40 (JSC::testXorRightShift64):
 41 (JSC::testXorUnsignedRightShift64):
 42 (JSC::testOrLeftShift32):
 43 (JSC::testOrRightShift32):
 44 (JSC::testOrUnsignedRightShift32):
 45 (JSC::testOrLeftShift64):
 46 (JSC::testOrRightShift64):
 47 (JSC::testOrUnsignedRightShift64):
 48 * b3/B3LowerToAir.cpp:
 49 * b3/air/AirOpcode.opcodes:
 50 * b3/testb3.h:
 51 * b3/testb3_2.cpp:
 52 (testMulArgs32SignExtend):
 53 (testMulArgs32ZeroExtend):
 54 (testAndLeftShift32):
 55 (testAndRightShift32):
 56 (testAndUnsignedRightShift32):
 57 (testAndLeftShift64):
 58 (testAndRightShift64):
 59 (testAndUnsignedRightShift64):
 60 (testXorLeftShift32):
 61 (testXorRightShift32):
 62 (testXorUnsignedRightShift32):
 63 (testXorLeftShift64):
 64 (testXorRightShift64):
 65 (testXorUnsignedRightShift64):
 66 (testOrLeftShift32):
 67 (testOrRightShift32):
 68 (testOrUnsignedRightShift32):
 69 (testOrLeftShift64):
 70 (testOrRightShift64):
 71 (testOrUnsignedRightShift64):
 72 (testBitAndZeroShiftRightArgImmMask32):
 73 (testBitAndZeroShiftRightArgImmMask64):
 74 (testBitAndArgs):
 75 (testBitAndSameArg):
 76 (testBitAndNotNot):
 77 (testBitAndNotNot32):
 78 (testBitAndNotImm):
 79 (testBitAndNotImm32):
 80 (addBitTests):
 81 * b3/testb3_3.cpp:
 82 (addArgTests):
 83
1842021-07-30 Yijia Huang <yijia_huang@apple.com>
285
386 Add Pre/Post-Indexed Address Mode to Air for ARM64

Source/JavaScriptCore/assembler/MacroAssemblerARM64.h

@@public:
649649 m_assembler.sub<64>(d, n, m, Assembler::LSR, amount.m_value);
650650 }
651651
 652 void andLeftShift32(RegisterID n, RegisterID m, TrustedImm32 amount, RegisterID d)
 653 {
 654 m_assembler.and_<32>(d, n, m, Assembler::LSL, amount.m_value);
 655 }
 656
 657 void andRightShift32(RegisterID n, RegisterID m, TrustedImm32 amount, RegisterID d)
 658 {
 659 m_assembler.and_<32>(d, n, m, Assembler::ASR, amount.m_value);
 660 }
 661
 662 void andUnsignedRightShift32(RegisterID n, RegisterID m, TrustedImm32 amount, RegisterID d)
 663 {
 664 m_assembler.and_<32>(d, n, m, Assembler::LSR, amount.m_value);
 665 }
 666
 667 void andLeftShift64(RegisterID n, RegisterID m, TrustedImm32 amount, RegisterID d)
 668 {
 669 m_assembler.and_<64>(d, n, m, Assembler::LSL, amount.m_value);
 670 }
 671
 672 void andRightShift64(RegisterID n, RegisterID m, TrustedImm32 amount, RegisterID d)
 673 {
 674 m_assembler.and_<64>(d, n, m, Assembler::ASR, amount.m_value);
 675 }
 676
 677 void andUnsignedRightShift64(RegisterID n, RegisterID m, TrustedImm32 amount, RegisterID d)
 678 {
 679 m_assembler.and_<64>(d, n, m, Assembler::LSR, amount.m_value);
 680 }
 681
 682 void xorLeftShift32(RegisterID n, RegisterID m, TrustedImm32 amount, RegisterID d)
 683 {
 684 m_assembler.eor<32>(d, n, m, Assembler::LSL, amount.m_value);
 685 }
 686
 687 void xorRightShift32(RegisterID n, RegisterID m, TrustedImm32 amount, RegisterID d)
 688 {
 689 m_assembler.eor<32>(d, n, m, Assembler::ASR, amount.m_value);
 690 }
 691
 692 void xorUnsignedRightShift32(RegisterID n, RegisterID m, TrustedImm32 amount, RegisterID d)
 693 {
 694 m_assembler.eor<32>(d, n, m, Assembler::LSR, amount.m_value);
 695 }
 696
 697 void xorLeftShift64(RegisterID n, RegisterID m, TrustedImm32 amount, RegisterID d)
 698 {
 699 m_assembler.eor<64>(d, n, m, Assembler::LSL, amount.m_value);
 700 }
 701
 702 void xorRightShift64(RegisterID n, RegisterID m, TrustedImm32 amount, RegisterID d)
 703 {
 704 m_assembler.eor<64>(d, n, m, Assembler::ASR, amount.m_value);
 705 }
 706
 707 void xorUnsignedRightShift64(RegisterID n, RegisterID m, TrustedImm32 amount, RegisterID d)
 708 {
 709 m_assembler.eor<64>(d, n, m, Assembler::LSR, amount.m_value);
 710 }
 711
 712 void orLeftShift32(RegisterID n, RegisterID m, TrustedImm32 amount, RegisterID d)
 713 {
 714 m_assembler.orr<32>(d, n, m, Assembler::LSL, amount.m_value);
 715 }
 716
 717 void orRightShift32(RegisterID n, RegisterID m, TrustedImm32 amount, RegisterID d)
 718 {
 719 m_assembler.orr<32>(d, n, m, Assembler::ASR, amount.m_value);
 720 }
 721
 722 void orUnsignedRightShift32(RegisterID n, RegisterID m, TrustedImm32 amount, RegisterID d)
 723 {
 724 m_assembler.orr<32>(d, n, m, Assembler::LSR, amount.m_value);
 725 }
 726
 727 void orLeftShift64(RegisterID n, RegisterID m, TrustedImm32 amount, RegisterID d)
 728 {
 729 m_assembler.orr<64>(d, n, m, Assembler::LSL, amount.m_value);
 730 }
 731
 732 void orRightShift64(RegisterID n, RegisterID m, TrustedImm32 amount, RegisterID d)
 733 {
 734 m_assembler.orr<64>(d, n, m, Assembler::ASR, amount.m_value);
 735 }
 736
 737 void orUnsignedRightShift64(RegisterID n, RegisterID m, TrustedImm32 amount, RegisterID d)
 738 {
 739 m_assembler.orr<64>(d, n, m, Assembler::LSR, amount.m_value);
 740 }
 741
652742 void clearBit64(RegisterID bitToClear, RegisterID dest, RegisterID scratchForMask = InvalidGPRReg)
653743 {
654744 if (scratchForMask == InvalidGPRReg)

@@public:
863953 m_assembler.smull(dest, left, right);
864954 }
865955
 956 void multiplyZeroExtend32(RegisterID left, RegisterID right, RegisterID dest)
 957 {
 958 m_assembler.umull(dest, left, right);
 959 }
 960
866961 void div32(RegisterID dividend, RegisterID divisor, RegisterID dest)
867962 {
868963 m_assembler.sdiv<32>(dest, dividend, divisor);

Source/JavaScriptCore/assembler/testmasm.cpp

@@void testMultiplySignExtend32()
921921 }
922922}
923923
 924void testMultiplyZeroExtend32()
 925{
 926 for (auto nOperand : int32Operands()) {
 927 auto mul = compile([=] (CCallHelpers& jit) {
 928 emitFunctionPrologue(jit);
 929
 930 jit.multiplyZeroExtend32(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1, GPRInfo::returnValueGPR);
 931
 932 emitFunctionEpilogue(jit);
 933 jit.ret();
 934 });
 935
 936 for (auto mOperand : int32Operands()) {
 937 uint32_t n = nOperand;
 938 uint32_t m = mOperand;
 939 CHECK_EQ(invoke<uint64_t>(mul, n, m), static_cast<uint64_t>(n) * static_cast<uint64_t>(m));
 940 }
 941 }
 942}
 943
924944void testMultiplyAddSignExtend32()
925945{
926946 // d = SExt32(n) * SExt32(m) + a

@@void testLoadPrePostIndex64()
23822402 CHECK_EQ(test2(5), 2);
23832403 CHECK_EQ(nums[2], 5);
23842404}
 2405
 2406void testAndLeftShift32()
 2407{
 2408 Vector<int32_t> amounts = { 0, 17, 31 };
 2409 for (auto n : int32Operands()) {
 2410 for (auto m : int32Operands()) {
 2411 for (auto amount : amounts) {
 2412 auto and32 = compile([=] (CCallHelpers& jit) {
 2413 emitFunctionPrologue(jit);
 2414
 2415 jit.andLeftShift32(GPRInfo::argumentGPR0,
 2416 GPRInfo::argumentGPR1,
 2417 CCallHelpers::TrustedImm32(amount),
 2418 GPRInfo::returnValueGPR);
 2419
 2420 emitFunctionEpilogue(jit);
 2421 jit.ret();
 2422 });
 2423
 2424 int32_t lhs = invoke<int32_t>(and32, n, m);
 2425 int32_t rhs = n & (m << amount);
 2426 CHECK_EQ(lhs, rhs);
 2427 }
 2428 }
 2429 }
 2430}
 2431
 2432void testAndRightShift32()
 2433{
 2434 Vector<int32_t> amounts = { 0, 17, 31 };
 2435 for (auto n : int32Operands()) {
 2436 for (auto m : int32Operands()) {
 2437 for (auto amount : amounts) {
 2438 auto and32 = compile([=] (CCallHelpers& jit) {
 2439 emitFunctionPrologue(jit);
 2440
 2441 jit.andRightShift32(GPRInfo::argumentGPR0,
 2442 GPRInfo::argumentGPR1,
 2443 CCallHelpers::TrustedImm32(amount),
 2444 GPRInfo::returnValueGPR);
 2445
 2446 emitFunctionEpilogue(jit);
 2447 jit.ret();
 2448 });
 2449
 2450 int32_t lhs = invoke<int32_t>(and32, n, m);
 2451 int32_t rhs = n & (m >> amount);
 2452 CHECK_EQ(lhs, rhs);
 2453 }
 2454 }
 2455 }
 2456}
 2457
 2458void testAndUnsignedRightShift32()
 2459{
 2460 Vector<uint32_t> amounts = { 0, 17, 31 };
 2461 for (auto n : int32Operands()) {
 2462 for (auto m : int32Operands()) {
 2463 for (auto amount : amounts) {
 2464 auto and32 = compile([=] (CCallHelpers& jit) {
 2465 emitFunctionPrologue(jit);
 2466
 2467 jit.andUnsignedRightShift32(GPRInfo::argumentGPR0,
 2468 GPRInfo::argumentGPR1,
 2469 CCallHelpers::TrustedImm32(amount),
 2470 GPRInfo::returnValueGPR);
 2471
 2472 emitFunctionEpilogue(jit);
 2473 jit.ret();
 2474 });
 2475
 2476 uint32_t lhs = invoke<uint32_t>(and32, n, m);
 2477 uint32_t rhs = static_cast<uint32_t>(n) & (static_cast<uint32_t>(m) >> amount);
 2478 CHECK_EQ(lhs, rhs);
 2479 }
 2480 }
 2481 }
 2482}
 2483
 2484void testAndLeftShift64()
 2485{
 2486 Vector<int32_t> amounts = { 0, 34, 63 };
 2487 for (auto n : int64Operands()) {
 2488 for (auto m : int64Operands()) {
 2489 for (auto amount : amounts) {
 2490 auto and64 = compile([=] (CCallHelpers& jit) {
 2491 emitFunctionPrologue(jit);
 2492
 2493 jit.andLeftShift64(GPRInfo::argumentGPR0,
 2494 GPRInfo::argumentGPR1,
 2495 CCallHelpers::TrustedImm32(amount),
 2496 GPRInfo::returnValueGPR);
 2497
 2498 emitFunctionEpilogue(jit);
 2499 jit.ret();
 2500 });
 2501
 2502 int64_t lhs = invoke<int64_t>(and64, n, m);
 2503 int64_t rhs = n & (m << amount);
 2504 CHECK_EQ(lhs, rhs);
 2505 }
 2506 }
 2507 }
 2508}
 2509
 2510void testAndRightShift64()
 2511{
 2512 Vector<int32_t> amounts = { 0, 34, 63 };
 2513 for (auto n : int64Operands()) {
 2514 for (auto m : int64Operands()) {
 2515 for (auto amount : amounts) {
 2516 auto and64 = compile([=] (CCallHelpers& jit) {
 2517 emitFunctionPrologue(jit);
 2518
 2519 jit.andRightShift64(GPRInfo::argumentGPR0,
 2520 GPRInfo::argumentGPR1,
 2521 CCallHelpers::TrustedImm32(amount),
 2522 GPRInfo::returnValueGPR);
 2523
 2524 emitFunctionEpilogue(jit);
 2525 jit.ret();
 2526 });
 2527
 2528 int64_t lhs = invoke<int64_t>(and64, n, m);
 2529 int64_t rhs = n & (m >> amount);
 2530 CHECK_EQ(lhs, rhs);
 2531 }
 2532 }
 2533 }
 2534}
 2535
 2536void testAndUnsignedRightShift64()
 2537{
 2538 Vector<uint32_t> amounts = { 0, 34, 63 };
 2539 for (auto n : int64Operands()) {
 2540 for (auto m : int64Operands()) {
 2541 for (auto amount : amounts) {
 2542 auto and64 = compile([=] (CCallHelpers& jit) {
 2543 emitFunctionPrologue(jit);
 2544
 2545 jit.andUnsignedRightShift64(GPRInfo::argumentGPR0,
 2546 GPRInfo::argumentGPR1,
 2547 CCallHelpers::TrustedImm32(amount),
 2548 GPRInfo::returnValueGPR);
 2549
 2550 emitFunctionEpilogue(jit);
 2551 jit.ret();
 2552 });
 2553
 2554 uint64_t lhs = invoke<uint64_t>(and64, n, m);
 2555 uint64_t rhs = static_cast<uint64_t>(n) & (static_cast<uint64_t>(m) >> amount);
 2556 CHECK_EQ(lhs, rhs);
 2557 }
 2558 }
 2559 }
 2560}
 2561
 2562void testXorLeftShift32()
 2563{
 2564 Vector<int32_t> amounts = { 0, 17, 31 };
 2565 for (auto n : int32Operands()) {
 2566 for (auto m : int32Operands()) {
 2567 for (auto amount : amounts) {
 2568 auto xor32 = compile([=] (CCallHelpers& jit) {
 2569 emitFunctionPrologue(jit);
 2570
 2571 jit.xorLeftShift32(GPRInfo::argumentGPR0,
 2572 GPRInfo::argumentGPR1,
 2573 CCallHelpers::TrustedImm32(amount),
 2574 GPRInfo::returnValueGPR);
 2575
 2576 emitFunctionEpilogue(jit);
 2577 jit.ret();
 2578 });
 2579
 2580 int32_t lhs = invoke<int32_t>(xor32, n, m);
 2581 int32_t rhs = n ^ (m << amount);
 2582 CHECK_EQ(lhs, rhs);
 2583 }
 2584 }
 2585 }
 2586}
 2587
 2588void testXorRightShift32()
 2589{
 2590 Vector<int32_t> amounts = { 0, 17, 31 };
 2591 for (auto n : int32Operands()) {
 2592 for (auto m : int32Operands()) {
 2593 for (auto amount : amounts) {
 2594 auto xor32 = compile([=] (CCallHelpers& jit) {
 2595 emitFunctionPrologue(jit);
 2596
 2597 jit.xorRightShift32(GPRInfo::argumentGPR0,
 2598 GPRInfo::argumentGPR1,
 2599 CCallHelpers::TrustedImm32(amount),
 2600 GPRInfo::returnValueGPR);
 2601
 2602 emitFunctionEpilogue(jit);
 2603 jit.ret();
 2604 });
 2605
 2606 int32_t lhs = invoke<int32_t>(xor32, n, m);
 2607 int32_t rhs = n ^ (m >> amount);
 2608 CHECK_EQ(lhs, rhs);
 2609 }
 2610 }
 2611 }
 2612}
 2613
 2614void testXorUnsignedRightShift32()
 2615{
 2616 Vector<uint32_t> amounts = { 0, 17, 31 };
 2617 for (auto n : int32Operands()) {
 2618 for (auto m : int32Operands()) {
 2619 for (auto amount : amounts) {
 2620 auto xor32 = compile([=] (CCallHelpers& jit) {
 2621 emitFunctionPrologue(jit);
 2622
 2623 jit.xorUnsignedRightShift32(GPRInfo::argumentGPR0,
 2624 GPRInfo::argumentGPR1,
 2625 CCallHelpers::TrustedImm32(amount),
 2626 GPRInfo::returnValueGPR);
 2627
 2628 emitFunctionEpilogue(jit);
 2629 jit.ret();
 2630 });
 2631
 2632 uint32_t lhs = invoke<uint32_t>(xor32, n, m);
 2633 uint32_t rhs = static_cast<uint32_t>(n) ^ (static_cast<uint32_t>(m) >> amount);
 2634 CHECK_EQ(lhs, rhs);
 2635 }
 2636 }
 2637 }
 2638}
 2639
 2640void testXorLeftShift64()
 2641{
 2642 Vector<int32_t> amounts = { 0, 34, 63 };
 2643 for (auto n : int64Operands()) {
 2644 for (auto m : int64Operands()) {
 2645 for (auto amount : amounts) {
 2646 auto xor64 = compile([=] (CCallHelpers& jit) {
 2647 emitFunctionPrologue(jit);
 2648
 2649 jit.xorLeftShift64(GPRInfo::argumentGPR0,
 2650 GPRInfo::argumentGPR1,
 2651 CCallHelpers::TrustedImm32(amount),
 2652 GPRInfo::returnValueGPR);
 2653
 2654 emitFunctionEpilogue(jit);
 2655 jit.ret();
 2656 });
 2657
 2658 int64_t lhs = invoke<int64_t>(xor64, n, m);
 2659 int64_t rhs = n ^ (m << amount);
 2660 CHECK_EQ(lhs, rhs);
 2661 }
 2662 }
 2663 }
 2664}
 2665
 2666void testXorRightShift64()
 2667{
 2668 Vector<int32_t> amounts = { 0, 34, 63 };
 2669 for (auto n : int64Operands()) {
 2670 for (auto m : int64Operands()) {
 2671 for (auto amount : amounts) {
 2672 auto xor64 = compile([=] (CCallHelpers& jit) {
 2673 emitFunctionPrologue(jit);
 2674
 2675 jit.xorRightShift64(GPRInfo::argumentGPR0,
 2676 GPRInfo::argumentGPR1,
 2677 CCallHelpers::TrustedImm32(amount),
 2678 GPRInfo::returnValueGPR);
 2679
 2680 emitFunctionEpilogue(jit);
 2681 jit.ret();
 2682 });
 2683
 2684 int64_t lhs = invoke<int64_t>(xor64, n, m);
 2685 int64_t rhs = n ^ (m >> amount);
 2686 CHECK_EQ(lhs, rhs);
 2687 }
 2688 }
 2689 }
 2690}
 2691
 2692void testXorUnsignedRightShift64()
 2693{
 2694 Vector<uint32_t> amounts = { 0, 34, 63 };
 2695 for (auto n : int64Operands()) {
 2696 for (auto m : int64Operands()) {
 2697 for (auto amount : amounts) {
 2698 auto xor64 = compile([=] (CCallHelpers& jit) {
 2699 emitFunctionPrologue(jit);
 2700
 2701 jit.xorUnsignedRightShift64(GPRInfo::argumentGPR0,
 2702 GPRInfo::argumentGPR1,
 2703 CCallHelpers::TrustedImm32(amount),
 2704 GPRInfo::returnValueGPR);
 2705
 2706 emitFunctionEpilogue(jit);
 2707 jit.ret();
 2708 });
 2709
 2710 uint64_t lhs = invoke<uint64_t>(xor64, n, m);
 2711 uint64_t rhs = static_cast<uint64_t>(n) ^ (static_cast<uint64_t>(m) >> amount);
 2712 CHECK_EQ(lhs, rhs);
 2713 }
 2714 }
 2715 }
 2716}
 2717
 2718void testOrLeftShift32()
 2719{
 2720 Vector<int32_t> amounts = { 0, 17, 31 };
 2721 for (auto n : int32Operands()) {
 2722 for (auto m : int32Operands()) {
 2723 for (auto amount : amounts) {
 2724 auto or32 = compile([=] (CCallHelpers& jit) {
 2725 emitFunctionPrologue(jit);
 2726
 2727 jit.orLeftShift32(GPRInfo::argumentGPR0,
 2728 GPRInfo::argumentGPR1,
 2729 CCallHelpers::TrustedImm32(amount),
 2730 GPRInfo::returnValueGPR);
 2731
 2732 emitFunctionEpilogue(jit);
 2733 jit.ret();
 2734 });
 2735
 2736 int32_t lhs = invoke<int32_t>(or32, n, m);
 2737 int32_t rhs = n | (m << amount);
 2738 CHECK_EQ(lhs, rhs);
 2739 }
 2740 }
 2741 }
 2742}
 2743
 2744void testOrRightShift32()
 2745{
 2746 Vector<int32_t> amounts = { 0, 17, 31 };
 2747 for (auto n : int32Operands()) {
 2748 for (auto m : int32Operands()) {
 2749 for (auto amount : amounts) {
 2750 auto or32 = compile([=] (CCallHelpers& jit) {
 2751 emitFunctionPrologue(jit);
 2752
 2753 jit.orRightShift32(GPRInfo::argumentGPR0,
 2754 GPRInfo::argumentGPR1,
 2755 CCallHelpers::TrustedImm32(amount),
 2756 GPRInfo::returnValueGPR);
 2757
 2758 emitFunctionEpilogue(jit);
 2759 jit.ret();
 2760 });
 2761
 2762 int32_t lhs = invoke<int32_t>(or32, n, m);
 2763 int32_t rhs = n | (m >> amount);
 2764 CHECK_EQ(lhs, rhs);
 2765 }
 2766 }
 2767 }
 2768}
 2769
 2770void testOrUnsignedRightShift32()
 2771{
 2772 Vector<uint32_t> amounts = { 0, 17, 31 };
 2773 for (auto n : int32Operands()) {
 2774 for (auto m : int32Operands()) {
 2775 for (auto amount : amounts) {
 2776 auto or32 = compile([=] (CCallHelpers& jit) {
 2777 emitFunctionPrologue(jit);
 2778
 2779 jit.orUnsignedRightShift32(GPRInfo::argumentGPR0,
 2780 GPRInfo::argumentGPR1,
 2781 CCallHelpers::TrustedImm32(amount),
 2782 GPRInfo::returnValueGPR);
 2783
 2784 emitFunctionEpilogue(jit);
 2785 jit.ret();
 2786 });
 2787
 2788 uint32_t lhs = invoke<uint32_t>(or32, n, m);
 2789 uint32_t rhs = static_cast<uint32_t>(n) | (static_cast<uint32_t>(m) >> amount);
 2790 CHECK_EQ(lhs, rhs);
 2791 }
 2792 }
 2793 }
 2794}
 2795
 2796void testOrLeftShift64()
 2797{
 2798 Vector<int32_t> amounts = { 0, 34, 63 };
 2799 for (auto n : int64Operands()) {
 2800 for (auto m : int64Operands()) {
 2801 for (auto amount : amounts) {
 2802 auto or64 = compile([=] (CCallHelpers& jit) {
 2803 emitFunctionPrologue(jit);
 2804
 2805 jit.orLeftShift64(GPRInfo::argumentGPR0,
 2806 GPRInfo::argumentGPR1,
 2807 CCallHelpers::TrustedImm32(amount),
 2808 GPRInfo::returnValueGPR);
 2809
 2810 emitFunctionEpilogue(jit);
 2811 jit.ret();
 2812 });
 2813
 2814 int64_t lhs = invoke<int64_t>(or64, n, m);
 2815 int64_t rhs = n | (m << amount);
 2816 CHECK_EQ(lhs, rhs);
 2817 }
 2818 }
 2819 }
 2820}
 2821
 2822void testOrRightShift64()
 2823{
 2824 Vector<int32_t> amounts = { 0, 34, 63 };
 2825 for (auto n : int64Operands()) {
 2826 for (auto m : int64Operands()) {
 2827 for (auto amount : amounts) {
 2828 auto or64 = compile([=] (CCallHelpers& jit) {
 2829 emitFunctionPrologue(jit);
 2830
 2831 jit.orRightShift64(GPRInfo::argumentGPR0,
 2832 GPRInfo::argumentGPR1,
 2833 CCallHelpers::TrustedImm32(amount),
 2834 GPRInfo::returnValueGPR);
 2835
 2836 emitFunctionEpilogue(jit);
 2837 jit.ret();
 2838 });
 2839
 2840 int64_t lhs = invoke<int64_t>(or64, n, m);
 2841 int64_t rhs = n | (m >> amount);
 2842 CHECK_EQ(lhs, rhs);
 2843 }
 2844 }
 2845 }
 2846}
 2847
 2848void testOrUnsignedRightShift64()
 2849{
 2850 Vector<uint32_t> amounts = { 0, 34, 63 };
 2851 for (auto n : int64Operands()) {
 2852 for (auto m : int64Operands()) {
 2853 for (auto amount : amounts) {
 2854 auto or64 = compile([=] (CCallHelpers& jit) {
 2855 emitFunctionPrologue(jit);
 2856
 2857 jit.orUnsignedRightShift64(GPRInfo::argumentGPR0,
 2858 GPRInfo::argumentGPR1,
 2859 CCallHelpers::TrustedImm32(amount),
 2860 GPRInfo::returnValueGPR);
 2861
 2862 emitFunctionEpilogue(jit);
 2863 jit.ret();
 2864 });
 2865
 2866 uint64_t lhs = invoke<uint64_t>(or64, n, m);
 2867 uint64_t rhs = static_cast<uint64_t>(n) | (static_cast<uint64_t>(m) >> amount);
 2868 CHECK_EQ(lhs, rhs);
 2869 }
 2870 }
 2871 }
 2872}
23852873#endif
23862874
23872875#if CPU(X86) || CPU(X86_64) || CPU(ARM64)

@@void run(const char* filter) WTF_IGNORES_THREAD_SAFETY_ANALYSIS
49155403 RUN(testLoadStorePair64Int64());
49165404 RUN(testLoadStorePair64Double());
49175405 RUN(testMultiplySignExtend32());
 5406 RUN(testMultiplyZeroExtend32());
49185407
49195408 RUN(testSub32Args());
49205409 RUN(testSub32Imm());

@@void run(const char* filter) WTF_IGNORES_THREAD_SAFETY_ANALYSIS
49805469 RUN(testStorePrePostIndex64());
49815470 RUN(testLoadPrePostIndex32());
49825471 RUN(testLoadPrePostIndex64());
 5472 RUN(testAndLeftShift32());
 5473 RUN(testAndRightShift32());
 5474 RUN(testAndUnsignedRightShift32());
 5475 RUN(testAndLeftShift64());
 5476 RUN(testAndRightShift64());
 5477 RUN(testAndUnsignedRightShift64());
 5478
 5479 RUN(testXorLeftShift32());
 5480 RUN(testXorRightShift32());
 5481 RUN(testXorUnsignedRightShift32());
 5482 RUN(testXorLeftShift64());
 5483 RUN(testXorRightShift64());
 5484 RUN(testXorUnsignedRightShift64());
 5485
 5486 RUN(testOrLeftShift32());
 5487 RUN(testOrRightShift32());
 5488 RUN(testOrUnsignedRightShift32());
 5489 RUN(testOrLeftShift64());
 5490 RUN(testOrRightShift64());
 5491 RUN(testOrUnsignedRightShift64());
49835492#endif
49845493
49855494#if CPU(ARM64E)

Source/JavaScriptCore/b3/B3LowerToAir.cpp

@@private:
28532853 }
28542854
28552855 case Mul: {
2856  if (m_value->type() == Int64
2857  && isValidForm(MultiplySignExtend32, Arg::Tmp, Arg::Tmp, Arg::Tmp)
2858  && m_value->child(0)->opcode() == SExt32
2859  && !m_locked.contains(m_value->child(0))) {
2860  Value* opLeft = m_value->child(0);
2861  Value* left = opLeft->child(0);
2862  Value* opRight = m_value->child(1);
2863  Value* right = nullptr;
2864 
2865  if (opRight->opcode() == SExt32 && !m_locked.contains(opRight->child(0))) {
2866  right = opRight->child(0);
2867  } else if (m_value->child(1)->isRepresentableAs<int32_t>() && !m_locked.contains(m_value->child(1))) {
2868  // We just use the 64-bit const int as a 32 bit const int directly
2869  right = opRight;
2870  }
 2856 Value* left = m_value->child(0);
 2857 Value* right = m_value->child(1);
28712858
2872  if (right) {
2873  append(MultiplySignExtend32, tmp(left), tmp(right), tmp(m_value));
2874  return;
 2859 auto tryAppendMultiplyWithExtend = [&] () -> bool {
 2860 auto tryAirOpcode = [&] () -> Air::Opcode {
 2861 if (m_value->type() != Int64)
 2862 return Air::Oops;
 2863 // SMULL: d = SExt32(n) * SExt32(m)
 2864 if (isMergeableValue(left, SExt32, true) && isMergeableValue(right, SExt32, true))
 2865 return MultiplySignExtend32;
 2866 // UMULL: d = ZExt32(n) * ZExt32(m)
 2867 if (isMergeableValue(left, ZExt32, true) && isMergeableValue(right, ZExt32, true))
 2868 return MultiplyZeroExtend32;
 2869 return Air::Oops;
 2870 };
 2871
 2872 Air::Opcode opcode = tryAirOpcode();
 2873 if (isValidForm(opcode, Arg::Tmp, Arg::Tmp, Arg::Tmp)) {
 2874 append(opcode, tmp(left->child(0)), tmp(right->child(0)), tmp(m_value));
 2875 commitInternal(left);
 2876 commitInternal(right);
 2877 return true;
28752878 }
2876  }
2877  appendBinOp<Mul32, Mul64, MulDouble, MulFloat, Commutative>(
2878  m_value->child(0), m_value->child(1));
 2879 return false;
 2880 };
 2881
 2882 if (tryAppendMultiplyWithExtend())
 2883 return;
 2884
 2885 appendBinOp<Mul32, Mul64, MulDouble, MulFloat, Commutative>(left, right);
28792886 return;
28802887 }
28812888

@@private:
29882995 if (tryAppendBIC(left, right) || tryAppendBIC(right, left))
29892996 return;
29902997
 2998 // and-with-shift Pattern: n & (m ShiftType amount)
 2999 auto tryAppendAndWithShift = [&] (Value* left, Value* right) -> bool {
 3000 Air::Opcode opcode = opcodeBasedOnShiftKind(right->opcode(),
 3001 AndLeftShift32, AndLeftShift64,
 3002 AndRightShift32, AndRightShift64,
 3003 AndUnsignedRightShift32, AndUnsignedRightShift64);
 3004 if (!isValidForm(opcode, Arg::Tmp, Arg::Tmp, Arg::Imm, Arg::Tmp))
 3005 return false;
 3006 if (!canBeInternal(right) || !imm(right->child(1)) || right->child(1)->asInt() < 0)
 3007 return false;
 3008
 3009 uint64_t amount = right->child(1)->asInt();
 3010 uint64_t datasize = m_value->type() == Int32 ? 32 : 64;
 3011 if (amount >= datasize)
 3012 return false;
 3013
 3014 append(opcode, tmp(left), tmp(right->child(0)), imm(right->child(1)), tmp(m_value));
 3015 commitInternal(right);
 3016 return true;
 3017 };
 3018
 3019 if (tryAppendAndWithShift(left, right) || tryAppendAndWithShift(right, left))
 3020 return;
 3021
29913022 appendBinOp<And32, And64, AndDouble, AndFloat, Commutative>(left, right);
29923023 return;
29933024 }

@@private:
30013032 // mask = (1 << lowWidth) - 1
30023033 auto tryAppendEXTR = [&] (Value* left, Value* right) -> bool {
30033034 Air::Opcode opcode = opcodeForType(ExtractRegister32, ExtractRegister64, m_value->type());
3004  if (!isValidForm(opcode, Arg::Tmp, Arg::Tmp, Arg::Imm, Arg::Tmp))
 3035 if (!isValidForm(opcode, Arg::Tmp, Arg::Tmp, Arg::Imm, Arg::Tmp))
30053036 return false;
30063037 if (left->opcode() != Shl || left->child(0)->opcode() != BitAnd || right->opcode() != ZShr)
30073038 return false;

@@private:
31553186 if (tryAppendORN(left, right) || tryAppendORN(right, left))
31563187 return;
31573188
 3189 // or-with-shift Pattern: n | (m ShiftType amount)
 3190 auto tryAppendOrWithShift = [&] (Value* left, Value* right) -> bool {
 3191 Air::Opcode opcode = opcodeBasedOnShiftKind(right->opcode(),
 3192 OrLeftShift32, OrLeftShift64,
 3193 OrRightShift32, OrRightShift64,
 3194 OrUnsignedRightShift32, OrUnsignedRightShift64);
 3195 if (!isValidForm(opcode, Arg::Tmp, Arg::Tmp, Arg::Imm, Arg::Tmp))
 3196 return false;
 3197 if (!canBeInternal(right) || !imm(right->child(1)) || right->child(1)->asInt() < 0)
 3198 return false;
 3199
 3200 uint64_t amount = right->child(1)->asInt();
 3201 uint64_t datasize = m_value->type() == Int32 ? 32 : 64;
 3202 if (amount >= datasize)
 3203 return false;
 3204
 3205 append(opcode, tmp(left), tmp(right->child(0)), imm(right->child(1)), tmp(m_value));
 3206 commitInternal(right);
 3207 return true;
 3208 };
 3209
 3210 if (tryAppendOrWithShift(left, right) || tryAppendOrWithShift(right, left))
 3211 return;
 3212
31583213 appendBinOp<Or32, Or64, OrDouble, OrFloat, Commutative>(left, right);
31593214 return;
31603215 }

@@private:
32253280 if (tryAppendEON(left, right) || tryAppendEON(right, left))
32263281 return;
32273282
 3283 // xor-with-shift Pattern: n ^ (m ShiftType amount)
 3284 auto tryAppendXorWithShift = [&] (Value* left, Value* right) -> bool {
 3285 Air::Opcode opcode = opcodeBasedOnShiftKind(right->opcode(),
 3286 XorLeftShift32, XorLeftShift64,
 3287 XorRightShift32, XorRightShift64,
 3288 XorUnsignedRightShift32, XorUnsignedRightShift64);
 3289 if (!isValidForm(opcode, Arg::Tmp, Arg::Tmp, Arg::Imm, Arg::Tmp))
 3290 return false;
 3291 if (!canBeInternal(right) || !imm(right->child(1)) || right->child(1)->asInt() < 0)
 3292 return false;
 3293
 3294 uint64_t amount = right->child(1)->asInt();
 3295 uint64_t datasize = m_value->type() == Int32 ? 32 : 64;
 3296 if (amount >= datasize)
 3297 return false;
 3298
 3299 append(opcode, tmp(left), tmp(right->child(0)), imm(right->child(1)), tmp(m_value));
 3300 commitInternal(right);
 3301 return true;
 3302 };
 3303
 3304 if (tryAppendXorWithShift(left, right) || tryAppendXorWithShift(right, left))
 3305 return;
 3306
32283307 appendBinOp<Xor32, Xor64, XorDouble, XorFloat, Commutative>(left, right);
32293308 return;
32303309 }

Source/JavaScriptCore/b3/air/AirOpcode.opcodes

@@arm64: MultiplyNegZeroExtend32 U:G:32, U:G:32, D:G:64
284284arm64: MultiplySignExtend32 U:G:32, U:G:32, D:G:64
285285 Tmp, Tmp, Tmp
286286
 287arm64: MultiplyZeroExtend32 U:G:32, U:G:32, D:G:64
 288 Tmp, Tmp, Tmp
 289
287290arm64: Div32 U:G:32, U:G:32, ZD:G:32
288291 Tmp, Tmp, Tmp
289292

@@arm64: SubRightShift64 U:G:64, U:G:64, U:G:64, D:G:64
955958arm64: SubUnsignedRightShift64 U:G:64, U:G:64, U:G:64, D:G:64
956959 Tmp, Tmp, Imm, Tmp
957960
 961arm64: AndLeftShift32 U:G:32, U:G:32, U:G:32, ZD:G:32
 962 Tmp, Tmp, Imm, Tmp
 963
 964arm64: AndRightShift32 U:G:32, U:G:32, U:G:32, ZD:G:32
 965 Tmp, Tmp, Imm, Tmp
 966
 967arm64: AndUnsignedRightShift32 U:G:32, U:G:32, U:G:32, ZD:G:32
 968 Tmp, Tmp, Imm, Tmp
 969
 970arm64: AndLeftShift64 U:G:64, U:G:64, U:G:64, D:G:64
 971 Tmp, Tmp, Imm, Tmp
 972
 973arm64: AndRightShift64 U:G:64, U:G:64, U:G:64, D:G:64
 974 Tmp, Tmp, Imm, Tmp
 975
 976arm64: AndUnsignedRightShift64 U:G:64, U:G:64, U:G:64, D:G:64
 977 Tmp, Tmp, Imm, Tmp
 978
 979arm64: XorLeftShift32 U:G:32, U:G:32, U:G:32, ZD:G:32
 980 Tmp, Tmp, Imm, Tmp
 981
 982arm64: XorRightShift32 U:G:32, U:G:32, U:G:32, ZD:G:32
 983 Tmp, Tmp, Imm, Tmp
 984
 985arm64: XorUnsignedRightShift32 U:G:32, U:G:32, U:G:32, ZD:G:32
 986 Tmp, Tmp, Imm, Tmp
 987
 988arm64: XorLeftShift64 U:G:64, U:G:64, U:G:64, D:G:64
 989 Tmp, Tmp, Imm, Tmp
 990
 991arm64: XorRightShift64 U:G:64, U:G:64, U:G:64, D:G:64
 992 Tmp, Tmp, Imm, Tmp
 993
 994arm64: XorUnsignedRightShift64 U:G:64, U:G:64, U:G:64, D:G:64
 995 Tmp, Tmp, Imm, Tmp
 996
 997arm64: OrLeftShift32 U:G:32, U:G:32, U:G:32, ZD:G:32
 998 Tmp, Tmp, Imm, Tmp
 999
 1000arm64: OrRightShift32 U:G:32, U:G:32, U:G:32, ZD:G:32
 1001 Tmp, Tmp, Imm, Tmp
 1002
 1003arm64: OrUnsignedRightShift32 U:G:32, U:G:32, U:G:32, ZD:G:32
 1004 Tmp, Tmp, Imm, Tmp
 1005
 1006arm64: OrLeftShift64 U:G:64, U:G:64, U:G:64, D:G:64
 1007 Tmp, Tmp, Imm, Tmp
 1008
 1009arm64: OrRightShift64 U:G:64, U:G:64, U:G:64, D:G:64
 1010 Tmp, Tmp, Imm, Tmp
 1011
 1012arm64: OrUnsignedRightShift64 U:G:64, U:G:64, U:G:64, D:G:64
 1013 Tmp, Tmp, Imm, Tmp
 1014
9581015# The first operand is rax.
9591016# FIXME: This formulation means that the boolean result cannot be put in eax, even though all users
9601017# of this would be OK with that.

Source/JavaScriptCore/b3/testb3.h

@@void testSubWithUnsignedRightShift32();
471471void testSubWithLeftShift64();
472472void testSubWithRightShift64();
473473void testSubWithUnsignedRightShift64();
 474
 475void testAndLeftShift32();
 476void testAndRightShift32();
 477void testAndUnsignedRightShift32();
 478void testAndLeftShift64();
 479void testAndRightShift64();
 480void testAndUnsignedRightShift64();
 481
 482void testXorLeftShift32();
 483void testXorRightShift32();
 484void testXorUnsignedRightShift32();
 485void testXorLeftShift64();
 486void testXorRightShift64();
 487void testXorUnsignedRightShift64();
 488
 489void testOrLeftShift32();
 490void testOrRightShift32();
 491void testOrUnsignedRightShift32();
 492void testOrLeftShift64();
 493void testOrRightShift64();
 494void testOrUnsignedRightShift64();
 495
474496void testSelectCompareDouble();
475497void testSelectCompareFloat(float, float);
476498void testSelectCompareFloatToDouble(float, float);

@@void testMulNegArgArg(int, int);
917939void testMulArgImm(int64_t, int64_t);
918940void testMulImmArg(int, int);
919941void testMulArgs32(int, int);
920 void testMulArgs32SignExtend(int, int);
 942void testMulArgs32SignExtend();
 943void testMulArgs32ZeroExtend();
921944void testMulImm32SignExtend(const int, int);
922945void testMulLoadTwice();
923946void testMulAddArgsLeft();

Source/JavaScriptCore/b3/testb3_2.cpp

@@void testMulArgs32(int a, int b)
12281228 CHECK(compileAndRun<int>(proc, a, b) == a * b);
12291229}
12301230
1231 void testMulArgs32SignExtend(int a, int b)
 1231void testMulArgs32SignExtend()
12321232{
12331233 Procedure proc;
1234  if (proc.optLevel() < 1)
 1234 if (proc.optLevel() < 2)
12351235 return;
12361236 BasicBlock* root = proc.addBlock();
12371237 Value* arg1 = root->appendNew<Value>(

@@void testMulArgs32SignExtend(int a, int b)
12471247
12481248 auto code = compileProc(proc);
12491249
1250  CHECK(invoke<long int>(*code, a, b) == ((long int) a) * ((long int) b));
 1250 for (auto nOperand : int32Operands()) {
 1251 for (auto mOperand : int32Operands()) {
 1252 int32_t n = nOperand.value;
 1253 int32_t m = mOperand.value;
 1254 CHECK_EQ(invoke<int64_t>(*code, n, m), static_cast<int64_t>(n) * static_cast<int64_t>(m));
 1255 }
 1256 }
 1257}
 1258
 1259void testMulArgs32ZeroExtend()
 1260{
 1261 Procedure proc;
 1262 if (proc.optLevel() < 2)
 1263 return;
 1264 BasicBlock* root = proc.addBlock();
 1265 Value* arg1 = root->appendNew<Value>(
 1266 proc, Trunc, Origin(),
 1267 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
 1268 Value* arg2 = root->appendNew<Value>(
 1269 proc, Trunc, Origin(),
 1270 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
 1271 Value* left = root->appendNew<Value>(proc, ZExt32, Origin(), arg1);
 1272 Value* right = root->appendNew<Value>(proc, ZExt32, Origin(), arg2);
 1273 Value* mul = root->appendNew<Value>(proc, Mul, Origin(), left, right);
 1274 root->appendNewControlValue(proc, Return, Origin(), mul);
 1275
 1276 auto code = compileProc(proc);
 1277
 1278 for (auto nOperand : int32Operands()) {
 1279 for (auto mOperand : int32Operands()) {
 1280 uint32_t n = nOperand.value;
 1281 uint32_t m = mOperand.value;
 1282 CHECK_EQ(invoke<uint64_t>(*code, n, m), static_cast<uint64_t>(n) * static_cast<uint64_t>(m));
 1283 }
 1284 }
12511285}
12521286
12531287void testMulImm32SignExtend(const int a, int b)

@@void testSubWithUnsignedRightShift64()
54615495 }
54625496}
54635497
5464 void testBitAndZeroShiftRightArgImmMask32()
 5498void testAndLeftShift32()
54655499{
5466  // Turn this: (tmp >> imm) & mask
5467  // Into this: tmp >> imm
5468  uint32_t tmp = 0xffffffff;
5469  Vector<uint32_t> imms = { 4, 28, 31 };
5470  Vector<uint32_t> masks = { 0x0fffffff, 0xf, 0xffff };
 5500 if (JSC::Options::defaultB3OptLevel() < 2)
 5501 return;
 5502 Vector<int32_t> amounts = { 1, 17, 31 };
54715503
5472  auto test = [&] (uint32_t imm, uint32_t mask) {
 5504 // Test Pattern: d = n & (m << amount)
 5505 auto test = [&] (int32_t n, int32_t m, int32_t amount) -> int32_t {
54735506 Procedure proc;
54745507 BasicBlock* root = proc.addBlock();
54755508
5476  Value* tmpValue = root->appendNew<Value>(
 5509 Value* nValue = root->appendNew<Value>(
54775510 proc, Trunc, Origin(),
54785511 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
5479  Value* immValue = root->appendNew<Const32Value>(proc, Origin(), imm);
5480  Value* leftValue = root->appendNew<Value>(proc, ZShr, Origin(), tmpValue, immValue);
5481  Value* rightValue = root->appendNew<Const32Value>(proc, Origin(), mask);
 5512 Value* mValue = root->appendNew<Value>(
 5513 proc, Trunc, Origin(),
 5514 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
 5515 Value* amountValue = root->appendNew<Const32Value>(proc, Origin(), amount);
 5516
 5517 Value* shiftValue = root->appendNew<Value>(proc, Shl, Origin(), mValue, amountValue);
54825518 root->appendNewControlValue(
5483  proc, Return, Origin(),
5484  root->appendNew<Value>(proc, BitAnd, Origin(), leftValue, rightValue));
 5519 proc, Return, Origin(),
 5520 root->appendNew<Value>(proc, BitAnd, Origin(), nValue, shiftValue));
54855521
54865522 auto code = compileProc(proc);
5487  if (isARM64())
5488  checkUsesInstruction(*code, "lsr");
5489  uint32_t lhs = invoke<uint32_t>(*code, tmp);
5490  uint32_t rhs = tmp >> imm;
5491  CHECK(lhs == rhs);
 5523 if (isARM64()) {
 5524 std::string regex(".*and.*,.*,.*,.*lsl #");
 5525 regex += std::to_string(amount) + ".*";
 5526 checkUsesInstruction(*code, regex.c_str(), true);
 5527 }
 5528 return invoke<int32_t>(*code, n, m);
54925529 };
54935530
5494  for (size_t i = 0; i < imms.size(); ++i)
5495  test(imms.at(i), masks.at(i));
 5531 for (auto nOperand : int32Operands()) {
 5532 for (auto mOperand : int32Operands()) {
 5533 for (auto amount : amounts) {
 5534 int32_t n = nOperand.value;
 5535 int32_t m = mOperand.value;
 5536 CHECK_EQ(test(n, m, amount), n & (m << amount));
 5537 }
 5538 }
 5539 }
54965540}
54975541
5498 void testBitAndZeroShiftRightArgImmMask64()
 5542void testAndRightShift32()
54995543{
5500  // Turn this: (tmp >> imm) & mask
5501  // Into this: tmp >> imm
5502  uint64_t tmp = 0xffffffffffffffff;
5503  Vector<uint64_t> imms = { 4, 60, 63 };
5504  Vector<uint64_t> masks = { 0x0fffffffffffffff, 0xf, 0xffff };
 5544 if (JSC::Options::defaultB3OptLevel() < 2)
 5545 return;
 5546 Vector<int32_t> amounts = { 1, 17, 31 };
55055547
5506  auto test = [&] (uint64_t imm, uint64_t mask) {
 5548 // Test Pattern: d = n & (m >> amount)
 5549 auto test = [&] (int32_t n, int32_t m, int32_t amount) -> int32_t {
55075550 Procedure proc;
55085551 BasicBlock* root = proc.addBlock();
55095552
5510  Value* tmpValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
5511  Value* immValue = root->appendNew<Const32Value>(proc, Origin(), imm);
5512  Value* leftValue = root->appendNew<Value>(proc, ZShr, Origin(), tmpValue, immValue);
5513  Value* rightValue = root->appendNew<Const64Value>(proc, Origin(), mask);
 5553 Value* nValue = root->appendNew<Value>(
 5554 proc, Trunc, Origin(),
 5555 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
 5556 Value* mValue = root->appendNew<Value>(
 5557 proc, Trunc, Origin(),
 5558 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
 5559 Value* amountValue = root->appendNew<Const32Value>(proc, Origin(), amount);
 5560
 5561 Value* shiftValue = root->appendNew<Value>(proc, SShr, Origin(), mValue, amountValue);
55145562 root->appendNewControlValue(
5515  proc, Return, Origin(),
5516  root->appendNew<Value>(proc, BitAnd, Origin(), leftValue, rightValue));
 5563 proc, Return, Origin(),
 5564 root->appendNew<Value>(proc, BitAnd, Origin(), nValue, shiftValue));
55175565
55185566 auto code = compileProc(proc);
5519  if (isARM64())
5520  checkUsesInstruction(*code, "lsr");
5521  uint64_t lhs = invoke<uint64_t>(*code, tmp);
5522  uint64_t rhs = tmp >> imm;
5523  CHECK(lhs == rhs);
 5567 if (isARM64()) {
 5568 std::string regex(".*and.*,.*,.*,.*asr #");
 5569 regex += std::to_string(amount) + ".*";
 5570 checkUsesInstruction(*code, regex.c_str(), true);
 5571 }
 5572 return invoke<int32_t>(*code, n, m);
55245573 };
55255574
5526  for (size_t i = 0; i < imms.size(); ++i)
5527  test(imms.at(i), masks.at(i));
 5575 for (auto nOperand : int32Operands()) {
 5576 for (auto mOperand : int32Operands()) {
 5577 for (auto amount : amounts) {
 5578 int32_t n = nOperand.value;
 5579 int32_t m = mOperand.value;
 5580 CHECK_EQ(test(n, m, amount), n & (m >> amount));
 5581 }
 5582 }
 5583 }
55285584}
55295585
5530 static void testBitAndArgs(int64_t a, int64_t b)
 5586void testAndUnsignedRightShift32()
55315587{
5532  Procedure proc;
5533  BasicBlock* root = proc.addBlock();
5534  root->appendNewControlValue(
5535  proc, Return, Origin(),
5536  root->appendNew<Value>(
5537  proc, BitAnd, Origin(),
5538  root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
5539  root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
 5588 if (JSC::Options::defaultB3OptLevel() < 2)
 5589 return;
 5590 Vector<uint32_t> amounts = { 1, 17, 31 };
55405591
5541  CHECK(compileAndRun<int64_t>(proc, a, b) == (a & b));
5542 }
 5592 // Test Pattern: d = n & (m >> amount)
 5593 auto test = [&] (uint32_t n, uint32_t m, uint32_t amount) -> uint32_t {
 5594 Procedure proc;
 5595 BasicBlock* root = proc.addBlock();
55435596
5544 static void testBitAndSameArg(int64_t a)
5545 {
5546  Procedure proc;
5547  BasicBlock* root = proc.addBlock();
5548  Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
5549  root->appendNewControlValue(
5550  proc, Return, Origin(),
5551  root->appendNew<Value>(
5552  proc, BitAnd, Origin(),
5553  argument,
5554  argument));
 5597 Value* nValue = root->appendNew<Value>(
 5598 proc, Trunc, Origin(),
 5599 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
 5600 Value* mValue = root->appendNew<Value>(
 5601 proc, Trunc, Origin(),
 5602 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
 5603 Value* amountValue = root->appendNew<Const32Value>(proc, Origin(), amount);
55555604
5556  CHECK(compileAndRun<int64_t>(proc, a) == a);
5557 }
 5605 Value* shiftValue = root->appendNew<Value>(proc, ZShr, Origin(), mValue, amountValue);
 5606 root->appendNewControlValue(
 5607 proc, Return, Origin(),
 5608 root->appendNew<Value>(proc, BitAnd, Origin(), nValue, shiftValue));
55585609
5559 static void testBitAndNotNot(int64_t a, int64_t b)
5560 {
5561  Procedure proc;
5562  BasicBlock* root = proc.addBlock();
5563  Value* argA = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
5564  Value* argB = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
5565  Value* notA = root->appendNew<Value>(proc, BitXor, Origin(), argA, root->appendNew<Const64Value>(proc, Origin(), -1));
5566  Value* notB = root->appendNew<Value>(proc, BitXor, Origin(), argB, root->appendNew<Const64Value>(proc, Origin(), -1));
5567  root->appendNewControlValue(
5568  proc, Return, Origin(),
5569  root->appendNew<Value>(
5570  proc, BitAnd, Origin(),
5571  notA,
5572  notB));
 5610 auto code = compileProc(proc);
 5611 if (isARM64()) {
 5612 std::string regex(".*and.*,.*,.*,.*lsr #");
 5613 regex += std::to_string(amount) + ".*";
 5614 checkUsesInstruction(*code, regex.c_str(), true);
 5615 }
 5616 return invoke<uint32_t>(*code, n, m);
 5617 };
55735618
5574  CHECK_EQ(compileAndRun<int64_t>(proc, a, b), (~a & ~b));
 5619 for (auto nOperand : int32Operands()) {
 5620 for (auto mOperand : int32Operands()) {
 5621 for (auto amount : amounts) {
 5622 uint32_t n = nOperand.value;
 5623 uint32_t m = mOperand.value;
 5624 CHECK_EQ(test(n, m, amount), n & (m >> amount));
 5625 }
 5626 }
 5627 }
55755628}
55765629
5577 static void testBitAndNotNot32(int32_t a, int32_t b)
 5630void testAndLeftShift64()
55785631{
5579  Procedure proc;
5580  BasicBlock* root = proc.addBlock();
5581  Value* argA = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
5582  Value* argB = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
5583  Value* notA = root->appendNew<Value>(proc, BitXor, Origin(), argA, root->appendNew<Const32Value>(proc, Origin(), -1));
5584  Value* notB = root->appendNew<Value>(proc, BitXor, Origin(), argB, root->appendNew<Const32Value>(proc, Origin(), -1));
5585  root->appendNewControlValue(
5586  proc, Return, Origin(),
5587  root->appendNew<Value>(
5588  proc, BitAnd, Origin(),
5589  notA,
5590  notB));
 5632 if (JSC::Options::defaultB3OptLevel() < 2)
 5633 return;
 5634 Vector<int32_t> amounts = { 1, 34, 63 };
55915635
5592  CHECK_EQ(compileAndRun<int32_t>(proc, a, b), (~a & ~b));
5593 }
 5636 // Test Pattern: d = n & (m << amount)
 5637 auto test = [&] (int64_t n, int64_t m, int32_t amount) -> int64_t {
 5638 Procedure proc;
 5639 BasicBlock* root = proc.addBlock();
55945640
5595 static void testBitAndNotImm(int64_t a, int64_t b)
5596 {
5597  Procedure proc;
5598  BasicBlock* root = proc.addBlock();
5599  Value* argA = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
5600  Value* notA = root->appendNew<Value>(proc, BitXor, Origin(), argA, root->appendNew<Const64Value>(proc, Origin(), -1));
5601  Value* cstB = root->appendNew<Const64Value>(proc, Origin(), b);
5602  root->appendNewControlValue(
5603  proc, Return, Origin(),
5604  root->appendNew<Value>(
5605  proc, BitAnd, Origin(),
5606  notA,
5607  cstB));
 5641 Value* nValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
 5642 Value* mValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
 5643 Value* amountValue = root->appendNew<Const32Value>(proc, Origin(), amount);
56085644
5609  CHECK_EQ(compileAndRun<int64_t>(proc, a), (~a & b));
 5645 Value* shiftValue = root->appendNew<Value>(proc, Shl, Origin(), mValue, amountValue);
 5646 root->appendNewControlValue(
 5647 proc, Return, Origin(),
 5648 root->appendNew<Value>(proc, BitAnd, Origin(), nValue, shiftValue));
 5649
 5650 auto code = compileProc(proc);
 5651 if (isARM64()) {
 5652 std::string regex(".*and.*,.*,.*,.*lsl #");
 5653 regex += std::to_string(amount) + ".*";
 5654 checkUsesInstruction(*code, regex.c_str(), true);
 5655 }
 5656 return invoke<int64_t>(*code, n, m);
 5657 };
 5658
 5659 for (auto nOperand : int64Operands()) {
 5660 for (auto mOperand : int64Operands()) {
 5661 for (auto amount : amounts) {
 5662 int64_t n = nOperand.value;
 5663 int64_t m = mOperand.value;
 5664 CHECK_EQ(test(n, m, amount), n & (m << amount));
 5665 }
 5666 }
 5667 }
56105668}
56115669
5612 static void testBitAndNotImm32(int32_t a, int32_t b)
 5670void testAndRightShift64()
56135671{
5614  Procedure proc;
5615  BasicBlock* root = proc.addBlock();
5616  Value* argA = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
5617  Value* notA = root->appendNew<Value>(proc, BitXor, Origin(), argA, root->appendNew<Const32Value>(proc, Origin(), -1));
5618  Value* cstB = root->appendNew<Const32Value>(proc, Origin(), b);
5619  root->appendNewControlValue(
5620  proc, Return, Origin(),
5621  root->appendNew<Value>(
5622  proc, BitAnd, Origin(),
 5672 if (JSC::Options::defaultB3OptLevel() < 2)
 5673 return;
 5674 Vector<int32_t> amounts = { 1, 34, 63 };
 5675
 5676 // Test Pattern: d = n & (m >> amount)
 5677 auto test = [&] (int64_t n, int64_t m, int32_t amount) -> int64_t {
 5678 Procedure proc;
 5679 BasicBlock* root = proc.addBlock();
 5680
 5681 Value* nValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
 5682 Value* mValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
 5683 Value* amountValue = root->appendNew<Const32Value>(proc, Origin(), amount);
 5684
 5685 Value* shiftValue = root->appendNew<Value>(proc, SShr, Origin(), mValue, amountValue);
 5686 root->appendNewControlValue(
 5687 proc, Return, Origin(),
 5688 root->appendNew<Value>(proc, BitAnd, Origin(), nValue, shiftValue));
 5689
 5690 auto code = compileProc(proc);
 5691 if (isARM64()) {
 5692 std::string regex(".*and.*,.*,.*,.*asr #");
 5693 regex += std::to_string(amount) + ".*";
 5694 checkUsesInstruction(*code, regex.c_str(), true);
 5695 }
 5696 return invoke<int64_t>(*code, n, m);
 5697 };
 5698
 5699 for (auto nOperand : int64Operands()) {
 5700 for (auto mOperand : int64Operands()) {
 5701 for (auto amount : amounts) {
 5702 int64_t n = nOperand.value;
 5703 int64_t m = mOperand.value;
 5704 CHECK_EQ(test(n, m, amount), n & (m >> amount));
 5705 }
 5706 }
 5707 }
 5708}
 5709
 5710void testAndUnsignedRightShift64()
 5711{
 5712 if (JSC::Options::defaultB3OptLevel() < 2)
 5713 return;
 5714 Vector<uint32_t> amounts = { 1, 17, 31 };
 5715
 5716 // Test Pattern: d = n & (m >> amount)
 5717 auto test = [&] (uint64_t n, uint64_t m, uint32_t amount) -> uint64_t {
 5718 Procedure proc;
 5719 BasicBlock* root = proc.addBlock();
 5720
 5721 Value* nValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
 5722 Value* mValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
 5723 Value* amountValue = root->appendNew<Const32Value>(proc, Origin(), amount);
 5724
 5725 Value* shiftValue = root->appendNew<Value>(proc, ZShr, Origin(), mValue, amountValue);
 5726 root->appendNewControlValue(
 5727 proc, Return, Origin(),
 5728 root->appendNew<Value>(proc, BitAnd, Origin(), nValue, shiftValue));
 5729
 5730 auto code = compileProc(proc);
 5731 if (isARM64()) {
 5732 std::string regex(".*and.*,.*,.*,.*lsr #");
 5733 regex += std::to_string(amount) + ".*";
 5734 checkUsesInstruction(*code, regex.c_str(), true);
 5735 }
 5736 return invoke<uint64_t>(*code, n, m);
 5737 };
 5738
 5739 for (auto nOperand : int64Operands()) {
 5740 for (auto mOperand : int64Operands()) {
 5741 for (auto amount : amounts) {
 5742 uint64_t n = nOperand.value;
 5743 uint64_t m = mOperand.value;
 5744 CHECK_EQ(test(n, m, amount), n & (m >> amount));
 5745 }
 5746 }
 5747 }
 5748}
 5749
 5750void testXorLeftShift32()
 5751{
 5752 if (JSC::Options::defaultB3OptLevel() < 2)
 5753 return;
 5754 Vector<int32_t> amounts = { 1, 17, 31 };
 5755
 5756 // Test Pattern: d = n ^ (m << amount)
 5757 auto test = [&] (int32_t n, int32_t m, int32_t amount) -> int32_t {
 5758 Procedure proc;
 5759 BasicBlock* root = proc.addBlock();
 5760
 5761 Value* nValue = root->appendNew<Value>(
 5762 proc, Trunc, Origin(),
 5763 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
 5764 Value* mValue = root->appendNew<Value>(
 5765 proc, Trunc, Origin(),
 5766 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
 5767 Value* amountValue = root->appendNew<Const32Value>(proc, Origin(), amount);
 5768
 5769 Value* shiftValue = root->appendNew<Value>(proc, Shl, Origin(), mValue, amountValue);
 5770 root->appendNewControlValue(
 5771 proc, Return, Origin(),
 5772 root->appendNew<Value>(proc, BitXor, Origin(), nValue, shiftValue));
 5773
 5774 auto code = compileProc(proc);
 5775 if (isARM64()) {
 5776 std::string regex(".*eor.*,.*,.*,.*lsl #");
 5777 regex += std::to_string(amount) + ".*";
 5778 checkUsesInstruction(*code, regex.c_str(), true);
 5779 }
 5780 return invoke<int32_t>(*code, n, m);
 5781 };
 5782
 5783 for (auto nOperand : int32Operands()) {
 5784 for (auto mOperand : int32Operands()) {
 5785 for (auto amount : amounts) {
 5786 int32_t n = nOperand.value;
 5787 int32_t m = mOperand.value;
 5788 CHECK_EQ(test(n, m, amount), n ^ (m << amount));
 5789 }
 5790 }
 5791 }
 5792}
 5793
 5794void testXorRightShift32()
 5795{
 5796 if (JSC::Options::defaultB3OptLevel() < 2)
 5797 return;
 5798 Vector<int32_t> amounts = { 1, 17, 31 };
 5799
 5800 // Test Pattern: d = n ^ (m >> amount)
 5801 auto test = [&] (int32_t n, int32_t m, int32_t amount) -> int32_t {
 5802 Procedure proc;
 5803 BasicBlock* root = proc.addBlock();
 5804
 5805 Value* nValue = root->appendNew<Value>(
 5806 proc, Trunc, Origin(),
 5807 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
 5808 Value* mValue = root->appendNew<Value>(
 5809 proc, Trunc, Origin(),
 5810 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
 5811 Value* amountValue = root->appendNew<Const32Value>(proc, Origin(), amount);
 5812
 5813 Value* shiftValue = root->appendNew<Value>(proc, SShr, Origin(), mValue, amountValue);
 5814 root->appendNewControlValue(
 5815 proc, Return, Origin(),
 5816 root->appendNew<Value>(proc, BitXor, Origin(), nValue, shiftValue));
 5817
 5818 auto code = compileProc(proc);
 5819 if (isARM64()) {
 5820 std::string regex(".*eor.*,.*,.*,.*asr #");
 5821 regex += std::to_string(amount) + ".*";
 5822 checkUsesInstruction(*code, regex.c_str(), true);
 5823 }
 5824 return invoke<int32_t>(*code, n, m);
 5825 };
 5826
 5827 for (auto nOperand : int32Operands()) {
 5828 for (auto mOperand : int32Operands()) {
 5829 for (auto amount : amounts) {
 5830 int32_t n = nOperand.value;
 5831 int32_t m = mOperand.value;
 5832 CHECK_EQ(test(n, m, amount), n ^ (m >> amount));
 5833 }
 5834 }
 5835 }
 5836}
 5837
 5838void testXorUnsignedRightShift32()
 5839{
 5840 if (JSC::Options::defaultB3OptLevel() < 2)
 5841 return;
 5842 Vector<uint32_t> amounts = { 1, 17, 31 };
 5843
 5844 // Test Pattern: d = n ^ (m >> amount)
 5845 auto test = [&] (uint32_t n, uint32_t m, uint32_t amount) -> uint32_t {
 5846 Procedure proc;
 5847 BasicBlock* root = proc.addBlock();
 5848
 5849 Value* nValue = root->appendNew<Value>(
 5850 proc, Trunc, Origin(),
 5851 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
 5852 Value* mValue = root->appendNew<Value>(
 5853 proc, Trunc, Origin(),
 5854 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
 5855 Value* amountValue = root->appendNew<Const32Value>(proc, Origin(), amount);
 5856
 5857 Value* shiftValue = root->appendNew<Value>(proc, ZShr, Origin(), mValue, amountValue);
 5858 root->appendNewControlValue(
 5859 proc, Return, Origin(),
 5860 root->appendNew<Value>(proc, BitXor, Origin(), nValue, shiftValue));
 5861
 5862 auto code = compileProc(proc);
 5863 if (isARM64()) {
 5864 std::string regex(".*eor.*,.*,.*,.*lsr #");
 5865 regex += std::to_string(amount) + ".*";
 5866 checkUsesInstruction(*code, regex.c_str(), true);
 5867 }
 5868 return invoke<uint32_t>(*code, n, m);
 5869 };
 5870
 5871 for (auto nOperand : int32Operands()) {
 5872 for (auto mOperand : int32Operands()) {
 5873 for (auto amount : amounts) {
 5874 uint32_t n = nOperand.value;
 5875 uint32_t m = mOperand.value;
 5876 CHECK_EQ(test(n, m, amount), n ^ (m >> amount));
 5877 }
 5878 }
 5879 }
 5880}
 5881
 5882void testXorLeftShift64()
 5883{
 5884 if (JSC::Options::defaultB3OptLevel() < 2)
 5885 return;
 5886 Vector<int32_t> amounts = { 1, 34, 63 };
 5887
 5888 // Test Pattern: d = n ^ (m << amount)
 5889 auto test = [&] (int64_t n, int64_t m, int32_t amount) -> int64_t {
 5890 Procedure proc;
 5891 BasicBlock* root = proc.addBlock();
 5892
 5893 Value* nValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
 5894 Value* mValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
 5895 Value* amountValue = root->appendNew<Const32Value>(proc, Origin(), amount);
 5896
 5897 Value* shiftValue = root->appendNew<Value>(proc, Shl, Origin(), mValue, amountValue);
 5898 root->appendNewControlValue(
 5899 proc, Return, Origin(),
 5900 root->appendNew<Value>(proc, BitXor, Origin(), nValue, shiftValue));
 5901
 5902 auto code = compileProc(proc);
 5903 if (isARM64()) {
 5904 std::string regex(".*eor.*,.*,.*,.*lsl #");
 5905 regex += std::to_string(amount) + ".*";
 5906 checkUsesInstruction(*code, regex.c_str(), true);
 5907 }
 5908 return invoke<int64_t>(*code, n, m);
 5909 };
 5910
 5911 for (auto nOperand : int64Operands()) {
 5912 for (auto mOperand : int64Operands()) {
 5913 for (auto amount : amounts) {
 5914 int64_t n = nOperand.value;
 5915 int64_t m = mOperand.value;
 5916 CHECK_EQ(test(n, m, amount), n ^ (m << amount));
 5917 }
 5918 }
 5919 }
 5920}
 5921
 5922void testXorRightShift64()
 5923{
 5924 if (JSC::Options::defaultB3OptLevel() < 2)
 5925 return;
 5926 Vector<int32_t> amounts = { 1, 34, 63 };
 5927
 5928 // Test Pattern: d = n ^ (m >> amount)
 5929 auto test = [&] (int64_t n, int64_t m, int32_t amount) -> int64_t {
 5930 Procedure proc;
 5931 BasicBlock* root = proc.addBlock();
 5932
 5933 Value* nValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
 5934 Value* mValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
 5935 Value* amountValue = root->appendNew<Const32Value>(proc, Origin(), amount);
 5936
 5937 Value* shiftValue = root->appendNew<Value>(proc, SShr, Origin(), mValue, amountValue);
 5938 root->appendNewControlValue(
 5939 proc, Return, Origin(),
 5940 root->appendNew<Value>(proc, BitXor, Origin(), nValue, shiftValue));
 5941
 5942 auto code = compileProc(proc);
 5943 if (isARM64()) {
 5944 std::string regex(".*eor.*,.*,.*,.*asr #");
 5945 regex += std::to_string(amount) + ".*";
 5946 checkUsesInstruction(*code, regex.c_str(), true);
 5947 }
 5948 return invoke<int64_t>(*code, n, m);
 5949 };
 5950
 5951 for (auto nOperand : int64Operands()) {
 5952 for (auto mOperand : int64Operands()) {
 5953 for (auto amount : amounts) {
 5954 int64_t n = nOperand.value;
 5955 int64_t m = mOperand.value;
 5956 CHECK_EQ(test(n, m, amount), n ^ (m >> amount));
 5957 }
 5958 }
 5959 }
 5960}
 5961
 5962void testXorUnsignedRightShift64()
 5963{
 5964 if (JSC::Options::defaultB3OptLevel() < 2)
 5965 return;
 5966 Vector<uint32_t> amounts = { 1, 17, 31 };
 5967
 5968 // Test Pattern: d = n ^ (m >> amount)
 5969 auto test = [&] (uint64_t n, uint64_t m, uint32_t amount) -> uint64_t {
 5970 Procedure proc;
 5971 BasicBlock* root = proc.addBlock();
 5972
 5973 Value* nValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
 5974 Value* mValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
 5975 Value* amountValue = root->appendNew<Const32Value>(proc, Origin(), amount);
 5976
 5977 Value* shiftValue = root->appendNew<Value>(proc, ZShr, Origin(), mValue, amountValue);
 5978 root->appendNewControlValue(
 5979 proc, Return, Origin(),
 5980 root->appendNew<Value>(proc, BitXor, Origin(), nValue, shiftValue));
 5981
 5982 auto code = compileProc(proc);
 5983 if (isARM64()) {
 5984 std::string regex(".*eor.*,.*,.*,.*lsr #");
 5985 regex += std::to_string(amount) + ".*";
 5986 checkUsesInstruction(*code, regex.c_str(), true);
 5987 }
 5988 return invoke<uint64_t>(*code, n, m);
 5989 };
 5990
 5991 for (auto nOperand : int64Operands()) {
 5992 for (auto mOperand : int64Operands()) {
 5993 for (auto amount : amounts) {
 5994 uint64_t n = nOperand.value;
 5995 uint64_t m = mOperand.value;
 5996 CHECK_EQ(test(n, m, amount), n ^ (m >> amount));
 5997 }
 5998 }
 5999 }
 6000}
 6001
 6002void testOrLeftShift32()
 6003{
 6004 if (JSC::Options::defaultB3OptLevel() < 2)
 6005 return;
 6006 Vector<int32_t> amounts = { 1, 17, 31 };
 6007
 6008 // Test Pattern: d = n | (m << amount)
 6009 auto test = [&] (int32_t n, int32_t m, int32_t amount) -> int32_t {
 6010 Procedure proc;
 6011 BasicBlock* root = proc.addBlock();
 6012
 6013 Value* nValue = root->appendNew<Value>(
 6014 proc, Trunc, Origin(),
 6015 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
 6016 Value* mValue = root->appendNew<Value>(
 6017 proc, Trunc, Origin(),
 6018 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
 6019 Value* amountValue = root->appendNew<Const32Value>(proc, Origin(), amount);
 6020
 6021 Value* shiftValue = root->appendNew<Value>(proc, Shl, Origin(), mValue, amountValue);
 6022 root->appendNewControlValue(
 6023 proc, Return, Origin(),
 6024 root->appendNew<Value>(proc, BitOr, Origin(), nValue, shiftValue));
 6025
 6026 auto code = compileProc(proc);
 6027 if (isARM64()) {
 6028 std::string regex(".*orr.*,.*,.*,.*lsl #");
 6029 regex += std::to_string(amount) + ".*";
 6030 checkUsesInstruction(*code, regex.c_str(), true);
 6031 }
 6032 return invoke<int32_t>(*code, n, m);
 6033 };
 6034
 6035 for (auto nOperand : int32Operands()) {
 6036 for (auto mOperand : int32Operands()) {
 6037 for (auto amount : amounts) {
 6038 int32_t n = nOperand.value;
 6039 int32_t m = mOperand.value;
 6040 CHECK_EQ(test(n, m, amount), n | (m << amount));
 6041 }
 6042 }
 6043 }
 6044}
 6045
 6046void testOrRightShift32()
 6047{
 6048 if (JSC::Options::defaultB3OptLevel() < 2)
 6049 return;
 6050 Vector<int32_t> amounts = { 1, 17, 31 };
 6051
 6052 // Test Pattern: d = n | (m >> amount)
 6053 auto test = [&] (int32_t n, int32_t m, int32_t amount) -> int32_t {
 6054 Procedure proc;
 6055 BasicBlock* root = proc.addBlock();
 6056
 6057 Value* nValue = root->appendNew<Value>(
 6058 proc, Trunc, Origin(),
 6059 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
 6060 Value* mValue = root->appendNew<Value>(
 6061 proc, Trunc, Origin(),
 6062 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
 6063 Value* amountValue = root->appendNew<Const32Value>(proc, Origin(), amount);
 6064
 6065 Value* shiftValue = root->appendNew<Value>(proc, SShr, Origin(), mValue, amountValue);
 6066 root->appendNewControlValue(
 6067 proc, Return, Origin(),
 6068 root->appendNew<Value>(proc, BitOr, Origin(), nValue, shiftValue));
 6069
 6070 auto code = compileProc(proc);
 6071 if (isARM64()) {
 6072 std::string regex(".*orr.*,.*,.*,.*asr #");
 6073 regex += std::to_string(amount) + ".*";
 6074 checkUsesInstruction(*code, regex.c_str(), true);
 6075 }
 6076 return invoke<int32_t>(*code, n, m);
 6077 };
 6078
 6079 for (auto nOperand : int32Operands()) {
 6080 for (auto mOperand : int32Operands()) {
 6081 for (auto amount : amounts) {
 6082 int32_t n = nOperand.value;
 6083 int32_t m = mOperand.value;
 6084 CHECK_EQ(test(n, m, amount), n | (m >> amount));
 6085 }
 6086 }
 6087 }
 6088}
 6089
 6090void testOrUnsignedRightShift32()
 6091{
 6092 if (JSC::Options::defaultB3OptLevel() < 2)
 6093 return;
 6094 Vector<uint32_t> amounts = { 1, 17, 31 };
 6095
 6096 // Test Pattern: d = n | (m >> amount)
 6097 auto test = [&] (uint32_t n, uint32_t m, uint32_t amount) -> uint32_t {
 6098 Procedure proc;
 6099 BasicBlock* root = proc.addBlock();
 6100
 6101 Value* nValue = root->appendNew<Value>(
 6102 proc, Trunc, Origin(),
 6103 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
 6104 Value* mValue = root->appendNew<Value>(
 6105 proc, Trunc, Origin(),
 6106 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
 6107 Value* amountValue = root->appendNew<Const32Value>(proc, Origin(), amount);
 6108
 6109 Value* shiftValue = root->appendNew<Value>(proc, ZShr, Origin(), mValue, amountValue);
 6110 root->appendNewControlValue(
 6111 proc, Return, Origin(),
 6112 root->appendNew<Value>(proc, BitOr, Origin(), nValue, shiftValue));
 6113
 6114 auto code = compileProc(proc);
 6115 if (isARM64()) {
 6116 std::string regex(".*orr.*,.*,.*,.*lsr #");
 6117 regex += std::to_string(amount) + ".*";
 6118 checkUsesInstruction(*code, regex.c_str(), true);
 6119 }
 6120 return invoke<uint32_t>(*code, n, m);
 6121 };
 6122
 6123 for (auto nOperand : int32Operands()) {
 6124 for (auto mOperand : int32Operands()) {
 6125 for (auto amount : amounts) {
 6126 uint32_t n = nOperand.value;
 6127 uint32_t m = mOperand.value;
 6128 CHECK_EQ(test(n, m, amount), n | (m >> amount));
 6129 }
 6130 }
 6131 }
 6132}
 6133
 6134void testOrLeftShift64()
 6135{
 6136 if (JSC::Options::defaultB3OptLevel() < 2)
 6137 return;
 6138 Vector<int32_t> amounts = { 1, 34, 63 };
 6139
 6140 // Test Pattern: d = n | (m << amount)
 6141 auto test = [&] (int64_t n, int64_t m, int32_t amount) -> int64_t {
 6142 Procedure proc;
 6143 BasicBlock* root = proc.addBlock();
 6144
 6145 Value* nValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
 6146 Value* mValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
 6147 Value* amountValue = root->appendNew<Const32Value>(proc, Origin(), amount);
 6148
 6149 Value* shiftValue = root->appendNew<Value>(proc, Shl, Origin(), mValue, amountValue);
 6150 root->appendNewControlValue(
 6151 proc, Return, Origin(),
 6152 root->appendNew<Value>(proc, BitOr, Origin(), nValue, shiftValue));
 6153
 6154 auto code = compileProc(proc);
 6155 if (isARM64()) {
 6156 std::string regex(".*orr.*,.*,.*,.*lsl #");
 6157 regex += std::to_string(amount) + ".*";
 6158 checkUsesInstruction(*code, regex.c_str(), true);
 6159 }
 6160 return invoke<int64_t>(*code, n, m);
 6161 };
 6162
 6163 for (auto nOperand : int64Operands()) {
 6164 for (auto mOperand : int64Operands()) {
 6165 for (auto amount : amounts) {
 6166 int64_t n = nOperand.value;
 6167 int64_t m = mOperand.value;
 6168 CHECK_EQ(test(n, m, amount), n | (m << amount));
 6169 }
 6170 }
 6171 }
 6172}
 6173
 6174void testOrRightShift64()
 6175{
 6176 if (JSC::Options::defaultB3OptLevel() < 2)
 6177 return;
 6178 Vector<int32_t> amounts = { 1, 34, 63 };
 6179
 6180 // Test Pattern: d = n | (m >> amount)
 6181 auto test = [&] (int64_t n, int64_t m, int32_t amount) -> int64_t {
 6182 Procedure proc;
 6183 BasicBlock* root = proc.addBlock();
 6184
 6185 Value* nValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
 6186 Value* mValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
 6187 Value* amountValue = root->appendNew<Const32Value>(proc, Origin(), amount);
 6188
 6189 Value* shiftValue = root->appendNew<Value>(proc, SShr, Origin(), mValue, amountValue);
 6190 root->appendNewControlValue(
 6191 proc, Return, Origin(),
 6192 root->appendNew<Value>(proc, BitOr, Origin(), nValue, shiftValue));
 6193
 6194 auto code = compileProc(proc);
 6195 if (isARM64()) {
 6196 std::string regex(".*orr.*,.*,.*,.*asr #");
 6197 regex += std::to_string(amount) + ".*";
 6198 checkUsesInstruction(*code, regex.c_str(), true);
 6199 }
 6200 return invoke<int64_t>(*code, n, m);
 6201 };
 6202
 6203 for (auto nOperand : int64Operands()) {
 6204 for (auto mOperand : int64Operands()) {
 6205 for (auto amount : amounts) {
 6206 int64_t n = nOperand.value;
 6207 int64_t m = mOperand.value;
 6208 CHECK_EQ(test(n, m, amount), n | (m >> amount));
 6209 }
 6210 }
 6211 }
 6212}
 6213
 6214void testOrUnsignedRightShift64()
 6215{
 6216 if (JSC::Options::defaultB3OptLevel() < 2)
 6217 return;
 6218 Vector<uint32_t> amounts = { 1, 17, 31 };
 6219
 6220 // Test Pattern: d = n | (m >> amount)
 6221 auto test = [&] (uint64_t n, uint64_t m, uint32_t amount) -> uint64_t {
 6222 Procedure proc;
 6223 BasicBlock* root = proc.addBlock();
 6224
 6225 Value* nValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
 6226 Value* mValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
 6227 Value* amountValue = root->appendNew<Const32Value>(proc, Origin(), amount);
 6228
 6229 Value* shiftValue = root->appendNew<Value>(proc, ZShr, Origin(), mValue, amountValue);
 6230 root->appendNewControlValue(
 6231 proc, Return, Origin(),
 6232 root->appendNew<Value>(proc, BitOr, Origin(), nValue, shiftValue));
 6233
 6234 auto code = compileProc(proc);
 6235 if (isARM64()) {
 6236 std::string regex(".*orr.*,.*,.*,.*lsr #");
 6237 regex += std::to_string(amount) + ".*";
 6238 checkUsesInstruction(*code, regex.c_str(), true);
 6239 }
 6240 return invoke<uint64_t>(*code, n, m);
 6241 };
 6242
 6243 for (auto nOperand : int64Operands()) {
 6244 for (auto mOperand : int64Operands()) {
 6245 for (auto amount : amounts) {
 6246 uint64_t n = nOperand.value;
 6247 uint64_t m = mOperand.value;
 6248 CHECK_EQ(test(n, m, amount), n | (m >> amount));
 6249 }
 6250 }
 6251 }
 6252}
 6253
 6254void testBitAndZeroShiftRightArgImmMask32()
 6255{
 6256 // Turn this: (tmp >> imm) & mask
 6257 // Into this: tmp >> imm
 6258 uint32_t tmp = 0xffffffff;
 6259 Vector<uint32_t> imms = { 4, 28, 31 };
 6260 Vector<uint32_t> masks = { 0x0fffffff, 0xf, 0xffff };
 6261
 6262 auto test = [&] (uint32_t imm, uint32_t mask) {
 6263 Procedure proc;
 6264 BasicBlock* root = proc.addBlock();
 6265
 6266 Value* tmpValue = root->appendNew<Value>(
 6267 proc, Trunc, Origin(),
 6268 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
 6269 Value* immValue = root->appendNew<Const32Value>(proc, Origin(), imm);
 6270 Value* leftValue = root->appendNew<Value>(proc, ZShr, Origin(), tmpValue, immValue);
 6271 Value* rightValue = root->appendNew<Const32Value>(proc, Origin(), mask);
 6272 root->appendNewControlValue(
 6273 proc, Return, Origin(),
 6274 root->appendNew<Value>(proc, BitAnd, Origin(), leftValue, rightValue));
 6275
 6276 auto code = compileProc(proc);
 6277 if (isARM64())
 6278 checkUsesInstruction(*code, "lsr");
 6279 uint32_t lhs = invoke<uint32_t>(*code, tmp);
 6280 uint32_t rhs = tmp >> imm;
 6281 CHECK(lhs == rhs);
 6282 };
 6283
 6284 for (size_t i = 0; i < imms.size(); ++i)
 6285 test(imms.at(i), masks.at(i));
 6286}
 6287
 6288void testBitAndZeroShiftRightArgImmMask64()
 6289{
 6290 // Turn this: (tmp >> imm) & mask
 6291 // Into this: tmp >> imm
 6292 uint64_t tmp = 0xffffffffffffffff;
 6293 Vector<uint64_t> imms = { 4, 60, 63 };
 6294 Vector<uint64_t> masks = { 0x0fffffffffffffff, 0xf, 0xffff };
 6295
 6296 auto test = [&] (uint64_t imm, uint64_t mask) {
 6297 Procedure proc;
 6298 BasicBlock* root = proc.addBlock();
 6299
 6300 Value* tmpValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
 6301 Value* immValue = root->appendNew<Const32Value>(proc, Origin(), imm);
 6302 Value* leftValue = root->appendNew<Value>(proc, ZShr, Origin(), tmpValue, immValue);
 6303 Value* rightValue = root->appendNew<Const64Value>(proc, Origin(), mask);
 6304 root->appendNewControlValue(
 6305 proc, Return, Origin(),
 6306 root->appendNew<Value>(proc, BitAnd, Origin(), leftValue, rightValue));
 6307
 6308 auto code = compileProc(proc);
 6309 if (isARM64())
 6310 checkUsesInstruction(*code, "lsr");
 6311 uint64_t lhs = invoke<uint64_t>(*code, tmp);
 6312 uint64_t rhs = tmp >> imm;
 6313 CHECK(lhs == rhs);
 6314 };
 6315
 6316 for (size_t i = 0; i < imms.size(); ++i)
 6317 test(imms.at(i), masks.at(i));
 6318}
 6319
 6320static void testBitAndArgs(int64_t a, int64_t b)
 6321{
 6322 Procedure proc;
 6323 BasicBlock* root = proc.addBlock();
 6324 root->appendNewControlValue(
 6325 proc, Return, Origin(),
 6326 root->appendNew<Value>(
 6327 proc, BitAnd, Origin(),
 6328 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
 6329 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
 6330
 6331 CHECK(compileAndRun<int64_t>(proc, a, b) == (a & b));
 6332}
 6333
 6334static void testBitAndSameArg(int64_t a)
 6335{
 6336 Procedure proc;
 6337 BasicBlock* root = proc.addBlock();
 6338 Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
 6339 root->appendNewControlValue(
 6340 proc, Return, Origin(),
 6341 root->appendNew<Value>(
 6342 proc, BitAnd, Origin(),
 6343 argument,
 6344 argument));
 6345
 6346 CHECK(compileAndRun<int64_t>(proc, a) == a);
 6347}
 6348
 6349static void testBitAndNotNot(int64_t a, int64_t b)
 6350{
 6351 Procedure proc;
 6352 BasicBlock* root = proc.addBlock();
 6353 Value* argA = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
 6354 Value* argB = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
 6355 Value* notA = root->appendNew<Value>(proc, BitXor, Origin(), argA, root->appendNew<Const64Value>(proc, Origin(), -1));
 6356 Value* notB = root->appendNew<Value>(proc, BitXor, Origin(), argB, root->appendNew<Const64Value>(proc, Origin(), -1));
 6357 root->appendNewControlValue(
 6358 proc, Return, Origin(),
 6359 root->appendNew<Value>(
 6360 proc, BitAnd, Origin(),
 6361 notA,
 6362 notB));
 6363
 6364 CHECK_EQ(compileAndRun<int64_t>(proc, a, b), (~a & ~b));
 6365}
 6366
 6367static void testBitAndNotNot32(int32_t a, int32_t b)
 6368{
 6369 Procedure proc;
 6370 BasicBlock* root = proc.addBlock();
 6371 Value* argA = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
 6372 Value* argB = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
 6373 Value* notA = root->appendNew<Value>(proc, BitXor, Origin(), argA, root->appendNew<Const32Value>(proc, Origin(), -1));
 6374 Value* notB = root->appendNew<Value>(proc, BitXor, Origin(), argB, root->appendNew<Const32Value>(proc, Origin(), -1));
 6375 root->appendNewControlValue(
 6376 proc, Return, Origin(),
 6377 root->appendNew<Value>(
 6378 proc, BitAnd, Origin(),
 6379 notA,
 6380 notB));
 6381
 6382 CHECK_EQ(compileAndRun<int32_t>(proc, a, b), (~a & ~b));
 6383}
 6384
 6385static void testBitAndNotImm(int64_t a, int64_t b)
 6386{
 6387 Procedure proc;
 6388 BasicBlock* root = proc.addBlock();
 6389 Value* argA = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
 6390 Value* notA = root->appendNew<Value>(proc, BitXor, Origin(), argA, root->appendNew<Const64Value>(proc, Origin(), -1));
 6391 Value* cstB = root->appendNew<Const64Value>(proc, Origin(), b);
 6392 root->appendNewControlValue(
 6393 proc, Return, Origin(),
 6394 root->appendNew<Value>(
 6395 proc, BitAnd, Origin(),
 6396 notA,
 6397 cstB));
 6398
 6399 CHECK_EQ(compileAndRun<int64_t>(proc, a), (~a & b));
 6400}
 6401
 6402static void testBitAndNotImm32(int32_t a, int32_t b)
 6403{
 6404 Procedure proc;
 6405 BasicBlock* root = proc.addBlock();
 6406 Value* argA = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
 6407 Value* notA = root->appendNew<Value>(proc, BitXor, Origin(), argA, root->appendNew<Const32Value>(proc, Origin(), -1));
 6408 Value* cstB = root->appendNew<Const32Value>(proc, Origin(), b);
 6409 root->appendNewControlValue(
 6410 proc, Return, Origin(),
 6411 root->appendNew<Value>(
 6412 proc, BitAnd, Origin(),
56236413 notA,
56246414 cstB));
56256415

@@void addBitTests(const char* filter, Deque<RefPtr<SharedTask<void()>>>& tasks)
63897179 RUN(testSubWithLeftShift64());
63907180 RUN(testSubWithRightShift64());
63917181 RUN(testSubWithUnsignedRightShift64());
 7182
 7183 RUN(testAndLeftShift32());
 7184 RUN(testAndRightShift32());
 7185 RUN(testAndUnsignedRightShift32());
 7186 RUN(testAndLeftShift64());
 7187 RUN(testAndRightShift64());
 7188 RUN(testAndUnsignedRightShift64());
 7189
 7190 RUN(testXorLeftShift32());
 7191 RUN(testXorRightShift32());
 7192 RUN(testXorUnsignedRightShift32());
 7193 RUN(testXorLeftShift64());
 7194 RUN(testXorRightShift64());
 7195 RUN(testXorUnsignedRightShift64());
 7196
 7197 RUN(testOrLeftShift32());
 7198 RUN(testOrRightShift32());
 7199 RUN(testOrUnsignedRightShift32());
 7200 RUN(testOrLeftShift64());
 7201 RUN(testOrRightShift64());
 7202 RUN(testOrUnsignedRightShift64());
 7203
63927204 RUN(testBitAndZeroShiftRightArgImmMask32());
63937205 RUN(testBitAndZeroShiftRightArgImmMask64());
63947206 RUN(testBitAndArgs(43, 43));

Source/JavaScriptCore/b3/testb3_3.cpp

@@void addArgTests(const char* filter, Deque<RefPtr<SharedTask<void()>>>& tasks)
37303730 RUN(testMulArgs32(1, 2));
37313731 RUN(testMulArgs32(0xFFFFFFFF, 0xFFFFFFFF));
37323732 RUN(testMulArgs32(0xFFFFFFFE, 0xFFFFFFFF));
3733  RUN(testMulArgs32SignExtend(1, 1));
3734  RUN(testMulArgs32SignExtend(1, 2));
3735  RUN(testMulArgs32SignExtend(0xFFFFFFFF, 0xFFFFFFFF));
3736  RUN(testMulArgs32SignExtend(0xFFFFFFFE, 0xFFFFFFFF));
 3733 RUN(testMulArgs32SignExtend());
 3734 RUN(testMulArgs32ZeroExtend());
37373735 RUN(testMulLoadTwice());
37383736 RUN(testMulAddArgsLeft());
37393737 RUN(testMulAddArgsRight());