OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_X64. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_X64. |
6 #if defined(TARGET_ARCH_X64) | 6 #if defined(TARGET_ARCH_X64) |
7 | 7 |
8 #include "vm/intrinsifier.h" | 8 #include "vm/intrinsifier.h" |
9 | 9 |
10 #include "vm/assembler.h" | 10 #include "vm/assembler.h" |
(...skipping 542 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
553 #undef TYPEDDATA_ALLOCATOR | 553 #undef TYPEDDATA_ALLOCATOR |
554 | 554 |
555 | 555 |
556 // Tests if two top most arguments are smis, jumps to label not_smi if not. | 556 // Tests if two top most arguments are smis, jumps to label not_smi if not. |
557 // Topmost argument is in RAX. | 557 // Topmost argument is in RAX. |
558 static void TestBothArgumentsSmis(Assembler* assembler, Label* not_smi) { | 558 static void TestBothArgumentsSmis(Assembler* assembler, Label* not_smi) { |
559 __ movq(RAX, Address(RSP, + 1 * kWordSize)); | 559 __ movq(RAX, Address(RSP, + 1 * kWordSize)); |
560 __ movq(RCX, Address(RSP, + 2 * kWordSize)); | 560 __ movq(RCX, Address(RSP, + 2 * kWordSize)); |
561 __ orq(RCX, RAX); | 561 __ orq(RCX, RAX); |
562 __ testq(RCX, Immediate(kSmiTagMask)); | 562 __ testq(RCX, Immediate(kSmiTagMask)); |
563 __ j(NOT_ZERO, not_smi, Assembler::kNearJump); | 563 __ j(NOT_ZERO, not_smi); |
564 } | 564 } |
565 | 565 |
566 | 566 |
567 bool Intrinsifier::Integer_addFromInteger(Assembler* assembler) { | 567 bool Intrinsifier::Integer_addFromInteger(Assembler* assembler) { |
568 Label fall_through; | 568 Label fall_through; |
569 TestBothArgumentsSmis(assembler, &fall_through); | 569 TestBothArgumentsSmis(assembler, &fall_through); |
570 // RAX contains right argument. | 570 // RAX contains right argument. |
571 __ addq(RAX, Address(RSP, + 2 * kWordSize)); | 571 __ addq(RAX, Address(RSP, + 2 * kWordSize)); |
572 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); | 572 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); |
573 // Result is in RAX. | 573 // Result is in RAX. |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
624 __ Bind(&fall_through); | 624 __ Bind(&fall_through); |
625 return false; | 625 return false; |
626 } | 626 } |
627 | 627 |
628 | 628 |
629 bool Intrinsifier::Integer_mul(Assembler* assembler) { | 629 bool Intrinsifier::Integer_mul(Assembler* assembler) { |
630 return Integer_mulFromInteger(assembler); | 630 return Integer_mulFromInteger(assembler); |
631 } | 631 } |
632 | 632 |
633 | 633 |
634 bool Intrinsifier::Integer_modulo(Assembler* assembler) { | 634 // Optimizations: |
635 Label fall_through, return_zero, try_modulo, not_32bit; | 635 // - result is 0 if: |
636 TestBothArgumentsSmis(assembler, &fall_through); | 636 // - left is 0 |
637 // RAX: right argument (divisor) | 637 // - left equals right |
638 // Check if modulo by zero -> exception thrown in main function. | 638 // - result is left if |
| 639 // - left > 0 && left < right |
| 640 // RAX: Tagged left (dividend). |
| 641 // RCX: Tagged right (divisor). |
| 642 // RAX: Untagged result (remainder). |
| 643 void EmitRemainderOperation(Assembler* assembler) { |
| 644 Label return_zero, try_modulo, not_32bit, done; |
| 645 // Check for quick zero results. |
639 __ cmpq(RAX, Immediate(0)); | 646 __ cmpq(RAX, Immediate(0)); |
640 __ j(EQUAL, &fall_through, Assembler::kNearJump); | |
641 __ movq(RCX, Address(RSP, + 2 * kWordSize)); // Left argument (dividend). | |
642 __ cmpq(RCX, Immediate(0)); | |
643 __ j(LESS, &fall_through, Assembler::kNearJump); | |
644 __ cmpq(RCX, RAX); | |
645 __ j(EQUAL, &return_zero, Assembler::kNearJump); | 647 __ j(EQUAL, &return_zero, Assembler::kNearJump); |
646 __ j(GREATER, &try_modulo, Assembler::kNearJump); | 648 __ cmpq(RAX, RCX); |
647 __ movq(RAX, RCX); // Return dividend as it is smaller than divisor. | 649 __ j(EQUAL, &return_zero, Assembler::kNearJump); |
| 650 |
| 651 // Check if result equals left. |
| 652 __ cmpq(RAX, Immediate(0)); |
| 653 __ j(LESS, &try_modulo, Assembler::kNearJump); |
| 654 // left is positive. |
| 655 __ cmpq(RAX, RCX); |
| 656 __ j(GREATER, &try_modulo, Assembler::kNearJump); |
| 657 // left is less than right, result is left (RAX). |
648 __ ret(); | 658 __ ret(); |
649 | 659 |
650 __ Bind(&return_zero); | 660 __ Bind(&return_zero); |
651 __ xorq(RAX, RAX); // Return zero. | 661 __ xorq(RAX, RAX); |
652 __ ret(); | 662 __ ret(); |
653 | 663 |
654 __ Bind(&try_modulo); | 664 __ Bind(&try_modulo); |
655 // RAX: right (non-null divisor). | |
656 __ movq(RCX, RAX); | |
657 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Left argument (dividend). | |
658 | 665 |
659 // Check if both operands fit into 32bits as idiv with 64bit operands | 666 // Check if both operands fit into 32bits as idiv with 64bit operands |
660 // requires twice as many cycles and has much higher latency. We are checking | 667 // requires twice as many cycles and has much higher latency. We are checking |
661 // this before untagging them to avoid corner case dividing INT_MAX by -1 that | 668 // this before untagging them to avoid corner case dividing INT_MAX by -1 that |
662 // raises exception because quotient is too large for 32bit register. | 669 // raises exception because quotient is too large for 32bit register. |
663 __ movsxd(RBX, RAX); | 670 __ movsxd(RBX, RAX); |
664 __ cmpq(RBX, RAX); | 671 __ cmpq(RBX, RAX); |
665 __ j(NOT_EQUAL, ¬_32bit); | 672 __ j(NOT_EQUAL, ¬_32bit, Assembler::kNearJump); |
666 __ movsxd(RBX, RCX); | 673 __ movsxd(RBX, RCX); |
667 __ cmpq(RBX, RCX); | 674 __ cmpq(RBX, RCX); |
668 __ j(NOT_EQUAL, ¬_32bit); | 675 __ j(NOT_EQUAL, ¬_32bit, Assembler::kNearJump); |
669 | 676 |
670 // Both operands are 31bit smis. Divide using 32bit idiv. | 677 // Both operands are 31bit smis. Divide using 32bit idiv. |
671 __ SmiUntag(RAX); | 678 __ SmiUntag(RAX); |
672 __ SmiUntag(RCX); | 679 __ SmiUntag(RCX); |
673 __ cdq(); | 680 __ cdq(); |
674 __ idivl(RCX); | 681 __ idivl(RCX); |
675 __ movsxd(RAX, RDX); | 682 __ movsxd(RAX, RDX); |
676 __ SmiTag(RAX); | 683 __ jmp(&done); |
677 __ ret(); | |
678 | 684 |
679 // Divide using 64bit idiv. | 685 // Divide using 64bit idiv. |
680 __ Bind(¬_32bit); | 686 __ Bind(¬_32bit); |
681 __ SmiUntag(RAX); | 687 __ SmiUntag(RAX); |
682 __ SmiUntag(RCX); | 688 __ SmiUntag(RCX); |
683 __ cqo(); | 689 __ cqo(); |
684 __ idivq(RCX); | 690 __ idivq(RCX); |
685 __ movq(RAX, RDX); | 691 __ movq(RAX, RDX); |
| 692 __ Bind(&done); |
| 693 } |
| 694 |
| 695 |
| 696 // Implementation: |
| 697 // res = left % right; |
| 698 // if (res < 0) { |
| 699 // if (right < 0) { |
| 700 // res = res - right; |
| 701 // } else { |
| 702 // res = res + right; |
| 703 // } |
| 704 // } |
| 705 bool Intrinsifier::Integer_modulo(Assembler* assembler) { |
| 706 Label fall_through, negative_result; |
| 707 TestBothArgumentsSmis(assembler, &fall_through); |
| 708 // RAX: right argument (divisor) |
| 709 __ movq(RCX, RAX); |
| 710 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Left argument (dividend). |
| 711 // RAX: Tagged left (dividend). |
| 712 // RCX: Tagged right (divisor). |
| 713 __ cmpq(RCX, Immediate(0)); |
| 714 __ j(EQUAL, &fall_through); |
| 715 EmitRemainderOperation(assembler); |
| 716 // Untagged remainder result in RAX. |
| 717 __ cmpq(RAX, Immediate(0)); |
| 718 __ j(LESS, &negative_result, Assembler::kNearJump); |
| 719 __ SmiTag(RAX); |
| 720 __ ret(); |
| 721 |
| 722 __ Bind(&negative_result); |
| 723 Label subtract; |
| 724 // RAX: Untagged result. |
| 725 // RCX: Untagged right. |
| 726 __ cmpq(RCX, Immediate(0)); |
| 727 __ j(LESS, &subtract, Assembler::kNearJump); |
| 728 __ addq(RAX, RCX); |
| 729 __ SmiTag(RAX); |
| 730 __ ret(); |
| 731 |
| 732 __ Bind(&subtract); |
| 733 __ subq(RAX, RCX); |
686 __ SmiTag(RAX); | 734 __ SmiTag(RAX); |
687 __ ret(); | 735 __ ret(); |
688 | 736 |
689 __ Bind(&fall_through); | 737 __ Bind(&fall_through); |
690 return false; | 738 return false; |
691 } | 739 } |
692 | 740 |
693 | 741 |
| 742 bool Intrinsifier::Integer_remainder(Assembler* assembler) { |
| 743 Label fall_through; |
| 744 TestBothArgumentsSmis(assembler, &fall_through); |
| 745 // RAX: right argument (divisor) |
| 746 __ movq(RCX, RAX); |
| 747 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Left argument (dividend). |
| 748 // RAX: Tagged left (dividend). |
| 749 // RCX: Tagged right (divisor). |
| 750 __ cmpq(RCX, Immediate(0)); |
| 751 __ j(EQUAL, &fall_through); |
| 752 EmitRemainderOperation(assembler); |
| 753 // Untagged remainder result in RAX. |
| 754 __ SmiTag(RAX); |
| 755 __ ret(); |
| 756 __ Bind(&fall_through); |
| 757 return false; |
| 758 } |
| 759 |
| 760 |
694 bool Intrinsifier::Integer_truncDivide(Assembler* assembler) { | 761 bool Intrinsifier::Integer_truncDivide(Assembler* assembler) { |
695 Label fall_through, not_32bit; | 762 Label fall_through, not_32bit; |
696 TestBothArgumentsSmis(assembler, &fall_through); | 763 TestBothArgumentsSmis(assembler, &fall_through); |
697 // RAX: right argument (divisor) | 764 // RAX: right argument (divisor) |
698 __ cmpq(RAX, Immediate(0)); | 765 __ cmpq(RAX, Immediate(0)); |
699 __ j(EQUAL, &fall_through, Assembler::kNearJump); | 766 __ j(EQUAL, &fall_through, Assembler::kNearJump); |
700 __ movq(RCX, RAX); | 767 __ movq(RCX, RAX); |
701 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Left argument (dividend). | 768 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Left argument (dividend). |
702 | 769 |
703 // Check if both operands fit into 32bits as idiv with 64bit operands | 770 // Check if both operands fit into 32bits as idiv with 64bit operands |
(...skipping 827 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1531 __ Bind(&fall_through); | 1598 __ Bind(&fall_through); |
1532 return false; | 1599 return false; |
1533 } | 1600 } |
1534 | 1601 |
1535 | 1602 |
1536 #undef __ | 1603 #undef __ |
1537 | 1604 |
1538 } // namespace dart | 1605 } // namespace dart |
1539 | 1606 |
1540 #endif // defined TARGET_ARCH_X64 | 1607 #endif // defined TARGET_ARCH_X64 |
OLD | NEW |