Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(633)

Side by Side Diff: runtime/vm/intrinsifier_x64.cc

Issue 14205023: Fully implement integer modulo in intrinsifier, fall-through only for throwing exceptions. Also int… (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/intrinsifier_mips.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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, &not_32bit); 672 __ j(NOT_EQUAL, &not_32bit, Assembler::kNearJump);
666 __ movsxd(RBX, RCX); 673 __ movsxd(RBX, RCX);
667 __ cmpq(RBX, RCX); 674 __ cmpq(RBX, RCX);
668 __ j(NOT_EQUAL, &not_32bit); 675 __ j(NOT_EQUAL, &not_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(&not_32bit); 686 __ Bind(&not_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
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
OLDNEW
« no previous file with comments | « runtime/vm/intrinsifier_mips.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698