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

[turbofan] Introduce simplified operator NumberAbs.

Add NumberAbs operator to implement an inline version of Math.abs, that
can be optimized and eliminated. We don't use any speculation here, but
for now stick to the information we can infer (this way we avoid the
inherent deopt loops that Crankshaft has around Math.abs).

CQ_INCLUDE_TRYBOTS=tryserver.blink:linux_blink_rel
R=jarin@chromium.org
BUG=v8:5086

Review-Url: https://codereview.chromium.org/2096403002
Cr-Commit-Position: refs/heads/master@{#37306}
parent 53d2d24c
......@@ -91,6 +91,18 @@ JSBuiltinReducer::JSBuiltinReducer(Editor* editor, JSGraph* jsgraph)
jsgraph_(jsgraph),
type_cache_(TypeCache::Get()) {}
// ES6 section 20.2.2.1 Math.abs ( x )
Reduction JSBuiltinReducer::ReduceMathAbs(Node* node) {
JSCallReduction r(node);
if (r.InputsMatchOne(Type::PlainPrimitive())) {
// Math.abs(a:plain-primitive) -> NumberAbs(ToNumber(a))
Node* input = ToNumber(r.GetJSCallInput(0));
Node* value = graph()->NewNode(simplified()->NumberAbs(), input);
return Replace(value);
}
return NoChange();
}
// ES6 section 20.2.2.6 Math.atan ( x )
Reduction JSBuiltinReducer::ReduceMathAtan(Node* node) {
JSCallReduction r(node);
......@@ -417,6 +429,9 @@ Reduction JSBuiltinReducer::Reduce(Node* node) {
// Dispatch according to the BuiltinFunctionId if present.
if (!r.HasBuiltinFunctionId()) return NoChange();
switch (r.GetBuiltinFunctionId()) {
case kMathAbs:
reduction = ReduceMathAbs(node);
break;
case kMathAtan:
reduction = ReduceMathAtan(node);
break;
......
......@@ -29,6 +29,7 @@ class JSBuiltinReducer final : public AdvancedReducer {
Reduction Reduce(Node* node) final;
private:
Reduction ReduceMathAbs(Node* node);
Reduction ReduceMathAtan(Node* node);
Reduction ReduceMathAtan2(Node* node);
Reduction ReduceMathAtanh(Node* node);
......
......@@ -200,6 +200,7 @@
V(NumberShiftRight) \
V(NumberShiftRightLogical) \
V(NumberImul) \
V(NumberAbs) \
V(NumberClz32) \
V(NumberCeil) \
V(NumberCos) \
......
......@@ -687,6 +687,8 @@ const Operator* RepresentationChanger::Float64OperatorFor(
case IrOpcode::kNumberLessThanOrEqual:
case IrOpcode::kSpeculativeNumberLessThanOrEqual:
return machine()->Float64LessThanOrEqual();
case IrOpcode::kNumberAbs:
return machine()->Float64Abs();
case IrOpcode::kNumberAtan:
return machine()->Float64Atan();
case IrOpcode::kNumberAtan2:
......
......@@ -1487,6 +1487,27 @@ class RepresentationSelector {
}
return;
}
case IrOpcode::kNumberAbs: {
if (InputIs(node, Type::Unsigned32())) {
VisitUnop(node, UseInfo::TruncatingWord32(),
MachineRepresentation::kWord32);
if (lower()) DeferReplacement(node, node->InputAt(0));
} else if (InputIs(node, type_cache_.kSafeSigned32)) {
VisitUnop(node, UseInfo::TruncatingWord32(),
MachineRepresentation::kWord32);
if (lower()) DeferReplacement(node, lowering->Int32Abs(node));
} else if (InputIs(node,
type_cache_.kPositiveIntegerOrMinusZeroOrNaN)) {
VisitUnop(node, UseInfo::TruncatingFloat64(),
MachineRepresentation::kFloat64);
if (lower()) DeferReplacement(node, node->InputAt(0));
} else {
VisitUnop(node, UseInfo::TruncatingFloat64(),
MachineRepresentation::kFloat64);
if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
}
return;
}
case IrOpcode::kNumberClz32: {
VisitUnop(node, UseInfo::TruncatingWord32(),
MachineRepresentation::kWord32);
......@@ -2782,6 +2803,17 @@ Node* SimplifiedLowering::Float64Trunc(Node* const node) {
vtrue0, vfalse0, merge0);
}
Node* SimplifiedLowering::Int32Abs(Node* const node) {
Node* const zero = jsgraph()->Int32Constant(0);
Node* const input = node->InputAt(0);
// if 0 < input then input else 0 - input
return graph()->NewNode(
common()->Select(MachineRepresentation::kWord32, BranchHint::kTrue),
graph()->NewNode(machine()->Int32LessThan(), zero, input), input,
graph()->NewNode(machine()->Int32Sub(), zero, input));
}
Node* SimplifiedLowering::Int32Div(Node* const node) {
Int32BinopMatcher m(node);
Node* const zero = jsgraph()->Int32Constant(0);
......
......@@ -68,6 +68,7 @@ class SimplifiedLowering final {
Node* Float64Floor(Node* const node);
Node* Float64Round(Node* const node);
Node* Float64Trunc(Node* const node);
Node* Int32Abs(Node* const node);
Node* Int32Div(Node* const node);
Node* Int32Mod(Node* const node);
Node* Uint32Div(Node* const node);
......
......@@ -157,6 +157,11 @@ Reduction SimplifiedOperatorReducer::Reduce(Node* node) {
}
break;
}
case IrOpcode::kNumberAbs: {
NumberMatcher m(node->InputAt(0));
if (m.HasValue()) return ReplaceNumber(std::fabs(m.Value()));
break;
}
case IrOpcode::kNumberCeil:
case IrOpcode::kNumberFloor:
case IrOpcode::kNumberRound:
......
......@@ -251,6 +251,7 @@ CompareOperationHints::Hint CompareOperationHintOf(const Operator* op) {
V(NumberShiftRight, Operator::kNoProperties, 2) \
V(NumberShiftRightLogical, Operator::kNoProperties, 2) \
V(NumberImul, Operator::kCommutative, 2) \
V(NumberAbs, Operator::kNoProperties, 1) \
V(NumberClz32, Operator::kNoProperties, 1) \
V(NumberCeil, Operator::kNoProperties, 1) \
V(NumberFloor, Operator::kNoProperties, 1) \
......
......@@ -175,6 +175,7 @@ class SimplifiedOperatorBuilder final : public ZoneObject {
const Operator* NumberShiftRight();
const Operator* NumberShiftRightLogical();
const Operator* NumberImul();
const Operator* NumberAbs();
const Operator* NumberClz32();
const Operator* NumberCeil();
const Operator* NumberFloor();
......
......@@ -243,6 +243,7 @@ class Typer::Visitor : public Reducer {
static Type* ToNumber(Type*, Typer*);
static Type* ToObject(Type*, Typer*);
static Type* ToString(Type*, Typer*);
static Type* NumberAbs(Type*, Typer*);
static Type* NumberCeil(Type*, Typer*);
static Type* NumberFloor(Type*, Typer*);
static Type* NumberRound(Type*, Typer*);
......@@ -478,6 +479,34 @@ Type* Typer::Visitor::ToString(Type* type, Typer* t) {
return Type::String();
}
// static
Type* Typer::Visitor::NumberAbs(Type* type, Typer* t) {
DCHECK(type->Is(Type::Number()));
Factory* const f = t->isolate()->factory();
bool const maybe_nan = type->Maybe(Type::NaN());
bool const maybe_minuszero = type->Maybe(Type::MinusZero());
type = Type::Intersect(type, Type::PlainNumber(), t->zone());
double const max = type->Max();
double const min = type->Min();
if (min < 0) {
if (type->Is(t->cache_.kInteger)) {
type =
Type::Range(0.0, std::max(std::fabs(min), std::fabs(max)), t->zone());
} else if (min == max) {
type = Type::Constant(f->NewNumber(std::fabs(min)), t->zone());
} else {
type = Type::PlainNumber();
}
}
if (maybe_minuszero) {
type = Type::Union(type, t->cache_.kSingletonZero, t->zone());
}
if (maybe_nan) {
type = Type::Union(type, Type::NaN(), t->zone());
}
return type;
}
// static
Type* Typer::Visitor::NumberCeil(Type* type, Typer* t) {
DCHECK(type->Is(Type::Number()));
......@@ -1597,6 +1626,10 @@ Type* Typer::Visitor::TypePlainPrimitiveToFloat64(Node* node) {
Type* Typer::Visitor::TypeNumberImul(Node* node) { return Type::Signed32(); }
Type* Typer::Visitor::TypeNumberAbs(Node* node) {
return TypeUnaryOp(node, NumberAbs);
}
Type* Typer::Visitor::TypeNumberClz32(Node* node) {
return typer_->cache_.kZeroToThirtyTwo;
}
......
......@@ -751,6 +751,7 @@ void Verifier::Visitor::Check(Node* node) {
CheckValueInputIs(node, 1, Type::Number());
CheckUpperIs(node, Type::Number());
break;
case IrOpcode::kNumberAbs:
case IrOpcode::kNumberCeil:
case IrOpcode::kNumberFloor:
case IrOpcode::kNumberFround:
......
......@@ -144,7 +144,6 @@ utils.InstallFunctions(GlobalMath, DONT_ENUM, [
"hypot", MathHypot,
]);
%SetForceInlineFlag(MathAbs);
%SetForceInlineFlag(MathRandom);
%SetForceInlineFlag(MathSign);
......
......@@ -48,11 +48,15 @@ class TypeCache final {
Type* const kZeroish =
Type::Union(kSingletonZero, Type::MinusZeroOrNaN(), zone());
Type* const kInteger = CreateRange(-V8_INFINITY, V8_INFINITY);
Type* const kPositiveInteger = CreateRange(0.0, V8_INFINITY);
Type* const kIntegerOrMinusZero =
Type::Union(kInteger, Type::MinusZero(), zone());
Type* const kIntegerOrMinusZeroOrNaN =
Type::Union(kIntegerOrMinusZero, Type::NaN(), zone());
Type* const kPositiveInteger = CreateRange(0.0, V8_INFINITY);
Type* const kPositiveIntegerOrMinusZero =
Type::Union(kPositiveInteger, Type::MinusZero(), zone());
Type* const kPositiveIntegerOrMinusZeroOrNaN =
Type::Union(kPositiveIntegerOrMinusZero, Type::NaN(), zone());
Type* const kAdditiveSafeInteger =
CreateRange(-4503599627370496.0, 4503599627370496.0);
......@@ -62,6 +66,7 @@ class TypeCache final {
Type* const kSafeIntegerOrMinusZero =
Type::Union(kSafeInteger, Type::MinusZero(), zone());
Type* const kPositiveSafeInteger = CreateRange(0.0, kMaxSafeInteger);
Type* const kSafeSigned32 = CreateRange(-kMaxInt, kMaxInt);
Type* const kUntaggedUndefined =
Type::Intersect(Type::Undefined(), Type::Untagged(), zone());
......
......@@ -86,6 +86,45 @@ Type* const kNumberTypes[] = {
} // namespace
// -----------------------------------------------------------------------------
// Math.abs
TEST_F(JSBuiltinReducerTest, MathAbsWithNumber) {
Node* function = MathFunction("abs");
Node* effect = graph()->start();
Node* control = graph()->start();
Node* context = UndefinedConstant();
Node* frame_state = graph()->start();
TRACED_FOREACH(Type*, t0, kNumberTypes) {
Node* p0 = Parameter(t0, 0);
Node* call = graph()->NewNode(javascript()->CallFunction(3), function,
UndefinedConstant(), p0, context, frame_state,
effect, control);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsNumberAbs(p0));
}
}
TEST_F(JSBuiltinReducerTest, MathAbsWithPlainPrimitive) {
Node* function = MathFunction("abs");
Node* effect = graph()->start();
Node* control = graph()->start();
Node* context = UndefinedConstant();
Node* frame_state = graph()->start();
Node* p0 = Parameter(Type::PlainPrimitive(), 0);
Node* call = graph()->NewNode(javascript()->CallFunction(3), function,
UndefinedConstant(), p0, context, frame_state,
effect, control);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsNumberAbs(IsPlainPrimitiveToNumber(p0)));
}
// -----------------------------------------------------------------------------
// Math.atan
......
......@@ -2310,6 +2310,7 @@ IS_UNOP_MATCHER(Float64RoundTruncate)
IS_UNOP_MATCHER(Float64RoundTiesAway)
IS_UNOP_MATCHER(Float64ExtractLowWord32)
IS_UNOP_MATCHER(Float64ExtractHighWord32)
IS_UNOP_MATCHER(NumberAbs)
IS_UNOP_MATCHER(NumberAtan)
IS_UNOP_MATCHER(NumberAtanh)
IS_UNOP_MATCHER(NumberCeil)
......
......@@ -224,6 +224,7 @@ Matcher<Node*> IsNumberShiftRightLogical(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsNumberImul(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsNumberAbs(const Matcher<Node*>& value_matcher);
Matcher<Node*> IsNumberAtan(const Matcher<Node*>& value_matcher);
Matcher<Node*> IsNumberAtan2(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher);
......
......@@ -398,6 +398,18 @@ TEST_F(SimplifiedOperatorReducerTest, CheckTaggedSignedWithNumberConstant) {
EXPECT_EQ(value, reduction.replacement());
}
// -----------------------------------------------------------------------------
// NumberAbs
TEST_F(SimplifiedOperatorReducerTest, NumberAbsWithNumberConstant) {
TRACED_FOREACH(double, n, kFloat64Values) {
Reduction reduction =
Reduce(graph()->NewNode(simplified()->NumberAbs(), NumberConstant(n)));
ASSERT_TRUE(reduction.Changed());
EXPECT_THAT(reduction.replacement(), IsNumberConstant(std::fabs(n)));
}
}
// -----------------------------------------------------------------------------
// ObjectIsSmi
......
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