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
This commit is contained in:
parent
4a9feef3d8
commit
28e733e7d0
@ -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);
|
||||
|
84
test/mjsunit/asm/math-abs.js
Normal file
84
test/mjsunit/asm/math-abs.js
Normal file
@ -0,0 +1,84 @@
|
||||
// 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));
|
Loading…
Reference in New Issue
Block a user