ARM: Use division instructions in lithium and stubs

BUG=none
TEST=Added to test/mjsunit/math-floor-of-div.js, math-floor-of-div-nosudiv.js

Review URL: https://codereview.chromium.org/11316105
Patch from Martyn Capewell <m.m.capewell@googlemail.com>.

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@13257 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
danno@chromium.org 2012-12-20 16:31:19 +00:00
parent a3f16f8e65
commit 653a66f527
6 changed files with 433 additions and 51 deletions

View File

@ -2441,33 +2441,112 @@ void BinaryOpStub_GenerateSmiSmiOperation(MacroAssembler* masm,
// We fall through here if we multiplied a negative number with 0, because // We fall through here if we multiplied a negative number with 0, because
// that would mean we should produce -0. // that would mean we should produce -0.
break; break;
case Token::DIV: case Token::DIV: {
Label div_with_sdiv;
// Check for 0 divisor.
__ cmp(right, Operand(0));
__ b(eq, &not_smi_result);
// Check for power of two on the right hand side. // Check for power of two on the right hand side.
__ JumpIfNotPowerOfTwoOrZero(right, scratch1, &not_smi_result); __ sub(scratch1, right, Operand(1));
// Check for positive and no remainder (scratch1 contains right - 1). __ tst(scratch1, right);
__ orr(scratch2, scratch1, Operand(0x80000000u)); if (CpuFeatures::IsSupported(SUDIV)) {
__ tst(left, scratch2); __ b(ne, &div_with_sdiv);
__ b(ne, &not_smi_result); // Check for no remainder.
__ tst(left, scratch1);
__ b(ne, &not_smi_result);
// Check for positive left hand side.
__ cmp(left, Operand(0));
__ b(mi, &div_with_sdiv);
} else {
__ b(ne, &not_smi_result);
// Check for positive and no remainder.
__ orr(scratch2, scratch1, Operand(0x80000000u));
__ tst(left, scratch2);
__ b(ne, &not_smi_result);
}
// Perform division by shifting. // Perform division by shifting.
__ CountLeadingZeros(scratch1, scratch1, scratch2); __ CountLeadingZeros(scratch1, scratch1, scratch2);
__ rsb(scratch1, scratch1, Operand(31)); __ rsb(scratch1, scratch1, Operand(31));
__ mov(right, Operand(left, LSR, scratch1)); __ mov(right, Operand(left, LSR, scratch1));
__ Ret(); __ Ret();
if (CpuFeatures::IsSupported(SUDIV)) {
Label result_not_zero;
__ bind(&div_with_sdiv);
// Do division.
__ sdiv(scratch1, left, right);
// Check that the remainder is zero.
__ mls(scratch2, scratch1, right, left);
__ cmp(scratch2, Operand(0));
__ b(ne, &not_smi_result);
// Check for negative zero result.
__ cmp(scratch1, Operand(0));
__ b(ne, &result_not_zero);
__ cmp(right, Operand(0));
__ b(lt, &not_smi_result);
__ bind(&result_not_zero);
// Check for the corner case of dividing the most negative smi by -1.
__ cmp(scratch1, Operand(0x40000000));
__ b(eq, &not_smi_result);
// Tag and return the result.
__ SmiTag(right, scratch1);
__ Ret();
}
break; break;
case Token::MOD: }
// Check for two positive smis. case Token::MOD: {
__ orr(scratch1, left, Operand(right)); Label modulo_with_sdiv;
__ tst(scratch1, Operand(0x80000000u | kSmiTagMask));
__ b(ne, &not_smi_result);
// Check for power of two on the right hand side. if (CpuFeatures::IsSupported(SUDIV)) {
__ JumpIfNotPowerOfTwoOrZero(right, scratch1, &not_smi_result); // Check for x % 0.
__ cmp(right, Operand(0));
__ b(eq, &not_smi_result);
// Perform modulus by masking. // Check for two positive smis.
__ orr(scratch1, left, Operand(right));
__ tst(scratch1, Operand(0x80000000u));
__ b(ne, &modulo_with_sdiv);
// Check for power of two on the right hand side.
__ sub(scratch1, right, Operand(1));
__ tst(scratch1, right);
__ b(ne, &modulo_with_sdiv);
} else {
// Check for two positive smis.
__ orr(scratch1, left, Operand(right));
__ tst(scratch1, Operand(0x80000000u));
__ b(ne, &not_smi_result);
// Check for power of two on the right hand side.
__ JumpIfNotPowerOfTwoOrZero(right, scratch1, &not_smi_result);
}
// Perform modulus by masking (scratch1 contains right - 1).
__ and_(right, left, Operand(scratch1)); __ and_(right, left, Operand(scratch1));
__ Ret(); __ Ret();
if (CpuFeatures::IsSupported(SUDIV)) {
__ bind(&modulo_with_sdiv);
__ mov(scratch2, right);
// Perform modulus with sdiv and mls.
__ sdiv(scratch1, left, right);
__ mls(right, scratch1, right, left);
// Return if the result is not 0.
__ cmp(right, Operand(0));
__ Ret(ne);
// The result is 0, check for -0 case.
__ cmp(left, Operand(0));
__ Ret(pl);
// This is a -0 case, restore the value of right.
__ mov(right, scratch2);
// We fall through here to not_smi_result to produce -0.
}
break; break;
}
case Token::BIT_OR: case Token::BIT_OR:
__ orr(right, left, Operand(right)); __ orr(right, left, Operand(right));
__ Ret(); __ Ret();

