[turbofan] Optimize Int32Mod by power-of-two.
authorbmeurer@chromium.org <bmeurer@chromium.org>
Mon, 13 Oct 2014 11:09:32 +0000 (11:09 +0000)
committerbmeurer@chromium.org <bmeurer@chromium.org>
Mon, 13 Oct 2014 11:09:32 +0000 (11:09 +0000)
TEST=mjsunit/asm/int32-tmod,unittests
R=dcarney@chromium.org

Review URL: https://codereview.chromium.org/649083005

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24554 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/compiler/machine-operator-reducer.cc
src/compiler/machine-operator-reducer.h
test/mjsunit/asm/int32-tmod.js
test/unittests/compiler/graph-unittest.cc
test/unittests/compiler/graph-unittest.h
test/unittests/compiler/machine-operator-reducer-unittest.cc

index f728dbf..cdb2182 100644 (file)
@@ -262,19 +262,8 @@ Reduction MachineOperatorReducer::Reduce(Node* node) {
       }
       break;
     }
-    case IrOpcode::kInt32Mod: {
-      Int32BinopMatcher m(node);
-      if (m.right().Is(1)) return ReplaceInt32(0);   // x % 1  => 0
-      if (m.right().Is(-1)) return ReplaceInt32(0);  // x % -1 => 0
-      // TODO(turbofan): if (m.left().Is(0))
-      // TODO(turbofan): if (m.right().IsPowerOf2())
-      // TODO(turbofan): if (m.right().Is(0))
-      // TODO(turbofan): if (m.LeftEqualsRight())
-      if (m.IsFoldable() && !m.right().Is(0)) {  // K % K => K
-        return ReplaceInt32(m.left().Value() % m.right().Value());
-      }
-      break;
-    }
+    case IrOpcode::kInt32Mod:
+      return ReduceInt32Mod(node);
     case IrOpcode::kUint32Mod: {
       Uint32BinopMatcher m(node);
       if (m.right().Is(1)) return ReplaceInt32(0);  // x % 1 => 0
@@ -510,6 +499,44 @@ Reduction MachineOperatorReducer::Reduce(Node* node) {
 }
 
 
+Reduction MachineOperatorReducer::ReduceInt32Mod(Node* const node) {
+  Int32BinopMatcher m(node);
+  if (m.right().Is(1)) return ReplaceInt32(0);   // x % 1  => 0
+  if (m.right().Is(-1)) return ReplaceInt32(0);  // x % -1 => 0
+  // TODO(turbofan): if (m.left().Is(0))
+  // TODO(turbofan): if (m.right().Is(0))
+  // TODO(turbofan): if (m.LeftEqualsRight())
+  if (m.IsFoldable() && !m.right().Is(0)) {  // K % K => K
+    return ReplaceInt32(m.left().Value() % m.right().Value());
+  }
+  if (m.right().IsPowerOf2()) {
+    int32_t const divisor = m.right().Value();
+    Node* zero = Int32Constant(0);
+    Node* mask = Int32Constant(divisor - 1);
+    Node* dividend = m.left().node();
+
+    Node* check = graph()->NewNode(machine()->Int32LessThan(), dividend, zero);
+    Node* branch =
+        graph()->NewNode(common()->Branch(), check, graph()->start());
+
+    Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
+    Node* neg = graph()->NewNode(
+        machine()->Int32Sub(), zero,
+        graph()->NewNode(
+            machine()->Word32And(),
+            graph()->NewNode(machine()->Int32Sub(), zero, dividend), mask));
+
+    Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
+    Node* pos = graph()->NewNode(machine()->Word32And(), dividend, mask);
+
+    Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
+    Node* phi = graph()->NewNode(common()->Phi(kMachInt32, 2), neg, pos, merge);
+    return Replace(phi);
+  }
+  return NoChange();
+}
+
+
 Reduction MachineOperatorReducer::ReduceProjection(size_t index, Node* node) {
   switch (node->opcode()) {
     case IrOpcode::kInt32AddWithOverflow: {
index e40ad65..d8978a4 100644 (file)
@@ -49,6 +49,7 @@ class MachineOperatorReducer FINAL : public Reducer {
     return Replace(Int64Constant(value));
   }
 
+  Reduction ReduceInt32Mod(Node* node);
   Reduction ReduceProjection(size_t index, Node* node);
 
   Graph* graph() const;
index 0e129c7..0e294d3 100644 (file)
@@ -4,6 +4,10 @@
 
 function Module(stdlib, foreign, heap) {
   "use asm";
+  function f0(i) {
+    i = i|0;
+    return i % 2 | 0;
+  }
   function f1(i) {
     i = i|0;
     return i % 3 | 0;
@@ -20,12 +24,13 @@ function Module(stdlib, foreign, heap) {
     i = i|0;
     return i % 3333339 | 0;
   }
-  return { f1: f1, f2: f2, f3: f3, f4: f4 };
+  return { f0: f0, f1: f1, f2: f2, f3: f3, f4: f4 };
 }
 
 var m = Module(this, {}, new ArrayBuffer(1024));
 
 for (var i = -2147483648; i < 2147483648; i += 3999773) {
+  assertEquals(i % 2 | 0, m.f0(i));
   assertEquals(i % 3 | 0, m.f1(i));
   assertEquals(i % 9 | 0, m.f2(i));
   assertEquals(i % 1024 | 0, m.f3(i));
index 090d572..4fc3c87 100644 (file)
@@ -948,7 +948,9 @@ IS_BINOP_MATCHER(Word64Sar)
 IS_BINOP_MATCHER(Word64Shl)
 IS_BINOP_MATCHER(Word64Equal)
 IS_BINOP_MATCHER(Int32AddWithOverflow)
+IS_BINOP_MATCHER(Int32Sub)
 IS_BINOP_MATCHER(Int32Mul)
+IS_BINOP_MATCHER(Int32LessThan)
 IS_BINOP_MATCHER(Uint32LessThan)
 IS_BINOP_MATCHER(Uint32LessThanOrEqual)
 #undef IS_BINOP_MATCHER
index 37fbe8a..84fb6ee 100644 (file)
@@ -148,8 +148,12 @@ Matcher<Node*> IsWord64Equal(const Matcher<Node*>& lhs_matcher,
                              const Matcher<Node*>& rhs_matcher);
 Matcher<Node*> IsInt32AddWithOverflow(const Matcher<Node*>& lhs_matcher,
                                       const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsInt32Sub(const Matcher<Node*>& lhs_matcher,
+                          const Matcher<Node*>& rhs_matcher);
 Matcher<Node*> IsInt32Mul(const Matcher<Node*>& lhs_matcher,
                           const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsInt32LessThan(const Matcher<Node*>& lhs_matcher,
+                               const Matcher<Node*>& rhs_matcher);
 Matcher<Node*> IsUint32LessThan(const Matcher<Node*>& lhs_matcher,
                                 const Matcher<Node*>& rhs_matcher);
 Matcher<Node*> IsUint32LessThanOrEqual(const Matcher<Node*>& lhs_matcher,
index 6c46a5b..9ee74ce 100644 (file)
@@ -7,6 +7,11 @@
 #include "src/compiler/machine-operator-reducer.h"
 #include "src/compiler/typer.h"
 #include "test/unittests/compiler/graph-unittest.h"
+#include "testing/gmock-support.h"
+
+using testing::AllOf;
+using testing::Capture;
+using testing::CaptureEq;
 
 namespace v8 {
 namespace internal {
@@ -564,6 +569,37 @@ TEST_F(MachineOperatorReducerTest, Word32ShlWithWord32Shr) {
 
 
 // -----------------------------------------------------------------------------
+// Int32Mod
+
+
+TEST_F(MachineOperatorReducerTest, Int32ModWithPowerOfTwo) {
+  Node* p0 = Parameter(0);
+  TRACED_FORRANGE(int32_t, x, 1, 30) {
+    int32_t const divisor = 1 << x;
+    Node* node =
+        graph()->NewNode(machine()->Int32Mod(), p0, Int32Constant(divisor));
+    Reduction r = Reduce(node);
+    ASSERT_TRUE(r.Changed());
+
+    Capture<Node*> branch;
+    Node* phi = r.replacement();
+    int32_t const mask = divisor - 1;
+    EXPECT_THAT(
+        phi, IsPhi(kMachInt32,
+                   IsInt32Sub(IsInt32Constant(0),
+                              IsWord32And(IsInt32Sub(IsInt32Constant(0), p0),
+                                          IsInt32Constant(mask))),
+                   IsWord32And(p0, IsInt32Constant(mask)),
+                   IsMerge(IsIfTrue(CaptureEq(&branch)),
+                           IsIfFalse(AllOf(
+                               CaptureEq(&branch),
+                               IsBranch(IsInt32LessThan(p0, IsInt32Constant(0)),
+                                        graph()->start()))))));
+  }
+}
+
+
+// -----------------------------------------------------------------------------
 // Int32AddWithOverflow