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

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

Issue 8995019: More optimizations (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: '' Created 9 years 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/opt_code_generator_ia32.h ('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) 2011, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2011, 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_IA32. 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32.
6 #if defined(TARGET_ARCH_IA32) 6 #if defined(TARGET_ARCH_IA32)
7 7
8 #include "vm/opt_code_generator.h" 8 #include "vm/opt_code_generator.h"
9 9
10 #include "vm/assembler_macros.h" 10 #include "vm/assembler_macros.h"
(...skipping 612 matching lines...) Expand 10 before | Expand all | Expand 10 after
623 } 623 }
624 if (cls1_found && cls2_found) { 624 if (cls1_found && cls2_found) {
625 return true; 625 return true;
626 } 626 }
627 } 627 }
628 } 628 }
629 return false; 629 return false;
630 } 630 }
631 631
632 632
633 // Look only at the first class in all check groups. 633 // Look only at the first class in all check groups. Returns true if all
634 // receiver classes are 'cls'.
634 static bool AtIdNodeHasReceiverClass(AstNode* node, 635 static bool AtIdNodeHasReceiverClass(AstNode* node,
635 intptr_t id, 636 intptr_t id,
636 const Class& cls) { 637 const Class& cls) {
637 ASSERT(node != NULL); 638 ASSERT(node != NULL);
638 ASSERT(!cls.IsNull()); 639 ASSERT(!cls.IsNull());
639 const ICData& ic_data = node->ICDataAtId(id); 640 const ICData& ic_data = node->ICDataAtId(id);
640 if (ic_data.NumberOfChecks() == 0) { 641 if (ic_data.NumberOfChecks() == 0) {
641 return false; 642 return false;
642 } 643 }
643 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { 644 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) {
(...skipping 27 matching lines...) Expand all
671 Function& target = Function::Handle(); 672 Function& target = Function::Handle();
672 GrowableArray<const Class*> classes; 673 GrowableArray<const Class*> classes;
673 ic_data.GetCheckAt(0, &classes, &target); 674 ic_data.GetCheckAt(0, &classes, &target);
674 if ((cls0.raw() == classes[0]->raw()) && (cls1.raw() == classes[1]->raw())) { 675 if ((cls0.raw() == classes[0]->raw()) && (cls1.raw() == classes[1]->raw())) {
675 return true; 676 return true;
676 } 677 }
677 return false; 678 return false;
678 } 679 }
679 680
680 681
681 static bool AtIdNodeHasOnlyClass(AstNode* node, intptr_t id, const Class& cls) {
682 ASSERT(node != NULL);
683 ASSERT(!cls.IsNull());
684 const ICData& ic_data = node->ICDataAtId(id);
685 if ((ic_data.NumberOfArgumentsChecked() != 1) ||
686 (ic_data.NumberOfChecks() != 1)) {
687 return false;
688 }
689 Class& target_cls = Class::Handle();
690 Function& target = Function::Handle();
691 ic_data.GetOneClassCheckAt(0, &target_cls, &target);
692 return target_cls.raw() == cls.raw();
693 }
694
695
696
697 // SHL: Implement with slow case so that it works both with Smi and Mint types. 682 // SHL: Implement with slow case so that it works both with Smi and Mint types.
698 // Result is in EAX. Mangles ECX, EBX, EDX. 683 // Result is in EAX. Mangles ECX, EBX, EDX.
699 void OptimizingCodeGenerator::GenerateSmiShiftBinaryOp(BinaryOpNode* node) { 684 void OptimizingCodeGenerator::GenerateSmiShiftBinaryOp(BinaryOpNode* node) {
700 if (node->kind() == Token::kSAR) { 685 if (node->kind() == Token::kSAR) {
701 // TODO(srdjan): Implement for Mint? 686 // TODO(srdjan): Implement for Mint?
702 DeoptimizationBlob* deopt_blob = 687 DeoptimizationBlob* deopt_blob =
703 AddDeoptimizationBlob(node, EAX, ECX, kDeoptSAR); 688 AddDeoptimizationBlob(node, EAX, ECX, kDeoptSAR);
704 // EAX: value to shift, ECX: amount to shift. 689 // EAX: value to shift, ECX: amount to shift.
705 VisitLoadTwo(node->left(), node->right(), EAX, ECX); 690 VisitLoadTwo(node->left(), node->right(), EAX, ECX);
706 // Check if both Smi. 691 // Check if both Smi.
707 __ movl(EBX, EAX); 692 __ movl(EBX, EAX);
708 __ orl(EBX, ECX); 693 __ orl(EBX, ECX);
709 __ testl(EBX, Immediate(kSmiTagMask)); 694 __ testl(EBX, Immediate(kSmiTagMask));
710 __ j(NOT_ZERO, deopt_blob->label()); 695 __ j(NOT_ZERO, deopt_blob->label());
711 Immediate count_limit = Immediate(0x1F); 696 Immediate count_limit = Immediate(0x1F);
712 __ SmiUntag(ECX); 697 __ SmiUntag(ECX);
713 __ cmpl(ECX, count_limit); 698 __ cmpl(ECX, count_limit);
714 Label shift_count_ok; 699 Label shift_count_ok;
715 __ j(LESS_EQUAL, &shift_count_ok, Assembler::kNearJump); 700 __ j(LESS_EQUAL, &shift_count_ok, Assembler::kNearJump);
716 __ movl(ECX, count_limit); 701 __ movl(ECX, count_limit);
717 __ Bind(&shift_count_ok); 702 __ Bind(&shift_count_ok);
718 // Shift amount must be in ECX. 703 // Shift amount must be in ECX.
719 __ SmiUntag(EAX); // Value. 704 __ SmiUntag(EAX); // Value.
720 __ sarl(EAX, ECX); 705 __ sarl(EAX, ECX);
721 __ SmiTag(EAX); 706 __ SmiTag(EAX);
722 return; 707 return;
723 } 708 }
724 ASSERT(node->kind() == Token::kSHL); 709 ASSERT(node->kind() == Token::kSHL);
725 Label done;
726 bool shift_generated = false;
727 if (node->right()->IsLiteralNode() && 710 if (node->right()->IsLiteralNode() &&
728 node->right()->AsLiteralNode()->literal().IsSmi()) { 711 node->right()->AsLiteralNode()->literal().IsSmi()) {
712 Label done;
729 // Shift count is a Smi literal. 713 // Shift count is a Smi literal.
730 Smi& smi = Smi::Handle(); 714 Smi& smi = Smi::Handle();
731 smi ^= node->right()->AsLiteralNode()->literal().raw(); 715 smi ^= node->right()->AsLiteralNode()->literal().raw();
732 if (smi.Value() < Smi::kBits) { 716 if (smi.Value() < Smi::kBits) {
733 Label slow_case; 717 Label slow_case;
734 VisitLoadOne(node->left(), EAX); 718 VisitLoadOne(node->left(), EAX);
735 __ testl(EAX, Immediate(kSmiTagMask)); 719 __ testl(EAX, Immediate(kSmiTagMask));
736 __ j(NOT_ZERO, &slow_case, Assembler::kNearJump); // left not smi 720 __ j(NOT_ZERO, &slow_case, Assembler::kNearJump); // left not smi
737 // Overflow test. 721 // Overflow test.
738 __ movl(EBX, EAX); 722 __ movl(EBX, EAX);
739 Immediate imm(smi.Value()); 723 Immediate imm(smi.Value());
740 __ shll(EBX, imm); 724 __ shll(EBX, imm);
741 __ sarl(EBX, imm); 725 __ sarl(EBX, imm);
742 __ cmpl(EAX, EBX); 726 __ cmpl(EAX, EBX);
743 __ j(NOT_EQUAL, &slow_case, Assembler::kNearJump); // Overflow. 727 __ j(NOT_EQUAL, &slow_case, Assembler::kNearJump); // Overflow.
744 __ shll(EAX, imm); // Shift for result now we know there is no overflow. 728 __ shll(EAX, imm); // Shift for result now we know there is no overflow.
745 __ jmp(&done); 729 __ jmp(&done);
746 __ Bind(&slow_case); 730 __ Bind(&slow_case);
747 __ pushl(EAX); 731 __ pushl(EAX);
748 __ pushl(Immediate(reinterpret_cast<int32_t>(smi.raw()))); 732 __ pushl(Immediate(reinterpret_cast<int32_t>(smi.raw())));
749 CodeGenerator::GenerateBinaryOperatorCall(node->id(), 733 const int number_of_arguments = 2;
750 node->token_index(), 734 const Array& no_optional_argument_names = Array::Handle();
751 node->Name()); 735 GenerateCheckedInstanceCalls(node,
752 shift_generated = true; 736 node->left(),
737 node->id(),
738 node->token_index(),
739 number_of_arguments,
740 no_optional_argument_names);
741 __ Bind(&done);
742 return;
753 } 743 }
754 } 744 }
755 745
756 if (!shift_generated) { 746 Label slow_case, done;
757 Label slow_case; 747 VisitLoadTwo(node->left(), node->right(), EAX, EDX);
758 VisitLoadTwo(node->left(), node->right(), EAX, EDX); 748 // TODO(srdjan): Better code for count being a Smi literal.
759 // TODO(srdjan): Better code for count being a Smi literal. 749 // EAX: value, EDX: shift amount. Preserve them for slow case.
760 // EAX: value, EDX: shift amount. Preserve them for slow case. 750 // Fast case only if both ar Smi.
761 // Fast case only if both ar Smi. 751 __ movl(EBX, EAX);
762 __ movl(EBX, EAX); 752 __ orl(EBX, EDX);
763 __ orl(EBX, EDX); 753 __ testl(EBX, Immediate(kSmiTagMask));
764 __ testl(EBX, Immediate(kSmiTagMask)); 754 __ j(NOT_ZERO, &slow_case, Assembler::kNearJump);
765 __ j(NOT_ZERO, &slow_case, Assembler::kNearJump); 755 // Check if count too large for handling it inlined.
766 // Check if count too large for handling it inlined. 756 __ cmpl(EDX, Immediate(reinterpret_cast<int32_t>(Smi::New(Smi::kBits))));
767 __ cmpl(EDX, Immediate(reinterpret_cast<int32_t>(Smi::New(Smi::kBits)))); 757 __ j(ABOVE_EQUAL, &slow_case, Assembler::kNearJump);
768 __ j(ABOVE_EQUAL, &slow_case, Assembler::kNearJump); 758 // Shift amount must be in ECX.
769 // Shift amount must be in ECX. 759 __ movl(ECX, EDX);
770 __ movl(ECX, EDX); 760 __ movl(EBX, EAX);
771 __ movl(EBX, EAX); 761 __ SmiUntag(ECX);
772 __ SmiUntag(ECX); 762 // Overflow test.
773 // Overflow test. 763 __ shll(EBX, ECX);
774 __ shll(EBX, ECX); 764 __ sarl(EBX, ECX);
775 __ sarl(EBX, ECX); 765 __ cmpl(EAX, EBX);
776 __ cmpl(EAX, EBX); 766 __ j(NOT_EQUAL, &slow_case, Assembler::kNearJump); // Overflow.
777 __ j(NOT_EQUAL, &slow_case, Assembler::kNearJump); // Overflow.
778 767
779 __ shll(EAX, ECX); // Shift for result now we know there is no overflow. 768 __ shll(EAX, ECX); // Shift for result now we know there is no overflow.
780 // EAX is the correctly tagged Smi. 769 // EAX is the correctly tagged Smi.
781 __ jmp(&done); 770 __ jmp(&done);
782 __ Bind(&slow_case); 771 __ Bind(&slow_case);
783 __ pushl(EAX); 772 __ pushl(EAX);
784 __ pushl(EDX); 773 __ pushl(EDX);
785 const int number_of_arguments = 2; 774 const int number_of_arguments = 2;
786 const Array& no_optional_argument_names = Array::Handle(); 775 const Array& no_optional_argument_names = Array::Handle();
787 GenerateCheckedInstanceCalls(node, 776 GenerateCheckedInstanceCalls(node,
788 node->left(), 777 node->left(),
789 node->id(), 778 node->id(),
790 node->token_index(), 779 node->token_index(),
791 number_of_arguments, 780 number_of_arguments,
792 no_optional_argument_names); 781 no_optional_argument_names);
793 shift_generated = true;
794 }
795 __ Bind(&done); 782 __ Bind(&done);
796 } 783 }
797 784
798 785
799 // Implement Token::kSUB and Token::kBIT_NOT. 786 // Implement Token::kSUB and Token::kBIT_NOT.
800 void OptimizingCodeGenerator::GenerateSmiUnaryOp(UnaryOpNode* node) { 787 void OptimizingCodeGenerator::GenerateSmiUnaryOp(UnaryOpNode* node) {
801 const ICData& ic_data = node->ICDataAtId(node->id()); 788 const ICData& ic_data = node->ICDataAtId(node->id());
802 ASSERT(ic_data.NumberOfArgumentsChecked() == 1); 789 ASSERT(ic_data.NumberOfArgumentsChecked() == 1);
803 DeoptReasonId deopt_reason_id = ic_data.NumberOfChecks() == 0 ? 790 DeoptReasonId deopt_reason_id = ic_data.NumberOfChecks() == 0 ?
804 kDeoptNoTypeFeedback : kDeoptUnaryOp; 791 kDeoptNoTypeFeedback : kDeoptUnaryOp;
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
875 ASSERT(kResultRegister == EAX); 862 ASSERT(kResultRegister == EAX);
876 node->info()->set_result_returned_in_eax(true); 863 node->info()->set_result_returned_in_eax(true);
877 } else { 864 } else {
878 __ pushl(kResultRegister); 865 __ pushl(kResultRegister);
879 } 866 }
880 } 867 }
881 } 868 }
882 869
883 870
884 // Handles only Smi & Smi. 871 // Handles only Smi & Smi.
872 // TODO(srdjan): Certain operations always overflow, and thus cause
873 // deoptimization. We need to mark those places and handle them.
885 void OptimizingCodeGenerator::GenerateSmiBinaryOp(BinaryOpNode* node) { 874 void OptimizingCodeGenerator::GenerateSmiBinaryOp(BinaryOpNode* node) {
886 const char* kOptMessage = "Inlines BinaryOp for Smi"; 875 const char* kOptMessage = "Inlines BinaryOp for Smi";
887 Label done; 876 Label done;
888 const Token::Kind kind = node->kind(); 877 const Token::Kind kind = node->kind();
889 if ((kind == Token::kADD) || 878 if ((kind == Token::kADD) ||
890 (kind == Token::kSUB) || 879 (kind == Token::kSUB) ||
891 (kind == Token::kMUL) || 880 (kind == Token::kMUL) ||
892 (kind == Token::kTRUNCDIV) || 881 (kind == Token::kTRUNCDIV) ||
893 (kind == Token::kBIT_AND) || 882 (kind == Token::kBIT_AND) ||
894 (kind == Token::kBIT_OR) || 883 (kind == Token::kBIT_OR) ||
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
1039 // Load lower Mint word, convert to Smi. It is OK to loose bits. 1028 // Load lower Mint word, convert to Smi. It is OK to loose bits.
1040 __ movl(EAX, FieldAddress(EAX, Mint::value_offset())); 1029 __ movl(EAX, FieldAddress(EAX, Mint::value_offset()));
1041 __ SmiTag(EAX); 1030 __ SmiTag(EAX);
1042 1031
1043 __ Bind(&is_smi); 1032 __ Bind(&is_smi);
1044 __ andl(EAX, EDX); 1033 __ andl(EAX, EDX);
1045 __ jmp(&done); 1034 __ jmp(&done);
1046 __ Bind(&slow_case); 1035 __ Bind(&slow_case);
1047 __ pushl(EAX); 1036 __ pushl(EAX);
1048 __ pushl(EDX); 1037 __ pushl(EDX);
1049 GenerateBinaryOperatorCall(node->id(), node->token_index(), node->Name()); 1038 const int number_of_arguments = 2;
1039 const Array& no_optional_argument_names = Array::Handle();
1040 GenerateCheckedInstanceCalls(node,
1041 node->left(),
1042 node->id(),
1043 node->token_index(),
1044 number_of_arguments,
1045 no_optional_argument_names);
1050 __ Bind(&done); 1046 __ Bind(&done);
1051 if (CodeGenerator::IsResultNeeded(node)) { 1047 if (CodeGenerator::IsResultNeeded(node)) {
1052 __ pushl(EAX); 1048 __ pushl(EAX);
1053 } 1049 }
1054 return; 1050 return;
1055 } 1051 }
1056 if ((kind == Token::kSHL) && allow_smi) { 1052 if ((kind == Token::kSHL) && allow_smi) {
1057 GenerateSmiShiftBinaryOp(node); 1053 GenerateSmiShiftBinaryOp(node);
1058 if (CodeGenerator::IsResultNeeded(node)) { 1054 if (CodeGenerator::IsResultNeeded(node)) {
1059 __ pushl(EAX); 1055 __ pushl(EAX);
(...skipping 23 matching lines...) Expand all
1083 Label* is_smi, 1079 Label* is_smi,
1084 Label* not_double_or_smi) { 1080 Label* not_double_or_smi) {
1085 __ testl(reg, Immediate(kSmiTagMask)); 1081 __ testl(reg, Immediate(kSmiTagMask));
1086 __ j(ZERO, is_smi); 1082 __ j(ZERO, is_smi);
1087 __ movl(temp, FieldAddress(reg, Object::class_offset())); 1083 __ movl(temp, FieldAddress(reg, Object::class_offset()));
1088 __ CompareObject(temp, double_class_); 1084 __ CompareObject(temp, double_class_);
1089 __ j(NOT_EQUAL, not_double_or_smi); 1085 __ j(NOT_EQUAL, not_double_or_smi);
1090 } 1086 }
1091 1087
1092 1088
1093 // TODO(srdjan): Detect double/Smi operation and remove extra code to
1094 // always check for Smi on the right hand side.
1095 // Result of the computation is a newly allocated double object or 1089 // Result of the computation is a newly allocated double object or
1096 // a temporary object if the parent node specifies a CodeGenInfo for this node 1090 // a temporary object if the parent node specifies a CodeGenInfo for this node
1097 // and therefore knows how to handle a temporary. A temporary object cannot 1091 // and therefore knows how to handle a temporary. A temporary object cannot
1098 // be used for long living values (e.g., the ones stored on stack or into other 1092 // be used for long living values (e.g., the ones stored on stack or into other
1099 // objects). 1093 // objects).
1100 void OptimizingCodeGenerator::GenerateDoubleBinaryOp(BinaryOpNode* node) { 1094 // Implement for combinations: Double/Double, Double/Smi, Smi/Double, as
1095 // the result is always double.
1096 // TODO(srdjan): Implement Smi/Smi for kDIV (result also double).
1097 void OptimizingCodeGenerator::GenerateDoubleBinaryOp(BinaryOpNode* node,
1098 bool receiver_can_be_smi) {
1101 const char* kOptMessage = "Inlines BinaryOp for Doubles"; 1099 const char* kOptMessage = "Inlines BinaryOp for Doubles";
1102 const Token::Kind kind = node->kind(); 1100 const Token::Kind kind = node->kind();
1103 if ((kind == Token::kADD) || 1101 if ((kind == Token::kADD) ||
1104 (kind == Token::kSUB) || 1102 (kind == Token::kSUB) ||
1105 (kind == Token::kMUL) || 1103 (kind == Token::kMUL) ||
1106 (kind == Token::kDIV)) { 1104 (kind == Token::kDIV)) {
1107 TraceOpt(node, kOptMessage); 1105 TraceOpt(node, kOptMessage);
1108 // All four register below must be different. 1106 // All four register below must be different.
1109 const Register kLeftRegister = EAX; 1107 const Register kLeftRegister = EAX;
1110 const Register kRightRegister = EDX; 1108 const Register kRightRegister = EDX;
(...skipping 21 matching lines...) Expand all
1132 result_register = kLeftRegister; 1130 result_register = kLeftRegister;
1133 } else if (right_info.IsClass(double_class_) && right_info.is_temp()) { 1131 } else if (right_info.IsClass(double_class_) && right_info.is_temp()) {
1134 result_register = kRightRegister; 1132 result_register = kRightRegister;
1135 } else { 1133 } else {
1136 result_register = kAllocatedRegister; 1134 result_register = kAllocatedRegister;
1137 // Use inlined temporary double object. 1135 // Use inlined temporary double object.
1138 const Double& double_object = 1136 const Double& double_object =
1139 Double::ZoneHandle(Double::New(0.0, Heap::kOld)); 1137 Double::ZoneHandle(Double::New(0.0, Heap::kOld));
1140 __ LoadObject(result_register, double_object); 1138 __ LoadObject(result_register, double_object);
1141 } 1139 }
1142 Label is_smi, extract_left; 1140
1143 DeoptimizationBlob* deopt_blob = NULL; 1141 DeoptimizationBlob* deopt_blob = NULL;
1144 Label* deopt_lbl = NULL; 1142 Label* deopt_lbl = NULL;
1143 // Deoptimization can only occur if one of arguments is not double.
1145 if (!left_info.IsClass(double_class_) || 1144 if (!left_info.IsClass(double_class_) ||
1146 !right_info.IsClass(double_class_)) { 1145 !right_info.IsClass(double_class_)) {
1147 deopt_blob = AddDeoptimizationBlob(node, 1146 deopt_blob = AddDeoptimizationBlob(node,
1148 kLeftRegister, 1147 kLeftRegister,
1149 kRightRegister, 1148 kRightRegister,
1150 kDeoptDoubleBinaryOp); 1149 kDeoptDoubleBinaryOp);
1151 deopt_lbl = deopt_blob->label(); 1150 deopt_lbl = deopt_blob->label();
1152 } 1151 }
1153 1152
1153 if (receiver_can_be_smi) {
1154 // Only deoptimize if both argument are Smi.
1155 __ movl(kTempRegister, kLeftRegister);
1156 __ orl(kTempRegister, kRightRegister);
1157 __ testl(kTempRegister, Immediate(kSmiTagMask));
1158 __ j(ZERO, deopt_lbl);
1159 }
1160
1154 bool nodes_of_same_type = AreNodesOfSameType(node->left(), node->right()); 1161 bool nodes_of_same_type = AreNodesOfSameType(node->left(), node->right());
1155 if (!left_info.IsClass(double_class_)) { 1162 if (!left_info.IsClass(double_class_)) {
1156 CheckIfDoubleOrSmi(kLeftRegister, kTempRegister, deopt_lbl, deopt_lbl); 1163 Label is_smi, done;
1157 // Fall through for double. Jump to 'deopt' if not double. 1164 CheckIfDoubleOrSmi(kLeftRegister, kTempRegister, &is_smi, deopt_lbl);
1165 // Fall through for double. Jump to 'is_smi' if double, jump to
1166 // 'deopt' if neither smi nor double.
1167 __ movsd(XMM0, FieldAddress(kLeftRegister, Double::value_offset()));
1168 __ jmp(&done);
1169 __ Bind(&is_smi);
1170 __ SmiUntag(kLeftRegister);
1171 __ cvtsi2sd(XMM0, kLeftRegister);
1172 __ Bind(&done);
1173 } else {
1174 __ movsd(XMM0, FieldAddress(kLeftRegister, Double::value_offset()));
1158 } 1175 }
1159 if (!right_info.IsClass(double_class_) && !nodes_of_same_type) { 1176 if (!right_info.IsClass(double_class_) && !nodes_of_same_type) {
1177 Label is_smi, done;
1160 CheckIfDoubleOrSmi(kRightRegister, kTempRegister, &is_smi, deopt_lbl); 1178 CheckIfDoubleOrSmi(kRightRegister, kTempRegister, &is_smi, deopt_lbl);
1161 // Fall through for double. Jump to 'is_smi' if double, jump to 1179 // Fall through for double. Jump to 'is_smi' if double, jump to
1162 // 'deopt' if neither smi nor double. 1180 // 'deopt' if neither smi nor double.
1163 __ movsd(XMM1, FieldAddress(kRightRegister, Double::value_offset())); 1181 __ movsd(XMM1, FieldAddress(kRightRegister, Double::value_offset()));
1164 __ jmp(&extract_left); 1182 __ jmp(&done);
1165 __ Bind(&is_smi); 1183 __ Bind(&is_smi);
1166 __ SmiUntag(kRightRegister); 1184 __ SmiUntag(kRightRegister);
1167 __ cvtsi2sd(XMM1, kRightRegister); 1185 __ cvtsi2sd(XMM1, kRightRegister);
1168 __ Bind(&extract_left); 1186 __ Bind(&done);
1169 } else { 1187 } else {
1170 __ movsd(XMM1, FieldAddress(kRightRegister, Double::value_offset())); 1188 __ movsd(XMM1, FieldAddress(kRightRegister, Double::value_offset()));
1171 } 1189 }
1172 __ movsd(XMM0, FieldAddress(kLeftRegister, Double::value_offset()));
1173 1190
1174 switch (kind) { 1191 switch (kind) {
1175 case Token::kADD: __ addsd(XMM0, XMM1); break; 1192 case Token::kADD: __ addsd(XMM0, XMM1); break;
1176 case Token::kSUB: __ subsd(XMM0, XMM1); break; 1193 case Token::kSUB: __ subsd(XMM0, XMM1); break;
1177 case Token::kMUL: __ mulsd(XMM0, XMM1); break; 1194 case Token::kMUL: __ mulsd(XMM0, XMM1); break;
1178 case Token::kDIV: __ divsd(XMM0, XMM1); break; 1195 case Token::kDIV: __ divsd(XMM0, XMM1); break;
1179 default: UNREACHABLE(); 1196 default: UNREACHABLE();
1180 } 1197 }
1181 __ movsd(FieldAddress(result_register, Double::value_offset()), XMM0); 1198 __ movsd(FieldAddress(result_register, Double::value_offset()), XMM0);
1182 if (CodeGenerator::IsResultNeeded(node)) { 1199 if (CodeGenerator::IsResultNeeded(node)) {
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
1299 __ jmp(deopt_blob->label()); 1316 __ jmp(deopt_blob->label());
1300 return; 1317 return;
1301 } 1318 }
1302 1319
1303 if (AtIdNodeHasTwoClasses(node, node->id(), smi_class_, smi_class_)) { 1320 if (AtIdNodeHasTwoClasses(node, node->id(), smi_class_, smi_class_)) {
1304 GenerateSmiBinaryOp(node); 1321 GenerateSmiBinaryOp(node);
1305 return; 1322 return;
1306 } 1323 }
1307 1324
1308 if (AtIdNodeHasReceiverClass(node, node->id(), double_class_)) { 1325 if (AtIdNodeHasReceiverClass(node, node->id(), double_class_)) {
1309 GenerateDoubleBinaryOp(node); 1326 const bool receiver_can_be_smi = false;
1327 GenerateDoubleBinaryOp(node, receiver_can_be_smi);
1328 return;
1329 }
1330
1331 if (AtIdNodeHasTwoClasses(node, node->id(), smi_class_, double_class_)) {
1332 const bool receiver_can_be_smi = true;
1333 GenerateDoubleBinaryOp(node, receiver_can_be_smi);
1310 return; 1334 return;
1311 } 1335 }
1312 1336
1313 const Class& mint_class = 1337 const Class& mint_class =
1314 Class::Handle(Isolate::Current()->object_store()->mint_class()); 1338 Class::Handle(Isolate::Current()->object_store()->mint_class());
1315 if (AtIdNodeHasReceiverClass(node, node->id(), mint_class)) { 1339 if (AtIdNodeHasReceiverClass(node, node->id(), mint_class)) {
1316 GenerateMintBinaryOp(node, false); 1340 GenerateMintBinaryOp(node, false);
1317 return; 1341 return;
1318 } 1342 }
1319 1343
(...skipping 997 matching lines...) Expand 10 before | Expand all | Expand 10 after
2317 } 2341 }
2318 2342
2319 2343
2320 void OptimizingCodeGenerator::VisitLoadIndexedNode(LoadIndexedNode* node) { 2344 void OptimizingCodeGenerator::VisitLoadIndexedNode(LoadIndexedNode* node) {
2321 const char* kMessage = "Inline indexed access"; 2345 const char* kMessage = "Inline indexed access";
2322 ObjectStore* object_store = Isolate::Current()->object_store(); 2346 ObjectStore* object_store = Isolate::Current()->object_store();
2323 const Class& object_array_class = 2347 const Class& object_array_class =
2324 Class::ZoneHandle(object_store->array_class()); 2348 Class::ZoneHandle(object_store->array_class());
2325 const Class& immutable_object_array_class = 2349 const Class& immutable_object_array_class =
2326 Class::ZoneHandle(object_store->immutable_array_class()); 2350 Class::ZoneHandle(object_store->immutable_array_class());
2327 if (AtIdNodeHasOnlyClass(node, node->id(), object_array_class) || 2351 if (AtIdNodeHasReceiverClass(node, node->id(), object_array_class) ||
2328 AtIdNodeHasOnlyClass(node, node->id(), immutable_object_array_class)) { 2352 AtIdNodeHasReceiverClass(node, node->id(),
2353 immutable_object_array_class)) {
2329 VisitLoadTwo(node->array(), node->index_expr(), EBX, EDX); 2354 VisitLoadTwo(node->array(), node->index_expr(), EBX, EDX);
2330 DeoptimizationBlob* deopt_blob = 2355 DeoptimizationBlob* deopt_blob =
2331 AddDeoptimizationBlob(node, EBX, EDX, kDeoptLoadIndexedFixedArray); 2356 AddDeoptimizationBlob(node, EBX, EDX, kDeoptLoadIndexedFixedArray);
2332 const Class& test_class = 2357 const Class& test_class =
2333 AtIdNodeHasOnlyClass(node, node->id(), object_array_class) ? 2358 AtIdNodeHasReceiverClass(node, node->id(), object_array_class) ?
2334 object_array_class : immutable_object_array_class; 2359 object_array_class : immutable_object_array_class;
2335 // Type checks of array. 2360 // Type checks of array.
2336 __ testl(EBX, Immediate(kSmiTagMask)); // Deoptimize if Smi. 2361 __ testl(EBX, Immediate(kSmiTagMask)); // Deoptimize if Smi.
2337 __ j(ZERO, deopt_blob->label()); 2362 __ j(ZERO, deopt_blob->label());
2338 __ movl(EAX, FieldAddress(EBX, Object::class_offset())); 2363 __ movl(EAX, FieldAddress(EBX, Object::class_offset()));
2339 __ CompareObject(EAX, test_class); 2364 __ CompareObject(EAX, test_class);
2340 __ j(NOT_EQUAL, deopt_blob->label()); 2365 __ j(NOT_EQUAL, deopt_blob->label());
2341 2366
2342 // Type check of index. 2367 // Type check of index.
2343 __ testl(EDX, Immediate(kSmiTagMask)); 2368 __ testl(EDX, Immediate(kSmiTagMask));
2344 __ j(NOT_ZERO, deopt_blob->label()); 2369 __ j(NOT_ZERO, deopt_blob->label());
2345 // Range check. 2370 // Range check.
2346 __ cmpl(EDX, FieldAddress(EBX, Array::length_offset())); 2371 __ cmpl(EDX, FieldAddress(EBX, Array::length_offset()));
2347 __ j(ABOVE_EQUAL, deopt_blob->label()); 2372 __ j(ABOVE_EQUAL, deopt_blob->label());
2348 // Note that EDX is Smi, i.e, times 2. 2373 // Note that EDX is Smi, i.e, times 2.
2349 ASSERT(kSmiTagShift == 1); 2374 ASSERT(kSmiTagShift == 1);
2350 __ movl(EAX, FieldAddress(EBX, EDX, TIMES_2, sizeof(RawArray))); 2375 __ movl(EAX, FieldAddress(EBX, EDX, TIMES_2, sizeof(RawArray)));
2351 if (CodeGenerator::IsResultNeeded(node)) { 2376 if (CodeGenerator::IsResultNeeded(node)) {
2352 __ pushl(EAX); 2377 __ pushl(EAX);
2353 } 2378 }
2354 TraceOpt(node, kMessage); 2379 TraceOpt(node, kMessage);
2355 return; 2380 return;
2356 } 2381 }
2357 2382
2358 const String& growable_object_array_class_name = String::Handle( 2383 const String& growable_object_array_class_name = String::Handle(
2359 String::NewSymbol(kGrowableArrayClassName)); 2384 String::NewSymbol(kGrowableArrayClassName));
2360 const Class& growable_array_class = Class::ZoneHandle( 2385 const Class& growable_array_class = Class::ZoneHandle(
2361 Library::Handle(Library::CoreImplLibrary()). 2386 Library::Handle(Library::CoreImplLibrary()).
2362 LookupClass(growable_object_array_class_name)); 2387 LookupClass(growable_object_array_class_name));
2363 if (AtIdNodeHasOnlyClass(node, node->id(), growable_array_class)) { 2388 if (AtIdNodeHasReceiverClass(node, node->id(), growable_array_class)) {
2364 const String& growable_array_length_field_name = 2389 const String& growable_array_length_field_name =
2365 String::Handle(String::NewSymbol(kGrowableArrayLengthFieldName)); 2390 String::Handle(String::NewSymbol(kGrowableArrayLengthFieldName));
2366 const String& growable_array_array_field_name = 2391 const String& growable_array_array_field_name =
2367 String::Handle(String::NewSymbol(kGrowableArrayArrayFieldName)); 2392 String::Handle(String::NewSymbol(kGrowableArrayArrayFieldName));
2368 intptr_t length_offset = GetFieldOffset(growable_array_class, 2393 intptr_t length_offset = GetFieldOffset(growable_array_class,
2369 growable_array_length_field_name); 2394 growable_array_length_field_name);
2370 intptr_t array_offset = GetFieldOffset(growable_array_class, 2395 intptr_t array_offset = GetFieldOffset(growable_array_class,
2371 growable_array_array_field_name); 2396 growable_array_array_field_name);
2372 VisitLoadTwo(node->array(), node->index_expr(), EDX, EAX); 2397 VisitLoadTwo(node->array(), node->index_expr(), EDX, EAX);
2373 DeoptimizationBlob* deopt_blob = 2398 DeoptimizationBlob* deopt_blob =
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
2411 const Class& object_array_class = 2436 const Class& object_array_class =
2412 Class::ZoneHandle(object_store->array_class()); 2437 Class::ZoneHandle(object_store->array_class());
2413 const ICData& ic_data = node->ICDataAtId(node->id()); 2438 const ICData& ic_data = node->ICDataAtId(node->id());
2414 if (ic_data.NumberOfChecks() == 0) { 2439 if (ic_data.NumberOfChecks() == 0) {
2415 VisitLoadTwo(node->index_expr(), node->value(), EBX, ECX); 2440 VisitLoadTwo(node->index_expr(), node->value(), EBX, ECX);
2416 DeoptimizationBlob* deopt_blob = 2441 DeoptimizationBlob* deopt_blob =
2417 AddDeoptimizationBlob(node, EBX, ECX, kDeoptNoTypeFeedback); 2442 AddDeoptimizationBlob(node, EBX, ECX, kDeoptNoTypeFeedback);
2418 __ jmp(deopt_blob->label()); 2443 __ jmp(deopt_blob->label());
2419 return; 2444 return;
2420 } 2445 }
2421 if (AtIdNodeHasOnlyClass(node, node->id(), object_array_class)) { 2446 if (AtIdNodeHasReceiverClass(node, node->id(), object_array_class)) {
2422 VisitLoadTwo(node->index_expr(), node->value(), EBX, ECX); 2447 VisitLoadTwo(node->index_expr(), node->value(), EBX, ECX);
2423 DeoptimizationBlob* deopt_blob = 2448 DeoptimizationBlob* deopt_blob =
2424 AddDeoptimizationBlob(node, EAX, EBX, ECX, kDeoptStoreIndexed); 2449 AddDeoptimizationBlob(node, EAX, EBX, ECX, kDeoptStoreIndexed);
2425 __ popl(EAX); // array. 2450 __ popl(EAX); // array.
2426 // ECX: value, EBX:index, EAX: array. 2451 // ECX: value, EBX:index, EAX: array.
2427 // Check type of array. 2452 // Check type of array.
2428 __ testl(EAX, Immediate(kSmiTagMask)); 2453 __ testl(EAX, Immediate(kSmiTagMask));
2429 __ j(ZERO, deopt_blob->label()); // Array is smi -> deopt. 2454 __ j(ZERO, deopt_blob->label()); // Array is smi -> deopt.
2430 __ movl(EDX, FieldAddress(EAX, Object::class_offset())); 2455 __ movl(EDX, FieldAddress(EAX, Object::class_offset()));
2431 __ CompareObject(EDX, object_array_class); 2456 __ CompareObject(EDX, object_array_class);
(...skipping 372 matching lines...) Expand 10 before | Expand all | Expand 10 after
2804 node->function_name(), 2829 node->function_name(),
2805 num_arguments, 2830 num_arguments,
2806 num_named_arguments)); 2831 num_named_arguments));
2807 Recognizer::Kind recognized = Recognizer::RecognizeKind(target); 2832 Recognizer::Kind recognized = Recognizer::RecognizeKind(target);
2808 if (FLAG_trace_optimization) { 2833 if (FLAG_trace_optimization) {
2809 OS::Print("Monomorphic inline candidate: %s -> %s\n", 2834 OS::Print("Monomorphic inline candidate: %s -> %s\n",
2810 target.ToFullyQualifiedCString(), 2835 target.ToFullyQualifiedCString(),
2811 Recognizer::KindToCString(recognized)); 2836 Recognizer::KindToCString(recognized));
2812 } 2837 }
2813 if ((recognized == Recognizer::kIntegerToDouble) && 2838 if ((recognized == Recognizer::kIntegerToDouble) &&
2814 AtIdNodeHasOnlyClass(node, node->id(), smi_class_)) { 2839 AtIdNodeHasReceiverClass(node, node->id(), smi_class_)) {
2815 // TODO(srdjan): Check if we could use temporary double instead of 2840 // TODO(srdjan): Check if we could use temporary double instead of
2816 // allocating a new object every time. 2841 // allocating a new object every time.
2817 const Code& stub = 2842 const Code& stub =
2818 Code::Handle(StubCode::GetAllocationStubForClass(double_class_)); 2843 Code::Handle(StubCode::GetAllocationStubForClass(double_class_));
2819 const ExternalLabel label(double_class_.ToCString(), stub.EntryPoint()); 2844 const ExternalLabel label(double_class_.ToCString(), stub.EntryPoint());
2820 GenerateCall(node->token_index(), &label); 2845 GenerateCall(node->token_index(), &label);
2821 // EAX is double object. 2846 // EAX is double object.
2822 DeoptimizationBlob* deopt_blob = 2847 DeoptimizationBlob* deopt_blob =
2823 AddDeoptimizationBlob(node, EBX, kDeoptIntegerToDouble); 2848 AddDeoptimizationBlob(node, EBX, kDeoptIntegerToDouble);
2824 __ popl(EBX); // Receiver 2849 __ popl(EBX); // Receiver
2825 __ testl(EBX, Immediate(kSmiTagMask)); 2850 __ testl(EBX, Immediate(kSmiTagMask));
2826 __ j(NOT_ZERO, deopt_blob->label()); // Deoptimize if not Smi. 2851 __ j(NOT_ZERO, deopt_blob->label()); // Deoptimize if not Smi.
2827 __ SmiUntag(EBX); 2852 __ SmiUntag(EBX);
2828 __ cvtsi2sd(XMM0, EBX); 2853 __ cvtsi2sd(XMM0, EBX);
2829 __ movsd(FieldAddress(EAX, Double::value_offset()), XMM0); 2854 __ movsd(FieldAddress(EAX, Double::value_offset()), XMM0);
2830 return true; 2855 return true;
2831 } 2856 }
2832 2857
2833 if ((recognized == Recognizer::kDoubleToDouble) && 2858 if ((recognized == Recognizer::kDoubleToDouble) &&
2834 AtIdNodeHasOnlyClass(node, node->id(), double_class_)) { 2859 AtIdNodeHasReceiverClass(node, node->id(), double_class_)) {
2835 DeoptimizationBlob* deopt_blob = 2860 DeoptimizationBlob* deopt_blob =
2836 AddDeoptimizationBlob(node, EAX, kDeoptDoubleToDouble); 2861 AddDeoptimizationBlob(node, EAX, kDeoptDoubleToDouble);
2837 __ popl(EAX); 2862 __ popl(EAX);
2838 CheckIfDoubleOrSmi(EAX, EBX, deopt_blob->label(), deopt_blob->label()); 2863 CheckIfDoubleOrSmi(EAX, EBX, deopt_blob->label(), deopt_blob->label());
2839 return true; 2864 return true;
2840 } 2865 }
2841 } 2866 }
2842 return false; 2867 return false;
2843 } 2868 }
2844 2869
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after
2978 if (IsResultInEaxRequested(node)) { 3003 if (IsResultInEaxRequested(node)) {
2979 node->info()->set_result_returned_in_eax(true); 3004 node->info()->set_result_returned_in_eax(true);
2980 } else { 3005 } else {
2981 __ pushl(EAX); 3006 __ pushl(EAX);
2982 } 3007 }
2983 } 3008 }
2984 return; 3009 return;
2985 } 3010 }
2986 3011
2987 if ((node->kind() == Token::kSUB) || (node->kind() == Token::kBIT_NOT)) { 3012 if ((node->kind() == Token::kSUB) || (node->kind() == Token::kBIT_NOT)) {
2988 if (AtIdNodeHasOnlyClass(node, node->id(), smi_class_)) { 3013 if (AtIdNodeHasReceiverClass(node, node->id(), smi_class_)) {
2989 const ICData& ic_data = node->ICDataAtId(node->id()); 3014 const ICData& ic_data = node->ICDataAtId(node->id());
2990 ASSERT(ic_data.NumberOfArgumentsChecked() == 1); 3015 ASSERT(ic_data.NumberOfArgumentsChecked() == 1);
2991 GenerateSmiUnaryOp(node); 3016 GenerateSmiUnaryOp(node);
2992 return; 3017 return;
2993 } 3018 }
2994 } 3019 }
2995 if (node->kind() == Token::kSUB) { 3020 if (node->kind() == Token::kSUB) {
2996 if (AtIdNodeHasReceiverClass(node, node->id(), double_class_)) { 3021 if (AtIdNodeHasReceiverClass(node, node->id(), double_class_)) {
2997 const ICData& ic_data = node->ICDataAtId(node->id()); 3022 const ICData& ic_data = node->ICDataAtId(node->id());
2998 ASSERT(ic_data.NumberOfArgumentsChecked() == 1); 3023 ASSERT(ic_data.NumberOfArgumentsChecked() == 1);
2999 GenerateDoubleUnaryOp(node); 3024 GenerateDoubleUnaryOp(node);
3000 return; 3025 return;
3001 } 3026 }
3002 } 3027 }
3003 // TODO(srdjan): Implement unary kSUB (negate) Mint. 3028 // TODO(srdjan): Implement unary kSUB (negate) Mint.
3004 CodeGenerator::VisitUnaryOpNode(node); 3029 CodeGenerator::VisitUnaryOpNode(node);
3005 } 3030 }
3006 3031
3007 3032
3008 } // namespace dart 3033 } // namespace dart
3009 3034
3010 #endif // defined TARGET_ARCH_IA32 3035 #endif // defined TARGET_ARCH_IA32
OLDNEW
« no previous file with comments | « runtime/vm/opt_code_generator_ia32.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698