View File

@ -1241,31 +1241,43 @@ HValue* LChunkBuilder::SimplifiedDividendForMathFloorOfDiv(HValue* dividend) {
HValue* LChunkBuilder::SimplifiedDivisorForMathFloorOfDiv(HValue* divisor) { HValue* LChunkBuilder::SimplifiedDivisorForMathFloorOfDiv(HValue* divisor) {
// Only optimize when we have magic numbers for the divisor. if (CpuFeatures::IsSupported(SUDIV)) {
// The standard integer division routine is usually slower than transitionning // A value with an integer representation does not need to be transformed.
// to VFP. if (divisor->representation().IsInteger32()) {
if (divisor->IsConstant() && return divisor;
HConstant::cast(divisor)->HasInteger32Value()) { // A change from an integer32 can be replaced by the integer32 value.
} else if (divisor->IsChange() &&
HChange::cast(divisor)->from().IsInteger32()) {
return HChange::cast(divisor)->value();
}
}
if (divisor->IsConstant() && HConstant::cast(divisor)->HasInteger32Value()) {
HConstant* constant_val = HConstant::cast(divisor); HConstant* constant_val = HConstant::cast(divisor);
int32_t int32_val = constant_val->Integer32Value(); int32_t int32_val = constant_val->Integer32Value();
if (LChunkBuilder::HasMagicNumberForDivisor(int32_val)) { if (LChunkBuilder::HasMagicNumberForDivisor(int32_val) ||
CpuFeatures::IsSupported(SUDIV)) {
return constant_val->CopyToRepresentation(Representation::Integer32(), return constant_val->CopyToRepresentation(Representation::Integer32(),
divisor->block()->zone()); divisor->block()->zone());
} }
} }
return NULL; return NULL;
} }
LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) { LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) {
HValue* right = instr->right(); HValue* right = instr->right();
LOperand* dividend = UseRegister(instr->left()); LOperand* dividend = UseRegister(instr->left());
LOperand* divisor = UseRegisterOrConstant(right); LOperand* divisor = CpuFeatures::IsSupported(SUDIV)
LOperand* remainder = TempRegister(); ? UseRegister(right)
ASSERT(right->IsConstant() && : UseOrConstant(right);
HConstant::cast(right)->HasInteger32Value() && LOperand* remainder = TempRegister();
HasMagicNumberForDivisor(HConstant::cast(right)->Integer32Value())); ASSERT(CpuFeatures::IsSupported(SUDIV) ||
return AssignEnvironment(DefineAsRegister( (right->IsConstant() &&
HConstant::cast(right)->HasInteger32Value() &&
HasMagicNumberForDivisor(HConstant::cast(right)->Integer32Value())));
return AssignEnvironment(DefineAsRegister(
new(zone()) LMathFloorOfDiv(dividend, divisor, remainder))); new(zone()) LMathFloorOfDiv(dividend, divisor, remainder)));
} }

