[turbofan] Optimize strict equality of unique values.
authorbmeurer <bmeurer@chromium.org>
Wed, 27 May 2015 04:23:29 +0000 (21:23 -0700)
committerCommit bot <commit-bot@chromium.org>
Wed, 27 May 2015 04:23:41 +0000 (04:23 +0000)
If both inputs to JSStrictEqual/JSStrictNotEqual are unique values (i.e.
values with a canonical representation), we can lower the comparison to
ReferenceEqual instead of StringEqual or CompareIC.

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

Cr-Commit-Position: refs/heads/master@{#28646}

src/compiler/js-typed-lowering.cc
test/unittests/compiler/js-typed-lowering-unittest.cc
test/unittests/compiler/node-test-utils.cc
test/unittests/compiler/node-test-utils.h

index 168fb48..8715fba 100644 (file)
@@ -566,6 +566,10 @@ Reduction JSTypedLowering::ReduceJSStrictEqual(Node* node, bool invert) {
     return r.ChangeToPureOperator(
         simplified()->ReferenceEqual(Type::Receiver()), invert);
   }
+  if (r.BothInputsAre(Type::Unique())) {
+    return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Unique()),
+                                  invert);
+  }
   if (r.BothInputsAre(Type::String())) {
     return r.ChangeToPureOperator(simplified()->StringEqual(), invert);
   }
index 9d713cf..ddff925 100644 (file)
@@ -436,18 +436,27 @@ TEST_F(JSTypedLoweringTest, JSToNumberWithPlainPrimitive) {
 TEST_F(JSTypedLoweringTest, JSStrictEqualWithTheHole) {
   Node* const the_hole = HeapConstant(factory()->the_hole_value());
   Node* const context = UndefinedConstant();
-  Node* const effect = graph()->start();
-  Node* const control = graph()->start();
   TRACED_FOREACH(Type*, type, kJSTypes) {
     Node* const lhs = Parameter(type);
-    Reduction r = Reduce(graph()->NewNode(javascript()->StrictEqual(), lhs,
-                                          the_hole, context, effect, control));
+    Reduction r = Reduce(
+        graph()->NewNode(javascript()->StrictEqual(), lhs, the_hole, context));
     ASSERT_TRUE(r.Changed());
     EXPECT_THAT(r.replacement(), IsFalseConstant());
   }
 }
 
 
+TEST_F(JSTypedLoweringTest, JSStrictEqualWithUnique) {
+  Node* const lhs = Parameter(Type::Unique(), 0);
+  Node* const rhs = Parameter(Type::Unique(), 1);
+  Node* const context = Parameter(Type::Any(), 2);
+  Reduction r =
+      Reduce(graph()->NewNode(javascript()->StrictEqual(), lhs, rhs, context));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsReferenceEqual(Type::Unique(), lhs, rhs));
+}
+
+
 // -----------------------------------------------------------------------------
 // JSShiftLeft
 
index 5fe4036..522eecf 100644 (file)
@@ -748,6 +748,32 @@ class IsTailCallMatcher final : public NodeMatcher {
 };
 
 
+class IsReferenceEqualMatcher final : public NodeMatcher {
+ public:
+  IsReferenceEqualMatcher(const Matcher<Type*>& type_matcher,
+                          const Matcher<Node*>& lhs_matcher,
+                          const Matcher<Node*>& rhs_matcher)
+      : NodeMatcher(IrOpcode::kReferenceEqual),
+        type_matcher_(type_matcher),
+        lhs_matcher_(lhs_matcher),
+        rhs_matcher_(rhs_matcher) {}
+
+  bool MatchAndExplain(Node* node, MatchResultListener* listener) const final {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            // TODO(bmeurer): The type parameter is currently ignored.
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "lhs",
+                                 lhs_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1), "rhs",
+                                 rhs_matcher_, listener));
+  }
+
+ private:
+  const Matcher<Type*> type_matcher_;
+  const Matcher<Node*> lhs_matcher_;
+  const Matcher<Node*> rhs_matcher_;
+};
+
+
 class IsAllocateMatcher final : public NodeMatcher {
  public:
   IsAllocateMatcher(const Matcher<Node*>& size_matcher,
@@ -1607,6 +1633,14 @@ Matcher<Node*> IsTailCall(
 }
 
 
+Matcher<Node*> IsReferenceEqual(const Matcher<Type*>& type_matcher,
+                                const Matcher<Node*>& lhs_matcher,
+                                const Matcher<Node*>& rhs_matcher) {
+  return MakeMatcher(
+      new IsReferenceEqualMatcher(type_matcher, lhs_matcher, rhs_matcher));
+}
+
+
 Matcher<Node*> IsAllocate(const Matcher<Node*>& size_matcher,
                           const Matcher<Node*>& effect_matcher,
                           const Matcher<Node*>& control_matcher) {
index 4ab1a6b..d7b17ab 100644 (file)
@@ -17,6 +17,10 @@ class ExternalReference;
 class HeapObject;
 template <class T>
 class Unique;
+template <class>
+class TypeImpl;
+struct ZoneTypeConfig;
+typedef TypeImpl<ZoneTypeConfig> Type;
 
 namespace compiler {
 
@@ -127,6 +131,9 @@ Matcher<Node*> IsTailCall(
     const Matcher<Node*>& control_matcher);
 
 Matcher<Node*> IsBooleanNot(const Matcher<Node*>& value_matcher);
+Matcher<Node*> IsReferenceEqual(const Matcher<Type*>& type_matcher,
+                                const Matcher<Node*>& lhs_matcher,
+                                const Matcher<Node*>& rhs_matcher);
 Matcher<Node*> IsNumberEqual(const Matcher<Node*>& lhs_matcher,
                              const Matcher<Node*>& rhs_matcher);
 Matcher<Node*> IsNumberLessThan(const Matcher<Node*>& lhs_matcher,