Revision: 24685
Author:   bmeu...@chromium.org
Date:     Fri Oct 17 09:35:45 2014 UTC
Log: [turbofan] Eliminate typed array bounds checks if both key and length are constant.

TEST=mjsunit,unittests
R=dcar...@chromium.org

Review URL: https://codereview.chromium.org/638853004
https://code.google.com/p/v8/source/detail?r=24685

Added:
 /branches/bleeding_edge/test/mjsunit/asm/int32array-constant-key.js
Modified:
 /branches/bleeding_edge/src/compiler/node-matchers.h
 /branches/bleeding_edge/src/compiler/pipeline.cc
 /branches/bleeding_edge/src/compiler/simplified-operator-reducer.cc
 /branches/bleeding_edge/src/compiler/simplified-operator-reducer.h
/branches/bleeding_edge/test/unittests/compiler/simplified-operator-reducer-unittest.cc

=======================================
--- /dev/null
+++ /branches/bleeding_edge/test/mjsunit/asm/int32array-constant-key.js Fri Oct 17 09:35:45 2014 UTC
@@ -0,0 +1,32 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib, foreign, heap) {
+  "use asm";
+  var MEM32 = new stdlib.Int32Array(heap);
+  function load0() {
+    return MEM32[0];
+  }
+  function load4() {
+    return MEM32[4];
+  }
+  function store0(v) {
+    MEM32[0] = v;
+  }
+  function store4(v) {
+    MEM32[4] = v;
+  }
+  return { load0: load0, store0: store0, load4: load4, store4: store4 };
+}
+
+var m = Module(this, {}, new ArrayBuffer(4));
+
+assertEquals(0, m.load0());
+assertEquals(undefined, m.load4());
+m.store0(0x12345678);
+assertEquals(0x12345678, m.load0());
+assertEquals(undefined, m.load4());
+m.store4(43);
+assertEquals(0x12345678, m.load0());
+assertEquals(undefined, m.load4());
=======================================
--- /branches/bleeding_edge/src/compiler/node-matchers.h Tue Oct 7 13:30:28 2014 UTC +++ /branches/bleeding_edge/src/compiler/node-matchers.h Fri Oct 17 09:35:45 2014 UTC
@@ -96,6 +96,41 @@
 typedef FloatMatcher<double, IrOpcode::kNumberConstant> NumberMatcher;


+// A pattern matcher for any numberic constant.
+struct NumericValueMatcher : public NodeMatcher {
+  explicit NumericValueMatcher(Node* const node) : NodeMatcher(node) {
+    switch (opcode()) {
+      case IrOpcode::kInt32Constant:
+        has_value_ = true;
+        value_ = OpParameter<int32_t>(node);
+        break;
+      case IrOpcode::kFloat32Constant:
+        has_value_ = true;
+        value_ = OpParameter<float>(node);
+        break;
+      case IrOpcode::kFloat64Constant:
+      case IrOpcode::kNumberConstant:
+        has_value_ = true;
+        value_ = OpParameter<double>(node);
+        break;
+      default:
+        has_value_ = false;
+        break;
+    }
+  }
+
+  bool HasValue() const { return has_value_; }
+  double Value() const {
+    DCHECK(HasValue());
+    return value_;
+  }
+
+ private:
+  double value_;
+  bool has_value_;
+};
+
+
 // A pattern matcher for heap object constants.
 template <typename T>
 struct HeapObjectMatcher FINAL
=======================================
--- /branches/bleeding_edge/src/compiler/pipeline.cc Thu Oct 16 11:29:31 2014 UTC +++ /branches/bleeding_edge/src/compiler/pipeline.cc Fri Oct 17 09:35:45 2014 UTC
@@ -301,9 +301,13 @@
                                 "typed lowering");
       SourcePositionTable::Scope pos(&source_positions,
                                      SourcePosition::Unknown());
+      ValueNumberingReducer vn_reducer(zone());
       JSTypedLowering lowering(&jsgraph);
+      SimplifiedOperatorReducer simple_reducer(&jsgraph);
       GraphReducer graph_reducer(&graph);
+      graph_reducer.AddReducer(&vn_reducer);
       graph_reducer.AddReducer(&lowering);
+      graph_reducer.AddReducer(&simple_reducer);
       graph_reducer.ReduceGraph();

       VerifyAndPrintGraph(&graph, "Lowered typed");
=======================================
--- /branches/bleeding_edge/src/compiler/simplified-operator-reducer.cc Tue Sep 16 16:20:10 2014 UTC +++ /branches/bleeding_edge/src/compiler/simplified-operator-reducer.cc Fri Oct 17 09:35:45 2014 UTC
@@ -12,6 +12,10 @@
 namespace internal {
 namespace compiler {

+SimplifiedOperatorReducer::SimplifiedOperatorReducer(JSGraph* jsgraph)
+    : jsgraph_(jsgraph), simplified_(jsgraph->zone()) {}
+
+
 SimplifiedOperatorReducer::~SimplifiedOperatorReducer() {}


@@ -95,6 +99,38 @@
       if (m.HasValue()) return ReplaceNumber(FastUI2D(m.Value()));
       break;
     }
+    case IrOpcode::kLoadElement: {
+      ElementAccess access = ElementAccessOf(node->op());
+      if (access.bounds_check == kTypedArrayBoundsCheck) {
+        NumericValueMatcher mkey(node->InputAt(1));
+        NumericValueMatcher mlength(node->InputAt(2));
+        if (mkey.HasValue() && mlength.HasValue()) {
+ // Skip the typed array bounds check if key and length are constant.
+          if (mkey.Value() < mlength.Value()) {
+            access.bounds_check = kNoBoundsCheck;
+            node->set_op(simplified()->LoadElement(access));
+            return Changed(node);
+          }
+        }
+      }
+      break;
+    }
+    case IrOpcode::kStoreElement: {
+      ElementAccess access = ElementAccessOf(node->op());
+      if (access.bounds_check == kTypedArrayBoundsCheck) {
+        NumericValueMatcher mkey(node->InputAt(1));
+        NumericValueMatcher mlength(node->InputAt(2));
+        if (mkey.HasValue() && mlength.HasValue()) {
+ // Skip the typed array bounds check if key and length are constant.
+          if (mkey.Value() < mlength.Value()) {
+            access.bounds_check = kNoBoundsCheck;
+            node->set_op(simplified()->StoreElement(access));
+            return Changed(node);
+          }
+        }
+      }
+      break;
+    }
     default:
       break;
   }