View File

@ -1433,25 +1433,68 @@ void LCodeGen::DoMathFloorOfDiv(LMathFloorOfDiv* instr) {
const Register remainder = ToRegister(instr->temp()); const Register remainder = ToRegister(instr->temp());
const Register scratch = scratch0(); const Register scratch = scratch0();
// We only optimize this for division by constants, because the standard if (!CpuFeatures::IsSupported(SUDIV)) {
// integer division routine is usually slower than transitionning to VFP. // If the CPU doesn't support sdiv instruction, we only optimize when we
// This could be optimized on processors with SDIV available. // have magic numbers for the divisor. The standard integer division routine
ASSERT(instr->right()->IsConstantOperand()); // is usually slower than transitionning to VFP.
int32_t divisor = ToInteger32(LConstantOperand::cast(instr->right())); ASSERT(instr->right()->IsConstantOperand());
if (divisor < 0) { int32_t divisor = ToInteger32(LConstantOperand::cast(instr->right()));
__ cmp(left, Operand(0)); ASSERT(LChunkBuilder::HasMagicNumberForDivisor(divisor));
if (divisor < 0) {
__ cmp(left, Operand(0));
DeoptimizeIf(eq, instr->environment());
}
EmitSignedIntegerDivisionByConstant(result,
left,
divisor,
remainder,
scratch,
instr->environment());
// We performed a truncating division. Correct the result if necessary.
__ cmp(remainder, Operand(0));
__ teq(remainder, Operand(divisor), ne);
__ sub(result, result, Operand(1), LeaveCC, mi);
} else {
CpuFeatures::Scope scope(SUDIV);
const Register right = ToRegister(instr->right());
// Check for x / 0.
__ cmp(right, Operand(0));
DeoptimizeIf(eq, instr->environment()); DeoptimizeIf(eq, instr->environment());
// Check for (kMinInt / -1).
if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
Label left_not_min_int;
__ cmp(left, Operand(kMinInt));
__ b(ne, &left_not_min_int);
__ cmp(right, Operand(-1));
DeoptimizeIf(eq, instr->environment());
__ bind(&left_not_min_int);
}
// Check for (0 / -x) that will produce negative zero.
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
__ cmp(right, Operand(0));
__ cmp(left, Operand(0), mi);
// "right" can't be null because the code would have already been
// deoptimized. The Z flag is set only if (right < 0) and (left == 0).
// In this case we need to deoptimize to produce a -0.
DeoptimizeIf(eq, instr->environment());
}
Label done;
__ sdiv(result, left, right);
// If both operands have the same sign then we are done.
__ eor(remainder, left, Operand(right), SetCC);
__ b(pl, &done);
// Check if the result needs to be corrected.
__ mls(remainder, result, right, left);
__ cmp(remainder, Operand(0));
__ sub(result, result, Operand(1), LeaveCC, ne);
__ bind(&done);
} }
EmitSignedIntegerDivisionByConstant(result,
left,
divisor,
remainder,
scratch,
instr->environment());
// We operated a truncating division. Correct the result if necessary.
__ cmp(remainder, Operand(0));
__ teq(remainder, Operand(divisor), ne);
__ sub(result, result, Operand(1), LeaveCC, mi);
} }

View File

