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)
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,
// -----------------------------------------------------------------------------
+// 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
};
+// 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);
// 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:
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);
--- /dev/null
+// 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));