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, &not_smi_result);
+
       // Check for power of two on the right hand side.
-      __ JumpIfNotPowerOfTwoOrZero(right, scratch1, &not_smi_result);
-      // Check for positive and no remainder (scratch1 contains right - 1).
-      __ orr(scratch2, scratch1, Operand(0x80000000u));
-      __ tst(left, scratch2);
-      __ b(ne, &not_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, &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.
       __ 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, &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;
-    case Token::MOD:
-      // Check for two positive smis.
-      __ orr(scratch1, left, Operand(right));
-      __ tst(scratch1, Operand(0x80000000u | kSmiTagMask));
-      __ b(ne, &not_smi_result);
+    }
+    case Token::MOD: {
+      Label modulo_with_sdiv;

-      // Check for power of two on the right hand side.
-      __ JumpIfNotPowerOfTwoOrZero(right, scratch1, &not_smi_result);
+      if (CpuFeatures::IsSupported(SUDIV)) {
+        // 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));
       __ 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

Reply via email to