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

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

Issue 3054047: IA32: Avoid going into stubs or runtime code for bitops even if the... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: Created 10 years, 4 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
OLDNEW
1 // Copyright 2010 the V8 project authors. All rights reserved. 1 // Copyright 2010 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 1021 matching lines...) Expand 10 before | Expand all | Expand 10 after
1032 overwrite_name, 1032 overwrite_name,
1033 (flags_ & NO_SMI_CODE_IN_STUB) ? "_NoSmiInStub" : "", 1033 (flags_ & NO_SMI_CODE_IN_STUB) ? "_NoSmiInStub" : "",
1034 args_in_registers_ ? "RegArgs" : "StackArgs", 1034 args_in_registers_ ? "RegArgs" : "StackArgs",
1035 args_reversed_ ? "_R" : "", 1035 args_reversed_ ? "_R" : "",
1036 static_operands_type_.ToString(), 1036 static_operands_type_.ToString(),
1037 BinaryOpIC::GetName(runtime_operands_type_)); 1037 BinaryOpIC::GetName(runtime_operands_type_));
1038 return name_; 1038 return name_;
1039 } 1039 }
1040 1040
1041 1041
1042 // Call the specialized stub for a binary operation. 1042 // Perform or call the specialized stub for a binary operation. Requires the
1043 // three registers left, right and dst to be distinct and spilled. This
1044 // deferred operation has up to three entry points: The main one calls the
1045 // runtime system. The second is for when the result is a non-Smi. The
1046 // third is for when at least one of the inputs is non-Smi and we have SSE2.
1043 class DeferredInlineBinaryOperation: public DeferredCode { 1047 class DeferredInlineBinaryOperation: public DeferredCode {
1044 public: 1048 public:
1045 DeferredInlineBinaryOperation(Token::Value op, 1049 DeferredInlineBinaryOperation(Token::Value op,
1046 Register dst, 1050 Register dst,
1047 Register left, 1051 Register left,
1048 Register right, 1052 Register right,
1049 TypeInfo left_info, 1053 TypeInfo left_info,
1050 TypeInfo right_info, 1054 TypeInfo right_info,
1051 OverwriteMode mode) 1055 OverwriteMode mode)
1052 : op_(op), dst_(dst), left_(left), right_(right), 1056 : op_(op), dst_(dst), left_(left), right_(right),
1053 left_info_(left_info), right_info_(right_info), mode_(mode) { 1057 left_info_(left_info), right_info_(right_info), mode_(mode) {
1054 set_comment("[ DeferredInlineBinaryOperation"); 1058 set_comment("[ DeferredInlineBinaryOperation");
1055 } 1059 }
1056 1060
1057 virtual void Generate(); 1061 virtual void Generate();
1058 1062
1063 // This stub makes explicit calls to SaveRegisters(), RestoreRegisters() and
1064 // Exit().
1065 virtual bool AutoSaveAndRestore() { return false; }
1066
1067 void JumpToAnswerOutOfRange(Condition cond);
1068 void JumpToConstantRhs(Condition cond, Smi* smi_value);
1069 Label* NonSmiInputLabel();
1070
1059 private: 1071 private:
1072 void GenerateAnswerOutOfRange();
1073 void GenerateNonSmiInput();
1074
1060 Token::Value op_; 1075 Token::Value op_;
1061 Register dst_; 1076 Register dst_;
1062 Register left_; 1077 Register left_;
1063 Register right_; 1078 Register right_;
1064 TypeInfo left_info_; 1079 TypeInfo left_info_;
1065 TypeInfo right_info_; 1080 TypeInfo right_info_;
1066 OverwriteMode mode_; 1081 OverwriteMode mode_;
1082 Label answer_out_of_range_;
1083 Label non_smi_input_;
1084 Label constant_rhs_;
1085 Smi* smi_value_;
1067 }; 1086 };
1068 1087
1069 1088
1089 Label* DeferredInlineBinaryOperation::NonSmiInputLabel() {
1090 if (Token::IsBitOp(op_) && CpuFeatures::IsSupported(SSE2)) {
1091 return &non_smi_input_;
1092 } else {
1093 return entry_label();
1094 }
1095 }
1096
1097
1098 void DeferredInlineBinaryOperation::JumpToAnswerOutOfRange(Condition cond) {
1099 __ j(cond, &answer_out_of_range_);
1100 }
1101
1102
1103 void DeferredInlineBinaryOperation::JumpToConstantRhs(Condition cond,
1104 Smi* smi_value) {
1105 smi_value_ = smi_value;
1106 __ j(cond, &constant_rhs_);
1107 }
1108
1109
1070 void DeferredInlineBinaryOperation::Generate() { 1110 void DeferredInlineBinaryOperation::Generate() {
1071 Label done; 1111 // Registers are not saved implicitly for this stub, so we should not
1072 if (CpuFeatures::IsSupported(SSE2) && ((op_ == Token::ADD) || 1112 // tread on the registers that were not passed to us.
1073 (op_ ==Token::SUB) || 1113 if (CpuFeatures::IsSupported(SSE2) &&
1074 (op_ == Token::MUL) || 1114 ((op_ == Token::ADD) ||
1075 (op_ == Token::DIV))) { 1115 (op_ == Token::SUB) ||
1116 (op_ == Token::MUL) ||
1117 (op_ == Token::DIV))) {
1076 CpuFeatures::Scope use_sse2(SSE2); 1118 CpuFeatures::Scope use_sse2(SSE2);
1077 Label call_runtime, after_alloc_failure; 1119 Label call_runtime, after_alloc_failure;
1078 Label left_smi, right_smi, load_right, do_op; 1120 Label left_smi, right_smi, load_right, do_op;
1079 if (!left_info_.IsSmi()) { 1121 if (!left_info_.IsSmi()) {
1080 __ test(left_, Immediate(kSmiTagMask)); 1122 __ test(left_, Immediate(kSmiTagMask));
1081 __ j(zero, &left_smi); 1123 __ j(zero, &left_smi);
1082 if (!left_info_.IsNumber()) { 1124 if (!left_info_.IsNumber()) {
1083 __ cmp(FieldOperand(left_, HeapObject::kMapOffset), 1125 __ cmp(FieldOperand(left_, HeapObject::kMapOffset),
1084 Factory::heap_number_map()); 1126 Factory::heap_number_map());
1085 __ j(not_equal, &call_runtime); 1127 __ j(not_equal, &call_runtime);
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
1125 __ jmp(&do_op); 1167 __ jmp(&do_op);
1126 1168
1127 __ bind(&right_smi); 1169 __ bind(&right_smi);
1128 } else { 1170 } else {
1129 if (FLAG_debug_code) __ AbortIfNotSmi(right_); 1171 if (FLAG_debug_code) __ AbortIfNotSmi(right_);
1130 } 1172 }
1131 __ SmiUntag(right_); 1173 __ SmiUntag(right_);
1132 __ cvtsi2sd(xmm1, Operand(right_)); 1174 __ cvtsi2sd(xmm1, Operand(right_));
1133 __ SmiTag(right_); 1175 __ SmiTag(right_);
1134 if (mode_ == OVERWRITE_RIGHT || mode_ == NO_OVERWRITE) { 1176 if (mode_ == OVERWRITE_RIGHT || mode_ == NO_OVERWRITE) {
1135 Label alloc_failure;
1136 __ push(left_); 1177 __ push(left_);
1137 __ AllocateHeapNumber(dst_, left_, no_reg, &after_alloc_failure); 1178 __ AllocateHeapNumber(dst_, left_, no_reg, &after_alloc_failure);
1138 __ pop(left_); 1179 __ pop(left_);
1139 } 1180 }
1140 1181
1141 __ bind(&do_op); 1182 __ bind(&do_op);
1142 switch (op_) { 1183 switch (op_) {
1143 case Token::ADD: __ addsd(xmm0, xmm1); break; 1184 case Token::ADD: __ addsd(xmm0, xmm1); break;
1144 case Token::SUB: __ subsd(xmm0, xmm1); break; 1185 case Token::SUB: __ subsd(xmm0, xmm1); break;
1145 case Token::MUL: __ mulsd(xmm0, xmm1); break; 1186 case Token::MUL: __ mulsd(xmm0, xmm1); break;
1146 case Token::DIV: __ divsd(xmm0, xmm1); break; 1187 case Token::DIV: __ divsd(xmm0, xmm1); break;
1147 default: UNREACHABLE(); 1188 default: UNREACHABLE();
1148 } 1189 }
1149 __ movdbl(FieldOperand(dst_, HeapNumber::kValueOffset), xmm0); 1190 __ movdbl(FieldOperand(dst_, HeapNumber::kValueOffset), xmm0);
1150 __ jmp(&done); 1191 Exit();
1192
1151 1193
1152 __ bind(&after_alloc_failure); 1194 __ bind(&after_alloc_failure);
1153 __ pop(left_); 1195 __ pop(left_);
1154 __ bind(&call_runtime); 1196 __ bind(&call_runtime);
1155 } 1197 }
1198 // Register spilling is not done implicitly for this stub.
1199 // We can't postpone it any more now though.
1200 SaveRegisters();
1201
1156 GenericBinaryOpStub stub(op_, 1202 GenericBinaryOpStub stub(op_,
1157 mode_, 1203 mode_,
1158 NO_SMI_CODE_IN_STUB, 1204 NO_SMI_CODE_IN_STUB,
1159 TypeInfo::Combine(left_info_, right_info_)); 1205 TypeInfo::Combine(left_info_, right_info_));
1160 stub.GenerateCall(masm_, left_, right_); 1206 stub.GenerateCall(masm_, left_, right_);
1161 if (!dst_.is(eax)) __ mov(dst_, eax); 1207 if (!dst_.is(eax)) __ mov(dst_, eax);
1162 __ bind(&done); 1208 RestoreRegisters();
1209 Exit();
1210
1211 if (non_smi_input_.is_linked() || constant_rhs_.is_linked()) {
1212 GenerateNonSmiInput();
1213 }
1214 if (answer_out_of_range_.is_linked()) {
1215 GenerateAnswerOutOfRange();
1216 }
1217 }
1218
1219
1220 void DeferredInlineBinaryOperation::GenerateNonSmiInput() {
1221 // We know at least one of the inputs was not a Smi.
1222 // This is a third entry point into the deferred code.
1223 // We may not overwrite left_ because we want to be able
1224 // to call the handling code for non-smi answer and it
1225 // might want to overwrite the heap number in left_.
1226 ASSERT(!right_.is(dst_));
1227 ASSERT(!left_.is(dst_));
1228 ASSERT(!left_.is(right_));
1229 // This entry point is used for bit ops where the right hand side
1230 // is a constant Smi and the left hand side is a heap object. It
1231 // is also used for bit ops where both sides are unknown, but where
1232 // at least one of them is a heap object.
1233 bool rhs_is_constant = constant_rhs_.is_linked();
1234 // We can't generate code for both cases.
1235 ASSERT(!non_smi_input_.is_linked() || !constant_rhs_.is_linked());
1236
1237 if (FLAG_debug_code) {
1238 __ int3(); // We don't fall through into this code.
1239 }
1240
1241 __ bind(&non_smi_input_);
1242
1243 if (rhs_is_constant) {
1244 __ bind(&constant_rhs_);
1245 // In this case the input is a heap object and it is in the dst_ register.
1246 // The left_ and right_ registers have not been initialized yet.
1247 __ mov(right_, Immediate(smi_value_));
1248 __ mov(left_, Operand(dst_));
1249 if (!CpuFeatures::IsSupported(SSE2)) {
1250 __ jmp(entry_label());
1251 return;
1252 } else {
1253 CpuFeatures::Scope use_sse2(SSE2);
1254 __ JumpIfNotNumber(dst_, left_info_, entry_label());
1255 __ JumpIfNotInt32(left_, dst_, left_info_, entry_label());
Lasse Reichstein 2010/08/06 08:20:12 The JumpIfNotInt32 name seems incorrect if it acce
Erik Corry 2010/08/09 13:13:49 Renamed to JumpIfNotInt32Range
1256 __ cvttsd2si(dst_, FieldOperand(left_, HeapNumber::kValueOffset));
1257 __ SmiUntag(right_);
1258 }
1259 } else {
1260 CpuFeatures::Scope use_sse2(SSE2);
Lasse Reichstein 2010/08/06 08:20:12 What if SSE2 is not supported? (It was tested in t
Erik Corry 2010/08/09 13:13:49 Comment added.
1261 // Handle the non-constant right hand side situation:
1262 if (left_info_.IsSmi()) {
1263 // Right is a heap object.
1264 __ JumpIfNotNumber(right_, right_info_, entry_label());
1265 __ JumpIfNotInt32(right_, dst_, right_info_, entry_label());
1266 __ cvttsd2si(right_, FieldOperand(right_, HeapNumber::kValueOffset));
1267 __ mov(dst_, Operand(left_));
1268 __ SmiUntag(dst_);
1269 } else if (right_info_.IsSmi()) {
1270 // Left is a heap object.
1271 __ JumpIfNotNumber(left_, left_info_, entry_label());
1272 __ JumpIfNotInt32(left_, dst_, left_info_, entry_label());
1273 __ cvttsd2si(dst_, FieldOperand(left_, HeapNumber::kValueOffset));
1274 __ SmiUntag(right_);
1275 } else {
1276 // Here we don't know if it's one or both that is a heap object.
1277 Label only_right_is_heap_object, got_both;
1278 __ mov(dst_, Operand(left_));
1279 __ SmiUntagAndBranchOnSmi(dst_, &only_right_is_heap_object);
1280 // Left was a heap object.
1281 __ JumpIfNotNumber(left_, left_info_, entry_label());
1282 __ JumpIfNotInt32(left_, dst_, left_info_, entry_label());
1283 __ cvttsd2si(dst_, FieldOperand(left_, HeapNumber::kValueOffset));
1284 __ SmiUntagAndBranchOnSmi(right_, &got_both);
1285 // Both were heap objects.
1286 __ rcl(right_, 1); // Put tag back.
1287 __ JumpIfNotNumber(right_, right_info_, entry_label());
1288 __ JumpIfNotInt32(right_, no_reg, right_info_, entry_label());
1289 __ cvttsd2si(right_, FieldOperand(right_, HeapNumber::kValueOffset));
1290 __ jmp(&got_both);
1291 __ bind(&only_right_is_heap_object);
1292 __ JumpIfNotNumber(right_, right_info_, entry_label());
1293 __ JumpIfNotInt32(right_, no_reg, right_info_, entry_label());
1294 __ cvttsd2si(right_, FieldOperand(right_, HeapNumber::kValueOffset));
1295 __ bind(&got_both);
1296 }
1297 }
1298 ASSERT(op_ == Token::BIT_AND ||
1299 op_ == Token::BIT_OR ||
1300 op_ == Token::BIT_XOR ||
1301 right_.is(ecx));
1302 switch (op_) {
1303 case Token::BIT_AND: __ and_(dst_, Operand(right_)); break;
1304 case Token::BIT_OR: __ or_(dst_, Operand(right_)); break;
1305 case Token::BIT_XOR: __ xor_(dst_, Operand(right_)); break;
1306 case Token::SHR: __ shr_cl(dst_); break;
1307 case Token::SAR: __ sar_cl(dst_); break;
1308 case Token::SHL: __ shl_cl(dst_); break;
1309 default: UNREACHABLE();
1310 }
1311 if (op_ == Token::SHR) {
1312 // Check that the *unsigned* result fits in a smi. Neither of
1313 // the two high-order bits can be set:
1314 // * 0x80000000: high bit would be lost when smi tagging.
1315 // * 0x40000000: this number would convert to negative when smi
1316 // tagging.
1317 __ test(dst_, Immediate(0xc0000000));
1318 __ j(not_zero, &answer_out_of_range_);
1319 } else {
1320 // Check that the *signed* result fits in a smi.
1321 __ cmp(dst_, 0xc0000000);
1322 __ j(negative, &answer_out_of_range_);
1323 }
1324 __ SmiTag(dst_);
1325 Exit();
1326 }
1327
1328
1329 void DeferredInlineBinaryOperation::GenerateAnswerOutOfRange() {
1330 Label after_alloc_failure2;
1331 Label allocation_ok;
1332 __ bind(&after_alloc_failure2);
1333 // We have to allocate a number, causing a GC, while keeping hold of
1334 // the answer in dst_. The answer is not a Smi. We can't just call the
1335 // runtime shift function here because we already threw away the inputs.
1336 __ xor_(left_, Operand(left_));
1337 __ shl(dst_, 1); // Put top bit in carry flag and Smi tag the low bits.
1338 __ rcr(left_, 1); // Rotate with carry.
1339 __ push(dst_); // Smi tagged low 31 bits.
1340 __ push(left_); // 0 or 0x80000000.
Lasse Reichstein 2010/08/06 08:20:12 Make comment and/or ASSERT saying that left_ must
Erik Corry 2010/08/09 13:13:49 Done.
1341 __ CallRuntime(Runtime::kNumberAlloc, 0);
1342 if (!left_.is(eax)) {
1343 __ mov(left_, eax);
1344 }
1345 __ pop(right_); // High bit.
1346 __ pop(dst_); // Low 31 bits.
1347 __ shr(dst_, 1); // Put 0 in top bit.
1348 __ or_(dst_, Operand(right_));
1349 __ jmp(&allocation_ok);
1350
1351 // This is the second entry point to the deferred code. It is used only by
1352 // the bit operations.
1353 // The dst_ register has the answer. It is not Smi tagged. If mode_ is
1354 // OVERWRITE_LEFT then left_ must contain either an overwritable heap number
1355 // or a Smi.
1356 // Put a heap number pointer in left_.
1357 __ bind(&answer_out_of_range_);
1358 SaveRegisters();
1359 if (mode_ == OVERWRITE_LEFT) {
1360 __ test(left_, Immediate(kSmiTagMask));
1361 __ j(not_zero, &allocation_ok);
1362 }
1363 // This trashes right_.
1364 __ AllocateHeapNumber(left_, right_, no_reg, &after_alloc_failure2);
1365 __ bind(&allocation_ok);
1366 if (CpuFeatures::IsSupported(SSE2) && op_ != Token::SHR) {
1367 CpuFeatures::Scope use_sse2(SSE2);
1368 ASSERT(Token::IsBitOp(op_));
1369 // Signed conversion.
1370 __ cvtsi2sd(xmm0, Operand(dst_));
1371 __ movdbl(FieldOperand(left_, HeapNumber::kValueOffset), xmm0);
1372 } else {
1373 if (op_ == Token::SHR) {
1374 __ push(dst_);
1375 __ push(Immediate(0)); // High word of unsigned value.
1376 __ fild_d(Operand(esp, 0));
1377 __ Drop(2);
1378 } else {
1379 ASSERT(Token::IsBitOp(op_));
1380 __ push(dst_);
1381 __ fild_s(Operand(esp, 0)); // Signed conversion.
1382 __ pop(dst_);
1383 }
1384 __ fstp_d(FieldOperand(left_, HeapNumber::kValueOffset));
1385 }
1386 __ mov(dst_, left_);
1387 RestoreRegisters();
1388 Exit();
1163 } 1389 }
1164 1390
1165 1391
1166 static TypeInfo CalculateTypeInfo(TypeInfo operands_type, 1392 static TypeInfo CalculateTypeInfo(TypeInfo operands_type,
1167 Token::Value op, 1393 Token::Value op,
1168 const Result& right, 1394 const Result& right,
1169 const Result& left) { 1395 const Result& left) {
1170 // Set TypeInfo of result according to the operation performed. 1396 // Set TypeInfo of result according to the operation performed.
1171 // Rely on the fact that smis have a 31 bit payload on ia32. 1397 // Rely on the fact that smis have a 31 bit payload on ia32.
1172 STATIC_ASSERT(kSmiValueSize == 31); 1398 STATIC_ASSERT(kSmiValueSize == 31);
(...skipping 320 matching lines...) Expand 10 before | Expand all | Expand 10 after
1493 } 1719 }
1494 } 1720 }
1495 1721
1496 1722
1497 void CodeGenerator::JumpIfNotBothSmiUsingTypeInfo(Register left, 1723 void CodeGenerator::JumpIfNotBothSmiUsingTypeInfo(Register left,
1498 Register right, 1724 Register right,
1499 Register scratch, 1725 Register scratch,
1500 TypeInfo left_info, 1726 TypeInfo left_info,
1501 TypeInfo right_info, 1727 TypeInfo right_info,
1502 DeferredCode* deferred) { 1728 DeferredCode* deferred) {
1729 JumpIfNotBothSmiUsingTypeInfo(left,
1730 right,
1731 scratch,
1732 left_info,
1733 right_info,
1734 deferred->entry_label());
1735 }
1736
1737
1738 void CodeGenerator::JumpIfNotBothSmiUsingTypeInfo(Register left,
1739 Register right,
1740 Register scratch,
1741 TypeInfo left_info,
1742 TypeInfo right_info,
1743 Label* on_not_smi) {
1503 if (left.is(right)) { 1744 if (left.is(right)) {
1504 if (!left_info.IsSmi()) { 1745 if (!left_info.IsSmi()) {
1505 __ test(left, Immediate(kSmiTagMask)); 1746 __ test(left, Immediate(kSmiTagMask));
1506 deferred->Branch(not_zero); 1747 __ j(not_zero, on_not_smi);
1507 } else { 1748 } else {
1508 if (FLAG_debug_code) __ AbortIfNotSmi(left); 1749 if (FLAG_debug_code) __ AbortIfNotSmi(left);
1509 } 1750 }
1510 } else if (!left_info.IsSmi()) { 1751 } else if (!left_info.IsSmi()) {
1511 if (!right_info.IsSmi()) { 1752 if (!right_info.IsSmi()) {
1512 __ mov(scratch, left); 1753 __ mov(scratch, left);
1513 __ or_(scratch, Operand(right)); 1754 __ or_(scratch, Operand(right));
1514 __ test(scratch, Immediate(kSmiTagMask)); 1755 __ test(scratch, Immediate(kSmiTagMask));
1515 deferred->Branch(not_zero); 1756 __ j(not_zero, on_not_smi);
1516 } else { 1757 } else {
1517 __ test(left, Immediate(kSmiTagMask)); 1758 __ test(left, Immediate(kSmiTagMask));
1518 deferred->Branch(not_zero); 1759 __ j(not_zero, on_not_smi);
1519 if (FLAG_debug_code) __ AbortIfNotSmi(right); 1760 if (FLAG_debug_code) __ AbortIfNotSmi(right);
1520 } 1761 }
1521 } else { 1762 } else {
1522 if (FLAG_debug_code) __ AbortIfNotSmi(left); 1763 if (FLAG_debug_code) __ AbortIfNotSmi(left);
1523 if (!right_info.IsSmi()) { 1764 if (!right_info.IsSmi()) {
1524 __ test(right, Immediate(kSmiTagMask)); 1765 __ test(right, Immediate(kSmiTagMask));
1525 deferred->Branch(not_zero); 1766 __ j(not_zero, on_not_smi);
1526 } else { 1767 } else {
1527 if (FLAG_debug_code) __ AbortIfNotSmi(right); 1768 if (FLAG_debug_code) __ AbortIfNotSmi(right);
1528 } 1769 }
1529 } 1770 }
1530 } 1771 }
1531 1772
1532 1773
1533 // Implements a binary operation using a deferred code object and some 1774 // Implements a binary operation using a deferred code object and some
1534 // inline code to operate on smis quickly. 1775 // inline code to operate on smis quickly.
1535 Result CodeGenerator::LikelySmiBinaryOperation(BinaryOperation* expr, 1776 Result CodeGenerator::LikelySmiBinaryOperation(BinaryOperation* expr,
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
1600 } 1841 }
1601 } 1842 }
1602 ASSERT(remainder.is_register() && remainder.reg().is(edx)); 1843 ASSERT(remainder.is_register() && remainder.reg().is(edx));
1603 ASSERT(!(left->is_register() && left->reg().is(edx))); 1844 ASSERT(!(left->is_register() && left->reg().is(edx)));
1604 ASSERT(!(right->is_register() && right->reg().is(edx))); 1845 ASSERT(!(right->is_register() && right->reg().is(edx)));
1605 1846
1606 left->ToRegister(); 1847 left->ToRegister();
1607 right->ToRegister(); 1848 right->ToRegister();
1608 frame_->Spill(eax); 1849 frame_->Spill(eax);
1609 frame_->Spill(edx); 1850 frame_->Spill(edx);
1851 // DeferredInlineBinaryOperation requires all the registers that it is
1852 // told about to be spilled.
1853 frame_->Spill(left->reg());
1854 frame_->Spill(right->reg());
1610 1855
1611 // Check that left and right are smi tagged. 1856 // Check that left and right are smi tagged.
1612 DeferredInlineBinaryOperation* deferred = 1857 DeferredInlineBinaryOperation* deferred =
1613 new DeferredInlineBinaryOperation(op, 1858 new DeferredInlineBinaryOperation(op,
1614 (op == Token::DIV) ? eax : edx, 1859 (op == Token::DIV) ? eax : edx,
1615 left->reg(), 1860 left->reg(),
1616 right->reg(), 1861 right->reg(),
1617 left_type_info, 1862 left_type_info,
1618 right_type_info, 1863 right_type_info,
1619 overwrite_mode); 1864 overwrite_mode);
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
1689 // Move left out of ecx if necessary. 1934 // Move left out of ecx if necessary.
1690 if (left->is_register() && left->reg().is(ecx)) { 1935 if (left->is_register() && left->reg().is(ecx)) {
1691 *left = allocator_->Allocate(); 1936 *left = allocator_->Allocate();
1692 ASSERT(left->is_valid()); 1937 ASSERT(left->is_valid());
1693 __ mov(left->reg(), ecx); 1938 __ mov(left->reg(), ecx);
1694 } 1939 }
1695 right->ToRegister(ecx); 1940 right->ToRegister(ecx);
1696 left->ToRegister(); 1941 left->ToRegister();
1697 ASSERT(left->is_register() && !left->reg().is(ecx)); 1942 ASSERT(left->is_register() && !left->reg().is(ecx));
1698 ASSERT(right->is_register() && right->reg().is(ecx)); 1943 ASSERT(right->is_register() && right->reg().is(ecx));
1944 if (left_type_info.IsSmi()) {
1945 if (FLAG_debug_code) __ AbortIfNotSmi(left->reg());
1946 }
1947 if (right_type_info.IsSmi()) {
1948 if (FLAG_debug_code) __ AbortIfNotSmi(right->reg());
1949 }
1699 1950
1700 // We will modify right, it must be spilled. 1951 // We will modify right, it must be spilled.
1701 frame_->Spill(ecx); 1952 frame_->Spill(ecx);
1953 // DeferredInlineBinaryOperation requires all the registers that it is told
1954 // about to be spilled.
1955 frame_->Spill(left->reg());
1702 1956
1703 // Use a fresh answer register to avoid spilling the left operand. 1957 // Use a fresh answer register to avoid spilling the left operand.
1704 answer = allocator_->Allocate(); 1958 answer = allocator_->Allocate();
1705 ASSERT(answer.is_valid()); 1959 ASSERT(answer.is_valid());
1706 // Check that both operands are smis using the answer register as a
1707 // temporary.
1708 DeferredInlineBinaryOperation* deferred = 1960 DeferredInlineBinaryOperation* deferred =
1709 new DeferredInlineBinaryOperation(op, 1961 new DeferredInlineBinaryOperation(op,
1710 answer.reg(), 1962 answer.reg(),
1711 left->reg(), 1963 left->reg(),
1712 ecx, 1964 ecx,
1713 left_type_info, 1965 left_type_info,
1714 right_type_info, 1966 right_type_info,
1715 overwrite_mode); 1967 overwrite_mode);
1968 JumpIfNotBothSmiUsingTypeInfo(left->reg(), right->reg(), answer.reg(),
1969 left_type_info, right_type_info,
1970 deferred->NonSmiInputLabel());
1716 1971
1717 Label do_op, left_nonsmi; 1972 // Untag both operands.
1718 // If right is a smi we make a fast case if left is either a smi 1973 __ mov(answer.reg(), left->reg());
1719 // or a heapnumber. 1974 __ SmiUntag(answer.reg());
1720 if (CpuFeatures::IsSupported(SSE2) && right_type_info.IsSmi()) { 1975 __ SmiUntag(right->reg()); // Right is ecx.
1721 CpuFeatures::Scope use_sse2(SSE2); 1976
1722 __ mov(answer.reg(), left->reg()); 1977 // Perform the operation.
1723 // Fast case - both are actually smis. 1978 ASSERT(right->reg().is(ecx));
1724 if (!left_type_info.IsSmi()) { 1979 switch (op) {
1725 __ test(answer.reg(), Immediate(kSmiTagMask)); 1980 case Token::SAR: {
1726 __ j(not_zero, &left_nonsmi); 1981 __ sar_cl(answer.reg());
1727 } else { 1982 if (!left_type_info.IsSmi()) {
1728 if (FLAG_debug_code) __ AbortIfNotSmi(left->reg()); 1983 // Check that the *signed* result fits in a smi.
1984 __ cmp(answer.reg(), 0xc0000000);
1985 deferred->JumpToAnswerOutOfRange(negative);
1986 }
1987 break;
1729 } 1988 }
1730 if (FLAG_debug_code) __ AbortIfNotSmi(right->reg());
1731 __ SmiUntag(answer.reg());
1732 __ jmp(&do_op);
1733
1734 __ bind(&left_nonsmi);
1735 // Branch if not a heapnumber.
1736 __ cmp(FieldOperand(answer.reg(), HeapObject::kMapOffset),
1737 Factory::heap_number_map());
1738 deferred->Branch(not_equal);
1739
1740 // Load integer value into answer register using truncation.
1741 __ cvttsd2si(answer.reg(),
1742 FieldOperand(answer.reg(), HeapNumber::kValueOffset));
1743 // Branch if we do not fit in a smi.
1744 __ cmp(answer.reg(), 0xc0000000);
1745 deferred->Branch(negative);
1746 } else {
1747 JumpIfNotBothSmiUsingTypeInfo(left->reg(), right->reg(), answer.reg(),
1748 left_type_info, right_type_info, deferred);
1749
1750 // Untag both operands.
1751 __ mov(answer.reg(), left->reg());
1752 __ SmiUntag(answer.reg());
1753 }
1754
1755 __ bind(&do_op);
1756 __ SmiUntag(ecx);
1757 // Perform the operation.
1758 switch (op) {
1759 case Token::SAR:
1760 __ sar_cl(answer.reg());
1761 // No checks of result necessary
1762 break;
1763 case Token::SHR: { 1989 case Token::SHR: {
1764 Label result_ok;
1765 __ shr_cl(answer.reg()); 1990 __ shr_cl(answer.reg());
1766 // Check that the *unsigned* result fits in a smi. Neither of 1991 // Check that the *unsigned* result fits in a smi. Neither of
1767 // the two high-order bits can be set: 1992 // the two high-order bits can be set:
1768 // * 0x80000000: high bit would be lost when smi tagging. 1993 // * 0x80000000: high bit would be lost when smi tagging.
1769 // * 0x40000000: this number would convert to negative when smi 1994 // * 0x40000000: this number would convert to negative when smi
1770 // tagging. 1995 // tagging.
1771 // These two cases can only happen with shifts by 0 or 1 when 1996 // These two cases can only happen with shifts by 0 or 1 when
1772 // handed a valid smi. If the answer cannot be represented by a 1997 // handed a valid smi. If the answer cannot be represented by a
1773 // smi, restore the left and right arguments, and jump to slow 1998 // smi, restore the left and right arguments, and jump to slow
1774 // case. The low bit of the left argument may be lost, but only 1999 // case. The low bit of the left argument may be lost, but only
1775 // in a case where it is dropped anyway. 2000 // in a case where it is dropped anyway.
1776 __ test(answer.reg(), Immediate(0xc0000000)); 2001 __ test(answer.reg(), Immediate(0xc0000000));
1777 __ j(zero, &result_ok); 2002 deferred->JumpToAnswerOutOfRange(not_zero);
1778 __ SmiTag(ecx);
1779 deferred->Jump();
1780 __ bind(&result_ok);
1781 break; 2003 break;
1782 } 2004 }
1783 case Token::SHL: { 2005 case Token::SHL: {
1784 Label result_ok;
1785 __ shl_cl(answer.reg()); 2006 __ shl_cl(answer.reg());
1786 // Check that the *signed* result fits in a smi. 2007 // Check that the *signed* result fits in a smi.
1787 __ cmp(answer.reg(), 0xc0000000); 2008 __ cmp(answer.reg(), 0xc0000000);
1788 __ j(positive, &result_ok); 2009 deferred->JumpToAnswerOutOfRange(negative);
1789 __ SmiTag(ecx);
1790 deferred->Jump();
1791 __ bind(&result_ok);
1792 break; 2010 break;
1793 } 2011 }
1794 default: 2012 default:
1795 UNREACHABLE(); 2013 UNREACHABLE();
1796 } 2014 }
1797 // Smi-tag the result in answer. 2015 // Smi-tag the result in answer.
1798 __ SmiTag(answer.reg()); 2016 __ SmiTag(answer.reg());
1799 deferred->BindExit(); 2017 deferred->BindExit();
1800 left->Unuse(); 2018 left->Unuse();
1801 right->Unuse(); 2019 right->Unuse();
1802 ASSERT(answer.is_valid()); 2020 ASSERT(answer.is_valid());
1803 return answer; 2021 return answer;
1804 } 2022 }
1805 2023
1806 // Handle the other binary operations. 2024 // Handle the other binary operations.
1807 left->ToRegister(); 2025 left->ToRegister();
1808 right->ToRegister(); 2026 right->ToRegister();
2027 // DeferredInlineBinaryOperation requires all the registers that it is told
2028 // about to be spilled.
2029 frame_->Spill(left->reg());
2030 frame_->Spill(right->reg());
1809 // A newly allocated register answer is used to hold the answer. The 2031 // A newly allocated register answer is used to hold the answer. The
1810 // registers containing left and right are not modified so they don't 2032 // registers containing left and right are not modified so they don't
1811 // need to be spilled in the fast case. 2033 // need to be spilled in the fast case.
1812 answer = allocator_->Allocate(); 2034 answer = allocator_->Allocate();
1813 ASSERT(answer.is_valid()); 2035 ASSERT(answer.is_valid());
1814 2036
1815 // Perform the smi tag check. 2037 // Perform the smi tag check.
1816 DeferredInlineBinaryOperation* deferred = 2038 DeferredInlineBinaryOperation* deferred =
1817 new DeferredInlineBinaryOperation(op, 2039 new DeferredInlineBinaryOperation(op,
1818 answer.reg(), 2040 answer.reg(),
1819 left->reg(), 2041 left->reg(),
1820 right->reg(), 2042 right->reg(),
1821 left_type_info, 2043 left_type_info,
1822 right_type_info, 2044 right_type_info,
1823 overwrite_mode); 2045 overwrite_mode);
1824 JumpIfNotBothSmiUsingTypeInfo(left->reg(), right->reg(), answer.reg(), 2046 Label non_smi_bit_op;
1825 left_type_info, right_type_info, deferred); 2047 if (op != Token::BIT_OR) {
2048 JumpIfNotBothSmiUsingTypeInfo(left->reg(), right->reg(), answer.reg(),
2049 left_type_info, right_type_info,
2050 deferred->NonSmiInputLabel());
2051 }
1826 2052
1827 __ mov(answer.reg(), left->reg()); 2053 __ mov(answer.reg(), left->reg());
1828 switch (op) { 2054 switch (op) {
1829 case Token::ADD: 2055 case Token::ADD:
1830 __ add(answer.reg(), Operand(right->reg())); 2056 __ add(answer.reg(), Operand(right->reg()));
1831 deferred->Branch(overflow); 2057 deferred->Branch(overflow);
1832 break; 2058 break;
1833 2059
1834 case Token::SUB: 2060 case Token::SUB:
1835 __ sub(answer.reg(), Operand(right->reg())); 2061 __ sub(answer.reg(), Operand(right->reg()));
(...skipping 22 matching lines...) Expand all
1858 __ or_(answer.reg(), Operand(right->reg())); 2084 __ or_(answer.reg(), Operand(right->reg()));
1859 deferred->Branch(negative); 2085 deferred->Branch(negative);
1860 __ xor_(answer.reg(), Operand(answer.reg())); // Positive 0 is correct. 2086 __ xor_(answer.reg(), Operand(answer.reg())); // Positive 0 is correct.
1861 __ bind(&non_zero_result); 2087 __ bind(&non_zero_result);
1862 } 2088 }
1863 break; 2089 break;
1864 } 2090 }
1865 2091
1866 case Token::BIT_OR: 2092 case Token::BIT_OR:
1867 __ or_(answer.reg(), Operand(right->reg())); 2093 __ or_(answer.reg(), Operand(right->reg()));
2094 __ test(answer.reg(), Immediate(kSmiTagMask));
2095 __ j(not_zero, deferred->NonSmiInputLabel());
1868 break; 2096 break;
1869 2097
1870 case Token::BIT_AND: 2098 case Token::BIT_AND:
1871 __ and_(answer.reg(), Operand(right->reg())); 2099 __ and_(answer.reg(), Operand(right->reg()));
1872 break; 2100 break;
1873 2101
1874 case Token::BIT_XOR: 2102 case Token::BIT_XOR:
1875 __ xor_(answer.reg(), Operand(right->reg())); 2103 __ xor_(answer.reg(), Operand(right->reg()));
1876 break; 2104 break;
1877 2105
1878 default: 2106 default:
1879 UNREACHABLE(); 2107 UNREACHABLE();
1880 break; 2108 break;
1881 } 2109 }
2110
1882 deferred->BindExit(); 2111 deferred->BindExit();
1883 left->Unuse(); 2112 left->Unuse();
1884 right->Unuse(); 2113 right->Unuse();
1885 ASSERT(answer.is_valid()); 2114 ASSERT(answer.is_valid());
1886 return answer; 2115 return answer;
1887 } 2116 }
1888 2117
1889 2118
1890 // Call the appropriate binary operation stub to compute src op value 2119 // Call the appropriate binary operation stub to compute src op value
1891 // and leave the result in dst. 2120 // and leave the result in dst.
(...skipping 465 matching lines...) Expand 10 before | Expand all | Expand 10 after
2357 deferred->BindExit(); 2586 deferred->BindExit();
2358 operand->Unuse(); 2587 operand->Unuse();
2359 } 2588 }
2360 } 2589 }
2361 break; 2590 break;
2362 2591
2363 case Token::BIT_OR: 2592 case Token::BIT_OR:
2364 case Token::BIT_XOR: 2593 case Token::BIT_XOR:
2365 case Token::BIT_AND: { 2594 case Token::BIT_AND: {
2366 operand->ToRegister(); 2595 operand->ToRegister();
2596 // DeferredInlineBinaryOperation requires all the registers that it is
2597 // told about to be spilled.
2367 frame_->Spill(operand->reg()); 2598 frame_->Spill(operand->reg());
2368 DeferredCode* deferred = NULL; 2599 DeferredInlineBinaryOperation* deferred = NULL;
2369 if (reversed) {
2370 deferred =
2371 new DeferredInlineSmiOperationReversed(op,
2372 operand->reg(),
2373 smi_value,
2374 operand->reg(),
2375 operand->type_info(),
2376 overwrite_mode);
2377 } else {
2378 deferred = new DeferredInlineSmiOperation(op,
2379 operand->reg(),
2380 operand->reg(),
2381 operand->type_info(),
2382 smi_value,
2383 overwrite_mode);
2384 }
2385 if (!operand->type_info().IsSmi()) { 2600 if (!operand->type_info().IsSmi()) {
2601 Result left = allocator()->Allocate();
2602 ASSERT(left.is_valid());
2603 Result right = allocator()->Allocate();
2604 ASSERT(right.is_valid());
2605 deferred = new DeferredInlineBinaryOperation(
2606 op,
2607 operand->reg(),
2608 left.reg(),
2609 right.reg(),
2610 operand->type_info(),
2611 TypeInfo::Smi(),
2612 overwrite_mode == NO_OVERWRITE ? NO_OVERWRITE : OVERWRITE_LEFT);
2386 __ test(operand->reg(), Immediate(kSmiTagMask)); 2613 __ test(operand->reg(), Immediate(kSmiTagMask));
2387 deferred->Branch(not_zero); 2614 deferred->JumpToConstantRhs(not_zero, smi_value);
2388 } else if (FLAG_debug_code) { 2615 } else if (FLAG_debug_code) {
2389 __ AbortIfNotSmi(operand->reg()); 2616 __ AbortIfNotSmi(operand->reg());
2390 } 2617 }
2391 if (op == Token::BIT_AND) { 2618 if (op == Token::BIT_AND) {
2392 __ and_(Operand(operand->reg()), Immediate(value)); 2619 __ and_(Operand(operand->reg()), Immediate(value));
2393 } else if (op == Token::BIT_XOR) { 2620 } else if (op == Token::BIT_XOR) {
2394 if (int_value != 0) { 2621 if (int_value != 0) {
2395 __ xor_(Operand(operand->reg()), Immediate(value)); 2622 __ xor_(Operand(operand->reg()), Immediate(value));
2396 } 2623 }
2397 } else { 2624 } else {
2398 ASSERT(op == Token::BIT_OR); 2625 ASSERT(op == Token::BIT_OR);
2399 if (int_value != 0) { 2626 if (int_value != 0) {
2400 __ or_(Operand(operand->reg()), Immediate(value)); 2627 __ or_(Operand(operand->reg()), Immediate(value));
2401 } 2628 }
2402 } 2629 }
2403 deferred->BindExit(); 2630 if (deferred != NULL) deferred->BindExit();
2404 answer = *operand; 2631 answer = *operand;
2405 break; 2632 break;
2406 } 2633 }
2407 2634
2408 case Token::DIV: 2635 case Token::DIV:
2409 if (!reversed && int_value == 2) { 2636 if (!reversed && int_value == 2) {
2410 operand->ToRegister(); 2637 operand->ToRegister();
2411 frame_->Spill(operand->reg()); 2638 frame_->Spill(operand->reg());
2412 2639
2413 DeferredInlineSmiOperation* deferred = 2640 DeferredInlineSmiOperation* deferred =
(...skipping 11545 matching lines...) Expand 10 before | Expand all | Expand 10 after
13959 masm.GetCode(&desc); 14186 masm.GetCode(&desc);
13960 // Call the function from C++. 14187 // Call the function from C++.
13961 return FUNCTION_CAST<MemCopyFunction>(buffer); 14188 return FUNCTION_CAST<MemCopyFunction>(buffer);
13962 } 14189 }
13963 14190
13964 #undef __ 14191 #undef __
13965 14192
13966 } } // namespace v8::internal 14193 } } // namespace v8::internal
13967 14194
13968 #endif // V8_TARGET_ARCH_IA32 14195 #endif // V8_TARGET_ARCH_IA32
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698