| 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 1126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1137 } | 1137 } |
| 1138 __ b(&done); | 1138 __ b(&done); |
| 1139 } | 1139 } |
| 1140 | 1140 |
| 1141 __ bind(÷nd_is_not_negative); | 1141 __ bind(÷nd_is_not_negative); |
| 1142 __ and_(dividend, dividend, Operand(mask)); | 1142 __ and_(dividend, dividend, Operand(mask)); |
| 1143 __ bind(&done); | 1143 __ bind(&done); |
| 1144 } | 1144 } |
| 1145 | 1145 |
| 1146 | 1146 |
| 1147 void LCodeGen::DoModByConstI(LModByConstI* instr) { |
| 1148 Register dividend = ToRegister(instr->dividend()); |
| 1149 int32_t divisor = instr->divisor(); |
| 1150 Register result = ToRegister(instr->result()); |
| 1151 ASSERT(!dividend.is(result)); |
| 1152 |
| 1153 if (divisor == 0) { |
| 1154 DeoptimizeIf(al, instr->environment()); |
| 1155 return; |
| 1156 } |
| 1157 |
| 1158 __ FlooringDiv(result, dividend, Abs(divisor)); |
| 1159 __ mov(ip, Operand(Abs(divisor))); |
| 1160 __ smull(result, ip, result, ip); |
| 1161 __ sub(result, dividend, result, SetCC); |
| 1162 |
| 1163 // Check for negative zero. |
| 1164 HMod* hmod = instr->hydrogen(); |
| 1165 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero) && |
| 1166 hmod->left()->CanBeNegative()) { |
| 1167 Label remainder_not_zero; |
| 1168 __ b(ne, &remainder_not_zero); |
| 1169 __ cmp(dividend, Operand::Zero()); |
| 1170 DeoptimizeIf(lt, instr->environment()); |
| 1171 __ bind(&remainder_not_zero); |
| 1172 } |
| 1173 } |
| 1174 |
| 1175 |
| 1147 void LCodeGen::DoModI(LModI* instr) { | 1176 void LCodeGen::DoModI(LModI* instr) { |
| 1148 HMod* hmod = instr->hydrogen(); | 1177 HMod* hmod = instr->hydrogen(); |
| 1149 HValue* left = hmod->left(); | 1178 HValue* left = hmod->left(); |
| 1150 HValue* right = hmod->right(); | 1179 HValue* right = hmod->right(); |
| 1151 if (CpuFeatures::IsSupported(SUDIV)) { | 1180 if (CpuFeatures::IsSupported(SUDIV)) { |
| 1152 CpuFeatureScope scope(masm(), SUDIV); | 1181 CpuFeatureScope scope(masm(), SUDIV); |
| 1153 | 1182 |
| 1154 Register left_reg = ToRegister(instr->left()); | 1183 Register left_reg = ToRegister(instr->left()); |
| 1155 Register right_reg = ToRegister(instr->right()); | 1184 Register right_reg = ToRegister(instr->right()); |
| 1156 Register result_reg = ToRegister(instr->result()); | 1185 Register result_reg = ToRegister(instr->result()); |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1251 hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { | 1280 hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 1252 __ b(ne, &done); | 1281 __ b(ne, &done); |
| 1253 __ cmp(left_reg, Operand::Zero()); | 1282 __ cmp(left_reg, Operand::Zero()); |
| 1254 DeoptimizeIf(mi, instr->environment()); | 1283 DeoptimizeIf(mi, instr->environment()); |
| 1255 } | 1284 } |
| 1256 __ bind(&done); | 1285 __ bind(&done); |
| 1257 } | 1286 } |
| 1258 } | 1287 } |
| 1259 | 1288 |
| 1260 | 1289 |
| 1261 void LCodeGen::EmitSignedIntegerDivisionByConstant( | |
| 1262 Register result, | |
| 1263 Register dividend, | |
| 1264 int32_t divisor, | |
| 1265 Register remainder, | |
| 1266 Register scratch, | |
| 1267 LEnvironment* environment) { | |
| 1268 ASSERT(!AreAliased(dividend, scratch, ip)); | |
| 1269 ASSERT(LChunkBuilder::HasMagicNumberForDivisor(divisor)); | |
| 1270 | |
| 1271 uint32_t divisor_abs = abs(divisor); | |
| 1272 | |
| 1273 int32_t power_of_2_factor = | |
| 1274 CompilerIntrinsics::CountTrailingZeros(divisor_abs); | |
| 1275 | |
| 1276 switch (divisor_abs) { | |
| 1277 case 0: | |
| 1278 DeoptimizeIf(al, environment); | |
| 1279 return; | |
| 1280 | |
| 1281 case 1: | |
| 1282 if (divisor > 0) { | |
| 1283 __ Move(result, dividend); | |
| 1284 } else { | |
| 1285 __ rsb(result, dividend, Operand::Zero(), SetCC); | |
| 1286 DeoptimizeIf(vs, environment); | |
| 1287 } | |
| 1288 // Compute the remainder. | |
| 1289 __ mov(remainder, Operand::Zero()); | |
| 1290 return; | |
| 1291 | |
| 1292 default: | |
| 1293 if (IsPowerOf2(divisor_abs)) { | |
| 1294 // Branch and condition free code for integer division by a power | |
| 1295 // of two. | |
| 1296 int32_t power = WhichPowerOf2(divisor_abs); | |
| 1297 if (power > 1) { | |
| 1298 __ mov(scratch, Operand(dividend, ASR, power - 1)); | |
| 1299 } | |
| 1300 __ add(scratch, dividend, Operand(scratch, LSR, 32 - power)); | |
| 1301 __ mov(result, Operand(scratch, ASR, power)); | |
| 1302 // Negate if necessary. | |
| 1303 // We don't need to check for overflow because the case '-1' is | |
| 1304 // handled separately. | |
| 1305 if (divisor < 0) { | |
| 1306 ASSERT(divisor != -1); | |
| 1307 __ rsb(result, result, Operand::Zero()); | |
| 1308 } | |
| 1309 // Compute the remainder. | |
| 1310 if (divisor > 0) { | |
| 1311 __ sub(remainder, dividend, Operand(result, LSL, power)); | |
| 1312 } else { | |
| 1313 __ add(remainder, dividend, Operand(result, LSL, power)); | |
| 1314 } | |
| 1315 return; | |
| 1316 } else { | |
| 1317 // Use magic numbers for a few specific divisors. | |
| 1318 // Details and proofs can be found in: | |
| 1319 // - Hacker's Delight, Henry S. Warren, Jr. | |
| 1320 // - The PowerPC Compiler Writer’s Guide | |
| 1321 // and probably many others. | |
| 1322 // | |
| 1323 // We handle | |
| 1324 // <divisor with magic numbers> * <power of 2> | |
| 1325 // but not | |
| 1326 // <divisor with magic numbers> * <other divisor with magic numbers> | |
| 1327 DivMagicNumbers magic_numbers = | |
| 1328 DivMagicNumberFor(divisor_abs >> power_of_2_factor); | |
| 1329 // Branch and condition free code for integer division by a power | |
| 1330 // of two. | |
| 1331 const int32_t M = magic_numbers.M; | |
| 1332 const int32_t s = magic_numbers.s + power_of_2_factor; | |
| 1333 | |
| 1334 __ mov(ip, Operand(M)); | |
| 1335 __ smull(ip, scratch, dividend, ip); | |
| 1336 if (M < 0) { | |
| 1337 __ add(scratch, scratch, Operand(dividend)); | |
| 1338 } | |
| 1339 if (s > 0) { | |
| 1340 __ mov(scratch, Operand(scratch, ASR, s)); | |
| 1341 } | |
| 1342 __ add(result, scratch, Operand(dividend, LSR, 31)); | |
| 1343 if (divisor < 0) __ rsb(result, result, Operand::Zero()); | |
| 1344 // Compute the remainder. | |
| 1345 __ mov(ip, Operand(divisor)); | |
| 1346 // This sequence could be replaced with 'mls' when | |
| 1347 // it gets implemented. | |
| 1348 __ mul(scratch, result, ip); | |
| 1349 __ sub(remainder, dividend, scratch); | |
| 1350 } | |
| 1351 } | |
| 1352 } | |
| 1353 | |
| 1354 | |
| 1355 void LCodeGen::DoDivByPowerOf2I(LDivByPowerOf2I* instr) { | 1290 void LCodeGen::DoDivByPowerOf2I(LDivByPowerOf2I* instr) { |
| 1356 Register dividend = ToRegister(instr->dividend()); | 1291 Register dividend = ToRegister(instr->dividend()); |
| 1357 int32_t divisor = instr->divisor(); | 1292 int32_t divisor = instr->divisor(); |
| 1358 Register result = ToRegister(instr->result()); | 1293 Register result = ToRegister(instr->result()); |
| 1359 ASSERT(divisor == kMinInt || (divisor != 0 && IsPowerOf2(Abs(divisor)))); | 1294 ASSERT(divisor == kMinInt || (divisor != 0 && IsPowerOf2(Abs(divisor)))); |
| 1360 ASSERT(!result.is(dividend)); | 1295 ASSERT(!result.is(dividend)); |
| 1361 | 1296 |
| 1362 // Check for (0 / -x) that will produce negative zero. | 1297 // Check for (0 / -x) that will produce negative zero. |
| 1363 HDiv* hdiv = instr->hydrogen(); | 1298 HDiv* hdiv = instr->hydrogen(); |
| 1364 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && | 1299 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && |
| (...skipping 26 matching lines...) Expand all Loading... |
| 1391 __ add(result, dividend, Operand(dividend, LSR, 31)); | 1326 __ add(result, dividend, Operand(dividend, LSR, 31)); |
| 1392 } else { | 1327 } else { |
| 1393 __ mov(result, Operand(dividend, ASR, 31)); | 1328 __ mov(result, Operand(dividend, ASR, 31)); |
| 1394 __ add(result, dividend, Operand(result, LSR, 32 - shift)); | 1329 __ add(result, dividend, Operand(result, LSR, 32 - shift)); |
| 1395 } | 1330 } |
| 1396 if (shift > 0) __ mov(result, Operand(result, ASR, shift)); | 1331 if (shift > 0) __ mov(result, Operand(result, ASR, shift)); |
| 1397 if (divisor < 0) __ rsb(result, result, Operand(0)); | 1332 if (divisor < 0) __ rsb(result, result, Operand(0)); |
| 1398 } | 1333 } |
| 1399 | 1334 |
| 1400 | 1335 |
| 1336 void LCodeGen::DoDivByConstI(LDivByConstI* instr) { |
| 1337 Register dividend = ToRegister(instr->dividend()); |
| 1338 int32_t divisor = instr->divisor(); |
| 1339 Register result = ToRegister(instr->result()); |
| 1340 ASSERT(!dividend.is(result)); |
| 1341 |
| 1342 if (divisor == 0) { |
| 1343 DeoptimizeIf(al, instr->environment()); |
| 1344 return; |
| 1345 } |
| 1346 |
| 1347 // Check for (0 / -x) that will produce negative zero. |
| 1348 HDiv* hdiv = instr->hydrogen(); |
| 1349 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && |
| 1350 hdiv->left()->RangeCanInclude(0) && divisor < 0) { |
| 1351 __ cmp(dividend, Operand::Zero()); |
| 1352 DeoptimizeIf(eq, instr->environment()); |
| 1353 } |
| 1354 |
| 1355 __ FlooringDiv(result, dividend, Abs(divisor)); |
| 1356 if (divisor < 0) __ rsb(result, result, Operand::Zero()); |
| 1357 |
| 1358 if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) { |
| 1359 __ mov(ip, Operand(divisor)); |
| 1360 __ smull(scratch0(), ip, result, ip); |
| 1361 __ sub(scratch0(), scratch0(), dividend, SetCC); |
| 1362 DeoptimizeIf(ne, instr->environment()); |
| 1363 } |
| 1364 } |
| 1365 |
| 1366 |
| 1401 void LCodeGen::DoDivI(LDivI* instr) { | 1367 void LCodeGen::DoDivI(LDivI* instr) { |
| 1402 const Register left = ToRegister(instr->left()); | 1368 const Register left = ToRegister(instr->left()); |
| 1403 const Register right = ToRegister(instr->right()); | 1369 const Register right = ToRegister(instr->right()); |
| 1404 const Register result = ToRegister(instr->result()); | 1370 const Register result = ToRegister(instr->result()); |
| 1405 | 1371 |
| 1406 // Check for x / 0. | 1372 // Check for x / 0. |
| 1407 if (instr->hydrogen_value()->CheckFlag(HValue::kCanBeDivByZero)) { | 1373 if (instr->hydrogen_value()->CheckFlag(HValue::kCanBeDivByZero)) { |
| 1408 __ cmp(right, Operand::Zero()); | 1374 __ cmp(right, Operand::Zero()); |
| 1409 DeoptimizeIf(eq, instr->environment()); | 1375 DeoptimizeIf(eq, instr->environment()); |
| 1410 } | 1376 } |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1524 __ b(&done); | 1490 __ b(&done); |
| 1525 } | 1491 } |
| 1526 } | 1492 } |
| 1527 __ bind(¬_kmin_int); | 1493 __ bind(¬_kmin_int); |
| 1528 __ mov(dividend, Operand(dividend, ASR, shift)); | 1494 __ mov(dividend, Operand(dividend, ASR, shift)); |
| 1529 __ bind(&done); | 1495 __ bind(&done); |
| 1530 } | 1496 } |
| 1531 | 1497 |
| 1532 | 1498 |
| 1533 void LCodeGen::DoFlooringDivByConstI(LFlooringDivByConstI* instr) { | 1499 void LCodeGen::DoFlooringDivByConstI(LFlooringDivByConstI* instr) { |
| 1534 Register left = ToRegister(instr->dividend()); | 1500 Register dividend = ToRegister(instr->dividend()); |
| 1535 Register remainder = ToRegister(instr->temp()); | 1501 int32_t divisor = instr->divisor(); |
| 1536 Register scratch = scratch0(); | |
| 1537 Register result = ToRegister(instr->result()); | 1502 Register result = ToRegister(instr->result()); |
| 1503 ASSERT(!dividend.is(result)); |
| 1538 | 1504 |
| 1539 if (!CpuFeatures::IsSupported(SUDIV)) { | 1505 if (divisor == 0) { |
| 1540 // If the CPU doesn't support sdiv instruction, we only optimize when we | 1506 DeoptimizeIf(al, instr->environment()); |
| 1541 // have magic numbers for the divisor. The standard integer division routine | 1507 return; |
| 1542 // is usually slower than transitionning to VFP. | 1508 } |
| 1543 ASSERT(instr->divisor()->IsConstantOperand()); | |
| 1544 int32_t divisor = ToInteger32(LConstantOperand::cast(instr->divisor())); | |
| 1545 ASSERT(LChunkBuilder::HasMagicNumberForDivisor(divisor)); | |
| 1546 if (divisor < 0) { | |
| 1547 __ cmp(left, Operand::Zero()); | |
| 1548 DeoptimizeIf(eq, instr->environment()); | |
| 1549 } | |
| 1550 EmitSignedIntegerDivisionByConstant(result, | |
| 1551 left, | |
| 1552 divisor, | |
| 1553 remainder, | |
| 1554 scratch, | |
| 1555 instr->environment()); | |
| 1556 // We performed a truncating division. Correct the result if necessary. | |
| 1557 __ cmp(remainder, Operand::Zero()); | |
| 1558 __ teq(remainder, Operand(divisor), ne); | |
| 1559 __ sub(result, result, Operand(1), LeaveCC, mi); | |
| 1560 } else { | |
| 1561 CpuFeatureScope scope(masm(), SUDIV); | |
| 1562 // TODO(svenpanne) We *statically* know the divisor, use that fact! | |
| 1563 Register right = ToRegister(instr->divisor()); | |
| 1564 | 1509 |
| 1565 // Check for x / 0. | 1510 // Check for (0 / -x) that will produce negative zero. |
| 1566 __ cmp(right, Operand::Zero()); | 1511 HMathFloorOfDiv* hdiv = instr->hydrogen(); |
| 1512 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && |
| 1513 hdiv->left()->RangeCanInclude(0) && divisor < 0) { |
| 1514 __ cmp(dividend, Operand::Zero()); |
| 1567 DeoptimizeIf(eq, instr->environment()); | 1515 DeoptimizeIf(eq, instr->environment()); |
| 1516 } |
| 1568 | 1517 |
| 1569 // Check for (kMinInt / -1). | 1518 __ FlooringDiv(result, dividend, divisor); |
| 1570 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { | |
| 1571 __ cmp(left, Operand(kMinInt)); | |
| 1572 __ cmp(right, Operand(-1), eq); | |
| 1573 DeoptimizeIf(eq, instr->environment()); | |
| 1574 } | |
| 1575 | |
| 1576 // Check for (0 / -x) that will produce negative zero. | |
| 1577 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { | |
| 1578 __ cmp(right, Operand::Zero()); | |
| 1579 __ cmp(left, Operand::Zero(), mi); | |
| 1580 // "right" can't be null because the code would have already been | |
| 1581 // deoptimized. The Z flag is set only if (right < 0) and (left == 0). | |
| 1582 // In this case we need to deoptimize to produce a -0. | |
| 1583 DeoptimizeIf(eq, instr->environment()); | |
| 1584 } | |
| 1585 | |
| 1586 Label done; | |
| 1587 __ sdiv(result, left, right); | |
| 1588 // If both operands have the same sign then we are done. | |
| 1589 __ eor(remainder, left, Operand(right), SetCC); | |
| 1590 __ b(pl, &done); | |
| 1591 | |
| 1592 // Check if the result needs to be corrected. | |
| 1593 __ mls(remainder, result, right, left); | |
| 1594 __ cmp(remainder, Operand::Zero()); | |
| 1595 __ sub(result, result, Operand(1), LeaveCC, ne); | |
| 1596 | |
| 1597 __ bind(&done); | |
| 1598 } | |
| 1599 } | 1519 } |
| 1600 | 1520 |
| 1601 | 1521 |
| 1602 void LCodeGen::DoMulI(LMulI* instr) { | 1522 void LCodeGen::DoMulI(LMulI* instr) { |
| 1603 Register result = ToRegister(instr->result()); | 1523 Register result = ToRegister(instr->result()); |
| 1604 // Note that result may alias left. | 1524 // Note that result may alias left. |
| 1605 Register left = ToRegister(instr->left()); | 1525 Register left = ToRegister(instr->left()); |
| 1606 LOperand* right_op = instr->right(); | 1526 LOperand* right_op = instr->right(); |
| 1607 | 1527 |
| 1608 bool bailout_on_minus_zero = | 1528 bool bailout_on_minus_zero = |
| (...skipping 4193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5802 __ sub(scratch, result, Operand::PointerOffsetFromSmiKey(index)); | 5722 __ sub(scratch, result, Operand::PointerOffsetFromSmiKey(index)); |
| 5803 __ ldr(result, FieldMemOperand(scratch, | 5723 __ ldr(result, FieldMemOperand(scratch, |
| 5804 FixedArray::kHeaderSize - kPointerSize)); | 5724 FixedArray::kHeaderSize - kPointerSize)); |
| 5805 __ bind(&done); | 5725 __ bind(&done); |
| 5806 } | 5726 } |
| 5807 | 5727 |
| 5808 | 5728 |
| 5809 #undef __ | 5729 #undef __ |
| 5810 | 5730 |
| 5811 } } // namespace v8::internal | 5731 } } // namespace v8::internal |
| OLD | NEW |