Commit c071a8f0 authored by bmeurer's avatar bmeurer Committed by Commit bot

[turbofan] Introduce dedicated NumberToBoolean operator.

Previously we always lowered JSToBoolean(x:Number) to the subgraph
NumberLessThan(0.0, NumberAbs(x)), which deals with both 0, -0 and
NaNs appropriately. However this doesn't always generate the best,
especially when we can later derive from feedback that x is always
an Integral32 value, where the ideal code would be just a single
comparison to 0 w/o the absolute value computation.

R=mvstanton@chromium.org
BUG=v8:5267,v8:5270

Review-Url: https://codereview.chromium.org/2309953002
Cr-Commit-Position: refs/heads/master@{#39194}
parent a0ff620f
......@@ -777,12 +777,10 @@ Reduction JSTypedLowering::ReduceJSToBoolean(Node* node) {
NodeProperties::ChangeOp(node, simplified()->BooleanNot());
return Changed(node);
} else if (input_type->Is(Type::Number())) {
// JSToBoolean(x:number) => NumberLessThan(#0,NumberAbs(x))
// JSToBoolean(x:number) => NumberToBoolean(x)
RelaxEffectsAndControls(node);
node->ReplaceInput(0, jsgraph()->ZeroConstant());
node->ReplaceInput(1, graph()->NewNode(simplified()->NumberAbs(), input));
node->TrimInputCount(2);
NodeProperties::ChangeOp(node, simplified()->NumberLessThan());
node->TrimInputCount(1);
NodeProperties::ChangeOp(node, simplified()->NumberToBoolean());
return Changed(node);
} else if (input_type->Is(Type::String())) {
// JSToBoolean(x:string) => NumberLessThan(#0,x.length)
......
......@@ -268,6 +268,7 @@
V(NumberTan) \
V(NumberTanh) \
V(NumberTrunc) \
V(NumberToBoolean) \
V(NumberToInt32) \
V(NumberToUint32) \
V(NumberSilenceNaN)
......
......@@ -460,6 +460,16 @@ Type* OperationTyper::NumberTrunc(Type* type) {
return cache_.kIntegerOrMinusZeroOrNaN;
}
Type* OperationTyper::NumberToBoolean(Type* type) {
DCHECK(type->Is(Type::Number()));
if (!type->IsInhabited()) return Type::None();
if (type->Is(cache_.kZeroish)) return singleton_false_;
if (type->Is(Type::PlainNumber()) && (type->Max() < 0 || 0 < type->Min())) {
return singleton_true_; // Ruled out nan, -0 and +0.
}
return Type::Boolean();
}
Type* OperationTyper::NumberToInt32(Type* type) {
DCHECK(type->Is(Type::Number()));
......
......@@ -2005,6 +2005,23 @@ class RepresentationSelector {
if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
return;
}
case IrOpcode::kNumberToBoolean: {
Type* const input_type = TypeOf(node->InputAt(0));
if (input_type->Is(Type::Integral32())) {
VisitUnop(node, UseInfo::TruncatingWord32(),
MachineRepresentation::kBit);
if (lower()) lowering->DoIntegral32ToBit(node);
} else if (input_type->Is(Type::OrderedNumber())) {
VisitUnop(node, UseInfo::TruncatingFloat64(),
MachineRepresentation::kBit);
if (lower()) lowering->DoOrderedNumberToBit(node);
} else {
VisitUnop(node, UseInfo::TruncatingFloat64(),
MachineRepresentation::kBit);
if (lower()) lowering->DoNumberToBit(node);
}
return;
}
case IrOpcode::kNumberToInt32: {
// Just change representation if necessary.
VisitUnop(node, UseInfo::TruncatingWord32(),
......@@ -3187,6 +3204,34 @@ void SimplifiedLowering::DoStringToNumber(Node* node) {
NodeProperties::ChangeOp(node, common()->Call(desc));
}
void SimplifiedLowering::DoIntegral32ToBit(Node* node) {
Node* const input = node->InputAt(0);
Node* const zero = jsgraph()->Int32Constant(0);
Operator const* const op = machine()->Word32Equal();
node->ReplaceInput(0, graph()->NewNode(op, input, zero));
node->AppendInput(graph()->zone(), zero);
NodeProperties::ChangeOp(node, op);
}
void SimplifiedLowering::DoOrderedNumberToBit(Node* node) {
Node* const input = node->InputAt(0);
node->ReplaceInput(0, graph()->NewNode(machine()->Float64Equal(), input,
jsgraph()->Float64Constant(0.0)));
node->AppendInput(graph()->zone(), jsgraph()->Int32Constant(0));
NodeProperties::ChangeOp(node, machine()->Word32Equal());
}
void SimplifiedLowering::DoNumberToBit(Node* node) {
Node* const input = node->InputAt(0);
node->ReplaceInput(0, jsgraph()->Float64Constant(0.0));
node->AppendInput(graph()->zone(),
graph()->NewNode(machine()->Float64Abs(), input));
NodeProperties::ChangeOp(node, machine()->Float64LessThan());
}
Node* SimplifiedLowering::ToNumberCode() {
if (!to_number_code_.is_set()) {
Callable callable = CodeFactory::ToNumber(isolate());
......
......@@ -41,6 +41,9 @@ class SimplifiedLowering final {
void DoStoreBuffer(Node* node);
void DoShift(Node* node, Operator const* op, Type* rhs_type);
void DoStringToNumber(Node* node);
void DoIntegral32ToBit(Node* node);
void DoOrderedNumberToBit(Node* node);
void DoNumberToBit(Node* node);
private:
JSGraph* const jsgraph_;
......
......@@ -381,6 +381,7 @@ NumberOperationHint NumberOperationHintOf(const Operator* op) {
V(NumberTan, Operator::kNoProperties, 1, 0) \
V(NumberTanh, Operator::kNoProperties, 1, 0) \
V(NumberTrunc, Operator::kNoProperties, 1, 0) \
V(NumberToBoolean, Operator::kNoProperties, 1, 0) \
V(NumberToInt32, Operator::kNoProperties, 1, 0) \
V(NumberToUint32, Operator::kNoProperties, 1, 0) \
V(NumberSilenceNaN, Operator::kNoProperties, 1, 0) \
......
......@@ -258,6 +258,7 @@ class SimplifiedOperatorBuilder final : public ZoneObject {
const Operator* NumberTan();
const Operator* NumberTanh();
const Operator* NumberTrunc();
const Operator* NumberToBoolean();
const Operator* NumberToInt32();
const Operator* NumberToUint32();
......
......@@ -423,8 +423,8 @@ Type* Typer::Visitor::ToBoolean(Type* type, Typer* t) {
if (type->Is(Type::Boolean())) return type;
if (type->Is(t->falsish_)) return t->singleton_false_;
if (type->Is(t->truish_)) return t->singleton_true_;
if (type->Is(Type::PlainNumber()) && (type->Max() < 0 || 0 < type->Min())) {
return t->singleton_true_; // Ruled out nan, -0 and +0.
if (type->Is(Type::Number())) {
return t->operation_typer()->NumberToBoolean(type);
}
return Type::Boolean();
}
......
......@@ -797,6 +797,11 @@ void Verifier::Visitor::Check(Node* node) {
CheckValueInputIs(node, 0, Type::Number());
CheckTypeIs(node, Type::Number());
break;
case IrOpcode::kNumberToBoolean:
// Number -> Boolean
CheckValueInputIs(node, 0, Type::Number());
CheckTypeIs(node, Type::Boolean());
break;
case IrOpcode::kNumberToInt32:
// Number -> Signed32
CheckValueInputIs(node, 0, Type::Number());
......
......@@ -113,8 +113,7 @@ TEST_F(JSTypedLoweringTest, JSToBooleanWithNumber) {
Reduction r = Reduce(graph()->NewNode(
javascript()->ToBoolean(ToBooleanHint::kAny), input, context));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(),
IsNumberLessThan(IsNumberConstant(0.0), IsNumberAbs(input)));
EXPECT_THAT(r.replacement(), IsNumberToBoolean(input));
}
TEST_F(JSTypedLoweringTest, JSToBooleanWithString) {
......
......@@ -2365,6 +2365,7 @@ IS_UNOP_MATCHER(NumberSqrt)
IS_UNOP_MATCHER(NumberTan)
IS_UNOP_MATCHER(NumberTanh)
IS_UNOP_MATCHER(NumberTrunc)
IS_UNOP_MATCHER(NumberToBoolean)
IS_UNOP_MATCHER(NumberToInt32)
IS_UNOP_MATCHER(NumberToUint32)
IS_UNOP_MATCHER(PlainPrimitiveToNumber)
......
......@@ -427,6 +427,7 @@ Matcher<Node*> IsToNumber(const Matcher<Node*>& base_matcher,
const Matcher<Node*>& control_matcher);
Matcher<Node*> IsLoadContext(const Matcher<ContextAccess>& access_matcher,
const Matcher<Node*>& context_matcher);
Matcher<Node*> IsNumberToBoolean(const Matcher<Node*>& input_matcher);
Matcher<Node*> IsNumberToInt32(const Matcher<Node*>& input_matcher);
Matcher<Node*> IsNumberToUint32(const Matcher<Node*>& input_matcher);
Matcher<Node*> IsParameter(const Matcher<int> 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