=======================================
--- /branches/bleeding_edge/src/compiler/simplified-operator-reducer.h Tue Sep 16 16:20:10 2014 UTC +++ /branches/bleeding_edge/src/compiler/simplified-operator-reducer.h Fri Oct 17 09:35:45 2014 UTC
@@ -6,6 +6,7 @@
 #define V8_COMPILER_SIMPLIFIED_OPERATOR_REDUCER_H_

 #include "src/compiler/graph-reducer.h"
+#include "src/compiler/simplified-operator.h"

 namespace v8 {
 namespace internal {
@@ -21,7 +22,7 @@

 class SimplifiedOperatorReducer FINAL : public Reducer {
  public:
- explicit SimplifiedOperatorReducer(JSGraph* jsgraph) : jsgraph_(jsgraph) {}
+  explicit SimplifiedOperatorReducer(JSGraph* jsgraph);
   virtual ~SimplifiedOperatorReducer();

   virtual Reduction Reduce(Node* node) OVERRIDE;
@@ -40,8 +41,10 @@
   Factory* factory() const;
   JSGraph* jsgraph() const { return jsgraph_; }
   MachineOperatorBuilder* machine() const;
+  SimplifiedOperatorBuilder* simplified() { return &simplified_; }

   JSGraph* jsgraph_;
+  SimplifiedOperatorBuilder simplified_;

   DISALLOW_COPY_AND_ASSIGN(SimplifiedOperatorReducer);
 };
=======================================
--- /branches/bleeding_edge/test/unittests/compiler/simplified-operator-reducer-unittest.cc Wed Oct 15 11:38:04 2014 UTC +++ /branches/bleeding_edge/test/unittests/compiler/simplified-operator-reducer-unittest.cc Fri Oct 17 09:35:45 2014 UTC
@@ -6,6 +6,7 @@
 #include "src/compiler/simplified-operator.h"
 #include "src/compiler/simplified-operator-reducer.h"
 #include "src/conversions.h"
+#include "src/types.h"
 #include "test/unittests/compiler/graph-unittest.h"

 namespace v8 {
@@ -475,6 +476,64 @@
     EXPECT_THAT(reduction.replacement(), IsNumberConstant(FastUI2D(n)));
   }
 }
+
+
+// -----------------------------------------------------------------------------
+// LoadElement
+
+
+TEST_F(SimplifiedOperatorReducerTest, LoadElementWithConstantKeyAndLength) {
+  ElementAccess const access = {kTypedArrayBoundsCheck, kUntaggedBase, 0,
+                                Type::Any(), kMachAnyTagged};
+  ElementAccess access_nocheck = access;
+  access_nocheck.bounds_check = kNoBoundsCheck;
+  Node* const base = Parameter(0);
+  Node* const effect = graph()->start();
+  Node* const control = graph()->start();
+  TRACED_FOREACH(double, key, kFloat64Values) {
+    TRACED_FOREACH(int32_t, length, kInt32Values) {
+      if (key < length) {
+        Reduction r = Reduce(graph()->NewNode(
+            simplified()->LoadElement(access), base, NumberConstant(key),
+            Int32Constant(length), effect, control));
+        ASSERT_TRUE(r.Changed());
+        EXPECT_THAT(r.replacement(),
+ IsLoadElement(access_nocheck, base, IsNumberConstant(key), + IsInt32Constant(length), effect, control));
+      }
+    }
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// StoreElement
+
+
+TEST_F(SimplifiedOperatorReducerTest, StoreElementWithConstantKeyAndLength) {
+  ElementAccess const access = {kTypedArrayBoundsCheck, kUntaggedBase, 0,
+                                Type::Any(), kMachAnyTagged};
+  ElementAccess access_nocheck = access;
+  access_nocheck.bounds_check = kNoBoundsCheck;
+  Node* const base = Parameter(0);
+  Node* const value = Parameter(1);
+  Node* const effect = graph()->start();
+  Node* const control = graph()->start();
+  TRACED_FOREACH(int32_t, key, kInt32Values) {
+    TRACED_FOREACH(double, length, kFloat64Values) {
+      if (key < length) {
+        Reduction r = Reduce(graph()->NewNode(
+            simplified()->StoreElement(access), base, Int32Constant(key),
+            NumberConstant(length), value, effect, control));
+        ASSERT_TRUE(r.Changed());
+        EXPECT_THAT(
+            r.replacement(),
+            IsStoreElement(access_nocheck, base, IsInt32Constant(key),
+ IsNumberConstant(length), value, effect, control));
+      }
+    }
+  }
+}

 }  // namespace compiler
 }  // namespace internal

--
--
v8-dev mailing list
v8-dev@googlegroups.com
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to v8-dev+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to