Optimizes integral divide operations to be fewer instructions.  Specially optimizes division by powers of two into shr ops.

Suggested by: knorton
Review by: spoon

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@2210 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/CastNormalizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/CastNormalizer.java
index 1e7cecb..3dd6b4f 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/CastNormalizer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/CastNormalizer.java
@@ -374,8 +374,7 @@
   }
 
   /**
-   * Explicitly cast all integral divide operations to trigger replacements with
-   * narrowing calls in the next pass.
+   * Handle integral divide operations which may have floating point results.
    */
   private class DivVisitor extends JModVisitor {
 
@@ -385,10 +384,18 @@
       if (x.getOp() == JBinaryOperator.DIV
           && type != program.getTypePrimitiveFloat()
           && type != program.getTypePrimitiveDouble()) {
+        /*
+         * If the numerator was already in range, we can assume the output is
+         * also in range. Therefore, we don't need to do the full conversion,
+         * but rather a narrowing int conversion instead.
+         */
+        String methodName = "Cast.narrow_" + type.getName();
+        JMethod castMethod = program.getIndexedMethod(methodName);
+        JMethodCall call = new JMethodCall(program, x.getSourceInfo(), null,
+            castMethod, type);
         x.setType(program.getTypePrimitiveDouble());
-        JCastOperation cast = new JCastOperation(program, x.getSourceInfo(),
-            type, x);
-        ctx.replaceMe(cast);
+        call.getArgs().add(x);
+        ctx.replaceMe(call);
       }
     }
   }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/DeadCodeElimination.java b/dev/core/src/com/google/gwt/dev/jjs/impl/DeadCodeElimination.java
index af6da97..9a15320 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/DeadCodeElimination.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/DeadCodeElimination.java
@@ -15,6 +15,7 @@
  */
 package com.google.gwt.dev.jjs.impl;
 
+import com.google.gwt.dev.jjs.SourceInfo;
 import com.google.gwt.dev.jjs.ast.Context;
 import com.google.gwt.dev.jjs.ast.JBinaryOperation;
 import com.google.gwt.dev.jjs.ast.JBinaryOperator;
@@ -137,7 +138,14 @@
           break;
         case ADD:
           if (x.getType() == program.getTypeJavaLangString()) {
-            evalConcat(ctx, lhs, rhs);
+            evalConcat(lhs, rhs, ctx);
+          }
+          break;
+        case DIV:
+        case ASG_DIV:
+          if (x.getType() != program.getTypePrimitiveFloat()
+              && x.getType() != program.getTypePrimitiveDouble()) {
+            divToShift(x, lhs, rhs, ctx);
           }
           break;
         default:
@@ -650,7 +658,41 @@
       return true;
     }
 
-    private void evalConcat(Context ctx, JExpression lhs, JExpression rhs) {
+    private void divToShift(JBinaryOperation x, JExpression lhs,
+        JExpression rhs, Context ctx) {
+      long divisor;
+      if (rhs instanceof JIntLiteral) {
+        divisor = ((JIntLiteral) rhs).getValue();
+      } else if (rhs instanceof JLongLiteral) {
+        divisor = ((JLongLiteral) rhs).getValue();
+      } else {
+        return;
+      }
+
+      if (divisor == 1) {
+        ctx.replaceMe(lhs);
+        return;
+      } else if (divisor == -1 && !x.getOp().isAssignment()) {
+        JPrefixOperation negOp = new JPrefixOperation(program,
+            x.getSourceInfo(), JUnaryOperator.NEG, lhs);
+        ctx.replaceMe(negOp);
+        return;
+      }
+
+      if (divisor > 1 && divisor == Long.highestOneBit(divisor)) {
+        // It's a power of two, convert to a shift operation.
+        int shift = Long.numberOfTrailingZeros(divisor);
+        JBinaryOperator op = x.getOp().isAssignment() ? JBinaryOperator.ASG_SHR
+            : JBinaryOperator.SHR;
+        JBinaryOperation binOp = new JBinaryOperation(program,
+            x.getSourceInfo(), lhs.getType(), op, lhs,
+            program.getLiteralInt(shift));
+        ctx.replaceMe(binOp);
+        return;
+      }
+    }
+
+    private void evalConcat(JExpression lhs, JExpression rhs, Context ctx) {
       if (lhs instanceof JValueLiteral && rhs instanceof JValueLiteral) {
         Object lhsObj = ((JValueLiteral) lhs).getValueObj();
         Object rhsObj = ((JValueLiteral) rhs).getValueObj();