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

Side by Side Diff: src/arm/lithium-codegen-arm.cc

Issue 175143002: Consistenly handle power-of-2 divisors in division-like operations (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Rebased Created 6 years, 9 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/arm/lithium-arm.cc ('k') | src/hydrogen-instructions.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 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
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, &dividend_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(&dividend_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
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
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, &not_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(&not_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
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
OLDNEW
« no previous file with comments | « src/arm/lithium-arm.cc ('k') | src/hydrogen-instructions.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698