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() {
}
// static
FieldAccess AccessBuilder::ForStringLength() {
return {kTaggedBase, String::kLengthOffset, Handle<Name>(),
Type::SignedSmall(), kMachAnyTagged};
}
// static
FieldAccess AccessBuilder::ForValue() {
return {kTaggedBase, JSValue::kValueOffset, Handle<Name>(), Type::Any(),
......
......@@ -37,6 +37,9 @@ class AccessBuilder FINAL : public AllStatic {
// 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();
......
......@@ -546,7 +546,38 @@ Reduction JSTypedLowering::ReduceJSToBooleanInput(Node* input) {
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();
}
......
......@@ -508,8 +508,12 @@ TEST(JSToBoolean) {
{ // 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)
......
// 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);
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));
......@@ -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
......
......@@ -355,11 +355,13 @@ class IsLoadFieldMatcher FINAL : public NodeMatcher {
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 @@ class IsLoadFieldMatcher FINAL : public NodeMatcher {
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 @@ class IsLoadFieldMatcher FINAL : public NodeMatcher {
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*> IsCall(const Matcher<CallDescriptor*>& descriptor_matcher,
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 @@ Matcher<Node*> IsStore(const Matcher<StoreRepresentation>& rep_matcher,
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 @@ IS_BINOP_MATCHER(Uint32LessThanOrEqual)
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)
......
......@@ -62,13 +62,17 @@ Matcher<Node*> IsCall(const Matcher<CallDescriptor*>& descriptor_matcher,
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,
......
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