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

Side by Side Diff: src/ia32/codegen-ia32.cc

Issue 119037: As a simplification, manually inline the function... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: Created 11 years, 6 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 | « no previous file | 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 2006-2009 the V8 project authors. All rights reserved. 1 // Copyright 2006-2009 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 758 matching lines...) Expand 10 before | Expand all | Expand 10 after
769 case Token::BIT_AND: return "GenericBinaryOpStub_BIT_AND"; 769 case Token::BIT_AND: return "GenericBinaryOpStub_BIT_AND";
770 case Token::BIT_XOR: return "GenericBinaryOpStub_BIT_XOR"; 770 case Token::BIT_XOR: return "GenericBinaryOpStub_BIT_XOR";
771 case Token::SAR: return "GenericBinaryOpStub_SAR"; 771 case Token::SAR: return "GenericBinaryOpStub_SAR";
772 case Token::SHL: return "GenericBinaryOpStub_SHL"; 772 case Token::SHL: return "GenericBinaryOpStub_SHL";
773 case Token::SHR: return "GenericBinaryOpStub_SHR"; 773 case Token::SHR: return "GenericBinaryOpStub_SHR";
774 default: return "GenericBinaryOpStub"; 774 default: return "GenericBinaryOpStub";
775 } 775 }
776 } 776 }
777 777
778 778
779 // A deferred code class implementing binary operations on likely smis. 779 // Call the specialized stub for a binary operation.
780 // This class generates both inline code and deferred code.
781 // The fastest path is implemented inline. Deferred code calls
782 // the GenericBinaryOpStub stub for slow cases.
783 class DeferredInlineBinaryOperation: public DeferredCode { 780 class DeferredInlineBinaryOperation: public DeferredCode {
784 public: 781 public:
785 DeferredInlineBinaryOperation(Token::Value op, 782 DeferredInlineBinaryOperation(Token::Value op,
786 OverwriteMode mode, 783 OverwriteMode mode)
787 GenericBinaryFlags flags) 784 : op_(op), mode_(mode) {
788 : stub_(op, mode, flags), op_(op) {
789 set_comment("[ DeferredInlineBinaryOperation"); 785 set_comment("[ DeferredInlineBinaryOperation");
790 } 786 }
791 787
792 // Consumes its arguments, left and right, leaving them invalid.
793 Result GenerateInlineCode(Result* left, Result* right);
794
795 virtual void Generate(); 788 virtual void Generate();
796 789
797 private: 790 private:
798 GenericBinaryOpStub stub_;
799 Token::Value op_; 791 Token::Value op_;
792 OverwriteMode mode_;
800 }; 793 };
801 794
802 795
803 void DeferredInlineBinaryOperation::Generate() { 796 void DeferredInlineBinaryOperation::Generate() {
804 Result left; 797 Result left;
805 Result right; 798 Result right;
806 enter()->Bind(&left, &right); 799 enter()->Bind(&left, &right);
807 cgen()->frame()->Push(&left); 800 cgen()->frame()->Push(&left);
808 cgen()->frame()->Push(&right); 801 cgen()->frame()->Push(&right);
809 Result answer = cgen()->frame()->CallStub(&stub_, 2); 802 GenericBinaryOpStub stub(op_, mode_, SMI_CODE_INLINED);
803 Result answer = cgen()->frame()->CallStub(&stub, 2);
810 exit_.Jump(&answer); 804 exit_.Jump(&answer);
811 } 805 }
812 806
813 807
814 void CodeGenerator::GenericBinaryOperation(Token::Value op, 808 void CodeGenerator::GenericBinaryOperation(Token::Value op,
815 SmiAnalysis* type, 809 SmiAnalysis* type,
816 OverwriteMode overwrite_mode) { 810 OverwriteMode overwrite_mode) {
817 Comment cmnt(masm_, "[ BinaryOperation"); 811 Comment cmnt(masm_, "[ BinaryOperation");
818 Comment cmnt_token(masm_, Token::String(op)); 812 Comment cmnt_token(masm_, Token::String(op));
819 813
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after
1000 } 994 }
1001 frame_->Push(Handle<Object>(answer_object)); 995 frame_->Push(Handle<Object>(answer_object));
1002 return true; 996 return true;
1003 } 997 }
1004 998
1005 999
1006 void CodeGenerator::LikelySmiBinaryOperation(Token::Value op, 1000 void CodeGenerator::LikelySmiBinaryOperation(Token::Value op,
1007 Result* left, 1001 Result* left,
1008 Result* right, 1002 Result* right,
1009 OverwriteMode overwrite_mode) { 1003 OverwriteMode overwrite_mode) {
1010 // Implements a binary operation using a deferred code object 1004 // Implements a binary operation using a deferred code object and
1011 // and some inline code to operate on smis quickly. 1005 // some inline code to operate on smis quickly.
1012 DeferredInlineBinaryOperation* deferred = 1006 DeferredInlineBinaryOperation* deferred =
1013 new DeferredInlineBinaryOperation(op, overwrite_mode, SMI_CODE_INLINED); 1007 new DeferredInlineBinaryOperation(op, overwrite_mode);
1014 // Generate the inline code that handles some smi operations, 1008
1015 // and jumps to the deferred code for everything else. 1009 // Special handling of div and mod because they use fixed registers.
1016 Result answer = deferred->GenerateInlineCode(left, right); 1010 if (op == Token::DIV || op == Token::MOD) {
1011 // We need eax as the quotient register, edx as the remainder
1012 // register, neither left nor right in eax or edx, and left copied
1013 // to eax.
1014 Result quotient;
1015 Result remainder;
1016 bool left_is_in_eax = false;
1017 // Step 1: get eax for quotient.
1018 if ((left->is_register() && left->reg().is(eax)) ||
1019 (right->is_register() && right->reg().is(eax))) {
1020 // One or both is in eax. Use a fresh non-edx register for
1021 // them.
1022 Result fresh = allocator_->Allocate();
1023 ASSERT(fresh.is_valid());
1024 if (fresh.reg().is(edx)) {
1025 remainder = fresh;
1026 fresh = allocator_->Allocate();
1027 ASSERT(fresh.is_valid());
1028 }
1029 if (left->is_register() && left->reg().is(eax)) {
1030 quotient = *left;
1031 *left = fresh;
1032 left_is_in_eax = true;
1033 }
1034 if (right->is_register() && right->reg().is(eax)) {
1035 quotient = *right;
1036 *right = fresh;
1037 }
1038 __ mov(fresh.reg(), eax);
1039 } else {
1040 // Neither left nor right is in eax.
1041 quotient = allocator_->Allocate(eax);
1042 }
1043 ASSERT(quotient.is_register() && quotient.reg().is(eax));
1044 ASSERT(!(left->is_register() && left->reg().is(eax)));
1045 ASSERT(!(right->is_register() && right->reg().is(eax)));
1046
1047 // Step 2: get edx for remainder if necessary.
1048 if (!remainder.is_valid()) {
1049 if ((left->is_register() && left->reg().is(edx)) ||
1050 (right->is_register() && right->reg().is(edx))) {
1051 Result fresh = allocator_->Allocate();
1052 ASSERT(fresh.is_valid());
1053 if (left->is_register() && left->reg().is(edx)) {
1054 remainder = *left;
1055 *left = fresh;
1056 }
1057 if (right->is_register() && right->reg().is(edx)) {
1058 remainder = *right;
1059 *right = fresh;
1060 }
1061 __ mov(fresh.reg(), edx);
1062 } else {
1063 // Neither left nor right is in edx.
1064 remainder = allocator_->Allocate(edx);
1065 }
1066 }
1067 ASSERT(remainder.is_register() && remainder.reg().is(edx));
1068 ASSERT(!(left->is_register() && left->reg().is(edx)));
1069 ASSERT(!(right->is_register() && right->reg().is(edx)));
1070
1071 left->ToRegister();
1072 right->ToRegister();
1073 frame_->Spill(quotient.reg());
1074 frame_->Spill(remainder.reg());
1075
1076 // Check that left and right are smi tagged.
1077 if (left->reg().is(right->reg())) {
1078 __ test(left->reg(), Immediate(kSmiTagMask));
1079 } else {
1080 // Use the quotient register as a scratch for the tag check.
1081 if (!left_is_in_eax) __ mov(quotient.reg(), left->reg());
1082 left_is_in_eax = false;
1083 __ or_(quotient.reg(), Operand(right->reg()));
1084 ASSERT(kSmiTag == 0); // Adjust test if not the case.
1085 __ test(quotient.reg(), Immediate(kSmiTagMask));
1086 }
1087 deferred->SetEntryFrame(left, right);
1088 deferred->enter()->Branch(not_zero, left, right);
1089
1090 if (!left_is_in_eax) __ mov(quotient.reg(), left->reg());
1091
1092 // Sign extend eax into edx:eax.
1093 __ cdq();
1094 // Check for 0 divisor.
1095 __ test(right->reg(), Operand(right->reg()));
1096 deferred->enter()->Branch(zero, left, right);
1097 // Divide edx:eax by the right operand.
1098 __ idiv(right->reg());
1099
1100 // Complete the operation.
1101 if (op == Token::DIV) {
1102 // Check for negative zero result. If result is zero, and divisor
1103 // is negative, return a floating point negative zero. The
1104 // virtual frame is unchanged in this block, so local control flow
1105 // can use a Label rather than a JumpTarget.
1106 Label non_zero_result;
1107 __ test(left->reg(), Operand(left->reg()));
1108 __ j(not_zero, &non_zero_result);
1109 __ test(right->reg(), Operand(right->reg()));
1110 deferred->enter()->Branch(negative, left, right);
1111 __ bind(&non_zero_result);
1112 // Check for the corner case of dividing the most negative smi by
1113 // -1. We cannot use the overflow flag, since it is not set by
1114 // idiv instruction.
1115 ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
1116 __ cmp(quotient.reg(), 0x40000000);
1117 deferred->enter()->Branch(equal, left, right);
1118 // Check that the remainder is zero.
1119 __ test(remainder.reg(), Operand(remainder.reg()));
1120 remainder.Unuse();
1121 deferred->enter()->Branch(not_zero, left, right);
1122 left->Unuse();
1123 right->Unuse();
1124 // Tag the result and store it in the quotient register.
1125 ASSERT(kSmiTagSize == times_2); // adjust code if not the case
1126 __ lea(quotient.reg(),
1127 Operand(quotient.reg(), quotient.reg(), times_1, kSmiTag));
1128 deferred->BindExit(&quotient);
1129 frame_->Push(&quotient);
1130 } else {
1131 ASSERT(op == Token::MOD);
1132 quotient.Unuse();
1133 // Check for a negative zero result. If the result is zero, and
1134 // the dividend is negative, return a floating point negative
1135 // zero. The frame is unchanged in this block, so local control
1136 // flow can use a Label rather than a JumpTarget.
1137 Label non_zero_result;
1138 __ test(remainder.reg(), Operand(remainder.reg()));
1139 __ j(not_zero, &non_zero_result, taken);
1140 __ test(left->reg(), Operand(left->reg()));
1141 deferred->enter()->Branch(negative, left, right);
1142 left->Unuse();
1143 right->Unuse();
1144 __ bind(&non_zero_result);
1145 deferred->BindExit(&remainder);
1146 frame_->Push(&remainder);
1147 }
1148 return;
1149 }
1150
1151 // Handle the other binary operations.
1152 left->ToRegister();
1153 right->ToRegister();
1154 // A newly allocated register answer is used to hold the answer. The
1155 // registers containing left and right are not modified in most cases,
1156 // so they usually don't need to be spilled in the fast case.
1157 Result answer = allocator_->Allocate();
1158
1159 ASSERT(answer.is_valid());
1160 // Perform the smi tag check.
1161 if (left->reg().is(right->reg())) {
1162 __ test(left->reg(), Immediate(kSmiTagMask));
1163 } else {
1164 __ mov(answer.reg(), left->reg());
1165 __ or_(answer.reg(), Operand(right->reg()));
1166 ASSERT(kSmiTag == 0); // Adjust test if not the case.
1167 __ test(answer.reg(), Immediate(kSmiTagMask));
1168 }
1169 switch (op) {
1170 case Token::ADD:
1171 deferred->SetEntryFrame(left, right);
1172 deferred->enter()->Branch(not_zero, left, right, not_taken);
1173 __ mov(answer.reg(), left->reg());
1174 __ add(answer.reg(), Operand(right->reg())); // Add optimistically.
1175 deferred->enter()->Branch(overflow, left, right, not_taken);
1176 break;
1177
1178 case Token::SUB:
1179 deferred->SetEntryFrame(left, right);
1180 deferred->enter()->Branch(not_zero, left, right, not_taken);
1181 __ mov(answer.reg(), left->reg());
1182 __ sub(answer.reg(), Operand(right->reg())); // Subtract optimistically.
1183 deferred->enter()->Branch(overflow, left, right, not_taken);
1184 break;
1185
1186 case Token::MUL: {
1187 deferred->SetEntryFrame(left, right);
1188 deferred->enter()->Branch(not_zero, left, right, not_taken);
1189 __ mov(answer.reg(), left->reg());
1190 // If the smi tag is 0 we can just leave the tag on one operand.
1191 ASSERT(kSmiTag == 0); // Adjust code below if not the case.
1192 // Remove smi tag from the left operand (but keep sign).
1193 // Left-hand operand has been copied into answer.
1194 __ sar(answer.reg(), kSmiTagSize);
1195 // Do multiplication of smis, leaving result in answer.
1196 __ imul(answer.reg(), Operand(right->reg()));
1197 // Go slow on overflows.
1198 deferred->enter()->Branch(overflow, left, right, not_taken);
1199 // Check for negative zero result. If product is zero, and one
1200 // argument is negative, go to slow case. The frame is unchanged
1201 // in this block, so local control flow can use a Label rather
1202 // than a JumpTarget.
1203 Label non_zero_result;
1204 __ test(answer.reg(), Operand(answer.reg()));
1205 __ j(not_zero, &non_zero_result, taken);
1206 __ mov(answer.reg(), left->reg());
1207 __ or_(answer.reg(), Operand(right->reg()));
1208 deferred->enter()->Branch(negative, left, right, not_taken);
1209 __ xor_(answer.reg(), Operand(answer.reg())); // Positive 0 is correct.
1210 __ bind(&non_zero_result);
1211 break;
1212 }
1213
1214 case Token::BIT_OR:
1215 deferred->enter()->Branch(not_zero, left, right, not_taken);
1216 __ mov(answer.reg(), left->reg());
1217 __ or_(answer.reg(), Operand(right->reg()));
1218 break;
1219
1220 case Token::BIT_AND:
1221 deferred->enter()->Branch(not_zero, left, right, not_taken);
1222 __ mov(answer.reg(), left->reg());
1223 __ and_(answer.reg(), Operand(right->reg()));
1224 break;
1225
1226 case Token::BIT_XOR:
1227 deferred->enter()->Branch(not_zero, left, right, not_taken);
1228 __ mov(answer.reg(), left->reg());
1229 __ xor_(answer.reg(), Operand(right->reg()));
1230 break;
1231
1232 case Token::SHL:
1233 case Token::SHR:
1234 case Token::SAR:
1235 deferred->enter()->Branch(not_zero, left, right, not_taken);
1236 __ mov(answer.reg(), left->reg());
1237 // Move right into ecx.
1238 // Left is in two registers already, so even if left or answer is ecx,
1239 // we can move right to it, and use the other one.
1240 // Right operand must be in register cl because x86 likes it that way.
1241 if (right->reg().is(ecx)) {
1242 // Right is already in the right place. Left may be in the
1243 // same register, which causes problems. Always use answer
1244 // instead of left, even if left is not ecx, since this avoids
1245 // spilling left.
1246 *left = answer;
1247 } else if (left->reg().is(ecx)) {
1248 frame_->Spill(left->reg());
1249 __ mov(left->reg(), right->reg());
1250 *right = *left;
1251 *left = answer; // Use copy of left in answer as left.
1252 } else if (answer.reg().is(ecx)) {
1253 __ mov(answer.reg(), right->reg());
1254 *right = answer;
1255 } else {
1256 Result reg_ecx = allocator_->Allocate(ecx);
1257 ASSERT(reg_ecx.is_valid());
1258 __ mov(ecx, right->reg());
1259 *right = reg_ecx;
1260 // Answer and left both contain the left operand. Use answer, so
1261 // left is not spilled.
1262 *left = answer;
1263 }
1264 ASSERT(left->reg().is_valid());
1265 ASSERT(!left->reg().is(ecx));
1266 ASSERT(right->reg().is(ecx));
1267 answer.Unuse(); // Answer may now be being used for left or right.
1268 // We will modify left and right, which we do not do in any other
1269 // binary operation. The exits to slow code need to restore the
1270 // original values of left and right, or at least values that give
1271 // the same answer.
1272
1273 // We are modifying left and right. They must be spilled!
1274 frame_->Spill(left->reg());
1275 frame_->Spill(right->reg());
1276
1277 // Remove tags from operands (but keep sign).
1278 __ sar(left->reg(), kSmiTagSize);
1279 __ sar(ecx, kSmiTagSize);
1280 // Perform the operation.
1281 switch (op) {
1282 case Token::SAR:
1283 __ sar(left->reg());
1284 // No checks of result necessary
1285 break;
1286 case Token::SHR: {
1287 __ shr(left->reg());
1288 // Check that the *unsigned* result fits in a smi.
1289 // Neither of the two high-order bits can be set:
1290 // - 0x80000000: high bit would be lost when smi tagging.
1291 // - 0x40000000: this number would convert to negative when
1292 // Smi tagging these two cases can only happen with shifts
1293 // by 0 or 1 when handed a valid smi.
1294 // If the answer cannot be represented by a SMI, restore
1295 // the left and right arguments, and jump to slow case.
1296 // The low bit of the left argument may be lost, but only
1297 // in a case where it is dropped anyway.
1298 JumpTarget result_ok;
1299 __ test(left->reg(), Immediate(0xc0000000));
1300 result_ok.Branch(zero, left, taken);
1301 __ shl(left->reg());
1302 ASSERT(kSmiTag == 0);
1303 __ shl(left->reg(), kSmiTagSize);
1304 __ shl(right->reg(), kSmiTagSize);
1305 deferred->enter()->Jump(left, right);
1306 result_ok.Bind(left);
1307 break;
1308 }
1309 case Token::SHL: {
1310 __ shl(left->reg());
1311 // Check that the *signed* result fits in a smi.
1312 JumpTarget result_ok;
1313 __ cmp(left->reg(), 0xc0000000);
1314 result_ok.Branch(positive, left, taken);
1315
1316 __ shr(left->reg());
1317 ASSERT(kSmiTag == 0);
1318 __ shl(left->reg(), kSmiTagSize);
1319 __ shl(right->reg(), kSmiTagSize);
1320 deferred->enter()->Jump(left, right);
1321 result_ok.Bind(left);
1322 break;
1323 }
1324 default:
1325 UNREACHABLE();
1326 }
1327 // Smi-tag the result, in left, and make answer an alias for left->
1328 answer = *left;
1329 answer.ToRegister();
1330 ASSERT(kSmiTagSize == times_2); // adjust code if not the case
1331 __ lea(answer.reg(),
1332 Operand(answer.reg(), answer.reg(), times_1, kSmiTag));
1333 break;
1334
1335 default:
1336 UNREACHABLE();
1337 break;
1338 }
1339 left->Unuse();
1340 right->Unuse();
1017 deferred->BindExit(&answer); 1341 deferred->BindExit(&answer);
1018 frame_->Push(&answer); 1342 frame_->Push(&answer);
1019 } 1343 }
1020 1344
1021 1345
1022 class DeferredInlineSmiOperation: public DeferredCode { 1346 class DeferredInlineSmiOperation: public DeferredCode {
1023 public: 1347 public:
1024 DeferredInlineSmiOperation(Token::Value op, 1348 DeferredInlineSmiOperation(Token::Value op,
1025 Smi* value, 1349 Smi* value,
1026 OverwriteMode overwrite_mode) 1350 OverwriteMode overwrite_mode)
(...skipping 4698 matching lines...) Expand 10 before | Expand all | Expand 10 after
5725 // Return 1/0 for true/false in eax. 6049 // Return 1/0 for true/false in eax.
5726 __ bind(&true_result); 6050 __ bind(&true_result);
5727 __ mov(eax, 1); 6051 __ mov(eax, 1);
5728 __ ret(1 * kPointerSize); 6052 __ ret(1 * kPointerSize);
5729 __ bind(&false_result); 6053 __ bind(&false_result);
5730 __ mov(eax, 0); 6054 __ mov(eax, 0);
5731 __ ret(1 * kPointerSize); 6055 __ ret(1 * kPointerSize);
5732 } 6056 }
5733 6057
5734 6058
5735 Result DeferredInlineBinaryOperation::GenerateInlineCode(Result* left,
5736 Result* right) {
5737 MacroAssembler* masm = cgen()->masm();
5738
5739 // Special handling of div and mod because they use fixed registers.
5740 if (op_ == Token::DIV || op_ == Token::MOD) {
5741 // We need eax as the quotient register, edx as the remainder
5742 // register, neither left nor right in eax or edx, and left copied
5743 // to eax.
5744 Result quotient;
5745 Result remainder;
5746 bool left_is_in_eax = false;
5747 // Step 1: get eax for quotient.
5748 if ((left->is_register() && left->reg().is(eax)) ||
5749 (right->is_register() && right->reg().is(eax))) {
5750 // One or both is in eax. Use a fresh non-edx register for
5751 // them.
5752 Result fresh = cgen()->allocator()->Allocate();
5753 ASSERT(fresh.is_valid());
5754 if (fresh.reg().is(edx)) {
5755 remainder = fresh;
5756 fresh = cgen()->allocator()->Allocate();
5757 ASSERT(fresh.is_valid());
5758 }
5759 if (left->is_register() && left->reg().is(eax)) {
5760 quotient = *left;
5761 *left = fresh;
5762 left_is_in_eax = true;
5763 }
5764 if (right->is_register() && right->reg().is(eax)) {
5765 quotient = *right;
5766 *right = fresh;
5767 }
5768 __ mov(fresh.reg(), eax);
5769 } else {
5770 // Neither left nor right is in eax.
5771 quotient = cgen()->allocator()->Allocate(eax);
5772 }
5773 ASSERT(quotient.is_register() && quotient.reg().is(eax));
5774 ASSERT(!(left->is_register() && left->reg().is(eax)));
5775 ASSERT(!(right->is_register() && right->reg().is(eax)));
5776
5777 // Step 2: get edx for remainder if necessary.
5778 if (!remainder.is_valid()) {
5779 if ((left->is_register() && left->reg().is(edx)) ||
5780 (right->is_register() && right->reg().is(edx))) {
5781 Result fresh = cgen()->allocator()->Allocate();
5782 ASSERT(fresh.is_valid());
5783 if (left->is_register() && left->reg().is(edx)) {
5784 remainder = *left;
5785 *left = fresh;
5786 }
5787 if (right->is_register() && right->reg().is(edx)) {
5788 remainder = *right;
5789 *right = fresh;
5790 }
5791 __ mov(fresh.reg(), edx);
5792 } else {
5793 // Neither left nor right is in edx.
5794 remainder = cgen()->allocator()->Allocate(edx);
5795 }
5796 }
5797 ASSERT(remainder.is_register() && remainder.reg().is(edx));
5798 ASSERT(!(left->is_register() && left->reg().is(edx)));
5799 ASSERT(!(right->is_register() && right->reg().is(edx)));
5800
5801 left->ToRegister();
5802 right->ToRegister();
5803 cgen()->frame()->Spill(quotient.reg());
5804 cgen()->frame()->Spill(remainder.reg());
5805
5806 // Check that left and right are smi tagged.
5807 if (left->reg().is(right->reg())) {
5808 __ test(left->reg(), Immediate(kSmiTagMask));
5809 } else {
5810 // Use the quotient register as a scratch for the tag check.
5811 if (!left_is_in_eax) __ mov(quotient.reg(), left->reg());
5812 left_is_in_eax = false;
5813 __ or_(quotient.reg(), Operand(right->reg()));
5814 ASSERT(kSmiTag == 0); // Adjust test if not the case.
5815 __ test(quotient.reg(), Immediate(kSmiTagMask));
5816 }
5817 SetEntryFrame(left, right);
5818 enter()->Branch(not_zero, left, right);
5819
5820 if (!left_is_in_eax) __ mov(quotient.reg(), left->reg());
5821
5822 // Sign extend eax into edx:eax.
5823 __ cdq();
5824 // Check for 0 divisor.
5825 __ test(right->reg(), Operand(right->reg()));
5826 enter()->Branch(zero, left, right);
5827 // Divide edx:eax by the right operand.
5828 __ idiv(right->reg());
5829
5830 // Complete the operation.
5831 if (op_ == Token::DIV) {
5832 // Check for negative zero result. If result is zero, and divisor
5833 // is negative, return a floating point negative zero. The
5834 // virtual frame is unchanged in this block, so local control flow
5835 // can use a Label rather than a JumpTarget.
5836 Label non_zero_result;
5837 __ test(left->reg(), Operand(left->reg()));
5838 __ j(not_zero, &non_zero_result);
5839 __ test(right->reg(), Operand(right->reg()));
5840 enter()->Branch(negative, left, right);
5841 __ bind(&non_zero_result);
5842 // Check for the corner case of dividing the most negative smi by
5843 // -1. We cannot use the overflow flag, since it is not set by
5844 // idiv instruction.
5845 ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
5846 __ cmp(quotient.reg(), 0x40000000);
5847 enter()->Branch(equal, left, right);
5848 // Check that the remainder is zero.
5849 __ test(remainder.reg(), Operand(remainder.reg()));
5850 enter()->Branch(not_zero, left, right);
5851 left->Unuse();
5852 right->Unuse();
5853 // Tag the result and store it in the quotient register.
5854 ASSERT(kSmiTagSize == times_2); // adjust code if not the case
5855 __ lea(quotient.reg(),
5856 Operand(quotient.reg(), quotient.reg(), times_1, kSmiTag));
5857 return quotient;
5858 } else {
5859 ASSERT(op_ == Token::MOD);
5860 // Check for a negative zero result. If the result is zero, and
5861 // the dividend is negative, return a floating point negative
5862 // zero. The frame is unchanged in this block, so local control
5863 // flow can use a Label rather than a JumpTarget.
5864 Label non_zero_result;
5865 __ test(remainder.reg(), Operand(remainder.reg()));
5866 __ j(not_zero, &non_zero_result, taken);
5867 __ test(left->reg(), Operand(left->reg()));
5868 enter()->Branch(negative, left, right);
5869 left->Unuse();
5870 right->Unuse();
5871 __ bind(&non_zero_result);
5872 return remainder;
5873 }
5874 }
5875
5876 // Handle the other binary operations.
5877 left->ToRegister();
5878 right->ToRegister();
5879 // A newly allocated register answer is used to hold the answer. The
5880 // registers containing left and right are not modified in most cases,
5881 // so they usually don't need to be spilled in the fast case.
5882 Result answer = cgen()->allocator()->Allocate();
5883
5884 ASSERT(answer.is_valid());
5885 // Perform the smi tag check.
5886 if (left->reg().is(right->reg())) {
5887 __ test(left->reg(), Immediate(kSmiTagMask));
5888 } else {
5889 __ mov(answer.reg(), left->reg());
5890 __ or_(answer.reg(), Operand(right->reg()));
5891 ASSERT(kSmiTag == 0); // Adjust test if not the case.
5892 __ test(answer.reg(), Immediate(kSmiTagMask));
5893 }
5894 switch (op_) {
5895 case Token::ADD:
5896 SetEntryFrame(left, right);
5897 enter()->Branch(not_zero, left, right, not_taken);
5898 __ mov(answer.reg(), left->reg());
5899 __ add(answer.reg(), Operand(right->reg())); // Add optimistically.
5900 enter()->Branch(overflow, left, right, not_taken);
5901 break;
5902
5903 case Token::SUB:
5904 SetEntryFrame(left, right);
5905 enter()->Branch(not_zero, left, right, not_taken);
5906 __ mov(answer.reg(), left->reg());
5907 __ sub(answer.reg(), Operand(right->reg())); // Subtract optimistically.
5908 enter()->Branch(overflow, left, right, not_taken);
5909 break;
5910
5911 case Token::MUL: {
5912 SetEntryFrame(left, right);
5913 enter()->Branch(not_zero, left, right, not_taken);
5914 __ mov(answer.reg(), left->reg());
5915 // If the smi tag is 0 we can just leave the tag on one operand.
5916 ASSERT(kSmiTag == 0); // Adjust code below if not the case.
5917 // Remove smi tag from the left operand (but keep sign).
5918 // Left-hand operand has been copied into answer.
5919 __ sar(answer.reg(), kSmiTagSize);
5920 // Do multiplication of smis, leaving result in answer.
5921 __ imul(answer.reg(), Operand(right->reg()));
5922 // Go slow on overflows.
5923 enter()->Branch(overflow, left, right, not_taken);
5924 // Check for negative zero result. If product is zero, and one
5925 // argument is negative, go to slow case. The frame is unchanged
5926 // in this block, so local control flow can use a Label rather
5927 // than a JumpTarget.
5928 Label non_zero_result;
5929 __ test(answer.reg(), Operand(answer.reg()));
5930 __ j(not_zero, &non_zero_result, taken);
5931 __ mov(answer.reg(), left->reg());
5932 __ or_(answer.reg(), Operand(right->reg()));
5933 enter()->Branch(negative, left, right, not_taken);
5934 __ xor_(answer.reg(), Operand(answer.reg())); // Positive 0 is correct.
5935 __ bind(&non_zero_result);
5936 break;
5937 }
5938
5939 case Token::BIT_OR:
5940 enter()->Branch(not_zero, left, right, not_taken);
5941 __ mov(answer.reg(), left->reg());
5942 __ or_(answer.reg(), Operand(right->reg()));
5943 break;
5944
5945 case Token::BIT_AND:
5946 enter()->Branch(not_zero, left, right, not_taken);
5947 __ mov(answer.reg(), left->reg());
5948 __ and_(answer.reg(), Operand(right->reg()));
5949 break;
5950
5951 case Token::BIT_XOR:
5952 enter()->Branch(not_zero, left, right, not_taken);
5953 __ mov(answer.reg(), left->reg());
5954 __ xor_(answer.reg(), Operand(right->reg()));
5955 break;
5956
5957 case Token::SHL:
5958 case Token::SHR:
5959 case Token::SAR:
5960 enter()->Branch(not_zero, left, right, not_taken);
5961 __ mov(answer.reg(), left->reg());
5962 // Move right into ecx.
5963 // Left is in two registers already, so even if left or answer is ecx,
5964 // we can move right to it, and use the other one.
5965 // Right operand must be in register cl because x86 likes it that way.
5966 if (right->reg().is(ecx)) {
5967 // Right is already in the right place. Left may be in the
5968 // same register, which causes problems. Always use answer
5969 // instead of left, even if left is not ecx, since this avoids
5970 // spilling left.
5971 *left = answer;
5972 } else if (left->reg().is(ecx)) {
5973 cgen()->frame()->Spill(left->reg());
5974 __ mov(left->reg(), right->reg());
5975 *right = *left;
5976 *left = answer; // Use copy of left in answer as left.
5977 } else if (answer.reg().is(ecx)) {
5978 __ mov(answer.reg(), right->reg());
5979 *right = answer;
5980 } else {
5981 Result reg_ecx = cgen()->allocator()->Allocate(ecx);
5982 ASSERT(reg_ecx.is_valid());
5983 __ mov(ecx, right->reg());
5984 *right = reg_ecx;
5985 // Answer and left both contain the left operand. Use answer, so
5986 // left is not spilled.
5987 *left = answer;
5988 }
5989 ASSERT(left->reg().is_valid());
5990 ASSERT(!left->reg().is(ecx));
5991 ASSERT(right->reg().is(ecx));
5992 answer.Unuse(); // Answer may now be being used for left or right.
5993 // We will modify left and right, which we do not do in any other
5994 // binary operation. The exits to slow code need to restore the
5995 // original values of left and right, or at least values that give
5996 // the same answer.
5997
5998 // We are modifying left and right. They must be spilled!
5999 cgen()->frame()->Spill(left->reg());
6000 cgen()->frame()->Spill(right->reg());
6001
6002 // Remove tags from operands (but keep sign).
6003 __ sar(left->reg(), kSmiTagSize);
6004 __ sar(ecx, kSmiTagSize);
6005 // Perform the operation.
6006 switch (op_) {
6007 case Token::SAR:
6008 __ sar(left->reg());
6009 // No checks of result necessary
6010 break;
6011 case Token::SHR: {
6012 __ shr(left->reg());
6013 // Check that the *unsigned* result fits in a smi.
6014 // Neither of the two high-order bits can be set:
6015 // - 0x80000000: high bit would be lost when smi tagging.
6016 // - 0x40000000: this number would convert to negative when
6017 // Smi tagging these two cases can only happen with shifts
6018 // by 0 or 1 when handed a valid smi.
6019 // If the answer cannot be represented by a SMI, restore
6020 // the left and right arguments, and jump to slow case.
6021 // The low bit of the left argument may be lost, but only
6022 // in a case where it is dropped anyway.
6023 JumpTarget result_ok;
6024 __ test(left->reg(), Immediate(0xc0000000));
6025 result_ok.Branch(zero, left, taken);
6026 __ shl(left->reg());
6027 ASSERT(kSmiTag == 0);
6028 __ shl(left->reg(), kSmiTagSize);
6029 __ shl(right->reg(), kSmiTagSize);
6030 enter()->Jump(left, right);
6031 result_ok.Bind(left);
6032 break;
6033 }
6034 case Token::SHL: {
6035 __ shl(left->reg());
6036 // Check that the *signed* result fits in a smi.
6037 JumpTarget result_ok;
6038 __ cmp(left->reg(), 0xc0000000);
6039 result_ok.Branch(positive, left, taken);
6040
6041 __ shr(left->reg());
6042 ASSERT(kSmiTag == 0);
6043 __ shl(left->reg(), kSmiTagSize);
6044 __ shl(right->reg(), kSmiTagSize);
6045 enter()->Jump(left, right);
6046 result_ok.Bind(left);
6047 break;
6048 }
6049 default:
6050 UNREACHABLE();
6051 }
6052 // Smi-tag the result, in left, and make answer an alias for left->
6053 answer = *left;
6054 answer.ToRegister();
6055 ASSERT(kSmiTagSize == times_2); // adjust code if not the case
6056 __ lea(answer.reg(),
6057 Operand(answer.reg(), answer.reg(), times_1, kSmiTag));
6058 break;
6059
6060 default:
6061 UNREACHABLE();
6062 break;
6063 }
6064 left->Unuse();
6065 right->Unuse();
6066 return answer;
6067 }
6068
6069
6070 void GenericBinaryOpStub::GenerateSmiCode(MacroAssembler* masm, Label* slow) { 6059 void GenericBinaryOpStub::GenerateSmiCode(MacroAssembler* masm, Label* slow) {
6071 // Perform fast-case smi code for the operation (eax <op> ebx) and 6060 // Perform fast-case smi code for the operation (eax <op> ebx) and
6072 // leave result in register eax. 6061 // leave result in register eax.
6073 6062
6074 // Prepare the smi check of both operands by or'ing them together 6063 // Prepare the smi check of both operands by or'ing them together
6075 // before checking against the smi mask. 6064 // before checking against the smi mask.
6076 __ mov(ecx, Operand(ebx)); 6065 __ mov(ecx, Operand(ebx));
6077 __ or_(ecx, Operand(eax)); 6066 __ or_(ecx, Operand(eax));
6078 6067
6079 switch (op_) { 6068 switch (op_) {
(...skipping 1221 matching lines...) Expand 10 before | Expand all | Expand 10 after
7301 7290
7302 // Slow-case: Go through the JavaScript implementation. 7291 // Slow-case: Go through the JavaScript implementation.
7303 __ bind(&slow); 7292 __ bind(&slow);
7304 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); 7293 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION);
7305 } 7294 }
7306 7295
7307 7296
7308 #undef __ 7297 #undef __
7309 7298
7310 } } // namespace v8::internal 7299 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698