Commit a75e4cea authored by Benedikt Meurer's avatar Benedikt Meurer

[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}
parent 5383257e
......@@ -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);
}
// JSUnaryNot(x,context) => BooleanNot(AnyToBoolean(x))
node->set_op(simplified()->BooleanNot());
node->ReplaceInput(0, graph()->NewNode(simplified()->AnyToBoolean(), input));
node->TrimInputCount(1);
} 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);
}
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);
}
// JSToBoolean(x,context) => AnyToBoolean(x)
node->set_op(simplified()->AnyToBoolean());
} 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);
}
return NoChange();
}
......
......@@ -153,7 +153,6 @@
#define SIMPLIFIED_OP_LIST(V) \
SIMPLIFIED_COMPARE_BINOP_LIST(V) \
V(AnyToBoolean) \
V(BooleanNot) \
V(BooleanToNumber) \
V(NumberAdd) \
......
......@@ -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;
......
......@@ -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();
}
......
......@@ -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_; }
......
......@@ -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) \
......
......@@ -128,8 +128,6 @@ class SimplifiedOperatorBuilder FINAL {
public:
explicit SimplifiedOperatorBuilder(Zone* zone);
const Operator* AnyToBoolean();
const Operator* BooleanNot();
const Operator* BooleanToNumber();
......
......@@ -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()));
}
......
......@@ -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());
......
......@@ -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;
......
......@@ -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());
......
......@@ -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());
}
......
......@@ -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)
......
......@@ -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);
......
......@@ -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
......
......@@ -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),
......
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