[turbofan] Remove indirection in JSToBoolean/JSUnaryNot lowering.

This reduces the overhead of typed lowering, because we lower
JSToBoolean/JSUnaryNot directly if possible, instead of first lowering
to AnyToBoolean, and then letting the SimplifiedOperatorReducer do the
further lowering.

Also remove some obsolete tests from the cctest suite that have since
been removed by proper unittests. And improve unitttest coverage for the
typed lowering cases.

R=mstarzinger@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#27295}
This commit is contained in:
Benedikt Meurer 2015-03-19 11:12:51 +01:00
parent 5383257ecc
commit a75e4cea8f
16 changed files with 82 additions and 200 deletions

View File

@ -526,39 +526,64 @@ Reduction JSTypedLowering::ReduceJSStrictEqual(Node* node, bool invert) {
Reduction JSTypedLowering::ReduceJSUnaryNot(Node* node) {
Node* input = node->InputAt(0);
Type* input_type = NodeProperties::GetBounds(input).upper;
Node* const input = node->InputAt(0);
Type* const input_type = NodeProperties::GetBounds(input).upper;
if (input_type->Is(Type::Boolean())) {
// JSUnaryNot(x:boolean,context) => BooleanNot(x)
// JSUnaryNot(x:boolean) => BooleanNot(x)
node->set_op(simplified()->BooleanNot());
node->TrimInputCount(1);
return Changed(node);
} else if (input_type->Is(Type::OrderedNumber())) {
// JSUnaryNot(x:number,context) => NumberEqual(x,#0)
// JSUnaryNot(x:number) => NumberEqual(x,#0)
node->set_op(simplified()->NumberEqual());
node->ReplaceInput(1, jsgraph()->ZeroConstant());
DCHECK_EQ(2, node->InputCount());
node->TrimInputCount(2);
return Changed(node);
} else if (input_type->Is(Type::String())) {
// JSUnaryNot(x:string) => NumberEqual(x.length,#0)
FieldAccess const access = AccessBuilder::ForStringLength();
// It is safe for the load to be effect-free (i.e. not linked into effect
// chain) because we assume String::length to be immutable.
Node* length = graph()->NewNode(simplified()->LoadField(access), input,
graph()->start(), graph()->start());
node->set_op(simplified()->NumberEqual());
node->ReplaceInput(0, length);
node->ReplaceInput(1, jsgraph()->ZeroConstant());
node->TrimInputCount(2);
NodeProperties::ReplaceWithValue(node, node, length);
return Changed(node);
}
// JSUnaryNot(x,context) => BooleanNot(AnyToBoolean(x))
node->set_op(simplified()->BooleanNot());
node->ReplaceInput(0, graph()->NewNode(simplified()->AnyToBoolean(), input));
node->TrimInputCount(1);
return Changed(node);
return NoChange();
}
Reduction JSTypedLowering::ReduceJSToBoolean(Node* node) {
Node* input = node->InputAt(0);
Type* input_type = NodeProperties::GetBounds(input).upper;
Node* const input = node->InputAt(0);
Type* const input_type = NodeProperties::GetBounds(input).upper;
if (input_type->Is(Type::Boolean())) {
// JSToBoolean(x:boolean,context) => x
// JSToBoolean(x:boolean) => x
return Replace(input);
} else if (input_type->Is(Type::OrderedNumber())) {
// JSToBoolean(x:ordered-number) => BooleanNot(NumberEqual(x,#0))
node->set_op(simplified()->BooleanNot());
node->ReplaceInput(0, graph()->NewNode(simplified()->NumberEqual(), input,
jsgraph()->ZeroConstant()));
node->TrimInputCount(1);
return Changed(node);
} else if (input_type->Is(Type::String())) {
// JSToBoolean(x:string) => NumberLessThan(#0,x.length)
FieldAccess const access = AccessBuilder::ForStringLength();
// It is safe for the load to be effect-free (i.e. not linked into effect
// chain) because we assume String::length to be immutable.
Node* length = graph()->NewNode(simplified()->LoadField(access), input,
graph()->start(), graph()->start());
node->set_op(simplified()->NumberLessThan());
node->ReplaceInput(0, jsgraph()->ZeroConstant());
node->ReplaceInput(1, length);
node->TrimInputCount(2);
return Changed(node);
}
// JSToBoolean(x,context) => AnyToBoolean(x)
node->set_op(simplified()->AnyToBoolean());
node->TrimInputCount(1);
return Changed(node);
return NoChange();
}

View File

@ -153,7 +153,6 @@
#define SIMPLIFIED_OP_LIST(V) \
SIMPLIFIED_COMPARE_BINOP_LIST(V) \
V(AnyToBoolean) \
V(BooleanNot) \
V(BooleanToNumber) \
V(NumberAdd) \

View File

@ -538,24 +538,6 @@ class RepresentationSelector {
//------------------------------------------------------------------
// Simplified operators.
//------------------------------------------------------------------
case IrOpcode::kAnyToBoolean: {
VisitUnop(node, kMachAnyTagged, kTypeBool | kRepTagged);
if (lower()) {
// AnyToBoolean(x) => Call(ToBooleanStub, x, no-context)
Operator::Properties properties = node->op()->properties();
Callable callable = CodeFactory::ToBoolean(
jsgraph_->isolate(), ToBooleanStub::RESULT_AS_ODDBALL);
CallDescriptor::Flags flags = CallDescriptor::kPatchableCallSite;
CallDescriptor* desc = Linkage::GetStubCallDescriptor(
jsgraph_->isolate(), jsgraph_->zone(), callable.descriptor(), 0,
flags, properties);
node->set_op(jsgraph_->common()->Call(desc));
node->InsertInput(jsgraph_->zone(), 0,
jsgraph_->HeapConstant(callable.code()));
node->AppendInput(jsgraph_->zone(), jsgraph_->NoContextConstant());
}
break;
}
case IrOpcode::kBooleanNot: {
if (lower()) {
MachineTypeUnion input = GetInfo(node->InputAt(0))->output;

View File

@ -4,11 +4,9 @@
#include "src/compiler/simplified-operator-reducer.h"
#include "src/compiler/access-builder.h"
#include "src/compiler/js-graph.h"
#include "src/compiler/machine-operator.h"
#include "src/compiler/node-matchers.h"
#include "src/compiler/node-properties.h"
#include "src/compiler/operator-properties.h"
namespace v8 {
@ -24,8 +22,6 @@ SimplifiedOperatorReducer::~SimplifiedOperatorReducer() {}
Reduction SimplifiedOperatorReducer::Reduce(Node* node) {
switch (node->opcode()) {
case IrOpcode::kAnyToBoolean:
return ReduceAnyToBoolean(node);
case IrOpcode::kBooleanNot: {
HeapObjectMatcher<HeapObject> m(node->InputAt(0));
if (m.Is(Unique<HeapObject>::CreateImmovable(factory()->false_value()))) {
@ -111,32 +107,6 @@ Reduction SimplifiedOperatorReducer::Reduce(Node* node) {
}
Reduction SimplifiedOperatorReducer::ReduceAnyToBoolean(Node* node) {
Node* const input = NodeProperties::GetValueInput(node, 0);
Type* const input_type = NodeProperties::GetBounds(input).upper;
if (input_type->Is(Type::Boolean())) {
// AnyToBoolean(x:boolean) => x
return Replace(input);
}
if (input_type->Is(Type::OrderedNumber())) {
// AnyToBoolean(x:ordered-number) => BooleanNot(NumberEqual(x, #0))
Node* compare = graph()->NewNode(simplified()->NumberEqual(), input,
jsgraph()->ZeroConstant());
return Change(node, simplified()->BooleanNot(), compare);
}
if (input_type->Is(Type::String())) {
// AnyToBoolean(x:string) => BooleanNot(NumberEqual(x.length, #0))
FieldAccess const access = AccessBuilder::ForStringLength();
Node* length = graph()->NewNode(simplified()->LoadField(access), input,
graph()->start(), graph()->start());
Node* compare = graph()->NewNode(simplified()->NumberEqual(), length,
jsgraph()->ZeroConstant());
return Change(node, simplified()->BooleanNot(), compare);
}
return NoChange();
}
Reduction SimplifiedOperatorReducer::Change(Node* node, const Operator* op,
Node* a) {
DCHECK_EQ(node->InputCount(), OperatorProperties::GetTotalInputCount(op));
@ -175,11 +145,6 @@ Factory* SimplifiedOperatorReducer::factory() const {
}
CommonOperatorBuilder* SimplifiedOperatorReducer::common() const {
return jsgraph()->common();
}
MachineOperatorBuilder* SimplifiedOperatorReducer::machine() const {
return jsgraph()->machine();
}

View File

@ -18,7 +18,6 @@ class Heap;
namespace compiler {
// Forward declarations.
class CommonOperatorBuilder;
class JSGraph;
class MachineOperatorBuilder;
@ -30,8 +29,6 @@ class SimplifiedOperatorReducer FINAL : public Reducer {
Reduction Reduce(Node* node) FINAL;
private:
Reduction ReduceAnyToBoolean(Node* node);
Reduction Change(Node* node, const Operator* op, Node* a);
Reduction ReplaceFloat64(double value);
Reduction ReplaceInt32(int32_t value);
@ -44,7 +41,6 @@ class SimplifiedOperatorReducer FINAL : public Reducer {
Graph* graph() const;
Factory* factory() const;
JSGraph* jsgraph() const { return jsgraph_; }
CommonOperatorBuilder* common() const;
MachineOperatorBuilder* machine() const;
SimplifiedOperatorBuilder* simplified() { return &simplified_; }

View File

@ -158,7 +158,6 @@ const ElementAccess& ElementAccessOf(const Operator* op) {
#define PURE_OP_LIST(V) \
V(AnyToBoolean, Operator::kNoProperties, 1) \
V(BooleanNot, Operator::kNoProperties, 1) \
V(BooleanToNumber, Operator::kNoProperties, 1) \
V(NumberEqual, Operator::kCommutative, 2) \

View File

@ -128,8 +128,6 @@ class SimplifiedOperatorBuilder FINAL {
public:
explicit SimplifiedOperatorBuilder(Zone* zone);
const Operator* AnyToBoolean();
const Operator* BooleanNot();
const Operator* BooleanToNumber();

View File

@ -1534,11 +1534,6 @@ Bounds Typer::Visitor::TypeJSStackCheck(Node* node) {
// Simplified operators.
Bounds Typer::Visitor::TypeAnyToBoolean(Node* node) {
return TypeUnaryOp(node, ToBoolean);
}
Bounds Typer::Visitor::TypeBooleanNot(Node* node) {
return Bounds(Type::None(zone()), Type::Boolean(zone()));
}

View File

@ -557,10 +557,6 @@ void Verifier::Visitor::Check(Node* node) {
// Simplified operators
// -------------------------------
case IrOpcode::kAnyToBoolean:
// Type is Boolean.
CheckUpperIs(node, Type::Boolean());
break;
case IrOpcode::kBooleanNot:
// Boolean -> Boolean
CheckValueInputIs(node, 0, Type::Boolean());

View File

@ -507,42 +507,6 @@ TEST(JSToNumberOfNumberOrOtherPrimitive) {
}
TEST(JSToBoolean) {
JSTypedLoweringTester R;
const Operator* op = R.javascript.ToBoolean();
{ // ToBoolean(undefined)
Node* r = R.ReduceUnop(op, Type::Undefined());
R.CheckFalse(r);
}
{ // ToBoolean(null)
Node* r = R.ReduceUnop(op, Type::Null());
R.CheckFalse(r);
}
{ // ToBoolean(boolean)
Node* r = R.ReduceUnop(op, Type::Boolean());
CHECK_EQ(IrOpcode::kParameter, r->opcode());
}
{ // ToBoolean(object)
Node* r = R.ReduceUnop(op, Type::DetectableObject());
R.CheckTrue(r);
}
{ // ToBoolean(undetectable)
Node* r = R.ReduceUnop(op, Type::Undetectable());
R.CheckFalse(r);
}
{ // ToBoolean(object)
Node* r = R.ReduceUnop(op, Type::Object());
CHECK_EQ(IrOpcode::kAnyToBoolean, r->opcode());
}
}
TEST(JSToString1) {
JSTypedLoweringTester R;
@ -724,24 +688,6 @@ TEST(MixedComparison1) {
}
TEST(UnaryNot) {
JSTypedLoweringTester R;
const Operator* opnot = R.javascript.UnaryNot();
for (size_t i = 0; i < arraysize(kJSTypes); i++) {
Node* orig = R.Unop(opnot, R.Parameter(kJSTypes[i]));
Node* r = R.reduce(orig);
if (r == orig && orig->opcode() == IrOpcode::kJSToBoolean) {
// The original node was turned into a ToBoolean.
CHECK_EQ(IrOpcode::kJSToBoolean, r->opcode());
} else if (r->opcode() != IrOpcode::kHeapConstant) {
CHECK_EQ(IrOpcode::kBooleanNot, r->opcode());
}
}
}
TEST(RemoveToNumberEffects) {
FLAG_turbo_deoptimization = true;

View File

@ -790,25 +790,6 @@ class TestingGraph : public HandleAndZoneScope, public GraphAndBuilders {
};
#if V8_TURBOFAN_TARGET
TEST(LowerAnyToBoolean_tagged_tagged) {
// AnyToBoolean(x: kRepTagged) used as kRepTagged
TestingGraph t(Type::Any());
Node* x = t.p0;
Node* cnv = t.graph()->NewNode(t.simplified()->AnyToBoolean(), x);
Node* use = t.Use(cnv, kRepTagged);
t.Return(use);
t.Lower();
CHECK_EQ(IrOpcode::kCall, cnv->opcode());
CHECK_EQ(IrOpcode::kHeapConstant, cnv->InputAt(0)->opcode());
CHECK_EQ(x, cnv->InputAt(1));
CHECK_EQ(t.jsgraph.NoContextConstant(), cnv->InputAt(2));
}
#endif
TEST(LowerBooleanNot_bit_bit) {
// BooleanNot(x: kRepBit) used as kRepBit
TestingGraph t(Type::Boolean());

View File

@ -184,13 +184,25 @@ TEST_F(JSTypedLoweringTest, JSUnaryNotWithNonZeroPlainNumber) {
}
TEST_F(JSTypedLoweringTest, JSUnaryNotWithString) {
Node* input = Parameter(Type::String(), 0);
Node* context = Parameter(Type::Any(), 1);
Reduction r =
Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(),
IsNumberEqual(IsLoadField(AccessBuilder::ForStringLength(), input,
graph()->start(), graph()->start()),
IsNumberConstant(0.0)));
}
TEST_F(JSTypedLoweringTest, JSUnaryNotWithAny) {
Node* input = Parameter(Type::Any(), 0);
Node* context = Parameter(Type::Any(), 1);
Reduction r =
Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsBooleanNot(IsAnyToBoolean(input)));
ASSERT_FALSE(r.Changed());
}
@ -360,13 +372,37 @@ TEST_F(JSTypedLoweringTest, JSToBooleanWithNonZeroPlainNumber) {
}
TEST_F(JSTypedLoweringTest, JSToBooleanWithOrderedNumber) {
Node* input = Parameter(Type::OrderedNumber(), 0);
Node* context = Parameter(Type::Any(), 1);
Reduction r =
Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(),
IsBooleanNot(IsNumberEqual(input, IsNumberConstant(0.0))));
}
TEST_F(JSTypedLoweringTest, JSToBooleanWithString) {
Node* input = Parameter(Type::String(), 0);
Node* context = Parameter(Type::Any(), 1);
Reduction r =
Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(
r.replacement(),
IsNumberLessThan(IsNumberConstant(0.0),
IsLoadField(AccessBuilder::ForStringLength(), input,
graph()->start(), graph()->start())));
}
TEST_F(JSTypedLoweringTest, JSToBooleanWithAny) {
Node* input = Parameter(Type::Any(), 0);
Node* context = Parameter(Type::Any(), 1);
Reduction r =
Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsAnyToBoolean(input));
ASSERT_FALSE(r.Changed());
}

View File

@ -1602,7 +1602,6 @@ IS_BINOP_MATCHER(Float64InsertHighWord32)
Matcher<Node*> Is##Name(const Matcher<Node*>& input_matcher) { \
return MakeMatcher(new IsUnopMatcher(IrOpcode::k##Name, input_matcher)); \
}
IS_UNOP_MATCHER(AnyToBoolean)
IS_UNOP_MATCHER(BooleanNot)
IS_UNOP_MATCHER(ChangeFloat64ToInt32)
IS_UNOP_MATCHER(ChangeFloat64ToUint32)

View File

@ -101,7 +101,6 @@ Matcher<Node*> IsCall(const Matcher<CallDescriptor*>& descriptor_matcher,
const Matcher<Node*>& effect_matcher,
const Matcher<Node*>& control_matcher);
Matcher<Node*> IsAnyToBoolean(const Matcher<Node*>& value_matcher);
Matcher<Node*> IsBooleanNot(const Matcher<Node*>& value_matcher);
Matcher<Node*> IsNumberEqual(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher);

View File

@ -118,39 +118,6 @@ const double kNaNs[] = {-std::numeric_limits<double>::quiet_NaN(),
} // namespace
// -----------------------------------------------------------------------------
// AnyToBoolean
TEST_F(SimplifiedOperatorReducerTest, AnyToBooleanWithBoolean) {
Node* p = Parameter(Type::Boolean());
Reduction r = Reduce(graph()->NewNode(simplified()->AnyToBoolean(), p));
ASSERT_TRUE(r.Changed());
EXPECT_EQ(p, r.replacement());
}
TEST_F(SimplifiedOperatorReducerTest, AnyToBooleanWithOrderedNumber) {
Node* p = Parameter(Type::OrderedNumber());
Reduction r = Reduce(graph()->NewNode(simplified()->AnyToBoolean(), p));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(),
IsBooleanNot(IsNumberEqual(p, IsNumberConstant(0))));
}
TEST_F(SimplifiedOperatorReducerTest, AnyToBooleanWithString) {
Node* p = Parameter(Type::String());
Reduction r = Reduce(graph()->NewNode(simplified()->AnyToBoolean(), p));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(),
IsBooleanNot(
IsNumberEqual(IsLoadField(AccessBuilder::ForStringLength(), p,
graph()->start(), graph()->start()),
IsNumberConstant(0))));
}
// -----------------------------------------------------------------------------
// BooleanNot

View File

@ -38,7 +38,6 @@ const PureOperator kPureOperators[] = {
&SimplifiedOperatorBuilder::Name, IrOpcode::k##Name, \
Operator::kPure | properties, input_count \
}
PURE(AnyToBoolean, Operator::kNoProperties, 1),
PURE(BooleanNot, Operator::kNoProperties, 1),
PURE(BooleanToNumber, Operator::kNoProperties, 1),
PURE(NumberEqual, Operator::kCommutative, 2),