Commit 95095af5 authored by bmeurer@chromium.org's avatar bmeurer@chromium.org

[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=dcarney@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#24919}
git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24919 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent f276c8d9
...@@ -58,6 +58,13 @@ FieldAccess AccessBuilder::ForMapInstanceType() { ...@@ -58,6 +58,13 @@ FieldAccess AccessBuilder::ForMapInstanceType() {
} }
// static
FieldAccess AccessBuilder::ForStringLength() {
return {kTaggedBase, String::kLengthOffset, Handle<Name>(),
Type::SignedSmall(), kMachAnyTagged};
}
// static // static
FieldAccess AccessBuilder::ForValue() { FieldAccess AccessBuilder::ForValue() {
return {kTaggedBase, JSValue::kValueOffset, Handle<Name>(), Type::Any(), return {kTaggedBase, JSValue::kValueOffset, Handle<Name>(), Type::Any(),
......
...@@ -37,6 +37,9 @@ class AccessBuilder FINAL : public AllStatic { ...@@ -37,6 +37,9 @@ class AccessBuilder FINAL : public AllStatic {
// Provides access to Map::instance_type() field. // Provides access to Map::instance_type() field.
static FieldAccess ForMapInstanceType(); static FieldAccess ForMapInstanceType();
// Provides access to String::length() field.
static FieldAccess ForStringLength();
// Provides access to JSValue::value() field. // Provides access to JSValue::value() field.
static FieldAccess ForValue(); static FieldAccess ForValue();
......
...@@ -546,7 +546,38 @@ Reduction JSTypedLowering::ReduceJSToBooleanInput(Node* input) { ...@@ -546,7 +546,38 @@ Reduction JSTypedLowering::ReduceJSToBooleanInput(Node* input) {
Node* inv = graph()->NewNode(simplified()->BooleanNot(), cmp); Node* inv = graph()->NewNode(simplified()->BooleanNot(), cmp);
return ReplaceWith(inv); 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(); return NoChange();
} }
......
...@@ -508,8 +508,12 @@ TEST(JSToBoolean) { ...@@ -508,8 +508,12 @@ TEST(JSToBoolean) {
{ // ToBoolean(string) { // ToBoolean(string)
Node* r = R.ReduceUnop(op, Type::String()); Node* r = R.ReduceUnop(op, Type::String());
// TODO(titzer): test will break with better js-typed-lowering CHECK_EQ(IrOpcode::kBooleanNot, r->opcode());
CHECK_EQ(IrOpcode::kJSToBoolean, 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) { // ToBoolean(object)
......
// 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));
...@@ -72,3 +72,10 @@ assertEquals('foo', o.p || false); ...@@ -72,3 +72,10 @@ assertEquals('foo', o.p || false);
assertEquals('foo', o.p || (o.p == 0)); assertEquals('foo', o.p || (o.p == 0));
assertEquals('foo', o.p || (o.p == null)); assertEquals('foo', o.p || (o.p == null));
assertEquals('foo', o.p || (o.p == o.p)); 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));
...@@ -68,6 +68,46 @@ class JSTypedLoweringTest : public TypedGraphTest { ...@@ -68,6 +68,46 @@ class JSTypedLoweringTest : public TypedGraphTest {
}; };
// -----------------------------------------------------------------------------
// 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));
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// JSLoadProperty // JSLoadProperty
......
...@@ -355,11 +355,13 @@ class IsLoadFieldMatcher FINAL : public NodeMatcher { ...@@ -355,11 +355,13 @@ class IsLoadFieldMatcher FINAL : public NodeMatcher {
public: public:
IsLoadFieldMatcher(const Matcher<FieldAccess>& access_matcher, IsLoadFieldMatcher(const Matcher<FieldAccess>& access_matcher,
const Matcher<Node*>& base_matcher, const Matcher<Node*>& base_matcher,
const Matcher<Node*>& effect_matcher) const Matcher<Node*>& effect_matcher,
const Matcher<Node*>& control_matcher)
: NodeMatcher(IrOpcode::kLoadField), : NodeMatcher(IrOpcode::kLoadField),
access_matcher_(access_matcher), access_matcher_(access_matcher),
base_matcher_(base_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 { virtual void DescribeTo(std::ostream* os) const OVERRIDE {
NodeMatcher::DescribeTo(os); NodeMatcher::DescribeTo(os);
...@@ -367,8 +369,10 @@ class IsLoadFieldMatcher FINAL : public NodeMatcher { ...@@ -367,8 +369,10 @@ class IsLoadFieldMatcher FINAL : public NodeMatcher {
access_matcher_.DescribeTo(os); access_matcher_.DescribeTo(os);
*os << "), base ("; *os << "), base (";
base_matcher_.DescribeTo(os); base_matcher_.DescribeTo(os);
*os << ") and effect ("; *os << "), effect (";
effect_matcher_.DescribeTo(os); effect_matcher_.DescribeTo(os);
*os << ") and control (";
control_matcher_.DescribeTo(os);
*os << ")"; *os << ")";
} }
...@@ -380,13 +384,16 @@ class IsLoadFieldMatcher FINAL : public NodeMatcher { ...@@ -380,13 +384,16 @@ class IsLoadFieldMatcher FINAL : public NodeMatcher {
PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "base", PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "base",
base_matcher_, listener) && base_matcher_, listener) &&
PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect", PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect",
effect_matcher_, listener)); effect_matcher_, listener) &&
PrintMatchAndExplain(NodeProperties::GetControlInput(node),
"control", control_matcher_, listener));
} }
private: private:
const Matcher<FieldAccess> access_matcher_; const Matcher<FieldAccess> access_matcher_;
const Matcher<Node*> base_matcher_; const Matcher<Node*> base_matcher_;
const Matcher<Node*> effect_matcher_; const Matcher<Node*> effect_matcher_;
const Matcher<Node*> control_matcher_;
}; };
...@@ -795,9 +802,10 @@ Matcher<Node*> IsCall(const Matcher<CallDescriptor*>& descriptor_matcher, ...@@ -795,9 +802,10 @@ Matcher<Node*> IsCall(const Matcher<CallDescriptor*>& descriptor_matcher,
Matcher<Node*> IsLoadField(const Matcher<FieldAccess>& access_matcher, Matcher<Node*> IsLoadField(const Matcher<FieldAccess>& access_matcher,
const Matcher<Node*>& base_matcher, const Matcher<Node*>& base_matcher,
const Matcher<Node*>& effect_matcher) { const Matcher<Node*>& effect_matcher,
return MakeMatcher( const Matcher<Node*>& control_matcher) {
new IsLoadFieldMatcher(access_matcher, base_matcher, effect_matcher)); return MakeMatcher(new IsLoadFieldMatcher(access_matcher, base_matcher,
effect_matcher, control_matcher));
} }
...@@ -854,6 +862,7 @@ Matcher<Node*> IsStore(const Matcher<StoreRepresentation>& rep_matcher, ...@@ -854,6 +862,7 @@ Matcher<Node*> IsStore(const Matcher<StoreRepresentation>& rep_matcher,
return MakeMatcher( \ return MakeMatcher( \
new IsBinopMatcher(IrOpcode::k##Name, lhs_matcher, rhs_matcher)); \ new IsBinopMatcher(IrOpcode::k##Name, lhs_matcher, rhs_matcher)); \
} }
IS_BINOP_MATCHER(NumberEqual)
IS_BINOP_MATCHER(NumberLessThan) IS_BINOP_MATCHER(NumberLessThan)
IS_BINOP_MATCHER(NumberSubtract) IS_BINOP_MATCHER(NumberSubtract)
IS_BINOP_MATCHER(Word32And) IS_BINOP_MATCHER(Word32And)
...@@ -881,6 +890,7 @@ IS_BINOP_MATCHER(Uint32LessThanOrEqual) ...@@ -881,6 +890,7 @@ IS_BINOP_MATCHER(Uint32LessThanOrEqual)
Matcher<Node*> Is##Name(const Matcher<Node*>& input_matcher) { \ Matcher<Node*> Is##Name(const Matcher<Node*>& input_matcher) { \
return MakeMatcher(new IsUnopMatcher(IrOpcode::k##Name, input_matcher)); \ return MakeMatcher(new IsUnopMatcher(IrOpcode::k##Name, input_matcher)); \
} }
IS_UNOP_MATCHER(BooleanNot)
IS_UNOP_MATCHER(ChangeFloat64ToInt32) IS_UNOP_MATCHER(ChangeFloat64ToInt32)
IS_UNOP_MATCHER(ChangeFloat64ToUint32) IS_UNOP_MATCHER(ChangeFloat64ToUint32)
IS_UNOP_MATCHER(ChangeInt32ToFloat64) IS_UNOP_MATCHER(ChangeInt32ToFloat64)
......
...@@ -62,13 +62,17 @@ Matcher<Node*> IsCall(const Matcher<CallDescriptor*>& descriptor_matcher, ...@@ -62,13 +62,17 @@ Matcher<Node*> IsCall(const Matcher<CallDescriptor*>& descriptor_matcher,
const Matcher<Node*>& effect_matcher, const Matcher<Node*>& effect_matcher,
const Matcher<Node*>& control_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, Matcher<Node*> IsNumberLessThan(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher); const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsNumberSubtract(const Matcher<Node*>& lhs_matcher, Matcher<Node*> IsNumberSubtract(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher); const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsLoadField(const Matcher<FieldAccess>& access_matcher, Matcher<Node*> IsLoadField(const Matcher<FieldAccess>& access_matcher,
const Matcher<Node*>& base_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, Matcher<Node*> IsLoadElement(const Matcher<ElementAccess>& access_matcher,
const Matcher<Node*>& base_matcher, const Matcher<Node*>& base_matcher,
const Matcher<Node*>& index_matcher, const Matcher<Node*>& index_matcher,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment