Revision: 24919
Author:   bmeu...@chromium.org
Date:     Tue Oct 28 08:33:52 2014 UTC
Log:      [turbofan] Improve typed lowering for JSToBoolean.

- JSToBoolean(x:string) => BooleanNot(NumberEqual(x.length, #0))
- JSToBoolean(phi(x1,...,xn):primitive) => phi(JSToBoolean(x1),...,JSToBoolean(xn))

TEST=cctest,mjsunit/asm/do-while,mjsunit/boolean,unittests
R=dcar...@chromium.org

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

Added:
 /branches/bleeding_edge/test/mjsunit/asm/do-while.js
Modified:
 /branches/bleeding_edge/src/compiler/access-builder.cc
 /branches/bleeding_edge/src/compiler/access-builder.h
 /branches/bleeding_edge/src/compiler/js-typed-lowering.cc
 /branches/bleeding_edge/test/cctest/compiler/test-js-typed-lowering.cc
 /branches/bleeding_edge/test/mjsunit/boolean.js
/branches/bleeding_edge/test/unittests/compiler/js-typed-lowering-unittest.cc
 /branches/bleeding_edge/test/unittests/compiler/node-test-utils.cc
 /branches/bleeding_edge/test/unittests/compiler/node-test-utils.h

=======================================
--- /dev/null
+++ /branches/bleeding_edge/test/mjsunit/asm/do-while.js Tue Oct 28 08:33:52 2014 UTC
@@ -0,0 +1,30 @@
+// 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, buffer) {
+  "use asm";
+  function f(i) {
+    var j;
+    i = i|0;
+    do {
+      if (i > 0) {
+        j = i != 0;
+        i = (i - 1) | 0;
+      } else {
+        j = 0;
+      }
+    } while (j);
+    return i;
+  }
+  return {f:f};
+}
+
+var m = Module(this, {}, new ArrayBuffer(64*1024));
+
+assertEquals(-1, m.f("-1"));
+assertEquals(0, m.f(-Math.infinity));
+assertEquals(0, m.f(undefined));
+assertEquals(0, m.f(0));
+assertEquals(0, m.f(1));
+assertEquals(0, m.f(100));
=======================================
--- /branches/bleeding_edge/src/compiler/access-builder.cc Mon Oct 20 07:56:50 2014 UTC +++ /branches/bleeding_edge/src/compiler/access-builder.cc Tue Oct 28 08:33:52 2014 UTC
@@ -56,6 +56,13 @@
   return {kTaggedBase, Map::kInstanceTypeOffset, Handle<Name>(),
           Type::UntaggedInt8(), kMachUint8};
 }
+
+
+// static
+FieldAccess AccessBuilder::ForStringLength() {
+  return {kTaggedBase, String::kLengthOffset, Handle<Name>(),
+          Type::SignedSmall(), kMachAnyTagged};
+}


 // static
=======================================
--- /branches/bleeding_edge/src/compiler/access-builder.h Mon Oct 20 07:56:50 2014 UTC +++ /branches/bleeding_edge/src/compiler/access-builder.h Tue Oct 28 08:33:52 2014 UTC
@@ -37,6 +37,9 @@
   // Provides access to Map::instance_type() field.
   static FieldAccess ForMapInstanceType();

+  // Provides access to String::length() field.
+  static FieldAccess ForStringLength();
+
   // Provides access to JSValue::value() field.
   static FieldAccess ForValue();

=======================================
--- /branches/bleeding_edge/src/compiler/js-typed-lowering.cc Tue Oct 28 08:28:36 2014 UTC +++ /branches/bleeding_edge/src/compiler/js-typed-lowering.cc Tue Oct 28 08:33:52 2014 UTC
@@ -546,7 +546,38 @@
     Node* inv = graph()->NewNode(simplified()->BooleanNot(), cmp);
     return ReplaceWith(inv);
   }
-  // TODO(turbofan): js-typed-lowering of ToBoolean(string)
+  if (input_type->Is(Type::String())) {
+    // JSToBoolean(x:string) => BooleanNot(NumberEqual(x.length, #0))
+    FieldAccess access = AccessBuilder::ForStringLength();
+    Node* length = graph()->NewNode(simplified()->LoadField(access), input,
+                                    graph()->start(), graph()->start());
+    Node* cmp = graph()->NewNode(simplified()->NumberEqual(), length,
+                                 jsgraph()->ZeroConstant());
+    Node* inv = graph()->NewNode(simplified()->BooleanNot(), cmp);
+    return ReplaceWith(inv);
+  }
+ if (input->opcode() == IrOpcode::kPhi && input_type->Is(Type::Primitive())) {
+    // JSToBoolean(phi(x1,...,xn):primitive)
+    //   => phi(JSToBoolean(x1),...,JSToBoolean(xn))
+    int input_count = input->InputCount() - 1;
+    Node** inputs = zone()->NewArray<Node*>(input_count + 1);
+    for (int i = 0; i < input_count; ++i) {
+      Node* value = input->InputAt(i);
+      // Recursively try to reduce the value first.
+      Reduction result = ReduceJSToBooleanInput(value);
+      if (result.Changed()) {
+        inputs[i] = result.replacement();
+      } else {
+        inputs[i] = graph()->NewNode(javascript()->ToBoolean(), value,
+                                     jsgraph()->ZeroConstant(),
+                                     graph()->start(), graph()->start());
+      }
+    }
+    inputs[input_count] = input->InputAt(input_count);
+ Node* phi = graph()->NewNode(common()->Phi(kMachAnyTagged, input_count),
+                                 input_count + 1, inputs);
+    return ReplaceWith(phi);
+  }
   return NoChange();
 }

=======================================
--- /branches/bleeding_edge/test/cctest/compiler/test-js-typed-lowering.cc Thu Oct 16 11:31:00 2014 UTC +++ /branches/bleeding_edge/test/cctest/compiler/test-js-typed-lowering.cc Tue Oct 28 08:33:52 2014 UTC
@@ -508,8 +508,12 @@

   {  // ToBoolean(string)
     Node* r = R.ReduceUnop(op, Type::String());
-    // TODO(titzer): test will break with better js-typed-lowering
-    CHECK_EQ(IrOpcode::kJSToBoolean, r->opcode());
+    CHECK_EQ(IrOpcode::kBooleanNot, r->opcode());
+    Node* i = r->InputAt(0);
+    CHECK_EQ(IrOpcode::kNumberEqual, i->opcode());
+    Node* j = i->InputAt(0);
+    CHECK_EQ(IrOpcode::kLoadField, j->opcode());
+    // ToBoolean(x:string) => BooleanNot(NumberEqual(x.length, #0))
   }

   {  // ToBoolean(object)
=======================================
--- /branches/bleeding_edge/test/mjsunit/boolean.js Wed Jun 15 13:33:10 2011 UTC +++ /branches/bleeding_edge/test/mjsunit/boolean.js Tue Oct 28 08:33:52 2014 UTC
@@ -72,3 +72,10 @@
 assertEquals('foo', o.p || (o.p == 0));
 assertEquals('foo', o.p || (o.p == null));
 assertEquals('foo', o.p || (o.p == o.p));
+
+// JSToBoolean(x:string)
+function f(x) { return !!("" + x); }
+assertEquals(false, f(""));
+assertEquals(true, f("narf"));
+assertEquals(true, f(12345678));
+assertEquals(true, f(undefined));
=======================================
--- /branches/bleeding_edge/test/unittests/compiler/js-typed-lowering-unittest.cc Tue Oct 28 08:28:36 2014 UTC +++ /branches/bleeding_edge/test/unittests/compiler/js-typed-lowering-unittest.cc Tue Oct 28 08:33:52 2014 UTC
@@ -66,6 +66,46 @@
  private:
   JSOperatorBuilder javascript_;
 };
+
+
+// -----------------------------------------------------------------------------
+// JSToBoolean
+
+
+TEST_F(JSTypedLoweringTest, JSToBooleanWithString) {
+  Node* input = Parameter(Type::String());
+  Node* context = UndefinedConstant();
+  Node* effect = graph()->start();
+  Node* control = graph()->start();
+
+  Reduction r = Reduce(graph()->NewNode(javascript()->ToBoolean(), input,
+                                        context, effect, control));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(),
+              IsBooleanNot(IsNumberEqual(
+                  IsLoadField(AccessBuilder::ForStringLength(), input,
+                              graph()->start(), graph()->start()),
+                  IsNumberConstant(0))));
+}
+
+
+TEST_F(JSTypedLoweringTest, JSToBooleanWithOrderedNumberAndBoolean) {
+  Node* p0 = Parameter(Type::OrderedNumber(), 0);
+  Node* p1 = Parameter(Type::Boolean(), 1);
+  Node* context = UndefinedConstant();
+  Node* effect = graph()->start();
+  Node* control = graph()->start();
+
+  Reduction r = Reduce(graph()->NewNode(
+      javascript()->ToBoolean(),
+      graph()->NewNode(common()->Phi(kMachAnyTagged, 2), p0, p1, control),
+      context, effect, control));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(
+      r.replacement(),
+      IsPhi(kMachAnyTagged,
+ IsBooleanNot(IsNumberEqual(p0, IsNumberConstant(0))), p1, control));
+}


