Revision: 13257
Author: [email protected]
Date: Thu Dec 20 08:31:19 2012
Log: 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 <[email protected]>.
http://code.google.com/p/v8/source/detail?r=13257
Added:
/branches/bleeding_edge/test/mjsunit/math-floor-of-div-nosudiv.js
Modified:
/branches/bleeding_edge/src/arm/code-stubs-arm.cc
/branches/bleeding_edge/src/arm/lithium-arm.cc
/branches/bleeding_edge/src/arm/lithium-codegen-arm.cc
/branches/bleeding_edge/test/mjsunit/math-floor-of-div.js
/branches/bleeding_edge/test/mjsunit/mjsunit.status
=======================================
--- /dev/null
+++ /branches/bleeding_edge/test/mjsunit/math-floor-of-div-nosudiv.js Thu
Dec 20 08:31:19 2012
@@ -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();
=======================================
--- /branches/bleeding_edge/src/arm/code-stubs-arm.cc Tue Dec 18 08:25:45
2012
+++ /branches/bleeding_edge/src/arm/code-stubs-arm.cc Thu Dec 20 08:31:19
2012
@@ -2441,33 +2441,112 @@
// We fall through here if we multiplied a negative number with 0,
because
// that would mean we should produce -0.
break;
- case Token::DIV:
+ case Token::DIV: {
+ Label div_with_sdiv;
+
+ // Check for 0 divisor.
+ __ cmp(right, Operand(0));
+ __ b(eq, ¬_smi_result);
+
// Check for power of two on the right hand side.
- __ JumpIfNotPowerOfTwoOrZero(right, scratch1, ¬_smi_result);
- // Check for positive and no remainder (scratch1 contains right - 1).
- __ orr(scratch2, scratch1, Operand(0x80000000u));
- __ tst(left, scratch2);
- __ b(ne, ¬_smi_result);
+ __ sub(scratch1, right, Operand(1));
+ __ tst(scratch1, right);
+ if (CpuFeatures::IsSupported(SUDIV)) {
+ __ b(ne, &div_with_sdiv);
+ // Check for no remainder.
+ __ tst(left, scratch1);
+ __ b(ne, ¬_smi_result);
+ // Check for positive left hand side.
+ __ cmp(left, Operand(0));
+ __ b(mi, &div_with_sdiv);
+ } else {
+ __ b(ne, ¬_smi_result);
+ // Check for positive and no remainder.
+ __ orr(scratch2, scratch1, Operand(0x80000000u));
+ __ tst(left, scratch2);
+ __ b(ne, ¬_smi_result);
+ }
// Perform division by shifting.
__ CountLeadingZeros(scratch1, scratch1, scratch2);
__ rsb(scratch1, scratch1, Operand(31));
__ mov(right, Operand(left, LSR, scratch1));
__ 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, ¬_smi_result);
+ // Check for negative zero result.
+ __ cmp(scratch1, Operand(0));
+ __ b(ne, &result_not_zero);
+ __ cmp(right, Operand(0));
+ __ b(lt, ¬_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, ¬_smi_result);
+ // Tag and return the result.
+ __ SmiTag(right, scratch1);
+ __ Ret();
+ }
break;
- case Token::MOD:
- // Check for two positive smis.
- __ orr(scratch1, left, Operand(right));
- __ tst(scratch1, Operand(0x80000000u | kSmiTagMask));
- __ b(ne, ¬_smi_result);
+ }
+ case Token::MOD: {
+ Label modulo_with_sdiv;
- // Check for power of two on the right hand side.
- __ JumpIfNotPowerOfTwoOrZero(right, scratch1, ¬_smi_result);
+ if (CpuFeatures::IsSupported(SUDIV)) {
+ // Check for x % 0.
+ __ cmp(right, Operand(0));
+ __ b(eq, ¬_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, ¬_smi_result);
+
+ // Check for power of two on the right hand side.
+ __ JumpIfNotPowerOfTwoOrZero(right, scratch1, ¬_smi_result);
+ }
+
+ // Perform modulus by masking (scratch1 contains right - 1).
__ and_(right, left, Operand(scratch1));
__ 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;
+ }
case Token::BIT_OR:
__ orr(right, left, Operand(right));
__ Ret();
=======================================
--- /branches/bleeding_edge/src/arm/lithium-arm.cc Tue Dec 18 08:25:45 2012
+++ /branches/bleeding_edge/src/arm/lithium-arm.cc Thu Dec 20 08:31:19 2012
@@ -1241,31 +1241,43 @@
HValue* LChunkBuilder::SimplifiedDivisorForMathFloorOfDiv(HValue* divisor)
{
- // Only optimize when we have magic numbers for the divisor.
- // The standard integer division routine is usually slower than
transitionning
- // to VFP.
- if (divisor->IsConstant() &&
- HConstant::cast(divisor)->HasInteger32Value()) {
+ if (CpuFeatures::IsSupported(SUDIV)) {
+ // A value with an integer representation does not need to be
transformed.
+ if (divisor->representation().IsInteger32()) {
+ return divisor;
+ // 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);
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(),
divisor->block()->zone());
}
}
+
return NULL;
}
LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) {
- HValue* right = instr->right();
- LOperand* dividend = UseRegister(instr->left());
- LOperand* divisor = UseRegisterOrConstant(right);
- LOperand* remainder = TempRegister();
- ASSERT(right->IsConstant() &&
- HConstant::cast(right)->HasInteger32Value() &&
-
HasMagicNumberForDivisor(HConstant::cast(right)->Integer32Value()));
- return AssignEnvironment(DefineAsRegister(
+ HValue* right = instr->right();
+ LOperand* dividend = UseRegister(instr->left());
+ LOperand* divisor = CpuFeatures::IsSupported(SUDIV)
+ ? UseRegister(right)
+ : UseOrConstant(right);
+ LOperand* remainder = TempRegister();
+ ASSERT(CpuFeatures::IsSupported(SUDIV) ||
+ (right->IsConstant() &&
+ HConstant::cast(right)->HasInteger32Value() &&
+
HasMagicNumberForDivisor(HConstant::cast(right)->Integer32Value())));
+ return AssignEnvironment(DefineAsRegister(
new(zone()) LMathFloorOfDiv(dividend, divisor, remainder)));
}
=======================================
--- /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Thu Dec 20
06:05:14 2012
+++ /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Thu Dec 20
08:31:19 2012
@@ -1433,25 +1433,68 @@
const Register remainder = ToRegister(instr->temp());
const Register scratch = scratch0();
- // We only optimize this for division by constants, because the standard
- // integer division routine is usually slower than transitionning to VFP.
- // This could be optimized on processors with SDIV available.
- ASSERT(instr->right()->IsConstantOperand());
- int32_t divisor = ToInteger32(LConstantOperand::cast(instr->right()));
- if (divisor < 0) {
- __ cmp(left, Operand(0));
+ if (!CpuFeatures::IsSupported(SUDIV)) {
+ // If the CPU doesn't support sdiv instruction, we only optimize when
we
+ // have magic numbers for the divisor. The standard integer division
routine
+ // is usually slower than transitionning to VFP.
+ ASSERT(instr->right()->IsConstantOperand());
+ int32_t divisor = ToInteger32(LConstantOperand::cast(instr->right()));
+ 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());
+
+ // 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);
}
=======================================
--- /branches/bleeding_edge/test/mjsunit/math-floor-of-div.js Tue Apr 24
08:59:07 2012
+++ /branches/bleeding_edge/test/mjsunit/math-floor-of-div.js Thu Dec 20
08:31:19 2012
@@ -25,7 +25,7 @@
// (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
+// Flags: --allow-natives-syntax --nouse_inlining --enable_sudiv
// Use this function as reference. Make sure it is not inlined.
function div(a, b) {
@@ -184,7 +184,7 @@
%OptimizeFunctionOnNextCall(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
// test unreachable.
@@ -197,20 +197,34 @@
function test_div_deopt_minus_zero() {
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() {
// We box the value in an array to avoid constant propagation.
var min_int_in_array = [-2147483648];
- // We use '| 0' to force the representation to int32.
- assertEquals(-min_int_in_array[0],
- Math.floor((min_int_in_array[0] | 0) / -1));
+ 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();
=======================================
--- /branches/bleeding_edge/test/mjsunit/mjsunit.status Thu Dec 6 05:13:01
2012
+++ /branches/bleeding_edge/test/mjsunit/mjsunit.status Thu Dec 20 08:31:19
2012
@@ -76,6 +76,10 @@
d8-os: PASS, SKIP if ($isolates || $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 ]
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev