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

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

Issue 3195028: Add inlining of binary smi operations in the full codegens on IA32... (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
« no previous file with comments | « src/full-codegen.cc ('k') | src/token.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 199 matching lines...) Expand 10 before | Expand all | Expand 10 after
210 __ RecordJSReturn(); 210 __ RecordJSReturn();
211 // Do not use the leave instruction here because it is too short to 211 // Do not use the leave instruction here because it is too short to
212 // patch with the code required by the debugger. 212 // patch with the code required by the debugger.
213 __ mov(esp, ebp); 213 __ mov(esp, ebp);
214 __ pop(ebp); 214 __ pop(ebp);
215 __ ret((scope()->num_parameters() + 1) * kPointerSize); 215 __ ret((scope()->num_parameters() + 1) * kPointerSize);
216 #ifdef ENABLE_DEBUGGER_SUPPORT 216 #ifdef ENABLE_DEBUGGER_SUPPORT
217 // Check that the size of the code used for returning matches what is 217 // Check that the size of the code used for returning matches what is
218 // expected by the debugger. 218 // expected by the debugger.
219 ASSERT_EQ(Assembler::kJSReturnSequenceLength, 219 ASSERT_EQ(Assembler::kJSReturnSequenceLength,
220 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize)); 220 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
221 #endif 221 #endif
222 } 222 }
223 } 223 }
224 224
225 225
226 FullCodeGenerator::ConstantOperand FullCodeGenerator::GetConstantOperand(
227 Token::Value op, Expression* left, Expression* right) {
228 ASSERT(ShouldInlineSmiCase(op));
229 if (op == Token::DIV || op == Token::MOD || op == Token::MUL) {
230 // We never generate inlined constant smi operations for these.
231 return kNoConstants;
232 } else if (right->IsSmiLiteral()) {
233 return kRightConstant;
234 } else if (left->IsSmiLiteral() && !Token::IsShiftOp(op)) {
235 return kLeftConstant;
236 } else {
237 return kNoConstants;
238 }
239 }
240
241
226 void FullCodeGenerator::Apply(Expression::Context context, Register reg) { 242 void FullCodeGenerator::Apply(Expression::Context context, Register reg) {
227 switch (context) { 243 switch (context) {
228 case Expression::kUninitialized: 244 case Expression::kUninitialized:
229 UNREACHABLE(); 245 UNREACHABLE();
230 246
231 case Expression::kEffect: 247 case Expression::kEffect:
232 // Nothing to do. 248 // Nothing to do.
233 break; 249 break;
234 250
235 case Expression::kValue: 251 case Expression::kValue:
(...skipping 909 matching lines...) Expand 10 before | Expand all | Expand 10 after
1145 // on the left-hand side. 1161 // on the left-hand side.
1146 if (!expr->target()->IsValidLeftHandSide()) { 1162 if (!expr->target()->IsValidLeftHandSide()) {
1147 VisitForEffect(expr->target()); 1163 VisitForEffect(expr->target());
1148 return; 1164 return;
1149 } 1165 }
1150 1166
1151 // Left-hand side can only be a property, a global or a (parameter or local) 1167 // Left-hand side can only be a property, a global or a (parameter or local)
1152 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. 1168 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
1153 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; 1169 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1154 LhsKind assign_type = VARIABLE; 1170 LhsKind assign_type = VARIABLE;
1155 Property* prop = expr->target()->AsProperty(); 1171 Property* property = expr->target()->AsProperty();
1156 if (prop != NULL) { 1172 if (property != NULL) {
1157 assign_type = 1173 assign_type = (property->key()->IsPropertyName())
1158 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY; 1174 ? NAMED_PROPERTY
1175 : KEYED_PROPERTY;
1159 } 1176 }
1160 1177
1161 // Evaluate LHS expression. 1178 // Evaluate LHS expression.
1162 switch (assign_type) { 1179 switch (assign_type) {
1163 case VARIABLE: 1180 case VARIABLE:
1164 // Nothing to do here. 1181 // Nothing to do here.
1165 break; 1182 break;
1166 case NAMED_PROPERTY: 1183 case NAMED_PROPERTY:
1167 if (expr->is_compound()) { 1184 if (expr->is_compound()) {
1168 // We need the receiver both on the stack and in the accumulator. 1185 // We need the receiver both on the stack and in the accumulator.
1169 VisitForValue(prop->obj(), kAccumulator); 1186 VisitForValue(property->obj(), kAccumulator);
1170 __ push(result_register()); 1187 __ push(result_register());
1171 } else { 1188 } else {
1172 VisitForValue(prop->obj(), kStack); 1189 VisitForValue(property->obj(), kStack);
1173 } 1190 }
1174 break; 1191 break;
1175 case KEYED_PROPERTY: 1192 case KEYED_PROPERTY:
1176 if (expr->is_compound()) { 1193 if (expr->is_compound()) {
1177 VisitForValue(prop->obj(), kStack); 1194 VisitForValue(property->obj(), kStack);
1178 VisitForValue(prop->key(), kAccumulator); 1195 VisitForValue(property->key(), kAccumulator);
1179 __ mov(edx, Operand(esp, 0)); 1196 __ mov(edx, Operand(esp, 0));
1180 __ push(eax); 1197 __ push(eax);
1181 } else { 1198 } else {
1182 VisitForValue(prop->obj(), kStack); 1199 VisitForValue(property->obj(), kStack);
1183 VisitForValue(prop->key(), kStack); 1200 VisitForValue(property->key(), kStack);
1184 } 1201 }
1185 break; 1202 break;
1186 } 1203 }
1187 1204
1188 // If we have a compound assignment: Get value of LHS expression and
1189 // store in on top of the stack.
1190 if (expr->is_compound()) { 1205 if (expr->is_compound()) {
1191 Location saved_location = location_; 1206 Location saved_location = location_;
1192 location_ = kStack; 1207 location_ = kAccumulator;
1193 switch (assign_type) { 1208 switch (assign_type) {
1194 case VARIABLE: 1209 case VARIABLE:
1195 EmitVariableLoad(expr->target()->AsVariableProxy()->var(), 1210 EmitVariableLoad(expr->target()->AsVariableProxy()->var(),
1196 Expression::kValue); 1211 Expression::kValue);
1197 break; 1212 break;
1198 case NAMED_PROPERTY: 1213 case NAMED_PROPERTY:
1199 EmitNamedPropertyLoad(prop); 1214 EmitNamedPropertyLoad(property);
1200 __ push(result_register());
1201 break; 1215 break;
1202 case KEYED_PROPERTY: 1216 case KEYED_PROPERTY:
1203 EmitKeyedPropertyLoad(prop); 1217 EmitKeyedPropertyLoad(property);
1204 __ push(result_register());
1205 break; 1218 break;
1206 } 1219 }
1207 location_ = saved_location;
1208 }
1209 1220
1210 // Evaluate RHS expression. 1221 Token::Value op = expr->binary_op();
1211 Expression* rhs = expr->value(); 1222 ConstantOperand constant = ShouldInlineSmiCase(op)
1212 VisitForValue(rhs, kAccumulator); 1223 ? GetConstantOperand(op, expr->target(), expr->value())
1224 : kNoConstants;
1225 ASSERT(constant == kRightConstant || constant == kNoConstants);
1226 if (constant == kNoConstants) {
1227 __ push(eax); // Left operand goes on the stack.
1228 VisitForValue(expr->value(), kAccumulator);
1229 }
1213 1230
1214 // If we have a compound assignment: Apply operator.
1215 if (expr->is_compound()) {
1216 Location saved_location = location_;
1217 location_ = kAccumulator;
1218 OverwriteMode mode = expr->value()->ResultOverwriteAllowed() 1231 OverwriteMode mode = expr->value()->ResultOverwriteAllowed()
1219 ? OVERWRITE_RIGHT 1232 ? OVERWRITE_RIGHT
1220 : NO_OVERWRITE; 1233 : NO_OVERWRITE;
1221 EmitBinaryOp(expr->binary_op(), Expression::kValue, mode); 1234 SetSourcePosition(expr->position() + 1);
1235 if (ShouldInlineSmiCase(op)) {
1236 EmitInlineSmiBinaryOp(expr,
1237 op,
1238 Expression::kValue,
1239 mode,
1240 expr->target(),
1241 expr->value(),
1242 constant);
1243 } else {
1244 EmitBinaryOp(op, Expression::kValue, mode);
1245 }
1222 location_ = saved_location; 1246 location_ = saved_location;
1247
1248 } else {
1249 VisitForValue(expr->value(), kAccumulator);
1223 } 1250 }
1224 1251
1225 // Record source position before possible IC call. 1252 // Record source position before possible IC call.
1226 SetSourcePosition(expr->position()); 1253 SetSourcePosition(expr->position());
1227 1254
1228 // Store the value. 1255 // Store the value.
1229 switch (assign_type) { 1256 switch (assign_type) {
1230 case VARIABLE: 1257 case VARIABLE:
1231 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(), 1258 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
1232 expr->op(), 1259 expr->op(),
(...skipping 20 matching lines...) Expand all
1253 1280
1254 1281
1255 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { 1282 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
1256 SetSourcePosition(prop->position()); 1283 SetSourcePosition(prop->position());
1257 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); 1284 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
1258 __ call(ic, RelocInfo::CODE_TARGET); 1285 __ call(ic, RelocInfo::CODE_TARGET);
1259 __ nop(); 1286 __ nop();
1260 } 1287 }
1261 1288
1262 1289
1290 void FullCodeGenerator::EmitConstantSmiAdd(Expression* expr,
1291 Expression::Context context,
1292 OverwriteMode mode,
1293 bool left_is_constant_smi,
1294 Smi* value) {
1295 Label call_stub, done;
1296 __ add(Operand(eax), Immediate(value));
1297 __ j(overflow, &call_stub);
1298 __ test(eax, Immediate(kSmiTagMask));
1299 __ j(zero, &done);
1300
1301 // Undo the optimistic add operation and call the shared stub.
1302 __ bind(&call_stub);
1303 __ sub(Operand(eax), Immediate(value));
1304 Token::Value op = Token::ADD;
1305 GenericBinaryOpStub stub(op, mode, NO_SMI_CODE_IN_STUB, TypeInfo::Unknown());
1306 if (left_is_constant_smi) {
1307 __ push(Immediate(value));
1308 __ push(eax);
1309 } else {
1310 __ push(eax);
1311 __ push(Immediate(value));
1312 }
1313 __ CallStub(&stub);
1314 __ bind(&done);
1315 Apply(context, eax);
1316 }
1317
1318
1319 void FullCodeGenerator::EmitConstantSmiSub(Expression* expr,
1320 Expression::Context context,
1321 OverwriteMode mode,
1322 bool left_is_constant_smi,
1323 Smi* value) {
1324 Label call_stub, done;
1325 if (left_is_constant_smi) {
1326 __ mov(ecx, eax);
1327 __ mov(eax, Immediate(value));
1328 __ sub(Operand(eax), ecx);
1329 } else {
1330 __ sub(Operand(eax), Immediate(value));
1331 }
1332 __ j(overflow, &call_stub);
1333 __ test(eax, Immediate(kSmiTagMask));
1334 __ j(zero, &done);
1335
1336 __ bind(&call_stub);
1337 if (left_is_constant_smi) {
1338 __ push(Immediate(value));
1339 __ push(ecx);
1340 } else {
1341 // Undo the optimistic sub operation.
1342 __ add(Operand(eax), Immediate(value));
1343
1344 __ push(eax);
1345 __ push(Immediate(value));
1346 }
1347
1348 Token::Value op = Token::SUB;
1349 GenericBinaryOpStub stub(op, mode, NO_SMI_CODE_IN_STUB, TypeInfo::Unknown());
1350 __ CallStub(&stub);
1351 __ bind(&done);
1352 Apply(context, eax);
1353 }
1354
1355
1356 void FullCodeGenerator::EmitConstantSmiShiftOp(Expression* expr,
1357 Token::Value op,
1358 Expression::Context context,
1359 OverwriteMode mode,
1360 Smi* value) {
1361 Label call_stub, smi_case, done;
1362 int shift_value = value->value() & 0x1f;
1363
1364 __ test(eax, Immediate(kSmiTagMask));
1365 __ j(zero, &smi_case);
1366
1367 __ bind(&call_stub);
1368 GenericBinaryOpStub stub(op, mode, NO_SMI_CODE_IN_STUB, TypeInfo::Unknown());
1369 __ push(eax);
1370 __ push(Immediate(value));
1371 __ CallStub(&stub);
1372 __ jmp(&done);
1373
1374 __ bind(&smi_case);
1375 switch (op) {
1376 case Token::SHL:
1377 if (shift_value != 0) {
1378 __ mov(edx, eax);
1379 if (shift_value > 1) {
1380 __ shl(edx, shift_value - 1);
1381 }
1382 // Convert int result to smi, checking that it is in int range.
1383 ASSERT(kSmiTagSize == 1); // Adjust code if not the case.
1384 __ add(edx, Operand(edx));
1385 __ j(overflow, &call_stub);
1386 __ mov(eax, edx); // Put result back into eax.
1387 }
1388 break;
1389 case Token::SAR:
1390 if (shift_value != 0) {
1391 __ sar(eax, shift_value);
1392 __ and_(eax, ~kSmiTagMask);
1393 }
1394 break;
1395 case Token::SHR:
1396 if (shift_value < 2) {
1397 __ mov(edx, eax);
1398 __ SmiUntag(edx);
1399 __ shr(edx, shift_value);
1400 __ test(edx, Immediate(0xc0000000));
1401 __ j(not_zero, &call_stub);
1402 __ SmiTag(edx);
1403 __ mov(eax, edx); // Put result back into eax.
1404 } else {
1405 __ SmiUntag(eax);
1406 __ shr(eax, shift_value);
1407 __ SmiTag(eax);
1408 }
1409 break;
1410 default:
1411 UNREACHABLE();
1412 }
1413
1414 __ bind(&done);
1415 Apply(context, eax);
1416 }
1417
1418
1419 void FullCodeGenerator::EmitConstantSmiBitOp(Expression* expr,
1420 Token::Value op,
1421 Expression::Context context,
1422 OverwriteMode mode,
1423 Smi* value) {
1424 Label smi_case, done;
1425 __ test(eax, Immediate(kSmiTagMask));
1426 __ j(zero, &smi_case);
1427
1428 GenericBinaryOpStub stub(op, mode, NO_SMI_CODE_IN_STUB, TypeInfo::Unknown());
1429 // The order of the arguments does not matter for bit-ops with a
1430 // constant operand.
1431 __ push(Immediate(value));
1432 __ push(eax);
1433 __ CallStub(&stub);
1434 __ jmp(&done);
1435
1436 __ bind(&smi_case);
1437 switch (op) {
1438 case Token::BIT_OR:
1439 __ or_(Operand(eax), Immediate(value));
1440 break;
1441 case Token::BIT_XOR:
1442 __ xor_(Operand(eax), Immediate(value));
1443 break;
1444 case Token::BIT_AND:
1445 __ and_(Operand(eax), Immediate(value));
1446 break;
1447 default:
1448 UNREACHABLE();
1449 }
1450
1451 __ bind(&done);
1452 Apply(context, eax);
1453 }
1454
1455
1456 void FullCodeGenerator::EmitConstantSmiBinaryOp(Expression* expr,
1457 Token::Value op,
1458 Expression::Context context,
1459 OverwriteMode mode,
1460 bool left_is_constant_smi,
1461 Smi* value) {
1462 switch (op) {
1463 case Token::BIT_OR:
1464 case Token::BIT_XOR:
1465 case Token::BIT_AND:
1466 EmitConstantSmiBitOp(expr, op, context, mode, value);
1467 break;
1468 case Token::SHL:
1469 case Token::SAR:
1470 case Token::SHR:
1471 ASSERT(!left_is_constant_smi);
1472 EmitConstantSmiShiftOp(expr, op, context, mode, value);
1473 break;
1474 case Token::ADD:
1475 EmitConstantSmiAdd(expr, context, mode, left_is_constant_smi, value);
1476 break;
1477 case Token::SUB:
1478 EmitConstantSmiSub(expr, context, mode, left_is_constant_smi, value);
1479 break;
1480 default:
1481 UNREACHABLE();
1482 }
1483 }
1484
1485
1486 void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr,
1487 Token::Value op,
1488 Expression::Context context,
1489 OverwriteMode mode,
1490 Expression* left,
1491 Expression* right,
1492 ConstantOperand constant) {
1493 if (constant == kRightConstant) {
1494 Smi* value = Smi::cast(*right->AsLiteral()->handle());
1495 EmitConstantSmiBinaryOp(expr, op, context, mode, false, value);
1496 return;
1497 } else if (constant == kLeftConstant) {
1498 Smi* value = Smi::cast(*left->AsLiteral()->handle());
1499 EmitConstantSmiBinaryOp(expr, op, context, mode, true, value);
1500 return;
1501 }
1502
1503 // Do combined smi check of the operands. Left operand is on the
1504 // stack. Right operand is in eax.
1505 Label done, stub_call, smi_case;
1506 __ pop(edx);
1507 __ mov(ecx, eax);
1508 __ or_(eax, Operand(edx));
1509 __ test(eax, Immediate(kSmiTagMask));
1510 __ j(zero, &smi_case);
1511
1512 __ bind(&stub_call);
1513 GenericBinaryOpStub stub(op, mode, NO_SMI_CODE_IN_STUB, TypeInfo::Unknown());
1514 if (stub.ArgsInRegistersSupported()) {
1515 stub.GenerateCall(masm_, edx, ecx);
1516 } else {
1517 __ push(edx);
1518 __ push(ecx);
1519 __ CallStub(&stub);
1520 }
1521 __ jmp(&done);
1522
1523 __ bind(&smi_case);
1524 __ mov(eax, edx); // Copy left operand in case of a stub call.
1525
1526 switch (op) {
1527 case Token::SAR:
1528 __ SmiUntag(eax);
1529 __ SmiUntag(ecx);
1530 __ sar_cl(eax); // No checks of result necessary
1531 __ SmiTag(eax);
1532 break;
1533 case Token::SHL: {
1534 Label result_ok;
1535 __ SmiUntag(eax);
1536 __ SmiUntag(ecx);
1537 __ shl_cl(eax);
1538 // Check that the *signed* result fits in a smi.
1539 __ cmp(eax, 0xc0000000);
1540 __ j(positive, &result_ok);
1541 __ SmiTag(ecx);
1542 __ jmp(&stub_call);
1543 __ bind(&result_ok);
1544 __ SmiTag(eax);
1545 break;
1546 }
1547 case Token::SHR: {
1548 Label result_ok;
1549 __ SmiUntag(eax);
1550 __ SmiUntag(ecx);
1551 __ shr_cl(eax);
1552 __ test(eax, Immediate(0xc0000000));
1553 __ j(zero, &result_ok);
1554 __ SmiTag(ecx);
1555 __ jmp(&stub_call);
1556 __ bind(&result_ok);
1557 __ SmiTag(eax);
1558 break;
1559 }
1560 case Token::ADD:
1561 __ add(eax, Operand(ecx));
1562 __ j(overflow, &stub_call);
1563 break;
1564 case Token::SUB:
1565 __ sub(eax, Operand(ecx));
1566 __ j(overflow, &stub_call);
1567 break;
1568 case Token::MUL: {
1569 __ SmiUntag(eax);
1570 __ imul(eax, Operand(ecx));
1571 __ j(overflow, &stub_call);
1572 __ test(eax, Operand(eax));
1573 __ j(not_zero, &done, taken);
1574 __ mov(ebx, edx);
1575 __ or_(ebx, Operand(ecx));
1576 __ j(negative, &stub_call);
1577 break;
1578 }
1579 case Token::BIT_OR:
1580 __ or_(eax, Operand(ecx));
1581 break;
1582 case Token::BIT_AND:
1583 __ and_(eax, Operand(ecx));
1584 break;
1585 case Token::BIT_XOR:
1586 __ xor_(eax, Operand(ecx));
1587 break;
1588 default:
1589 UNREACHABLE();
1590 }
1591
1592 __ bind(&done);
1593 Apply(context, eax);
1594 }
1595
1596
1263 void FullCodeGenerator::EmitBinaryOp(Token::Value op, 1597 void FullCodeGenerator::EmitBinaryOp(Token::Value op,
1264 Expression::Context context, 1598 Expression::Context context,
1265 OverwriteMode mode) { 1599 OverwriteMode mode) {
1266 TypeInfo type = TypeInfo::Unknown(); 1600 TypeInfo type = TypeInfo::Unknown();
1267 GenericBinaryOpStub stub(op, mode, NO_GENERIC_BINARY_FLAGS, type); 1601 GenericBinaryOpStub stub(op, mode, NO_GENERIC_BINARY_FLAGS, type);
1268 if (stub.ArgsInRegistersSupported()) { 1602 if (stub.ArgsInRegistersSupported()) {
1269 __ pop(edx); 1603 __ pop(edx);
1270 stub.GenerateCall(masm_, edx, eax); 1604 stub.GenerateCall(masm_, edx, eax);
1271 } else { 1605 } else {
1272 __ push(result_register()); 1606 __ push(result_register());
(...skipping 1898 matching lines...) Expand 10 before | Expand all | Expand 10 after
3171 // And return. 3505 // And return.
3172 __ ret(0); 3506 __ ret(0);
3173 } 3507 }
3174 3508
3175 3509
3176 #undef __ 3510 #undef __
3177 3511
3178 } } // namespace v8::internal 3512 } } // namespace v8::internal
3179 3513
3180 #endif // V8_TARGET_ARCH_IA32 3514 #endif // V8_TARGET_ARCH_IA32
OLDNEW
« no previous file with comments | « src/full-codegen.cc ('k') | src/token.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698