| 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 703 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 714 return false; | 714 return false; |
| 715 } | 715 } |
| 716 | 716 |
| 717 | 717 |
| 718 bool Intrinsifier::Integer_mul(Assembler* assembler) { | 718 bool Intrinsifier::Integer_mul(Assembler* assembler) { |
| 719 return Integer_mulFromInteger(assembler); | 719 return Integer_mulFromInteger(assembler); |
| 720 } | 720 } |
| 721 | 721 |
| 722 | 722 |
| 723 bool Intrinsifier::Integer_modulo(Assembler* assembler) { | 723 bool Intrinsifier::Integer_modulo(Assembler* assembler) { |
| 724 Label fall_through, return_zero, try_modulo; | 724 Label fall_through, return_zero, try_modulo, not_32bit; |
| 725 TestBothArgumentsSmis(assembler, &fall_through); | 725 TestBothArgumentsSmis(assembler, &fall_through); |
| 726 // RAX: right argument (divisor) | 726 // RAX: right argument (divisor) |
| 727 // Check if modulo by zero -> exception thrown in main function. | 727 // Check if modulo by zero -> exception thrown in main function. |
| 728 __ cmpq(RAX, Immediate(0)); | 728 __ cmpq(RAX, Immediate(0)); |
| 729 __ j(EQUAL, &fall_through, Assembler::kNearJump); | 729 __ j(EQUAL, &fall_through, Assembler::kNearJump); |
| 730 __ movq(RCX, Address(RSP, + 2 * kWordSize)); // Left argument (dividend). | 730 __ movq(RCX, Address(RSP, + 2 * kWordSize)); // Left argument (dividend). |
| 731 __ cmpq(RCX, Immediate(0)); | 731 __ cmpq(RCX, Immediate(0)); |
| 732 __ j(LESS, &fall_through, Assembler::kNearJump); | 732 __ j(LESS, &fall_through, Assembler::kNearJump); |
| 733 __ cmpq(RCX, RAX); | 733 __ cmpq(RCX, RAX); |
| 734 __ j(EQUAL, &return_zero, Assembler::kNearJump); | 734 __ j(EQUAL, &return_zero, Assembler::kNearJump); |
| 735 __ j(GREATER, &try_modulo, Assembler::kNearJump); | 735 __ j(GREATER, &try_modulo, Assembler::kNearJump); |
| 736 __ movq(RAX, RCX); // Return dividend as it is smaller than divisor. | 736 __ movq(RAX, RCX); // Return dividend as it is smaller than divisor. |
| 737 __ ret(); | 737 __ ret(); |
| 738 |
| 738 __ Bind(&return_zero); | 739 __ Bind(&return_zero); |
| 739 __ xorq(RAX, RAX); // Return zero. | 740 __ xorq(RAX, RAX); // Return zero. |
| 740 __ ret(); | 741 __ ret(); |
| 742 |
| 741 __ Bind(&try_modulo); | 743 __ Bind(&try_modulo); |
| 742 // RAX: right (non-null divisor). | 744 // RAX: right (non-null divisor). |
| 743 __ movq(RCX, RAX); | 745 __ movq(RCX, RAX); |
| 746 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Left argument (dividend). |
| 747 |
| 748 // Check if both operands fit into 32bits as idiv with 64bit operands |
| 749 // requires twice as many cycles and has much higher latency. We are checking |
| 750 // this before untagging them to avoid corner case dividing INT_MAX by -1 that |
| 751 // raises exception because quotient is too large for 32bit register. |
| 752 __ movsxl(RBX, RAX); |
| 753 __ cmpq(RBX, RAX); |
| 754 __ j(NOT_EQUAL, ¬_32bit); |
| 755 __ movsxl(RBX, RCX); |
| 756 __ cmpq(RBX, RCX); |
| 757 __ j(NOT_EQUAL, ¬_32bit); |
| 758 |
| 759 // Both operands are 31bit smis. Divide using 32bit idiv. |
| 760 __ SmiUntag(RAX); |
| 744 __ SmiUntag(RCX); | 761 __ SmiUntag(RCX); |
| 745 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Left argument (dividend). | 762 __ cdq(); |
| 763 __ idivl(RCX); |
| 764 __ movsxl(RAX, RDX); |
| 765 __ SmiTag(RAX); |
| 766 __ ret(); |
| 767 |
| 768 // Divide using 64bit idiv. |
| 769 __ Bind(¬_32bit); |
| 746 __ SmiUntag(RAX); | 770 __ SmiUntag(RAX); |
| 771 __ SmiUntag(RCX); |
| 747 __ cqo(); | 772 __ cqo(); |
| 748 __ idivq(RCX); | 773 __ idivq(RCX); |
| 749 __ movq(RAX, RDX); | 774 __ movq(RAX, RDX); |
| 750 __ SmiTag(RAX); | 775 __ SmiTag(RAX); |
| 751 __ ret(); | 776 __ ret(); |
| 777 |
| 752 __ Bind(&fall_through); | 778 __ Bind(&fall_through); |
| 753 return false; | 779 return false; |
| 754 } | 780 } |
| 755 | 781 |
| 756 | 782 |
| 757 bool Intrinsifier::Integer_truncDivide(Assembler* assembler) { | 783 bool Intrinsifier::Integer_truncDivide(Assembler* assembler) { |
| 758 Label fall_through; | 784 Label fall_through, not_32bit; |
| 759 TestBothArgumentsSmis(assembler, &fall_through); | 785 TestBothArgumentsSmis(assembler, &fall_through); |
| 760 // RAX: right argument (divisor) | 786 // RAX: right argument (divisor) |
| 761 __ cmpq(RAX, Immediate(0)); | 787 __ cmpq(RAX, Immediate(0)); |
| 762 __ j(EQUAL, &fall_through, Assembler::kNearJump); | 788 __ j(EQUAL, &fall_through, Assembler::kNearJump); |
| 763 __ movq(RCX, RAX); | 789 __ movq(RCX, RAX); |
| 790 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Left argument (dividend). |
| 791 |
| 792 // Check if both operands fit into 32bits as idiv with 64bit operands |
| 793 // requires twice as many cycles and has much higher latency. We are checking |
| 794 // this before untagging them to avoid corner case dividing INT_MAX by -1 that |
| 795 // raises exception because quotient is too large for 32bit register. |
| 796 __ movsxl(RBX, RAX); |
| 797 __ cmpq(RBX, RAX); |
| 798 __ j(NOT_EQUAL, ¬_32bit); |
| 799 __ movsxl(RBX, RCX); |
| 800 __ cmpq(RBX, RCX); |
| 801 __ j(NOT_EQUAL, ¬_32bit); |
| 802 |
| 803 // Both operands are 31bit smis. Divide using 32bit idiv. |
| 804 __ SmiUntag(RAX); |
| 764 __ SmiUntag(RCX); | 805 __ SmiUntag(RCX); |
| 765 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Left argument (dividend). | 806 __ cdq(); |
| 807 __ idivl(RCX); |
| 808 __ movsxl(RAX, RAX); |
| 809 __ SmiTag(RAX); // Result is guaranteed to fit into a smi. |
| 810 __ ret(); |
| 811 |
| 812 // Divide using 64bit idiv. |
| 813 __ Bind(¬_32bit); |
| 766 __ SmiUntag(RAX); | 814 __ SmiUntag(RAX); |
| 815 __ SmiUntag(RCX); |
| 767 __ pushq(RDX); // Preserve RDX in case of 'fall_through'. | 816 __ pushq(RDX); // Preserve RDX in case of 'fall_through'. |
| 768 __ cqo(); | 817 __ cqo(); |
| 769 __ idivq(RCX); | 818 __ idivq(RCX); |
| 770 __ popq(RDX); | 819 __ popq(RDX); |
| 771 // Check the corner case of dividing the 'MIN_SMI' with -1, in which case we | 820 // Check the corner case of dividing the 'MIN_SMI' with -1, in which case we |
| 772 // cannot tag the result. | 821 // cannot tag the result. |
| 773 __ cmpq(RAX, Immediate(0x4000000000000000)); | 822 __ cmpq(RAX, Immediate(0x4000000000000000)); |
| 774 __ j(EQUAL, &fall_through); | 823 __ j(EQUAL, &fall_through); |
| 775 __ SmiTag(RAX); | 824 __ SmiTag(RAX); |
| 776 __ ret(); | 825 __ ret(); |
| (...skipping 681 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1458 __ ret(); | 1507 __ ret(); |
| 1459 return true; | 1508 return true; |
| 1460 } | 1509 } |
| 1461 | 1510 |
| 1462 | 1511 |
| 1463 #undef __ | 1512 #undef __ |
| 1464 | 1513 |
| 1465 } // namespace dart | 1514 } // namespace dart |
| 1466 | 1515 |
| 1467 #endif // defined TARGET_ARCH_X64 | 1516 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |