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

Side by Side Diff: src/mips/code-stubs-mips.cc

Issue 26002002: MIPS: Hydrogenisation of binops (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: add comment Created 7 years, 2 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 | src/spaces.cc » ('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 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 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 1209 matching lines...) Expand 10 before | Expand all | Expand 10 after
1220 argument_count); 1220 argument_count);
1221 if (save_doubles_ == kSaveFPRegs) { 1221 if (save_doubles_ == kSaveFPRegs) {
1222 __ MultiPopFPU(kCallerSavedFPU); 1222 __ MultiPopFPU(kCallerSavedFPU);
1223 } 1223 }
1224 1224
1225 __ MultiPop(kJSCallerSaved | ra.bit()); 1225 __ MultiPop(kJSCallerSaved | ra.bit());
1226 __ Ret(); 1226 __ Ret();
1227 } 1227 }
1228 1228
1229 1229
1230 // Generates code to call a C function to do a double operation. 1230 void BinaryOpStub::InitializeInterfaceDescriptor(
1231 // This code never falls through, but returns with a heap number containing 1231 Isolate* isolate,
1232 // the result in v0. 1232 CodeStubInterfaceDescriptor* descriptor) {
1233 // Register heap_number_result must be a heap number in which the 1233 static Register registers[] = { a1, a0 };
1234 // result of the operation will be stored. 1234 descriptor->register_param_count_ = 2;
1235 // Requires the following layout on entry: 1235 descriptor->register_params_ = registers;
1236 // a0: Left value (least significant part of mantissa). 1236 descriptor->deoptimization_handler_ = FUNCTION_ADDR(BinaryOpIC_Miss);
1237 // a1: Left value (sign, exponent, top of mantissa). 1237 descriptor->SetMissHandler(
1238 // a2: Right value (least significant part of mantissa). 1238 ExternalReference(IC_Utility(IC::kBinaryOpIC_Miss), isolate));
1239 // a3: Right value (sign, exponent, top of mantissa).
1240 static void CallCCodeForDoubleOperation(MacroAssembler* masm,
1241 Token::Value op,
1242 Register heap_number_result,
1243 Register scratch) {
1244 // Assert that heap_number_result is saved.
1245 // We currently always use s0 to pass it.
1246 ASSERT(heap_number_result.is(s0));
1247
1248 // Push the current return address before the C call.
1249 __ push(ra);
1250 __ PrepareCallCFunction(4, scratch); // Two doubles are 4 arguments.
1251 {
1252 AllowExternalCallThatCantCauseGC scope(masm);
1253 __ CallCFunction(
1254 ExternalReference::double_fp_operation(op, masm->isolate()), 0, 2);
1255 }
1256 // Store answer in the overwritable heap number.
1257 // Double returned in register f0.
1258 __ sdc1(f0, FieldMemOperand(heap_number_result, HeapNumber::kValueOffset));
1259 // Place heap_number_result in v0 and return to the pushed return address.
1260 __ pop(ra);
1261 __ Ret(USE_DELAY_SLOT);
1262 __ mov(v0, heap_number_result);
1263 } 1239 }
1264 1240
1265 1241
1266 void BinaryOpStub::Initialize() {
1267 platform_specific_bit_ = true; // FPU is a base requirement for V8.
1268 }
1269
1270
1271 void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
1272 Label get_result;
1273
1274 __ Push(a1, a0);
1275
1276 __ li(a2, Operand(Smi::FromInt(MinorKey())));
1277 __ push(a2);
1278
1279 __ TailCallExternalReference(
1280 ExternalReference(IC_Utility(IC::kBinaryOp_Patch),
1281 masm->isolate()),
1282 3,
1283 1);
1284 }
1285
1286
1287 void BinaryOpStub::GenerateTypeTransitionWithSavedArgs(
1288 MacroAssembler* masm) {
1289 UNIMPLEMENTED();
1290 }
1291
1292
1293 void BinaryOpStub_GenerateSmiSmiOperation(MacroAssembler* masm,
1294 Token::Value op) {
1295 Register left = a1;
1296 Register right = a0;
1297
1298 Register scratch1 = t0;
1299 Register scratch2 = t1;
1300
1301 ASSERT(right.is(a0));
1302 STATIC_ASSERT(kSmiTag == 0);
1303
1304 Label not_smi_result;
1305 switch (op) {
1306 case Token::ADD:
1307 __ AdduAndCheckForOverflow(v0, left, right, scratch1);
1308 __ RetOnNoOverflow(scratch1);
1309 // No need to revert anything - right and left are intact.
1310 break;
1311 case Token::SUB:
1312 __ SubuAndCheckForOverflow(v0, left, right, scratch1);
1313 __ RetOnNoOverflow(scratch1);
1314 // No need to revert anything - right and left are intact.
1315 break;
1316 case Token::MUL: {
1317 // Remove tag from one of the operands. This way the multiplication result
1318 // will be a smi if it fits the smi range.
1319 __ SmiUntag(scratch1, right);
1320 // Do multiplication.
1321 // lo = lower 32 bits of scratch1 * left.
1322 // hi = higher 32 bits of scratch1 * left.
1323 __ Mult(left, scratch1);
1324 // Check for overflowing the smi range - no overflow if higher 33 bits of
1325 // the result are identical.
1326 __ mflo(scratch1);
1327 __ mfhi(scratch2);
1328 __ sra(scratch1, scratch1, 31);
1329 __ Branch(&not_smi_result, ne, scratch1, Operand(scratch2));
1330 // Go slow on zero result to handle -0.
1331 __ mflo(v0);
1332 __ Ret(ne, v0, Operand(zero_reg));
1333 // We need -0 if we were multiplying a negative number with 0 to get 0.
1334 // We know one of them was zero.
1335 __ Addu(scratch2, right, left);
1336 Label skip;
1337 // ARM uses the 'pl' condition, which is 'ge'.
1338 // Negating it results in 'lt'.
1339 __ Branch(&skip, lt, scratch2, Operand(zero_reg));
1340 ASSERT(Smi::FromInt(0) == 0);
1341 __ Ret(USE_DELAY_SLOT);
1342 __ mov(v0, zero_reg); // Return smi 0 if the non-zero one was positive.
1343 __ bind(&skip);
1344 // We fall through here if we multiplied a negative number with 0, because
1345 // that would mean we should produce -0.
1346 }
1347 break;
1348 case Token::DIV: {
1349 Label done;
1350 __ SmiUntag(scratch2, right);
1351 __ SmiUntag(scratch1, left);
1352 __ Div(scratch1, scratch2);
1353 // A minor optimization: div may be calculated asynchronously, so we check
1354 // for division by zero before getting the result.
1355 __ Branch(&not_smi_result, eq, scratch2, Operand(zero_reg));
1356 // If the result is 0, we need to make sure the dividsor (right) is
1357 // positive, otherwise it is a -0 case.
1358 // Quotient is in 'lo', remainder is in 'hi'.
1359 // Check for no remainder first.
1360 __ mfhi(scratch1);
1361 __ Branch(&not_smi_result, ne, scratch1, Operand(zero_reg));
1362 __ mflo(scratch1);
1363 __ Branch(&done, ne, scratch1, Operand(zero_reg));
1364 __ Branch(&not_smi_result, lt, scratch2, Operand(zero_reg));
1365 __ bind(&done);
1366 // Check that the signed result fits in a Smi.
1367 __ Addu(scratch2, scratch1, Operand(0x40000000));
1368 __ Branch(&not_smi_result, lt, scratch2, Operand(zero_reg));
1369 __ Ret(USE_DELAY_SLOT); // SmiTag emits one instruction in delay slot.
1370 __ SmiTag(v0, scratch1);
1371 }
1372 break;
1373 case Token::MOD: {
1374 Label done;
1375 __ SmiUntag(scratch2, right);
1376 __ SmiUntag(scratch1, left);
1377 __ Div(scratch1, scratch2);
1378 // A minor optimization: div may be calculated asynchronously, so we check
1379 // for division by 0 before calling mfhi.
1380 // Check for zero on the right hand side.
1381 __ Branch(&not_smi_result, eq, scratch2, Operand(zero_reg));
1382 // If the result is 0, we need to make sure the dividend (left) is
1383 // positive (or 0), otherwise it is a -0 case.
1384 // Remainder is in 'hi'.
1385 __ mfhi(scratch2);
1386 __ Branch(&done, ne, scratch2, Operand(zero_reg));
1387 __ Branch(&not_smi_result, lt, scratch1, Operand(zero_reg));
1388 __ bind(&done);
1389 // Check that the signed result fits in a Smi.
1390 __ Addu(scratch1, scratch2, Operand(0x40000000));
1391 __ Branch(&not_smi_result, lt, scratch1, Operand(zero_reg));
1392 __ Ret(USE_DELAY_SLOT); // SmiTag emits one instruction in delay slot.
1393 __ SmiTag(v0, scratch2);
1394 }
1395 break;
1396 case Token::BIT_OR:
1397 __ Ret(USE_DELAY_SLOT);
1398 __ or_(v0, left, right);
1399 break;
1400 case Token::BIT_AND:
1401 __ Ret(USE_DELAY_SLOT);
1402 __ and_(v0, left, right);
1403 break;
1404 case Token::BIT_XOR:
1405 __ Ret(USE_DELAY_SLOT);
1406 __ xor_(v0, left, right);
1407 break;
1408 case Token::SAR:
1409 // Remove tags from right operand.
1410 __ GetLeastBitsFromSmi(scratch1, right, 5);
1411 __ srav(scratch1, left, scratch1);
1412 // Smi tag result.
1413 __ And(v0, scratch1, ~kSmiTagMask);
1414 __ Ret();
1415 break;
1416 case Token::SHR:
1417 // Remove tags from operands. We can't do this on a 31 bit number
1418 // because then the 0s get shifted into bit 30 instead of bit 31.
1419 __ SmiUntag(scratch1, left);
1420 __ GetLeastBitsFromSmi(scratch2, right, 5);
1421 __ srlv(v0, scratch1, scratch2);
1422 // Unsigned shift is not allowed to produce a negative number, so
1423 // check the sign bit and the sign bit after Smi tagging.
1424 __ And(scratch1, v0, Operand(0xc0000000));
1425 __ Branch(&not_smi_result, ne, scratch1, Operand(zero_reg));
1426 // Smi tag result.
1427 __ Ret(USE_DELAY_SLOT); // SmiTag emits one instruction in delay slot.
1428 __ SmiTag(v0);
1429 break;
1430 case Token::SHL:
1431 // Remove tags from operands.
1432 __ SmiUntag(scratch1, left);
1433 __ GetLeastBitsFromSmi(scratch2, right, 5);
1434 __ sllv(scratch1, scratch1, scratch2);
1435 // Check that the signed result fits in a Smi.
1436 __ Addu(scratch2, scratch1, Operand(0x40000000));
1437 __ Branch(&not_smi_result, lt, scratch2, Operand(zero_reg));
1438 __ Ret(USE_DELAY_SLOT);
1439 __ SmiTag(v0, scratch1); // SmiTag emits one instruction in delay slot.
1440 break;
1441 default:
1442 UNREACHABLE();
1443 }
1444 __ bind(&not_smi_result);
1445 }
1446
1447
1448 void BinaryOpStub_GenerateHeapResultAllocation(MacroAssembler* masm,
1449 Register result,
1450 Register heap_number_map,
1451 Register scratch1,
1452 Register scratch2,
1453 Label* gc_required,
1454 OverwriteMode mode);
1455
1456
1457 void BinaryOpStub_GenerateFPOperation(MacroAssembler* masm,
1458 BinaryOpIC::TypeInfo left_type,
1459 BinaryOpIC::TypeInfo right_type,
1460 bool smi_operands,
1461 Label* not_numbers,
1462 Label* gc_required,
1463 Label* miss,
1464 Token::Value op,
1465 OverwriteMode mode) {
1466 Register left = a1;
1467 Register right = a0;
1468 Register scratch1 = t3;
1469 Register scratch2 = t5;
1470
1471 ASSERT(smi_operands || (not_numbers != NULL));
1472 if (smi_operands) {
1473 __ AssertSmi(left);
1474 __ AssertSmi(right);
1475 }
1476 if (left_type == BinaryOpIC::SMI) {
1477 __ JumpIfNotSmi(left, miss);
1478 }
1479 if (right_type == BinaryOpIC::SMI) {
1480 __ JumpIfNotSmi(right, miss);
1481 }
1482
1483 Register heap_number_map = t2;
1484 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
1485
1486 switch (op) {
1487 case Token::ADD:
1488 case Token::SUB:
1489 case Token::MUL:
1490 case Token::DIV:
1491 case Token::MOD: {
1492 // Allocate new heap number for result.
1493 Register result = s0;
1494 BinaryOpStub_GenerateHeapResultAllocation(
1495 masm, result, heap_number_map, scratch1, scratch2, gc_required, mode);
1496
1497 // Load left and right operands into f12 and f14.
1498 if (smi_operands) {
1499 __ SmiUntag(scratch1, a0);
1500 __ mtc1(scratch1, f14);
1501 __ cvt_d_w(f14, f14);
1502 __ SmiUntag(scratch1, a1);
1503 __ mtc1(scratch1, f12);
1504 __ cvt_d_w(f12, f12);
1505 } else {
1506 // Load right operand to f14.
1507 if (right_type == BinaryOpIC::INT32) {
1508 __ LoadNumberAsInt32Double(
1509 right, f14, heap_number_map, scratch1, scratch2, f2, miss);
1510 } else {
1511 Label* fail = (right_type == BinaryOpIC::NUMBER) ? miss : not_numbers;
1512 __ LoadNumber(right, f14, heap_number_map, scratch1, fail);
1513 }
1514 // Load left operand to f12 or a0/a1. This keeps a0/a1 intact if it
1515 // jumps to |miss|.
1516 if (left_type == BinaryOpIC::INT32) {
1517 __ LoadNumberAsInt32Double(
1518 left, f12, heap_number_map, scratch1, scratch2, f2, miss);
1519 } else {
1520 Label* fail = (left_type == BinaryOpIC::NUMBER) ? miss : not_numbers;
1521 __ LoadNumber(left, f12, heap_number_map, scratch1, fail);
1522 }
1523 }
1524
1525 // Calculate the result.
1526 if (op != Token::MOD) {
1527 // Using FPU registers:
1528 // f12: Left value.
1529 // f14: Right value.
1530 switch (op) {
1531 case Token::ADD:
1532 __ add_d(f10, f12, f14);
1533 break;
1534 case Token::SUB:
1535 __ sub_d(f10, f12, f14);
1536 break;
1537 case Token::MUL:
1538 __ mul_d(f10, f12, f14);
1539 break;
1540 case Token::DIV:
1541 __ div_d(f10, f12, f14);
1542 break;
1543 default:
1544 UNREACHABLE();
1545 }
1546
1547 // ARM uses a workaround here because of the unaligned HeapNumber
1548 // kValueOffset. On MIPS this workaround is built into sdc1 so
1549 // there's no point in generating even more instructions.
1550 __ sdc1(f10, FieldMemOperand(result, HeapNumber::kValueOffset));
1551 __ Ret(USE_DELAY_SLOT);
1552 __ mov(v0, result);
1553 } else {
1554 // Call the C function to handle the double operation.
1555 CallCCodeForDoubleOperation(masm, op, result, scratch1);
1556 if (FLAG_debug_code) {
1557 __ stop("Unreachable code.");
1558 }
1559 }
1560 break;
1561 }
1562 case Token::BIT_OR:
1563 case Token::BIT_XOR:
1564 case Token::BIT_AND:
1565 case Token::SAR:
1566 case Token::SHR:
1567 case Token::SHL: {
1568 if (smi_operands) {
1569 __ SmiUntag(a3, left);
1570 __ SmiUntag(a2, right);
1571 } else {
1572 // Convert operands to 32-bit integers. Right in a2 and left in a3.
1573 __ TruncateNumberToI(left, a3, heap_number_map, scratch1, not_numbers);
1574 __ TruncateNumberToI(right, a2, heap_number_map, scratch1, not_numbers);
1575 }
1576 Label result_not_a_smi;
1577 switch (op) {
1578 case Token::BIT_OR:
1579 __ Or(a2, a3, Operand(a2));
1580 break;
1581 case Token::BIT_XOR:
1582 __ Xor(a2, a3, Operand(a2));
1583 break;
1584 case Token::BIT_AND:
1585 __ And(a2, a3, Operand(a2));
1586 break;
1587 case Token::SAR:
1588 // Use only the 5 least significant bits of the shift count.
1589 __ GetLeastBitsFromInt32(a2, a2, 5);
1590 __ srav(a2, a3, a2);
1591 break;
1592 case Token::SHR:
1593 // Use only the 5 least significant bits of the shift count.
1594 __ GetLeastBitsFromInt32(a2, a2, 5);
1595 __ srlv(a2, a3, a2);
1596 // SHR is special because it is required to produce a positive answer.
1597 // The code below for writing into heap numbers isn't capable of
1598 // writing the register as an unsigned int so we go to slow case if we
1599 // hit this case.
1600 __ Branch(&result_not_a_smi, lt, a2, Operand(zero_reg));
1601 break;
1602 case Token::SHL:
1603 // Use only the 5 least significant bits of the shift count.
1604 __ GetLeastBitsFromInt32(a2, a2, 5);
1605 __ sllv(a2, a3, a2);
1606 break;
1607 default:
1608 UNREACHABLE();
1609 }
1610 // Check that the *signed* result fits in a smi.
1611 __ Addu(a3, a2, Operand(0x40000000));
1612 __ Branch(&result_not_a_smi, lt, a3, Operand(zero_reg));
1613 __ Ret(USE_DELAY_SLOT); // SmiTag emits one instruction in delay slot.
1614 __ SmiTag(v0, a2);
1615
1616 // Allocate new heap number for result.
1617 __ bind(&result_not_a_smi);
1618 Register result = t1;
1619 if (smi_operands) {
1620 __ AllocateHeapNumber(
1621 result, scratch1, scratch2, heap_number_map, gc_required);
1622 } else {
1623 BinaryOpStub_GenerateHeapResultAllocation(
1624 masm, result, heap_number_map, scratch1, scratch2, gc_required,
1625 mode);
1626 }
1627
1628 // a2: Answer as signed int32.
1629 // t1: Heap number to write answer into.
1630
1631 // Nothing can go wrong now, so move the heap number to v0, which is the
1632 // result.
1633 __ mov(v0, t1);
1634 // Convert the int32 in a2 to the heap number in a0. As
1635 // mentioned above SHR needs to always produce a positive result.
1636 __ mtc1(a2, f0);
1637 if (op == Token::SHR) {
1638 __ Cvt_d_uw(f0, f0, f22);
1639 } else {
1640 __ cvt_d_w(f0, f0);
1641 }
1642 // ARM uses a workaround here because of the unaligned HeapNumber
1643 // kValueOffset. On MIPS this workaround is built into sdc1 so
1644 // there's no point in generating even more instructions.
1645 __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
1646 __ Ret();
1647 break;
1648 }
1649 default:
1650 UNREACHABLE();
1651 }
1652 }
1653
1654
1655 // Generate the smi code. If the operation on smis are successful this return is
1656 // generated. If the result is not a smi and heap number allocation is not
1657 // requested the code falls through. If number allocation is requested but a
1658 // heap number cannot be allocated the code jumps to the label gc_required.
1659 void BinaryOpStub_GenerateSmiCode(
1660 MacroAssembler* masm,
1661 Label* use_runtime,
1662 Label* gc_required,
1663 Token::Value op,
1664 BinaryOpStub::SmiCodeGenerateHeapNumberResults allow_heapnumber_results,
1665 OverwriteMode mode) {
1666 Label not_smis;
1667
1668 Register left = a1;
1669 Register right = a0;
1670 Register scratch1 = t3;
1671
1672 // Perform combined smi check on both operands.
1673 __ Or(scratch1, left, Operand(right));
1674 STATIC_ASSERT(kSmiTag == 0);
1675 __ JumpIfNotSmi(scratch1, &not_smis);
1676
1677 // If the smi-smi operation results in a smi return is generated.
1678 BinaryOpStub_GenerateSmiSmiOperation(masm, op);
1679
1680 // If heap number results are possible generate the result in an allocated
1681 // heap number.
1682 if (allow_heapnumber_results == BinaryOpStub::ALLOW_HEAPNUMBER_RESULTS) {
1683 BinaryOpStub_GenerateFPOperation(
1684 masm, BinaryOpIC::UNINITIALIZED, BinaryOpIC::UNINITIALIZED, true,
1685 use_runtime, gc_required, &not_smis, op, mode);
1686 }
1687 __ bind(&not_smis);
1688 }
1689
1690
1691 void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) {
1692 Label right_arg_changed, call_runtime;
1693
1694 if (op_ == Token::MOD && encoded_right_arg_.has_value) {
1695 // It is guaranteed that the value will fit into a Smi, because if it
1696 // didn't, we wouldn't be here, see BinaryOp_Patch.
1697 __ Branch(&right_arg_changed,
1698 ne,
1699 a0,
1700 Operand(Smi::FromInt(fixed_right_arg_value())));
1701 }
1702
1703 if (result_type_ == BinaryOpIC::UNINITIALIZED ||
1704 result_type_ == BinaryOpIC::SMI) {
1705 // Only allow smi results.
1706 BinaryOpStub_GenerateSmiCode(
1707 masm, &call_runtime, NULL, op_, NO_HEAPNUMBER_RESULTS, mode_);
1708 } else {
1709 // Allow heap number result and don't make a transition if a heap number
1710 // cannot be allocated.
1711 BinaryOpStub_GenerateSmiCode(
1712 masm, &call_runtime, &call_runtime, op_, ALLOW_HEAPNUMBER_RESULTS,
1713 mode_);
1714 }
1715
1716 // Code falls through if the result is not returned as either a smi or heap
1717 // number.
1718 __ bind(&right_arg_changed);
1719 GenerateTypeTransition(masm);
1720
1721 __ bind(&call_runtime);
1722 {
1723 FrameScope scope(masm, StackFrame::INTERNAL);
1724 GenerateRegisterArgsPush(masm);
1725 GenerateCallRuntime(masm);
1726 }
1727 __ Ret();
1728 }
1729
1730
1731 void BinaryOpStub::GenerateBothStringStub(MacroAssembler* masm) {
1732 Label call_runtime;
1733 ASSERT(left_type_ == BinaryOpIC::STRING && right_type_ == BinaryOpIC::STRING);
1734 ASSERT(op_ == Token::ADD);
1735 // If both arguments are strings, call the string add stub.
1736 // Otherwise, do a transition.
1737
1738 // Registers containing left and right operands respectively.
1739 Register left = a1;
1740 Register right = a0;
1741
1742 // Test if left operand is a string.
1743 __ JumpIfSmi(left, &call_runtime);
1744 __ GetObjectType(left, a2, a2);
1745 __ Branch(&call_runtime, ge, a2, Operand(FIRST_NONSTRING_TYPE));
1746
1747 // Test if right operand is a string.
1748 __ JumpIfSmi(right, &call_runtime);
1749 __ GetObjectType(right, a2, a2);
1750 __ Branch(&call_runtime, ge, a2, Operand(FIRST_NONSTRING_TYPE));
1751
1752 StringAddStub string_add_stub(
1753 (StringAddFlags)(STRING_ADD_CHECK_NONE | STRING_ADD_ERECT_FRAME));
1754 GenerateRegisterArgsPush(masm);
1755 __ TailCallStub(&string_add_stub);
1756
1757 __ bind(&call_runtime);
1758 GenerateTypeTransition(masm);
1759 }
1760
1761
1762 void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
1763 ASSERT(Max(left_type_, right_type_) == BinaryOpIC::INT32);
1764
1765 Register left = a1;
1766 Register right = a0;
1767 Register scratch1 = t3;
1768 Register scratch2 = t5;
1769 FPURegister double_scratch = f0;
1770 FPURegister single_scratch = f6;
1771
1772 Register heap_number_result = no_reg;
1773 Register heap_number_map = t2;
1774 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
1775
1776 Label call_runtime;
1777 // Labels for type transition, used for wrong input or output types.
1778 // Both label are currently actually bound to the same position. We use two
1779 // different label to differentiate the cause leading to type transition.
1780 Label transition;
1781
1782 // Smi-smi fast case.
1783 Label skip;
1784 __ Or(scratch1, left, right);
1785 __ JumpIfNotSmi(scratch1, &skip);
1786 BinaryOpStub_GenerateSmiSmiOperation(masm, op_);
1787 // Fall through if the result is not a smi.
1788 __ bind(&skip);
1789
1790 switch (op_) {
1791 case Token::ADD:
1792 case Token::SUB:
1793 case Token::MUL:
1794 case Token::DIV:
1795 case Token::MOD: {
1796 // It could be that only SMIs have been seen at either the left
1797 // or the right operand. For precise type feedback, patch the IC
1798 // again if this changes.
1799 if (left_type_ == BinaryOpIC::SMI) {
1800 __ JumpIfNotSmi(left, &transition);
1801 }
1802 if (right_type_ == BinaryOpIC::SMI) {
1803 __ JumpIfNotSmi(right, &transition);
1804 }
1805 // Load both operands and check that they are 32-bit integer.
1806 // Jump to type transition if they are not. The registers a0 and a1 (right
1807 // and left) are preserved for the runtime call.
1808
1809 __ LoadNumberAsInt32Double(
1810 right, f14, heap_number_map, scratch1, scratch2, f2, &transition);
1811 __ LoadNumberAsInt32Double(
1812 left, f12, heap_number_map, scratch1, scratch2, f2, &transition);
1813
1814 if (op_ != Token::MOD) {
1815 Label return_heap_number;
1816 switch (op_) {
1817 case Token::ADD:
1818 __ add_d(f10, f12, f14);
1819 break;
1820 case Token::SUB:
1821 __ sub_d(f10, f12, f14);
1822 break;
1823 case Token::MUL:
1824 __ mul_d(f10, f12, f14);
1825 break;
1826 case Token::DIV:
1827 __ div_d(f10, f12, f14);
1828 break;
1829 default:
1830 UNREACHABLE();
1831 }
1832
1833 if (result_type_ <= BinaryOpIC::INT32) {
1834 Register except_flag = scratch2;
1835 const FPURoundingMode kRoundingMode = op_ == Token::DIV ?
1836 kRoundToMinusInf : kRoundToZero;
1837 const CheckForInexactConversion kConversion = op_ == Token::DIV ?
1838 kCheckForInexactConversion : kDontCheckForInexactConversion;
1839 __ EmitFPUTruncate(kRoundingMode,
1840 scratch1,
1841 f10,
1842 at,
1843 f16,
1844 except_flag,
1845 kConversion);
1846 // If except_flag != 0, result does not fit in a 32-bit integer.
1847 __ Branch(&transition, ne, except_flag, Operand(zero_reg));
1848 // Try to tag the result as a Smi, return heap number on overflow.
1849 __ SmiTagCheckOverflow(scratch1, scratch1, scratch2);
1850 __ Branch(&return_heap_number, lt, scratch2, Operand(zero_reg));
1851 // Check for minus zero, transition in that case (because we need
1852 // to return a heap number).
1853 Label not_zero;
1854 ASSERT(kSmiTag == 0);
1855 __ Branch(&not_zero, ne, scratch1, Operand(zero_reg));
1856 __ mfc1(scratch2, f11);
1857 __ And(scratch2, scratch2, HeapNumber::kSignMask);
1858 __ Branch(&transition, ne, scratch2, Operand(zero_reg));
1859 __ bind(&not_zero);
1860
1861 __ Ret(USE_DELAY_SLOT);
1862 __ mov(v0, scratch1);
1863 }
1864
1865 __ bind(&return_heap_number);
1866 // Return a heap number, or fall through to type transition or runtime
1867 // call if we can't.
1868 // We are using FPU registers so s0 is available.
1869 heap_number_result = s0;
1870 BinaryOpStub_GenerateHeapResultAllocation(masm,
1871 heap_number_result,
1872 heap_number_map,
1873 scratch1,
1874 scratch2,
1875 &call_runtime,
1876 mode_);
1877 __ sdc1(f10,
1878 FieldMemOperand(heap_number_result, HeapNumber::kValueOffset));
1879 __ Ret(USE_DELAY_SLOT);
1880 __ mov(v0, heap_number_result);
1881
1882 // A DIV operation expecting an integer result falls through
1883 // to type transition.
1884
1885 } else {
1886 if (encoded_right_arg_.has_value) {
1887 __ Move(f16, fixed_right_arg_value());
1888 __ BranchF(&transition, NULL, ne, f14, f16);
1889 }
1890
1891 Label pop_and_call_runtime;
1892
1893 // Allocate a heap number to store the result.
1894 heap_number_result = s0;
1895 BinaryOpStub_GenerateHeapResultAllocation(masm,
1896 heap_number_result,
1897 heap_number_map,
1898 scratch1,
1899 scratch2,
1900 &pop_and_call_runtime,
1901 mode_);
1902
1903 // Call the C function to handle the double operation.
1904 CallCCodeForDoubleOperation(masm, op_, heap_number_result, scratch1);
1905 if (FLAG_debug_code) {
1906 __ stop("Unreachable code.");
1907 }
1908
1909 __ bind(&pop_and_call_runtime);
1910 __ Drop(2);
1911 __ Branch(&call_runtime);
1912 }
1913
1914 break;
1915 }
1916
1917 case Token::BIT_OR:
1918 case Token::BIT_XOR:
1919 case Token::BIT_AND:
1920 case Token::SAR:
1921 case Token::SHR:
1922 case Token::SHL: {
1923 Label return_heap_number;
1924 // Convert operands to 32-bit integers. Right in a2 and left in a3. The
1925 // registers a0 and a1 (right and left) are preserved for the runtime
1926 // call.
1927 __ LoadNumberAsInt32(
1928 left, a3, heap_number_map, scratch1, scratch2, f0, f2, &transition);
1929 __ LoadNumberAsInt32(
1930 right, a2, heap_number_map, scratch1, scratch2, f0, f2, &transition);
1931
1932 // The ECMA-262 standard specifies that, for shift operations, only the
1933 // 5 least significant bits of the shift value should be used.
1934 switch (op_) {
1935 case Token::BIT_OR:
1936 __ Or(a2, a3, Operand(a2));
1937 break;
1938 case Token::BIT_XOR:
1939 __ Xor(a2, a3, Operand(a2));
1940 break;
1941 case Token::BIT_AND:
1942 __ And(a2, a3, Operand(a2));
1943 break;
1944 case Token::SAR:
1945 __ And(a2, a2, Operand(0x1f));
1946 __ srav(a2, a3, a2);
1947 break;
1948 case Token::SHR:
1949 __ And(a2, a2, Operand(0x1f));
1950 __ srlv(a2, a3, a2);
1951 // SHR is special because it is required to produce a positive answer.
1952 // We only get a negative result if the shift value (a2) is 0.
1953 // This result cannot be respresented as a signed 32-bit integer, try
1954 // to return a heap number if we can.
1955 __ Branch((result_type_ <= BinaryOpIC::INT32)
1956 ? &transition
1957 : &return_heap_number,
1958 lt,
1959 a2,
1960 Operand(zero_reg));
1961 break;
1962 case Token::SHL:
1963 __ And(a2, a2, Operand(0x1f));
1964 __ sllv(a2, a3, a2);
1965 break;
1966 default:
1967 UNREACHABLE();
1968 }
1969
1970 // Check if the result fits in a smi.
1971 __ Addu(scratch1, a2, Operand(0x40000000));
1972 // If not try to return a heap number. (We know the result is an int32.)
1973 __ Branch(&return_heap_number, lt, scratch1, Operand(zero_reg));
1974 // Tag the result and return.
1975 __ Ret(USE_DELAY_SLOT); // SmiTag emits one instruction in delay slot.
1976 __ SmiTag(v0, a2);
1977
1978 __ bind(&return_heap_number);
1979 heap_number_result = t1;
1980 BinaryOpStub_GenerateHeapResultAllocation(masm,
1981 heap_number_result,
1982 heap_number_map,
1983 scratch1,
1984 scratch2,
1985 &call_runtime,
1986 mode_);
1987
1988 if (op_ != Token::SHR) {
1989 // Convert the result to a floating point value.
1990 __ mtc1(a2, double_scratch);
1991 __ cvt_d_w(double_scratch, double_scratch);
1992 } else {
1993 // The result must be interpreted as an unsigned 32-bit integer.
1994 __ mtc1(a2, double_scratch);
1995 __ Cvt_d_uw(double_scratch, double_scratch, single_scratch);
1996 }
1997
1998 // Store the result.
1999 __ sdc1(double_scratch,
2000 FieldMemOperand(heap_number_result, HeapNumber::kValueOffset));
2001 __ Ret(USE_DELAY_SLOT);
2002 __ mov(v0, heap_number_result);
2003
2004 break;
2005 }
2006
2007 default:
2008 UNREACHABLE();
2009 }
2010
2011 // We never expect DIV to yield an integer result, so we always generate
2012 // type transition code for DIV operations expecting an integer result: the
2013 // code will fall through to this type transition.
2014 if (transition.is_linked() ||
2015 ((op_ == Token::DIV) && (result_type_ <= BinaryOpIC::INT32))) {
2016 __ bind(&transition);
2017 GenerateTypeTransition(masm);
2018 }
2019
2020 __ bind(&call_runtime);
2021 {
2022 FrameScope scope(masm, StackFrame::INTERNAL);
2023 GenerateRegisterArgsPush(masm);
2024 GenerateCallRuntime(masm);
2025 }
2026 __ Ret();
2027 }
2028
2029
2030 void BinaryOpStub::GenerateOddballStub(MacroAssembler* masm) {
2031 Label call_runtime;
2032
2033 if (op_ == Token::ADD) {
2034 // Handle string addition here, because it is the only operation
2035 // that does not do a ToNumber conversion on the operands.
2036 GenerateAddStrings(masm);
2037 }
2038
2039 // Convert oddball arguments to numbers.
2040 Label check, done;
2041 __ LoadRoot(t0, Heap::kUndefinedValueRootIndex);
2042 __ Branch(&check, ne, a1, Operand(t0));
2043 if (Token::IsBitOp(op_)) {
2044 __ li(a1, Operand(Smi::FromInt(0)));
2045 } else {
2046 __ LoadRoot(a1, Heap::kNanValueRootIndex);
2047 }
2048 __ jmp(&done);
2049 __ bind(&check);
2050 __ LoadRoot(t0, Heap::kUndefinedValueRootIndex);
2051 __ Branch(&done, ne, a0, Operand(t0));
2052 if (Token::IsBitOp(op_)) {
2053 __ li(a0, Operand(Smi::FromInt(0)));
2054 } else {
2055 __ LoadRoot(a0, Heap::kNanValueRootIndex);
2056 }
2057 __ bind(&done);
2058
2059 GenerateNumberStub(masm);
2060 }
2061
2062
2063 void BinaryOpStub::GenerateNumberStub(MacroAssembler* masm) {
2064 Label call_runtime, transition;
2065 BinaryOpStub_GenerateFPOperation(
2066 masm, left_type_, right_type_, false,
2067 &transition, &call_runtime, &transition, op_, mode_);
2068
2069 __ bind(&transition);
2070 GenerateTypeTransition(masm);
2071
2072 __ bind(&call_runtime);
2073 {
2074 FrameScope scope(masm, StackFrame::INTERNAL);
2075 GenerateRegisterArgsPush(masm);
2076 GenerateCallRuntime(masm);
2077 }
2078 __ Ret();
2079 }
2080
2081
2082 void BinaryOpStub::GenerateGeneric(MacroAssembler* masm) {
2083 Label call_runtime, call_string_add_or_runtime, transition;
2084
2085 BinaryOpStub_GenerateSmiCode(
2086 masm, &call_runtime, &call_runtime, op_, ALLOW_HEAPNUMBER_RESULTS, mode_);
2087
2088 BinaryOpStub_GenerateFPOperation(
2089 masm, left_type_, right_type_, false,
2090 &call_string_add_or_runtime, &call_runtime, &transition, op_, mode_);
2091
2092 __ bind(&transition);
2093 GenerateTypeTransition(masm);
2094
2095 __ bind(&call_string_add_or_runtime);
2096 if (op_ == Token::ADD) {
2097 GenerateAddStrings(masm);
2098 }
2099
2100 __ bind(&call_runtime);
2101 {
2102 FrameScope scope(masm, StackFrame::INTERNAL);
2103 GenerateRegisterArgsPush(masm);
2104 GenerateCallRuntime(masm);
2105 }
2106 __ Ret();
2107 }
2108
2109
2110 void BinaryOpStub::GenerateAddStrings(MacroAssembler* masm) {
2111 ASSERT(op_ == Token::ADD);
2112 Label left_not_string, call_runtime;
2113
2114 Register left = a1;
2115 Register right = a0;
2116
2117 // Check if left argument is a string.
2118 __ JumpIfSmi(left, &left_not_string);
2119 __ GetObjectType(left, a2, a2);
2120 __ Branch(&left_not_string, ge, a2, Operand(FIRST_NONSTRING_TYPE));
2121
2122 StringAddStub string_add_left_stub(
2123 (StringAddFlags)(STRING_ADD_CHECK_RIGHT | STRING_ADD_ERECT_FRAME));
2124 GenerateRegisterArgsPush(masm);
2125 __ TailCallStub(&string_add_left_stub);
2126
2127 // Left operand is not a string, test right.
2128 __ bind(&left_not_string);
2129 __ JumpIfSmi(right, &call_runtime);
2130 __ GetObjectType(right, a2, a2);
2131 __ Branch(&call_runtime, ge, a2, Operand(FIRST_NONSTRING_TYPE));
2132
2133 StringAddStub string_add_right_stub(
2134 (StringAddFlags)(STRING_ADD_CHECK_LEFT | STRING_ADD_ERECT_FRAME));
2135 GenerateRegisterArgsPush(masm);
2136 __ TailCallStub(&string_add_right_stub);
2137
2138 // At least one argument is not a string.
2139 __ bind(&call_runtime);
2140 }
2141
2142
2143 void BinaryOpStub_GenerateHeapResultAllocation(MacroAssembler* masm,
2144 Register result,
2145 Register heap_number_map,
2146 Register scratch1,
2147 Register scratch2,
2148 Label* gc_required,
2149 OverwriteMode mode) {
2150 // Code below will scratch result if allocation fails. To keep both arguments
2151 // intact for the runtime call result cannot be one of these.
2152 ASSERT(!result.is(a0) && !result.is(a1));
2153
2154 if (mode == OVERWRITE_LEFT || mode == OVERWRITE_RIGHT) {
2155 Label skip_allocation, allocated;
2156 Register overwritable_operand = mode == OVERWRITE_LEFT ? a1 : a0;
2157 // If the overwritable operand is already an object, we skip the
2158 // allocation of a heap number.
2159 __ JumpIfNotSmi(overwritable_operand, &skip_allocation);
2160 // Allocate a heap number for the result.
2161 __ AllocateHeapNumber(
2162 result, scratch1, scratch2, heap_number_map, gc_required);
2163 __ Branch(&allocated);
2164 __ bind(&skip_allocation);
2165 // Use object holding the overwritable operand for result.
2166 __ mov(result, overwritable_operand);
2167 __ bind(&allocated);
2168 } else {
2169 ASSERT(mode == NO_OVERWRITE);
2170 __ AllocateHeapNumber(
2171 result, scratch1, scratch2, heap_number_map, gc_required);
2172 }
2173 }
2174
2175
2176 void BinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) {
2177 __ Push(a1, a0);
2178 }
2179
2180
2181
2182 void TranscendentalCacheStub::Generate(MacroAssembler* masm) { 1242 void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
2183 // Untagged case: double input in f4, double result goes 1243 // Untagged case: double input in f4, double result goes
2184 // into f4. 1244 // into f4.
2185 // Tagged case: tagged input on top of stack and in a0, 1245 // Tagged case: tagged input on top of stack and in a0,
2186 // tagged result (heap number) goes into v0. 1246 // tagged result (heap number) goes into v0.
2187 1247
2188 Label input_not_smi; 1248 Label input_not_smi;
2189 Label loaded; 1249 Label loaded;
2190 Label calculate; 1250 Label calculate;
2191 Label invalid_cache; 1251 Label invalid_cache;
(...skipping 449 matching lines...) Expand 10 before | Expand all | Expand 10 after
2641 1701
2642 1702
2643 void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) { 1703 void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
2644 CEntryStub::GenerateAheadOfTime(isolate); 1704 CEntryStub::GenerateAheadOfTime(isolate);
2645 WriteInt32ToHeapNumberStub::GenerateFixedRegStubsAheadOfTime(isolate); 1705 WriteInt32ToHeapNumberStub::GenerateFixedRegStubsAheadOfTime(isolate);
2646 StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate); 1706 StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate);
2647 StubFailureTrampolineStub::GenerateAheadOfTime(isolate); 1707 StubFailureTrampolineStub::GenerateAheadOfTime(isolate);
2648 RecordWriteStub::GenerateFixedRegStubsAheadOfTime(isolate); 1708 RecordWriteStub::GenerateFixedRegStubsAheadOfTime(isolate);
2649 ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate); 1709 ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
2650 CreateAllocationSiteStub::GenerateAheadOfTime(isolate); 1710 CreateAllocationSiteStub::GenerateAheadOfTime(isolate);
1711 BinaryOpStub::GenerateAheadOfTime(isolate);
2651 } 1712 }
2652 1713
2653 1714
2654 void CodeStub::GenerateFPStubs(Isolate* isolate) { 1715 void CodeStub::GenerateFPStubs(Isolate* isolate) {
2655 SaveFPRegsMode mode = kSaveFPRegs; 1716 SaveFPRegsMode mode = kSaveFPRegs;
2656 CEntryStub save_doubles(1, mode); 1717 CEntryStub save_doubles(1, mode);
2657 StoreBufferOverflowStub stub(mode); 1718 StoreBufferOverflowStub stub(mode);
2658 // These stubs might already be in the snapshot, detect that and don't 1719 // These stubs might already be in the snapshot, detect that and don't
2659 // regenerate, which would lead to code stub initialization state being messed 1720 // regenerate, which would lead to code stub initialization state being messed
2660 // up. 1721 // up.
(...skipping 4509 matching lines...) Expand 10 before | Expand all | Expand 10 after
7170 __ bind(&fast_elements_case); 6231 __ bind(&fast_elements_case);
7171 GenerateCase(masm, FAST_ELEMENTS); 6232 GenerateCase(masm, FAST_ELEMENTS);
7172 } 6233 }
7173 6234
7174 6235
7175 #undef __ 6236 #undef __
7176 6237
7177 } } // namespace v8::internal 6238 } } // namespace v8::internal
7178 6239
7179 #endif // V8_TARGET_ARCH_MIPS 6240 #endif // V8_TARGET_ARCH_MIPS
OLDNEW
« no previous file with comments | « no previous file | src/spaces.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698