From 28e733e7d0c173843844669226fa24d49328ab6a Mon Sep 17 00:00:00 2001 From: "mstarzinger@chromium.org" Date: Fri, 26 Sep 2014 14:06:56 +0000 Subject: [PATCH] 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 --- src/compiler/graph-unittest.cc | 1 + src/compiler/graph-unittest.h | 2 + src/compiler/js-builtin-reducer-unittest.cc | 33 ++++++++++++ src/compiler/js-builtin-reducer.cc | 29 ++++++++++ src/compiler/js-builtin-reducer.h | 1 + test/mjsunit/asm/math-abs.js | 84 +++++++++++++++++++++++++++++ 6 files changed, 150 insertions(+) create mode 100644 test/mjsunit/asm/math-abs.js diff --git a/src/compiler/graph-unittest.cc b/src/compiler/graph-unittest.cc index 0071b81..35585e8 100644 --- a/src/compiler/graph-unittest.cc +++ b/src/compiler/graph-unittest.cc @@ -744,6 +744,7 @@ Matcher IsStore(const Matcher& 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) diff --git a/src/compiler/graph-unittest.h b/src/compiler/graph-unittest.h index 04d4af0..b821165 100644 --- a/src/compiler/graph-unittest.h +++ b/src/compiler/graph-unittest.h @@ -87,6 +87,8 @@ Matcher IsCall(const Matcher& descriptor_matcher, Matcher IsNumberLessThan(const Matcher& lhs_matcher, const Matcher& rhs_matcher); +Matcher IsNumberSubtract(const Matcher& lhs_matcher, + const Matcher& rhs_matcher); Matcher IsLoad(const Matcher& rep_matcher, const Matcher& base_matcher, diff --git a/src/compiler/js-builtin-reducer-unittest.cc b/src/compiler/js-builtin-reducer-unittest.cc index 598a553..5177d8d 100644 --- a/src/compiler/js-builtin-reducer-unittest.cc +++ b/src/compiler/js-builtin-reducer-unittest.cc @@ -60,6 +60,39 @@ Type* const kNumberTypes[] = { // ----------------------------------------------------------------------------- +// Math.abs + + +TEST_F(JSBuiltinReducerTest, MathAbs) { + Handle f(isolate()->context()->math_abs_fun()); + + TRACED_FOREACH(Type*, t0, kNumberTypes) { + Node* p0 = Parameter(t0, 0); + Node* fun = HeapConstant(Unique::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 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 diff --git a/src/compiler/js-builtin-reducer.cc b/src/compiler/js-builtin-reducer.cc index f1aef31..ec73742 100644 --- a/src/compiler/js-builtin-reducer.cc +++ b/src/compiler/js-builtin-reducer.cc @@ -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: diff --git a/src/compiler/js-builtin-reducer.h b/src/compiler/js-builtin-reducer.h index e5a1b83..f3b862f 100644 --- a/src/compiler/js-builtin-reducer.h +++ b/src/compiler/js-builtin-reducer.h @@ -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); diff --git a/test/mjsunit/asm/math-abs.js b/test/mjsunit/asm/math-abs.js new file mode 100644 index 0000000..6387749 --- /dev/null +++ b/test/mjsunit/asm/math-abs.js @@ -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)); -- 2.7.4