| 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 |