Revision: 7582
Author:   [email protected]
Date:     Mon Apr 11 23:44:15 2011
Log:      ARM: Add optimization for constant RHS in DoMulI.

Patch by ARM Ltd.

Review URL: http://codereview.chromium.org/6756033
http://code.google.com/p/v8/source/detail?r=7582

Modified:
 /branches/bleeding_edge/src/arm/code-stubs-arm.cc
 /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc
 /branches/bleeding_edge/src/arm/macro-assembler-arm.cc
 /branches/bleeding_edge/src/utils.h

=======================================
--- /branches/bleeding_edge/src/arm/code-stubs-arm.cc Mon Apr 11 02:39:21 2011 +++ /branches/bleeding_edge/src/arm/code-stubs-arm.cc Mon Apr 11 23:44:15 2011
@@ -2375,9 +2375,11 @@
           // DIV just falls through to allocating a heap number.
         }

+        __ bind(&return_heap_number);
+ // Return a heap number, or fall through to type transition or runtime
+        // call if we can't.
         if (result_type_ >= (op_ == Token::DIV) ? TRBinaryOpIC::HEAP_NUMBER
                                                 : TRBinaryOpIC::INT32) {
-          __ bind(&return_heap_number);
           // We are using vfp registers so r5 is available.
           heap_number_result = r5;
           GenerateHeapResultAllocation(masm,
@@ -2540,7 +2542,11 @@
       UNREACHABLE();
   }

-  if (transition.is_linked()) {
+  // We never expect DIV to yield an integer result, so we always generate
+ // type transition code for DIV operations expecting an integer result: the
+  // code will fall through to this type transition.
+  if (transition.is_linked() ||
+      ((op_ == Token::DIV) && (result_type_ <= TRBinaryOpIC::INT32))) {
     __ bind(&transition);
     GenerateTypeTransition(masm);
   }
=======================================
--- /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Fri Apr 8 07:30:10 2011 +++ /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Mon Apr 11 23:44:15 2011
@@ -1069,40 +1069,130 @@


 void LCodeGen::DoMulI(LMulI* instr) {
+  LOperand* left_op = instr->InputAt(0);
+  LOperand* right_op = instr->InputAt(1);
+
   Register scratch = scratch0();
-  Register left = ToRegister(instr->InputAt(0));
-  Register right = EmitLoadRegister(instr->InputAt(1), scratch);
-
-  if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero) &&
-      !instr->InputAt(1)->IsConstantOperand()) {
-    __ orr(ToRegister(instr->TempAt(0)), left, right);
-  }
-
-  if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
-    // scratch:left = left * right.
-    __ smull(left, scratch, left, right);
-    __ mov(ip, Operand(left, ASR, 31));
-    __ cmp(ip, Operand(scratch));
-    DeoptimizeIf(ne, instr->environment());
+  Register left = ToRegister(left_op);
+
+  ASSERT(left_op->Equals(instr->result()));
+
+  bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
+  bool bailout_on_minus_zero =
+    instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero);
+
+  if (right_op->IsConstantOperand()) {
+    // Use optimized code for specific constants.
+    int32_t constant = ToInteger32(LConstantOperand::cast(right_op));
+    Condition overflow_deopt_cond = kNoCondition;
+
+    switch (constant) {
+      case -1:
+        overflow_deopt_cond = can_overflow ? vs : kNoCondition;
+        __ rsb(left,
+               left,
+               Operand(0),
+               can_overflow ? SetCC : LeaveCC);
+        break;
+      case 0:
+        if (bailout_on_minus_zero) {
+          // If left is strictly negative and the constant is null, the
+          // result is -0. Deoptimize if required, otherwise return 0.
+          __ cmp(left, Operand(0));
+          DeoptimizeIf(mi, instr->environment());
+        }
+        __ mov(left, Operand(0));
+        break;
+      case 1:
+        // Do nothing.
+        break;
+      default:
+        // Multiplying by powers of two and powers of two plus or minus
+        // one can be done faster with shifted operands.
+        // For other constants we emit standard code.
+        int32_t mask = constant >> 31;
+        uint32_t constant_abs = (constant + mask) ^ mask;
+
+        if (IsPowerOf2(constant_abs)) {
+          if (!can_overflow) {
+            int32_t shift = WhichPowerOf2(constant_abs);
+            __ mov(left, Operand(left, LSL, shift));
+            if (constant < 0)  __ rsb(left, left, Operand(0));
+          } else {
+            // scratch:left = left * constant.
+            __ mov(ip, Operand(constant));
+            __ smull(left, scratch, left, ip);
+            __ cmp(scratch, Operand(left, ASR, 31));
+            overflow_deopt_cond = ne;
+          }
+        } else if (IsPowerOf2(constant_abs - 1)) {
+          int32_t shift = WhichPowerOf2(constant_abs - 1);
+          __ add(left,
+                 left,
+                 Operand(left, LSL, shift),
+                 can_overflow ? SetCC : LeaveCC);
+          overflow_deopt_cond = can_overflow ? vs : kNoCondition;
+          if (constant < 0)  __ rsb(left, left, Operand(0));
+        } else if (IsPowerOf2(constant_abs + 1)) {
+          int32_t shift = WhichPowerOf2(constant_abs + 1);
+          __ rsb(left,
+                 left,
+                 Operand(left, LSL, shift),
+                 can_overflow ? SetCC : LeaveCC);
+          overflow_deopt_cond = can_overflow ? vs : kNoCondition;
+          if (constant < 0)  __ rsb(left, left, Operand(0));
+        } else {
+          if (!can_overflow) {
+            __ mov(ip, Operand(constant));
+            __ mul(left, left, ip);
+          } else {
+            // scratch:left = left * constant.
+            __ mov(ip, Operand(constant));
+            __ smull(left, scratch, left, ip);
+            __ cmp(scratch, Operand(left, ASR, 31));
+            overflow_deopt_cond = ne;
+          }
+        }
+        break;
+    }
+
+
+    if (can_overflow && (constant != 0) && (constant != 1)) {
+      ASSERT(overflow_deopt_cond != kNoCondition);
+      DeoptimizeIf(overflow_deopt_cond, instr->environment());
+    }
+
+    if (bailout_on_minus_zero && (constant < 0)) {
+      // The case of a null constant was handled separately.
+      // If constant is negative and left is null, the result should be -0.
+      __ cmp(left, Operand(0));
+      DeoptimizeIf(eq, instr->environment());
+    }
+
   } else {
-    __ mul(left, left, right);
-  }
-
-  if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
-    // Bail out if the result is supposed to be negative zero.
-    Label done;
-    __ cmp(left, Operand(0));
-    __ b(ne, &done);
-    if (instr->InputAt(1)->IsConstantOperand()) {
-      if (ToInteger32(LConstantOperand::cast(instr->InputAt(1))) <= 0) {
-        DeoptimizeIf(al, instr->environment());
-      }
+    Register right = EmitLoadRegister(right_op, scratch);
+    if (bailout_on_minus_zero) {
+      __ orr(ToRegister(instr->TempAt(0)), left, right);
+    }
+
+    if (can_overflow) {
+      // scratch:left = left * right.
+      __ smull(left, scratch, left, right);
+      __ cmp(scratch, Operand(left, ASR, 31));
+      DeoptimizeIf(ne, instr->environment());
     } else {
-      // Test the non-zero operand for negative sign.
+      __ mul(left, left, right);
+    }
+
+    if (bailout_on_minus_zero) {
+      // Bail out if the result is supposed to be negative zero.
+      Label done;
+      __ cmp(left, Operand(0));
+      __ b(ne, &done);
       __ cmp(ToRegister(instr->TempAt(0)), Operand(0));
       DeoptimizeIf(mi, instr->environment());
-    }
-    __ bind(&done);
+      __ bind(&done);
+    }
   }
 }

