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 
12 using testing::Capture;
13 
14 namespace v8 {
15 namespace internal {
16 namespace compiler {
17 
18 class JSBuiltinReducerTest : public GraphTest {
19  public:
JSBuiltinReducerTest()20   JSBuiltinReducerTest() : javascript_(zone()) {}
21 
22  protected:
Reduce(Node * node)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 
Parameter(Type * t,int32_t index=0)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 
UndefinedConstant()37   Node* UndefinedConstant() {
38     return HeapConstant(
39         Unique<HeapObject>::CreateImmovable(factory()->undefined_value()));
40   }
41 
javascript()42   JSOperatorBuilder* javascript() { return &javascript_; }
43 
44  private:
45   JSOperatorBuilder javascript_;
46 };
47 
48 
49 namespace {
50 
51 // TODO(mstarzinger): Find a common place and unify with test-js-typed-lowering.
52 Type* 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 
TEST_F(JSBuiltinReducerTest,MathSqrt)66 TEST_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 
TEST_F(JSBuiltinReducerTest,MathMax0)86 TEST_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 
TEST_F(JSBuiltinReducerTest,MathMax1)99 TEST_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 
TEST_F(JSBuiltinReducerTest,MathMax2)115 TEST_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 
TEST_F(JSBuiltinReducerTest,MathImul)151 TEST_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