OLD | NEW |
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 1093 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1104 UNREACHABLE(); | 1104 UNREACHABLE(); |
1105 } | 1105 } |
1106 } | 1106 } |
1107 | 1107 |
1108 | 1108 |
1109 void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) { | 1109 void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) { |
1110 GenerateOsrPrologue(); | 1110 GenerateOsrPrologue(); |
1111 } | 1111 } |
1112 | 1112 |
1113 | 1113 |
| 1114 void LCodeGen::DoModByPowerOf2I(LModByPowerOf2I* instr) { |
| 1115 Register dividend = ToRegister(instr->dividend()); |
| 1116 int32_t divisor = instr->divisor(); |
| 1117 ASSERT(dividend.is(ToRegister(instr->result()))); |
| 1118 |
| 1119 // Theoretically, a variation of the branch-free code for integer division by |
| 1120 // a power of 2 (calculating the remainder via an additional multiplication |
| 1121 // (which gets simplified to an 'and') and subtraction) should be faster, and |
| 1122 // this is exactly what GCC and clang emit. Nevertheless, benchmarks seem to |
| 1123 // indicate that positive dividends are heavily favored, so the branching |
| 1124 // version performs better. |
| 1125 HMod* hmod = instr->hydrogen(); |
| 1126 int32_t mask = divisor < 0 ? -(divisor + 1) : (divisor - 1); |
| 1127 Label dividend_is_not_negative, done; |
| 1128 if (hmod->left()->CanBeNegative()) { |
| 1129 __ cmp(dividend, Operand::Zero()); |
| 1130 __ b(pl, ÷nd_is_not_negative); |
| 1131 // Note that this is correct even for kMinInt operands. |
| 1132 __ rsb(dividend, dividend, Operand::Zero()); |
| 1133 __ and_(dividend, dividend, Operand(mask)); |
| 1134 __ rsb(dividend, dividend, Operand::Zero(), SetCC); |
| 1135 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 1136 DeoptimizeIf(eq, instr->environment()); |
| 1137 } |
| 1138 __ b(&done); |
| 1139 } |
| 1140 |
| 1141 __ bind(÷nd_is_not_negative); |
| 1142 __ and_(dividend, dividend, Operand(mask)); |
| 1143 __ bind(&done); |
| 1144 } |
| 1145 |
| 1146 |
1114 void LCodeGen::DoModI(LModI* instr) { | 1147 void LCodeGen::DoModI(LModI* instr) { |
1115 HMod* hmod = instr->hydrogen(); | 1148 HMod* hmod = instr->hydrogen(); |
1116 HValue* left = hmod->left(); | 1149 HValue* left = hmod->left(); |
1117 HValue* right = hmod->right(); | 1150 HValue* right = hmod->right(); |
1118 if (hmod->RightIsPowerOf2()) { | 1151 if (CpuFeatures::IsSupported(SUDIV)) { |
1119 // TODO(svenpanne) We should really do the strength reduction on the | |
1120 // Hydrogen level. | |
1121 Register left_reg = ToRegister(instr->left()); | |
1122 Register result_reg = ToRegister(instr->result()); | |
1123 | |
1124 // Note: The code below even works when right contains kMinInt. | |
1125 int32_t divisor = Abs(right->GetInteger32Constant()); | |
1126 | |
1127 Label left_is_not_negative, done; | |
1128 if (left->CanBeNegative()) { | |
1129 __ cmp(left_reg, Operand::Zero()); | |
1130 __ b(pl, &left_is_not_negative); | |
1131 __ rsb(result_reg, left_reg, Operand::Zero()); | |
1132 __ and_(result_reg, result_reg, Operand(divisor - 1)); | |
1133 __ rsb(result_reg, result_reg, Operand::Zero(), SetCC); | |
1134 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { | |
1135 DeoptimizeIf(eq, instr->environment()); | |
1136 } | |
1137 __ b(&done); | |
1138 } | |
1139 | |
1140 __ bind(&left_is_not_negative); | |
1141 __ and_(result_reg, left_reg, Operand(divisor - 1)); | |
1142 __ bind(&done); | |
1143 } else if (CpuFeatures::IsSupported(SUDIV)) { | |
1144 CpuFeatureScope scope(masm(), SUDIV); | 1152 CpuFeatureScope scope(masm(), SUDIV); |
1145 | 1153 |
1146 Register left_reg = ToRegister(instr->left()); | 1154 Register left_reg = ToRegister(instr->left()); |
1147 Register right_reg = ToRegister(instr->right()); | 1155 Register right_reg = ToRegister(instr->right()); |
1148 Register result_reg = ToRegister(instr->result()); | 1156 Register result_reg = ToRegister(instr->result()); |
1149 | 1157 |
1150 Label done; | 1158 Label done; |
1151 // Check for x % 0, sdiv might signal an exception. We have to deopt in this | 1159 // Check for x % 0, sdiv might signal an exception. We have to deopt in this |
1152 // case because we can't return a NaN. | 1160 // case because we can't return a NaN. |
1153 if (right->CanBeZero()) { | 1161 if (right->CanBeZero()) { |
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1337 __ mov(ip, Operand(divisor)); | 1345 __ mov(ip, Operand(divisor)); |
1338 // This sequence could be replaced with 'mls' when | 1346 // This sequence could be replaced with 'mls' when |
1339 // it gets implemented. | 1347 // it gets implemented. |
1340 __ mul(scratch, result, ip); | 1348 __ mul(scratch, result, ip); |
1341 __ sub(remainder, dividend, scratch); | 1349 __ sub(remainder, dividend, scratch); |
1342 } | 1350 } |
1343 } | 1351 } |
1344 } | 1352 } |
1345 | 1353 |
1346 | 1354 |
| 1355 void LCodeGen::DoDivByPowerOf2I(LDivByPowerOf2I* instr) { |
| 1356 Register dividend = ToRegister(instr->dividend()); |
| 1357 int32_t divisor = instr->divisor(); |
| 1358 Register result = ToRegister(instr->result()); |
| 1359 ASSERT(divisor == kMinInt || (divisor != 0 && IsPowerOf2(Abs(divisor)))); |
| 1360 ASSERT(!result.is(dividend)); |
| 1361 |
| 1362 // Check for (0 / -x) that will produce negative zero. |
| 1363 HDiv* hdiv = instr->hydrogen(); |
| 1364 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && |
| 1365 hdiv->left()->RangeCanInclude(0) && divisor < 0) { |
| 1366 __ cmp(dividend, Operand::Zero()); |
| 1367 DeoptimizeIf(eq, instr->environment()); |
| 1368 } |
| 1369 // Check for (kMinInt / -1). |
| 1370 if (hdiv->CheckFlag(HValue::kCanOverflow) && |
| 1371 hdiv->left()->RangeCanInclude(kMinInt) && divisor == -1) { |
| 1372 __ cmp(dividend, Operand(kMinInt)); |
| 1373 DeoptimizeIf(eq, instr->environment()); |
| 1374 } |
| 1375 // Deoptimize if remainder will not be 0. |
| 1376 if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) && |
| 1377 divisor != 1 && divisor != -1) { |
| 1378 int32_t mask = divisor < 0 ? -(divisor + 1) : (divisor - 1); |
| 1379 __ tst(dividend, Operand(mask)); |
| 1380 DeoptimizeIf(ne, instr->environment()); |
| 1381 } |
| 1382 |
| 1383 if (divisor == -1) { // Nice shortcut, not needed for correctness. |
| 1384 __ rsb(result, dividend, Operand(0)); |
| 1385 return; |
| 1386 } |
| 1387 int32_t shift = WhichPowerOf2Abs(divisor); |
| 1388 if (shift == 0) { |
| 1389 __ mov(result, dividend); |
| 1390 } else if (shift == 1) { |
| 1391 __ add(result, dividend, Operand(dividend, LSR, 31)); |
| 1392 } else { |
| 1393 __ mov(result, Operand(dividend, ASR, 31)); |
| 1394 __ add(result, dividend, Operand(result, LSR, 32 - shift)); |
| 1395 } |
| 1396 if (shift > 0) __ mov(result, Operand(result, ASR, shift)); |
| 1397 if (divisor < 0) __ rsb(result, result, Operand(0)); |
| 1398 } |
| 1399 |
| 1400 |
1347 void LCodeGen::DoDivI(LDivI* instr) { | 1401 void LCodeGen::DoDivI(LDivI* instr) { |
1348 if (!instr->is_flooring() && instr->hydrogen()->RightIsPowerOf2()) { | |
1349 Register dividend = ToRegister(instr->left()); | |
1350 HDiv* hdiv = instr->hydrogen(); | |
1351 int32_t divisor = hdiv->right()->GetInteger32Constant(); | |
1352 Register result = ToRegister(instr->result()); | |
1353 ASSERT(!result.is(dividend)); | |
1354 | |
1355 // Check for (0 / -x) that will produce negative zero. | |
1356 if (hdiv->left()->RangeCanInclude(0) && divisor < 0 && | |
1357 hdiv->CheckFlag(HValue::kBailoutOnMinusZero)) { | |
1358 __ cmp(dividend, Operand::Zero()); | |
1359 DeoptimizeIf(eq, instr->environment()); | |
1360 } | |
1361 // Check for (kMinInt / -1). | |
1362 if (hdiv->left()->RangeCanInclude(kMinInt) && divisor == -1 && | |
1363 hdiv->CheckFlag(HValue::kCanOverflow)) { | |
1364 __ cmp(dividend, Operand(kMinInt)); | |
1365 DeoptimizeIf(eq, instr->environment()); | |
1366 } | |
1367 // Deoptimize if remainder will not be 0. | |
1368 if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) && | |
1369 Abs(divisor) != 1) { | |
1370 __ tst(dividend, Operand(Abs(divisor) - 1)); | |
1371 DeoptimizeIf(ne, instr->environment()); | |
1372 } | |
1373 if (divisor == -1) { // Nice shortcut, not needed for correctness. | |
1374 __ rsb(result, dividend, Operand(0)); | |
1375 return; | |
1376 } | |
1377 int32_t shift = WhichPowerOf2(Abs(divisor)); | |
1378 if (shift == 0) { | |
1379 __ mov(result, dividend); | |
1380 } else if (shift == 1) { | |
1381 __ add(result, dividend, Operand(dividend, LSR, 31)); | |
1382 } else { | |
1383 __ mov(result, Operand(dividend, ASR, 31)); | |
1384 __ add(result, dividend, Operand(result, LSR, 32 - shift)); | |
1385 } | |
1386 if (shift > 0) __ mov(result, Operand(result, ASR, shift)); | |
1387 if (divisor < 0) __ rsb(result, result, Operand(0)); | |
1388 return; | |
1389 } | |
1390 | |
1391 const Register left = ToRegister(instr->left()); | 1402 const Register left = ToRegister(instr->left()); |
1392 const Register right = ToRegister(instr->right()); | 1403 const Register right = ToRegister(instr->right()); |
1393 const Register result = ToRegister(instr->result()); | 1404 const Register result = ToRegister(instr->result()); |
1394 | 1405 |
1395 // Check for x / 0. | 1406 // Check for x / 0. |
1396 if (instr->hydrogen_value()->CheckFlag(HValue::kCanBeDivByZero)) { | 1407 if (instr->hydrogen_value()->CheckFlag(HValue::kCanBeDivByZero)) { |
1397 __ cmp(right, Operand::Zero()); | 1408 __ cmp(right, Operand::Zero()); |
1398 DeoptimizeIf(eq, instr->environment()); | 1409 DeoptimizeIf(eq, instr->environment()); |
1399 } | 1410 } |
1400 | 1411 |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1475 DwVfpRegister multiplier = ToDoubleRegister(instr->multiplier()); | 1486 DwVfpRegister multiplier = ToDoubleRegister(instr->multiplier()); |
1476 DwVfpRegister multiplicand = ToDoubleRegister(instr->multiplicand()); | 1487 DwVfpRegister multiplicand = ToDoubleRegister(instr->multiplicand()); |
1477 | 1488 |
1478 // This is computed in-place. | 1489 // This is computed in-place. |
1479 ASSERT(minuend.is(ToDoubleRegister(instr->result()))); | 1490 ASSERT(minuend.is(ToDoubleRegister(instr->result()))); |
1480 | 1491 |
1481 __ vmls(minuend, multiplier, multiplicand); | 1492 __ vmls(minuend, multiplier, multiplicand); |
1482 } | 1493 } |
1483 | 1494 |
1484 | 1495 |
1485 void LCodeGen::DoMathFloorOfDiv(LMathFloorOfDiv* instr) { | 1496 void LCodeGen::DoFlooringDivByPowerOf2I(LFlooringDivByPowerOf2I* instr) { |
1486 const Register result = ToRegister(instr->result()); | 1497 Register dividend = ToRegister(instr->dividend()); |
1487 const Register left = ToRegister(instr->left()); | 1498 int32_t divisor = instr->divisor(); |
1488 const Register remainder = ToRegister(instr->temp()); | 1499 ASSERT(dividend.is(ToRegister(instr->result()))); |
1489 const Register scratch = scratch0(); | 1500 |
| 1501 // If the divisor is positive, things are easy: There can be no deopts and we |
| 1502 // can simply do an arithmetic right shift. |
| 1503 if (divisor == 1) return; |
| 1504 int32_t shift = WhichPowerOf2Abs(divisor); |
| 1505 if (divisor > 1) { |
| 1506 __ mov(dividend, Operand(dividend, ASR, shift)); |
| 1507 return; |
| 1508 } |
| 1509 |
| 1510 // If the divisor is negative, we have to negate and handle edge cases. |
| 1511 Label not_kmin_int, done; |
| 1512 __ rsb(dividend, dividend, Operand::Zero(), SetCC); |
| 1513 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 1514 DeoptimizeIf(eq, instr->environment()); |
| 1515 } |
| 1516 if (instr->hydrogen()->left()->RangeCanInclude(kMinInt)) { |
| 1517 // Note that we could emit branch-free code, but that would need one more |
| 1518 // register. |
| 1519 __ b(vc, ¬_kmin_int); |
| 1520 if (divisor == -1) { |
| 1521 DeoptimizeIf(al, instr->environment()); |
| 1522 } else { |
| 1523 __ mov(dividend, Operand(kMinInt / divisor)); |
| 1524 __ b(&done); |
| 1525 } |
| 1526 } |
| 1527 __ bind(¬_kmin_int); |
| 1528 __ mov(dividend, Operand(dividend, ASR, shift)); |
| 1529 __ bind(&done); |
| 1530 } |
| 1531 |
| 1532 |
| 1533 void LCodeGen::DoFlooringDivByConstI(LFlooringDivByConstI* instr) { |
| 1534 Register left = ToRegister(instr->dividend()); |
| 1535 Register remainder = ToRegister(instr->temp()); |
| 1536 Register scratch = scratch0(); |
| 1537 Register result = ToRegister(instr->result()); |
1490 | 1538 |
1491 if (!CpuFeatures::IsSupported(SUDIV)) { | 1539 if (!CpuFeatures::IsSupported(SUDIV)) { |
1492 // If the CPU doesn't support sdiv instruction, we only optimize when we | 1540 // If the CPU doesn't support sdiv instruction, we only optimize when we |
1493 // have magic numbers for the divisor. The standard integer division routine | 1541 // have magic numbers for the divisor. The standard integer division routine |
1494 // is usually slower than transitionning to VFP. | 1542 // is usually slower than transitionning to VFP. |
1495 ASSERT(instr->right()->IsConstantOperand()); | 1543 ASSERT(instr->divisor()->IsConstantOperand()); |
1496 int32_t divisor = ToInteger32(LConstantOperand::cast(instr->right())); | 1544 int32_t divisor = ToInteger32(LConstantOperand::cast(instr->divisor())); |
1497 ASSERT(LChunkBuilder::HasMagicNumberForDivisor(divisor)); | 1545 ASSERT(LChunkBuilder::HasMagicNumberForDivisor(divisor)); |
1498 if (divisor < 0) { | 1546 if (divisor < 0) { |
1499 __ cmp(left, Operand::Zero()); | 1547 __ cmp(left, Operand::Zero()); |
1500 DeoptimizeIf(eq, instr->environment()); | 1548 DeoptimizeIf(eq, instr->environment()); |
1501 } | 1549 } |
1502 EmitSignedIntegerDivisionByConstant(result, | 1550 EmitSignedIntegerDivisionByConstant(result, |
1503 left, | 1551 left, |
1504 divisor, | 1552 divisor, |
1505 remainder, | 1553 remainder, |
1506 scratch, | 1554 scratch, |
1507 instr->environment()); | 1555 instr->environment()); |
1508 // We performed a truncating division. Correct the result if necessary. | 1556 // We performed a truncating division. Correct the result if necessary. |
1509 __ cmp(remainder, Operand::Zero()); | 1557 __ cmp(remainder, Operand::Zero()); |
1510 __ teq(remainder, Operand(divisor), ne); | 1558 __ teq(remainder, Operand(divisor), ne); |
1511 __ sub(result, result, Operand(1), LeaveCC, mi); | 1559 __ sub(result, result, Operand(1), LeaveCC, mi); |
1512 } else { | 1560 } else { |
1513 CpuFeatureScope scope(masm(), SUDIV); | 1561 CpuFeatureScope scope(masm(), SUDIV); |
1514 const Register right = ToRegister(instr->right()); | 1562 // TODO(svenpanne) We *statically* know the divisor, use that fact! |
| 1563 Register right = ToRegister(instr->divisor()); |
1515 | 1564 |
1516 // Check for x / 0. | 1565 // Check for x / 0. |
1517 __ cmp(right, Operand::Zero()); | 1566 __ cmp(right, Operand::Zero()); |
1518 DeoptimizeIf(eq, instr->environment()); | 1567 DeoptimizeIf(eq, instr->environment()); |
1519 | 1568 |
1520 // Check for (kMinInt / -1). | 1569 // Check for (kMinInt / -1). |
1521 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { | 1570 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { |
1522 __ cmp(left, Operand(kMinInt)); | 1571 __ cmp(left, Operand(kMinInt)); |
1523 __ cmp(right, Operand(-1), eq); | 1572 __ cmp(right, Operand(-1), eq); |
1524 DeoptimizeIf(eq, instr->environment()); | 1573 DeoptimizeIf(eq, instr->environment()); |
(...skipping 4228 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5753 __ sub(scratch, result, Operand::PointerOffsetFromSmiKey(index)); | 5802 __ sub(scratch, result, Operand::PointerOffsetFromSmiKey(index)); |
5754 __ ldr(result, FieldMemOperand(scratch, | 5803 __ ldr(result, FieldMemOperand(scratch, |
5755 FixedArray::kHeaderSize - kPointerSize)); | 5804 FixedArray::kHeaderSize - kPointerSize)); |
5756 __ bind(&done); | 5805 __ bind(&done); |
5757 } | 5806 } |
5758 | 5807 |
5759 | 5808 |
5760 #undef __ | 5809 #undef __ |
5761 | 5810 |
5762 } } // namespace v8::internal | 5811 } } // namespace v8::internal |
OLD | NEW |