1// Copyright 2014 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "src/compiler/graph-unittest.h" 6#include "src/compiler/js-builtin-reducer.h" 7#include "src/compiler/js-graph.h" 8#include "src/compiler/node-properties-inl.h" 9#include "src/compiler/typer.h" 10#include "testing/gmock-support.h" 11 12using testing::Capture; 13 14namespace v8 { 15namespace internal { 16namespace compiler { 17 18class JSBuiltinReducerTest : public GraphTest { 19 public: 20 JSBuiltinReducerTest() : javascript_(zone()) {} 21 22 protected: 23 Reduction Reduce(Node* node) { 24 Typer typer(zone()); 25 MachineOperatorBuilder machine; 26 JSGraph jsgraph(graph(), common(), javascript(), &typer, &machine); 27 JSBuiltinReducer reducer(&jsgraph); 28 return reducer.Reduce(node); 29 } 30 31 Node* Parameter(Type* t, int32_t index = 0) { 32 Node* n = graph()->NewNode(common()->Parameter(index), graph()->start()); 33 NodeProperties::SetBounds(n, Bounds(Type::None(), t)); 34 return n; 35 } 36 37 Node* UndefinedConstant() { 38 return HeapConstant( 39 Unique<HeapObject>::CreateImmovable(factory()->undefined_value())); 40 } 41 42 JSOperatorBuilder* javascript() { return &javascript_; } 43 44 private: 45 JSOperatorBuilder javascript_; 46}; 47 48 49namespace { 50 51// TODO(mstarzinger): Find a common place and unify with test-js-typed-lowering. 52Type* const kNumberTypes[] = { 53 Type::UnsignedSmall(), Type::OtherSignedSmall(), Type::OtherUnsigned31(), 54 Type::OtherUnsigned32(), Type::OtherSigned32(), Type::SignedSmall(), 55 Type::Signed32(), Type::Unsigned32(), Type::Integral32(), 56 Type::MinusZero(), Type::NaN(), Type::OtherNumber(), 57 Type::OrderedNumber(), Type::Number()}; 58 59} // namespace 60 61 62// ----------------------------------------------------------------------------- 63// Math.sqrt 64 65 66TEST_F(JSBuiltinReducerTest, MathSqrt) { 67 Handle<JSFunction> f(isolate()->context()->math_sqrt_fun()); 68 69 TRACED_FOREACH(Type*, t0, kNumberTypes) { 70 Node* p0 = Parameter(t0, 0); 71 Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f)); 72 Node* call = graph()->NewNode(javascript()->Call(3, NO_CALL_FUNCTION_FLAGS), 73 fun, UndefinedConstant(), p0); 74 Reduction r = Reduce(call); 75 76 ASSERT_TRUE(r.Changed()); 77 EXPECT_THAT(r.replacement(), IsFloat64Sqrt(p0)); 78 } 79} 80 81 82// ----------------------------------------------------------------------------- 83// Math.max 84 85 86TEST_F(JSBuiltinReducerTest, MathMax0) { 87 Handle<JSFunction> f(isolate()->context()->math_max_fun()); 88 89 Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f)); 90 Node* call = graph()->NewNode(javascript()->Call(2, NO_CALL_FUNCTION_FLAGS), 91 fun, UndefinedConstant()); 92 Reduction r = Reduce(call); 93 94 ASSERT_TRUE(r.Changed()); 95 EXPECT_THAT(r.replacement(), IsNumberConstant(-V8_INFINITY)); 96} 97 98 99TEST_F(JSBuiltinReducerTest, MathMax1) { 100 Handle<JSFunction> f(isolate()->context()->math_max_fun()); 101 102 TRACED_FOREACH(Type*, t0, kNumberTypes) { 103 Node* p0 = Parameter(t0, 0); 104 Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f)); 105 Node* call = graph()->NewNode(javascript()->Call(3, NO_CALL_FUNCTION_FLAGS), 106 fun, UndefinedConstant(), p0); 107 Reduction r = Reduce(call); 108 109 ASSERT_TRUE(r.Changed()); 110 EXPECT_THAT(r.replacement(), p0); 111 } 112} 113 114 115TEST_F(JSBuiltinReducerTest, MathMax2) { 116 Handle<JSFunction> f(isolate()->context()->math_max_fun()); 117 118 TRACED_FOREACH(Type*, t0, kNumberTypes) { 119 TRACED_FOREACH(Type*, t1, kNumberTypes) { 120 Node* p0 = Parameter(t0, 0); 121 Node* p1 = Parameter(t1, 1); 122 Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f)); 123 Node* call = 124 graph()->NewNode(javascript()->Call(4, NO_CALL_FUNCTION_FLAGS), fun, 125 UndefinedConstant(), p0, p1); 126 Reduction r = Reduce(call); 127 128 if (t0->Is(Type::Integral32()) && t1->Is(Type::Integral32())) { 129 Capture<Node*> branch; 130 ASSERT_TRUE(r.Changed()); 131 EXPECT_THAT( 132 r.replacement(), 133 IsPhi(kMachNone, p1, p0, 134 IsMerge(IsIfTrue(CaptureEq(&branch)), 135 IsIfFalse(AllOf(CaptureEq(&branch), 136 IsBranch(IsNumberLessThan(p0, p1), 137 graph()->start())))))); 138 } else { 139 ASSERT_FALSE(r.Changed()); 140 EXPECT_EQ(IrOpcode::kJSCallFunction, call->opcode()); 141 } 142 } 143 } 144} 145 146 147// ----------------------------------------------------------------------------- 148// Math.imul 149 150 151TEST_F(JSBuiltinReducerTest, MathImul) { 152 Handle<JSFunction> f(isolate()->context()->math_imul_fun()); 153 154 TRACED_FOREACH(Type*, t0, kNumberTypes) { 155 TRACED_FOREACH(Type*, t1, kNumberTypes) { 156 Node* p0 = Parameter(t0, 0); 157 Node* p1 = Parameter(t1, 1); 158 Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f)); 159 Node* call = 160 graph()->NewNode(javascript()->Call(4, NO_CALL_FUNCTION_FLAGS), fun, 161 UndefinedConstant(), p0, p1); 162 Reduction r = Reduce(call); 163 164 if (t0->Is(Type::Integral32()) && t1->Is(Type::Integral32())) { 165 ASSERT_TRUE(r.Changed()); 166 EXPECT_THAT(r.replacement(), IsInt32Mul(p0, p1)); 167 } else { 168 ASSERT_FALSE(r.Changed()); 169 EXPECT_EQ(IrOpcode::kJSCallFunction, call->opcode()); 170 } 171 } 172 } 173} 174 175} // namespace compiler 176} // namespace internal 177} // namespace v8 178