@ -0,0 +1,230 @@
// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --allow-natives-syntax --nouse_inlining --noenable_sudiv
// Use this function as reference. Make sure it is not inlined.
function div(a, b) {
return a / b;
}
var limit = 0x1000000;
var exhaustive_limit = 100;
var step = 10;
var values = [0x10000001,
0x12345678,
-0x789abcdf, // 0x87654321
0x01234567,
0x76543210,
-0x80000000, // 0x80000000
0x7fffffff,
-0x0fffffff, // 0xf0000001
0x00000010,
-0x01000000 // 0xff000000
];
function test_div() {
var c = 0;
for (var k = 0; k <= limit; k++) {
if (k > exhaustive_limit) { c += step; k += c; }
assertEquals(Math.floor(div(k, 1)), Math.floor(k / 1));
assertEquals(Math.floor(div(k, -1)), Math.floor(k / -1));
assertEquals(Math.floor(div(k, 2)), Math.floor(k / 2));
assertEquals(Math.floor(div(k, -2)), Math.floor(k / -2));
assertEquals(Math.floor(div(k, 3)), Math.floor(k / 3));
assertEquals(Math.floor(div(k, -3)), Math.floor(k / -3));
assertEquals(Math.floor(div(k, 4)), Math.floor(k / 4));
assertEquals(Math.floor(div(k, -4)), Math.floor(k / -4));
assertEquals(Math.floor(div(k, 5)), Math.floor(k / 5));
assertEquals(Math.floor(div(k, -5)), Math.floor(k / -5));
assertEquals(Math.floor(div(k, 6)), Math.floor(k / 6));
assertEquals(Math.floor(div(k, -6)), Math.floor(k / -6));
assertEquals(Math.floor(div(k, 7)), Math.floor(k / 7));
assertEquals(Math.floor(div(k, -7)), Math.floor(k / -7));
assertEquals(Math.floor(div(k, 8)), Math.floor(k / 8));
assertEquals(Math.floor(div(k, -8)), Math.floor(k / -8));
assertEquals(Math.floor(div(k, 9)), Math.floor(k / 9));
assertEquals(Math.floor(div(k, -9)), Math.floor(k / -9));
assertEquals(Math.floor(div(k, 10)), Math.floor(k / 10));
assertEquals(Math.floor(div(k, -10)), Math.floor(k / -10));
assertEquals(Math.floor(div(k, 11)), Math.floor(k / 11));
assertEquals(Math.floor(div(k, -11)), Math.floor(k / -11));
assertEquals(Math.floor(div(k, 12)), Math.floor(k / 12));
assertEquals(Math.floor(div(k, -12)), Math.floor(k / -12));
assertEquals(Math.floor(div(k, 13)), Math.floor(k / 13));
assertEquals(Math.floor(div(k, -13)), Math.floor(k / -13));
assertEquals(Math.floor(div(k, 14)), Math.floor(k / 14));
assertEquals(Math.floor(div(k, -14)), Math.floor(k / -14));
assertEquals(Math.floor(div(k, 15)), Math.floor(k / 15));
assertEquals(Math.floor(div(k, -15)), Math.floor(k / -15));
assertEquals(Math.floor(div(k, 16)), Math.floor(k / 16));
assertEquals(Math.floor(div(k, -16)), Math.floor(k / -16));
assertEquals(Math.floor(div(k, 17)), Math.floor(k / 17));
assertEquals(Math.floor(div(k, -17)), Math.floor(k / -17));
assertEquals(Math.floor(div(k, 18)), Math.floor(k / 18));
assertEquals(Math.floor(div(k, -18)), Math.floor(k / -18));
assertEquals(Math.floor(div(k, 19)), Math.floor(k / 19));
assertEquals(Math.floor(div(k, -19)), Math.floor(k / -19));
assertEquals(Math.floor(div(k, 20)), Math.floor(k / 20));
assertEquals(Math.floor(div(k, -20)), Math.floor(k / -20));
assertEquals(Math.floor(div(k, 21)), Math.floor(k / 21));
assertEquals(Math.floor(div(k, -21)), Math.floor(k / -21));
assertEquals(Math.floor(div(k, 22)), Math.floor(k / 22));
assertEquals(Math.floor(div(k, -22)), Math.floor(k / -22));
assertEquals(Math.floor(div(k, 23)), Math.floor(k / 23));
assertEquals(Math.floor(div(k, -23)), Math.floor(k / -23));
assertEquals(Math.floor(div(k, 24)), Math.floor(k / 24));
assertEquals(Math.floor(div(k, -24)), Math.floor(k / -24));
assertEquals(Math.floor(div(k, 25)), Math.floor(k / 25));
assertEquals(Math.floor(div(k, -25)), Math.floor(k / -25));
assertEquals(Math.floor(div(k, 125)), Math.floor(k / 125));
assertEquals(Math.floor(div(k, -125)), Math.floor(k / -125));
assertEquals(Math.floor(div(k, 625)), Math.floor(k / 625));
assertEquals(Math.floor(div(k, -625)), Math.floor(k / -625));
}
c = 0;
for (var k = 0; k <= limit; k++) {
if (k > exhaustive_limit) { c += step; k += c; }
assertEquals(Math.floor(div(-k, 1)), Math.floor(-k / 1));
assertEquals(Math.floor(div(-k, -1)), Math.floor(-k / -1));
assertEquals(Math.floor(div(-k, 2)), Math.floor(-k / 2));
assertEquals(Math.floor(div(-k, -2)), Math.floor(-k / -2));
assertEquals(Math.floor(div(-k, 3)), Math.floor(-k / 3));
assertEquals(Math.floor(div(-k, -3)), Math.floor(-k / -3));
assertEquals(Math.floor(div(-k, 4)), Math.floor(-k / 4));
assertEquals(Math.floor(div(-k, -4)), Math.floor(-k / -4));
assertEquals(Math.floor(div(-k, 5)), Math.floor(-k / 5));
assertEquals(Math.floor(div(-k, -5)), Math.floor(-k / -5));
assertEquals(Math.floor(div(-k, 6)), Math.floor(-k / 6));
assertEquals(Math.floor(div(-k, -6)), Math.floor(-k / -6));
assertEquals(Math.floor(div(-k, 7)), Math.floor(-k / 7));
assertEquals(Math.floor(div(-k, -7)), Math.floor(-k / -7));
assertEquals(Math.floor(div(-k, 8)), Math.floor(-k / 8));
assertEquals(Math.floor(div(-k, -8)), Math.floor(-k / -8));
assertEquals(Math.floor(div(-k, 9)), Math.floor(-k / 9));
assertEquals(Math.floor(div(-k, -9)), Math.floor(-k / -9));
assertEquals(Math.floor(div(-k, 10)), Math.floor(-k / 10));
assertEquals(Math.floor(div(-k, -10)), Math.floor(-k / -10));
assertEquals(Math.floor(div(-k, 11)), Math.floor(-k / 11));
assertEquals(Math.floor(div(-k, -11)), Math.floor(-k / -11));
assertEquals(Math.floor(div(-k, 12)), Math.floor(-k / 12));
assertEquals(Math.floor(div(-k, -12)), Math.floor(-k / -12));
assertEquals(Math.floor(div(-k, 13)), Math.floor(-k / 13));
assertEquals(Math.floor(div(-k, -13)), Math.floor(-k / -13));
assertEquals(Math.floor(div(-k, 14)), Math.floor(-k / 14));
assertEquals(Math.floor(div(-k, -14)), Math.floor(-k / -14));
assertEquals(Math.floor(div(-k, 15)), Math.floor(-k / 15));
assertEquals(Math.floor(div(-k, -15)), Math.floor(-k / -15));
assertEquals(Math.floor(div(-k, 16)), Math.floor(-k / 16));
assertEquals(Math.floor(div(-k, -16)), Math.floor(-k / -16));
assertEquals(Math.floor(div(-k, 17)), Math.floor(-k / 17));
assertEquals(Math.floor(div(-k, -17)), Math.floor(-k / -17));
assertEquals(Math.floor(div(-k, 18)), Math.floor(-k / 18));
assertEquals(Math.floor(div(-k, -18)), Math.floor(-k / -18));
assertEquals(Math.floor(div(-k, 19)), Math.floor(-k / 19));
assertEquals(Math.floor(div(-k, -19)), Math.floor(-k / -19));
assertEquals(Math.floor(div(-k, 20)), Math.floor(-k / 20));
assertEquals(Math.floor(div(-k, -20)), Math.floor(-k / -20));
assertEquals(Math.floor(div(-k, 21)), Math.floor(-k / 21));
assertEquals(Math.floor(div(-k, -21)), Math.floor(-k / -21));
assertEquals(Math.floor(div(-k, 22)), Math.floor(-k / 22));
assertEquals(Math.floor(div(-k, -22)), Math.floor(-k / -22));
assertEquals(Math.floor(div(-k, 23)), Math.floor(-k / 23));
assertEquals(Math.floor(div(-k, -23)), Math.floor(-k / -23));
assertEquals(Math.floor(div(-k, 24)), Math.floor(-k / 24));
assertEquals(Math.floor(div(-k, -24)), Math.floor(-k / -24));
assertEquals(Math.floor(div(-k, 25)), Math.floor(-k / 25));
assertEquals(Math.floor(div(-k, -25)), Math.floor(-k / -25));
assertEquals(Math.floor(div(-k, 125)), Math.floor(-k / 125));
assertEquals(Math.floor(div(-k, -125)), Math.floor(-k / -125));
assertEquals(Math.floor(div(-k, 625)), Math.floor(-k / 625));
assertEquals(Math.floor(div(-k, -625)), Math.floor(-k / -625));
}
// Test for edge cases.
// Use (values[key] | 0) to force the integer type.
for (var i = 0; i < values.length; i++) {
for (var j = 0; j < values.length; j++) {
assertEquals(Math.floor(div((values[i] | 0), (values[j] | 0))),
Math.floor((values[i] | 0) / (values[j] | 0)));
assertEquals(Math.floor(div(-(values[i] | 0), (values[j] | 0))),
Math.floor(-(values[i] | 0) / (values[j] | 0)));
assertEquals(Math.floor(div((values[i] | 0), -(values[j] | 0))),
Math.floor((values[i] | 0) / -(values[j] | 0)));
assertEquals(Math.floor(div(-(values[i] | 0), -(values[j] | 0))),
Math.floor(-(values[i] | 0) / -(values[j] | 0)));
}
}
}
test_div();
%OptimizeFunctionOnNextCall(test_div);
test_div();
// Test for negative zero, overflow and division by 0.
// Separate the tests to prevent deoptimizations from making the other optimized
// test unreachable.
function IsNegativeZero(x) {
assertTrue(x == 0); // Is 0 or -0.
var y = 1 / x;
assertFalse(isFinite(y));
return y < 0;
}
function test_div_deopt_minus_zero() {
var zero_in_array = [0];
for (var i = 0; i < 2; ++i) {
assertTrue(IsNegativeZero(Math.floor((zero_in_array[0] | 0) / -1)));
}
}
function test_div_deopt_overflow() {
// We box the value in an array to avoid constant propagation.
var min_int_in_array = [-2147483648];
for (var i = 0; i < 2; ++i) {
// We use '| 0' to force the representation to int32.
assertEquals(-min_int_in_array[0],
Math.floor((min_int_in_array[0] | 0) / -1));
}
}
function test_div_deopt_div_by_zero() {
for (var i = 0; i < 2; ++i) {
assertEquals(div(i, 0),
Math.floor(i / 0));
}
}
test_div_deopt_minus_zero();
test_div_deopt_overflow();
test_div_deopt_div_by_zero();
%OptimizeFunctionOnNextCall(test_div_deopt_minus_zero);
%OptimizeFunctionOnNextCall(test_div_deopt_overflow);
%OptimizeFunctionOnNextCall(test_div_deopt_div_by_zero);
test_div_deopt_minus_zero();
test_div_deopt_overflow();
test_div_deopt_div_by_zero();