// -----------------------------------------------------------------------------
=======================================
--- /branches/bleeding_edge/test/unittests/compiler/node-test-utils.cc Mon Oct 20 11:26:23 2014 UTC +++ /branches/bleeding_edge/test/unittests/compiler/node-test-utils.cc Tue Oct 28 08:33:52 2014 UTC
@@ -355,11 +355,13 @@
  public:
   IsLoadFieldMatcher(const Matcher<FieldAccess>& access_matcher,
                      const Matcher<Node*>& base_matcher,
-                     const Matcher<Node*>& effect_matcher)
+                     const Matcher<Node*>& effect_matcher,
+                     const Matcher<Node*>& control_matcher)
       : NodeMatcher(IrOpcode::kLoadField),
         access_matcher_(access_matcher),
         base_matcher_(base_matcher),
-        effect_matcher_(effect_matcher) {}
+        effect_matcher_(effect_matcher),
+        control_matcher_(control_matcher) {}

   virtual void DescribeTo(std::ostream* os) const OVERRIDE {
     NodeMatcher::DescribeTo(os);
@@ -367,8 +369,10 @@
     access_matcher_.DescribeTo(os);
     *os << "), base (";
     base_matcher_.DescribeTo(os);
-    *os << ") and effect (";
+    *os << "), effect (";
     effect_matcher_.DescribeTo(os);
+    *os << ") and control (";
+    control_matcher_.DescribeTo(os);
     *os << ")";
   }

@@ -380,13 +384,16 @@
PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "base",
                                  base_matcher_, listener) &&
PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect",
-                                 effect_matcher_, listener));
+                                 effect_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetControlInput(node),
+                                 "control", control_matcher_, listener));
   }

  private:
   const Matcher<FieldAccess> access_matcher_;
   const Matcher<Node*> base_matcher_;
   const Matcher<Node*> effect_matcher_;
+  const Matcher<Node*> control_matcher_;
 };


@@ -795,9 +802,10 @@

 Matcher<Node*> IsLoadField(const Matcher<FieldAccess>& access_matcher,
                            const Matcher<Node*>& base_matcher,
-                           const Matcher<Node*>& effect_matcher) {
-  return MakeMatcher(
- new IsLoadFieldMatcher(access_matcher, base_matcher, effect_matcher));
+                           const Matcher<Node*>& effect_matcher,
+                           const Matcher<Node*>& control_matcher) {
+  return MakeMatcher(new IsLoadFieldMatcher(access_matcher, base_matcher,
+ effect_matcher, control_matcher));
 }


@@ -854,6 +862,7 @@
     return MakeMatcher(                                                   \
         new IsBinopMatcher(IrOpcode::k##Name, lhs_matcher, rhs_matcher)); \
   }
+IS_BINOP_MATCHER(NumberEqual)
 IS_BINOP_MATCHER(NumberLessThan)
 IS_BINOP_MATCHER(NumberSubtract)
 IS_BINOP_MATCHER(Word32And)
@@ -881,6 +890,7 @@
Matcher<Node*> Is##Name(const Matcher<Node*>& input_matcher) { \ return MakeMatcher(new IsUnopMatcher(IrOpcode::k##Name, input_matcher)); \
   }
+IS_UNOP_MATCHER(BooleanNot)
 IS_UNOP_MATCHER(ChangeFloat64ToInt32)
 IS_UNOP_MATCHER(ChangeFloat64ToUint32)
 IS_UNOP_MATCHER(ChangeInt32ToFloat64)
=======================================
--- /branches/bleeding_edge/test/unittests/compiler/node-test-utils.h Mon Oct 20 11:26:23 2014 UTC +++ /branches/bleeding_edge/test/unittests/compiler/node-test-utils.h Tue Oct 28 08:33:52 2014 UTC
@@ -62,13 +62,17 @@
                       const Matcher<Node*>& effect_matcher,
                       const Matcher<Node*>& control_matcher);

+Matcher<Node*> IsBooleanNot(const Matcher<Node*>& value_matcher);
+Matcher<Node*> IsNumberEqual(const Matcher<Node*>& lhs_matcher,
+                             const Matcher<Node*>& rhs_matcher);
 Matcher<Node*> IsNumberLessThan(const Matcher<Node*>& lhs_matcher,
                                 const Matcher<Node*>& rhs_matcher);
 Matcher<Node*> IsNumberSubtract(const Matcher<Node*>& lhs_matcher,
                                 const Matcher<Node*>& rhs_matcher);
 Matcher<Node*> IsLoadField(const Matcher<FieldAccess>& access_matcher,
                            const Matcher<Node*>& base_matcher,
-                           const Matcher<Node*>& effect_matcher);
+                           const Matcher<Node*>& effect_matcher,
+                           const Matcher<Node*>& control_matcher);
 Matcher<Node*> IsLoadElement(const Matcher<ElementAccess>& access_matcher,
                              const Matcher<Node*>& base_matcher,
                              const Matcher<Node*>& index_matcher,

--
--
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