Extend JSBuiltinReducer to cover Math.abs as well.

R=titzer@chromium.org
TEST=compiler-unittests/JSBuiltinReducerTest.MathAbs

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24255 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 4a9feef3
......@@ -744,6 +744,7 @@ Matcher<Node*> IsStore(const Matcher<MachineType>& type_matcher,
new IsBinopMatcher(IrOpcode::k##Name, lhs_matcher, rhs_matcher)); \
}
IS_BINOP_MATCHER(NumberLessThan)
IS_BINOP_MATCHER(NumberSubtract)
IS_BINOP_MATCHER(Word32And)
IS_BINOP_MATCHER(Word32Sar)
IS_BINOP_MATCHER(Word32Shl)
......
......@@ -87,6 +87,8 @@ Matcher<Node*> IsCall(const Matcher<CallDescriptor*>& descriptor_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*> IsLoad(const Matcher<LoadRepresentation>& rep_matcher,
const Matcher<Node*>& base_matcher,
......
......@@ -59,6 +59,39 @@ Type* const kNumberTypes[] = {
} // namespace
// -----------------------------------------------------------------------------
// Math.abs
TEST_F(JSBuiltinReducerTest, MathAbs) {
Handle<JSFunction> f(isolate()->context()->math_abs_fun());
TRACED_FOREACH(Type*, t0, kNumberTypes) {
Node* p0 = Parameter(t0, 0);
Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
Node* call = graph()->NewNode(javascript()->Call(3, NO_CALL_FUNCTION_FLAGS),
fun, UndefinedConstant(), p0);
Reduction r = Reduce(call);
if (t0->Is(Type::Unsigned32())) {
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), p0);
} else {
Capture<Node*> branch;
ASSERT_TRUE(r.Changed());
EXPECT_THAT(
r.replacement(),
IsPhi(kMachNone, p0, IsNumberSubtract(IsNumberConstant(0), p0),
IsMerge(IsIfTrue(CaptureEq(&branch)),
IsIfFalse(AllOf(
CaptureEq(&branch),
IsBranch(IsNumberLessThan(IsNumberConstant(0), p0),
graph()->start()))))));
}
}
}
// -----------------------------------------------------------------------------
// Math.sqrt
......
......@@ -95,6 +95,33 @@ class JSCallReduction {
};
// ECMA-262, section 15.8.2.1.
Reduction JSBuiltinReducer::ReduceMathAbs(Node* node) {
JSCallReduction r(node);
if (r.InputsMatchOne(Type::Unsigned32())) {
// Math.abs(a:uint32) -> a
return Replace(r.left());
}
if (r.InputsMatchOne(Type::Number())) {
// Math.abs(a:number) -> (a > 0 ? a : 0 - a)
Node* value = r.left();
Node* zero = jsgraph()->ZeroConstant();
Node* control = graph()->start();
Node* tag = graph()->NewNode(simplified()->NumberLessThan(), zero, value);
Node* branch = graph()->NewNode(common()->Branch(), tag, control);
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
Node* neg = graph()->NewNode(simplified()->NumberSubtract(), zero, value);
value = graph()->NewNode(common()->Phi(kMachNone, 2), value, neg, merge);
return Replace(value);
}
return NoChange();
}
// ECMA-262, section 15.8.2.17.
Reduction JSBuiltinReducer::ReduceMathSqrt(Node* node) {
JSCallReduction r(node);
......@@ -170,6 +197,8 @@ Reduction JSBuiltinReducer::Reduce(Node* node) {
// Dispatch according to the BuiltinFunctionId if present.
if (!r.HasBuiltinFunctionId()) return NoChange();
switch (r.GetBuiltinFunctionId()) {
case kMathAbs:
return ReplaceWithPureReduction(node, ReduceMathAbs(node));
case kMathSqrt:
return ReplaceWithPureReduction(node, ReduceMathSqrt(node));
case kMathMax:
......
......@@ -30,6 +30,7 @@ class JSBuiltinReducer FINAL : public Reducer {
MachineOperatorBuilder* machine() const { return jsgraph_->machine(); }
SimplifiedOperatorBuilder* simplified() { return &simplified_; }
Reduction ReduceMathAbs(Node* node);
Reduction ReduceMathSqrt(Node* node);
Reduction ReduceMathMax(Node* node);
Reduction ReduceMathImul(Node* node);
......
// 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) {
"use asm";
var abs = stdlib.Math.abs;
// f: double -> double
function f(a) {
a = +a;
return +abs(a);
}
// g: unsigned -> double
function g(a) {
a = a>>>0;
return +abs(a);
}
// h: signed -> double
function h(a) {
a = a|0;
return +abs(a);
}
return { f: f, g: g, h: h };
}
var m = Module({ Math: Math });
var f = m.f;
var g = m.g;
var h = m.h;
assertTrue(isNaN(f(NaN)));
assertTrue(isNaN(f(undefined)));
assertTrue(isNaN(f(function() {})));
assertEquals("Infinity", String(1/f(0)));
assertEquals("Infinity", String(1/f(-0)));
assertEquals("Infinity", String(f(Infinity)));
assertEquals("Infinity", String(f(-Infinity)));
assertEquals(0, f(0));
assertEquals(0.1, f(0.1));
assertEquals(0.5, f(0.5));
assertEquals(0.1, f(-0.1));
assertEquals(0.5, f(-0.5));
assertEquals(1, f(1));
assertEquals(1.1, f(1.1));
assertEquals(1.5, f(1.5));
assertEquals(1, f(-1));
assertEquals(1.1, f(-1.1));
assertEquals(1.5, f(-1.5));
assertEquals(0, g(0));
assertEquals(0, g(0.1));
assertEquals(0, g(0.5));
assertEquals(0, g(-0.1));
assertEquals(0, g(-0.5));
assertEquals(1, g(1));
assertEquals(1, g(1.1));
assertEquals(1, g(1.5));
assertEquals(4294967295, g(-1));
assertEquals(4294967295, g(-1.1));
assertEquals(4294967295, g(-1.5));
assertEquals(0, h(0));
assertEquals(0, h(0.1));
assertEquals(0, h(0.5));
assertEquals(0, h(-0.1));
assertEquals(0, h(-0.5));
assertEquals(1, h(1));
assertEquals(1, h(1.1));
assertEquals(1, h(1.5));
assertEquals(1, h(-1));
assertEquals(1, h(-1.1));
assertEquals(1, h(-1.5));
assertEquals(Number.MIN_VALUE, f(Number.MIN_VALUE));
assertEquals(Number.MIN_VALUE, f(-Number.MIN_VALUE));
assertEquals(Number.MAX_VALUE, f(Number.MAX_VALUE));
assertEquals(Number.MAX_VALUE, f(-Number.MAX_VALUE));
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