View File

@ -25,7 +25,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --allow-natives-syntax --nouse_inlining // Flags: --allow-natives-syntax --nouse_inlining --enable_sudiv
// Use this function as reference. Make sure it is not inlined. // Use this function as reference. Make sure it is not inlined.
function div(a, b) { function div(a, b) {
@ -184,7 +184,7 @@ test_div();
%OptimizeFunctionOnNextCall(test_div); %OptimizeFunctionOnNextCall(test_div);
test_div(); test_div();
// Test for negative zero and overflow. // Test for negative zero, overflow and division by 0.
// Separate the tests to prevent deoptimizations from making the other optimized // Separate the tests to prevent deoptimizations from making the other optimized
// test unreachable. // test unreachable.
@ -197,20 +197,34 @@ function IsNegativeZero(x) {
function test_div_deopt_minus_zero() { function test_div_deopt_minus_zero() {
var zero_in_array = [0]; var zero_in_array = [0];
assertTrue(IsNegativeZero(Math.floor((zero_in_array[0] | 0) / -1))); for (var i = 0; i < 2; ++i) {
assertTrue(IsNegativeZero(Math.floor((zero_in_array[0] | 0) / -1)));
}
} }
function test_div_deopt_overflow() { function test_div_deopt_overflow() {
// We box the value in an array to avoid constant propagation. // We box the value in an array to avoid constant propagation.
var min_int_in_array = [-2147483648]; var min_int_in_array = [-2147483648];
// We use '| 0' to force the representation to int32. for (var i = 0; i < 2; ++i) {
assertEquals(-min_int_in_array[0], // We use '| 0' to force the representation to int32.
Math.floor((min_int_in_array[0] | 0) / -1)); assertEquals(-min_int_in_array[0],
Math.floor((min_int_in_array[0] | 0) / -1));
}
}
function test_div_deopt_div_by_zero() {
for (var i = 0; i < 2; ++i) {
assertEquals(div(i, 0),
Math.floor(i / 0));
}
} }
test_div_deopt_minus_zero(); test_div_deopt_minus_zero();
test_div_deopt_overflow(); test_div_deopt_overflow();
test_div_deopt_div_by_zero();
%OptimizeFunctionOnNextCall(test_div_deopt_minus_zero); %OptimizeFunctionOnNextCall(test_div_deopt_minus_zero);
%OptimizeFunctionOnNextCall(test_div_deopt_overflow); %OptimizeFunctionOnNextCall(test_div_deopt_overflow);
%OptimizeFunctionOnNextCall(test_div_deopt_div_by_zero);
test_div_deopt_minus_zero(); test_div_deopt_minus_zero();
test_div_deopt_overflow(); test_div_deopt_overflow();
test_div_deopt_div_by_zero();

View File

@ -76,6 +76,10 @@ regress/regress-crbug-160010: PASS, SKIP if $mode == debug
d8-os: PASS, SKIP if ($isolates || $arch == android_arm || $arch == android_ia32) d8-os: PASS, SKIP if ($isolates || $arch == android_arm || $arch == android_ia32)
tools/tickprocessor: PASS, SKIP if ($arch == android_arm || $arch == android_ia32) tools/tickprocessor: PASS, SKIP if ($arch == android_arm || $arch == android_ia32)
##############################################################################
# This test is the same as math-floor-of-div for non ARM architectures.
math-floor-of-div-nosudiv: PASS, SKIP if ($arch != arm && $arch != android_arm)
############################################################################## ##############################################################################
[ $arch == arm || $arch == android_arm ] [ $arch == arm || $arch == android_arm ]