=======================================
--- /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Mon Apr 11 02:04:30 2011 +++ /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Mon Apr 11 23:44:15 2011
@@ -297,7 +297,8 @@
              !src2.must_use_constant_pool() &&
              CpuFeatures::IsSupported(ARMv7) &&
              IsPowerOf2(src2.immediate() + 1)) {
-    ubfx(dst, src1, 0, WhichPowerOf2(src2.immediate() + 1), cond);
+    ubfx(dst, src1, 0,
+        WhichPowerOf2(static_cast<uint32_t>(src2.immediate()) + 1), cond);

   } else {
     and_(dst, src1, src2, LeaveCC, cond);
=======================================
--- /branches/bleeding_edge/src/utils.h Mon Mar 21 09:10:05 2011
+++ /branches/bleeding_edge/src/utils.h Mon Apr 11 23:44:15 2011
@@ -52,11 +52,9 @@


 // X must be a power of 2.  Returns the number of trailing zeros.
-template <typename T>
-static inline int WhichPowerOf2(T x) {
+static inline int WhichPowerOf2(uint32_t x) {
   ASSERT(IsPowerOf2(x));
   ASSERT(x != 0);
-  if (x < 0) return 31;
   int bits = 0;
 #ifdef DEBUG
   int original_x = x;

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to