b5c688e147616f68e26d376ce43565d29ea15d78
[platform/upstream/nodejs.git] / deps / v8 / test / unittests / compiler / js-builtin-reducer-unittest.cc
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/js-builtin-reducer.h"
6 #include "src/compiler/js-graph.h"
7 #include "src/compiler/node-properties.h"
8 #include "src/compiler/typer.h"
9 #include "test/unittests/compiler/graph-unittest.h"
10 #include "test/unittests/compiler/node-test-utils.h"
11 #include "testing/gmock-support.h"
12
13 using testing::BitEq;
14 using testing::Capture;
15
16 namespace v8 {
17 namespace internal {
18 namespace compiler {
19
20 class JSBuiltinReducerTest : public TypedGraphTest {
21  public:
22   JSBuiltinReducerTest() : javascript_(zone()) {}
23
24  protected:
25   Reduction Reduce(Node* node, MachineOperatorBuilder::Flags flags =
26                                    MachineOperatorBuilder::Flag::kNoFlags) {
27     MachineOperatorBuilder machine(zone(), kMachPtr, flags);
28     JSGraph jsgraph(isolate(), graph(), common(), javascript(), &machine);
29     JSBuiltinReducer reducer(&jsgraph);
30     return reducer.Reduce(node);
31   }
32
33   Handle<JSFunction> MathFunction(const char* name) {
34     Handle<Object> m =
35         JSObject::GetProperty(isolate()->global_object(),
36                               isolate()->factory()->NewStringFromAsciiChecked(
37                                   "Math")).ToHandleChecked();
38     Handle<JSFunction> f = Handle<JSFunction>::cast(
39         JSObject::GetProperty(
40             m, isolate()->factory()->NewStringFromAsciiChecked(name))
41             .ToHandleChecked());
42     return f;
43   }
44
45   JSOperatorBuilder* javascript() { return &javascript_; }
46
47  private:
48   JSOperatorBuilder javascript_;
49 };
50
51
52 namespace {
53
54 // TODO(mstarzinger): Find a common place and unify with test-js-typed-lowering.
55 Type* const kNumberTypes[] = {
56     Type::UnsignedSmall(), Type::Negative32(),  Type::Unsigned31(),
57     Type::SignedSmall(),   Type::Signed32(),    Type::Unsigned32(),
58     Type::Integral32(),    Type::MinusZero(),   Type::NaN(),
59     Type::OrderedNumber(), Type::PlainNumber(), Type::Number()};
60
61 }  // namespace
62
63
64 // -----------------------------------------------------------------------------
65 // Math.abs
66
67
68 TEST_F(JSBuiltinReducerTest, MathAbs) {
69   Handle<JSFunction> f = MathFunction("abs");
70
71   TRACED_FOREACH(Type*, t0, kNumberTypes) {
72     Node* p0 = Parameter(t0, 0);
73     Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
74     Node* call =
75         graph()->NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS),
76                          fun, UndefinedConstant(), p0);
77     Reduction r = Reduce(call);
78
79     if (t0->Is(Type::Unsigned32())) {
80       ASSERT_TRUE(r.Changed());
81       EXPECT_THAT(r.replacement(), p0);
82     } else {
83       Capture<Node*> branch;
84       ASSERT_TRUE(r.Changed());
85       EXPECT_THAT(
86           r.replacement(),
87           IsSelect(kMachNone,
88                    IsNumberLessThan(IsNumberConstant(BitEq(0.0)), p0), p0,
89                    IsNumberSubtract(IsNumberConstant(BitEq(0.0)), p0)));
90     }
91   }
92 }
93
94
95 // -----------------------------------------------------------------------------
96 // Math.sqrt
97
98
99 TEST_F(JSBuiltinReducerTest, MathSqrt) {
100   Handle<JSFunction> f = MathFunction("sqrt");
101
102   TRACED_FOREACH(Type*, t0, kNumberTypes) {
103     Node* p0 = Parameter(t0, 0);
104     Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
105     Node* call =
106         graph()->NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS),
107                          fun, UndefinedConstant(), p0);
108     Reduction r = Reduce(call);
109
110     ASSERT_TRUE(r.Changed());
111     EXPECT_THAT(r.replacement(), IsFloat64Sqrt(p0));
112   }
113 }
114
115
116 // -----------------------------------------------------------------------------
117 // Math.max
118
119
120 TEST_F(JSBuiltinReducerTest, MathMax0) {
121   Handle<JSFunction> f = MathFunction("max");
122
123   Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
124   Node* call =
125       graph()->NewNode(javascript()->CallFunction(2, NO_CALL_FUNCTION_FLAGS),
126                        fun, UndefinedConstant());
127   Reduction r = Reduce(call);
128
129   ASSERT_TRUE(r.Changed());
130   EXPECT_THAT(r.replacement(), IsNumberConstant(-V8_INFINITY));
131 }
132
133
134 TEST_F(JSBuiltinReducerTest, MathMax1) {
135   Handle<JSFunction> f = MathFunction("max");
136
137   TRACED_FOREACH(Type*, t0, kNumberTypes) {
138     Node* p0 = Parameter(t0, 0);
139     Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
140     Node* call =
141         graph()->NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS),
142                          fun, UndefinedConstant(), p0);
143     Reduction r = Reduce(call);
144
145     ASSERT_TRUE(r.Changed());
146     EXPECT_THAT(r.replacement(), p0);
147   }
148 }
149
150
151 TEST_F(JSBuiltinReducerTest, MathMax2) {
152   Handle<JSFunction> f = MathFunction("max");
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 = graph()->NewNode(
160           javascript()->CallFunction(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(),
167                     IsSelect(kMachNone, IsNumberLessThan(p1, p0), p0, p1));
168       } else {
169         ASSERT_FALSE(r.Changed());
170         EXPECT_EQ(IrOpcode::kJSCallFunction, call->opcode());
171       }
172     }
173   }
174 }
175
176
177 // -----------------------------------------------------------------------------
178 // Math.imul
179
180
181 TEST_F(JSBuiltinReducerTest, MathImul) {
182   Handle<JSFunction> f = MathFunction("imul");
183
184   TRACED_FOREACH(Type*, t0, kNumberTypes) {
185     TRACED_FOREACH(Type*, t1, kNumberTypes) {
186       Node* p0 = Parameter(t0, 0);
187       Node* p1 = Parameter(t1, 1);
188       Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
189       Node* call = graph()->NewNode(
190           javascript()->CallFunction(4, NO_CALL_FUNCTION_FLAGS), fun,
191           UndefinedConstant(), p0, p1);
192       Reduction r = Reduce(call);
193
194       if (t0->Is(Type::Integral32()) && t1->Is(Type::Integral32())) {
195         ASSERT_TRUE(r.Changed());
196         EXPECT_THAT(r.replacement(), IsInt32Mul(p0, p1));
197       } else {
198         ASSERT_FALSE(r.Changed());
199         EXPECT_EQ(IrOpcode::kJSCallFunction, call->opcode());
200       }
201     }
202   }
203 }
204
205
206 // -----------------------------------------------------------------------------
207 // Math.fround
208
209
210 TEST_F(JSBuiltinReducerTest, MathFround) {
211   Handle<JSFunction> f = MathFunction("fround");
212
213   TRACED_FOREACH(Type*, t0, kNumberTypes) {
214     Node* p0 = Parameter(t0, 0);
215     Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
216     Node* call =
217         graph()->NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS),
218                          fun, UndefinedConstant(), p0);
219     Reduction r = Reduce(call);
220
221     ASSERT_TRUE(r.Changed());
222     EXPECT_THAT(r.replacement(), IsTruncateFloat64ToFloat32(p0));
223   }
224 }
225
226
227 // -----------------------------------------------------------------------------
228 // Math.floor
229
230
231 TEST_F(JSBuiltinReducerTest, MathFloorAvailable) {
232   Handle<JSFunction> f = MathFunction("floor");
233
234   TRACED_FOREACH(Type*, t0, kNumberTypes) {
235     Node* p0 = Parameter(t0, 0);
236     Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
237     Node* call =
238         graph()->NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS),
239                          fun, UndefinedConstant(), p0);
240     Reduction r = Reduce(call, MachineOperatorBuilder::Flag::kFloat64Floor);
241
242     ASSERT_TRUE(r.Changed());
243     EXPECT_THAT(r.replacement(), IsFloat64Floor(p0));
244   }
245 }
246
247
248 TEST_F(JSBuiltinReducerTest, MathFloorUnavailable) {
249   Handle<JSFunction> f = MathFunction("floor");
250
251   TRACED_FOREACH(Type*, t0, kNumberTypes) {
252     Node* p0 = Parameter(t0, 0);
253     Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
254     Node* call =
255         graph()->NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS),
256                          fun, UndefinedConstant(), p0);
257     Reduction r = Reduce(call, MachineOperatorBuilder::Flag::kNoFlags);
258
259     ASSERT_FALSE(r.Changed());
260   }
261 }
262
263
264 // -----------------------------------------------------------------------------
265 // Math.ceil
266
267
268 TEST_F(JSBuiltinReducerTest, MathCeilAvailable) {
269   Handle<JSFunction> f = MathFunction("ceil");
270
271   TRACED_FOREACH(Type*, t0, kNumberTypes) {
272     Node* p0 = Parameter(t0, 0);
273     Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
274     Node* call =
275         graph()->NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS),
276                          fun, UndefinedConstant(), p0);
277     Reduction r = Reduce(call, MachineOperatorBuilder::Flag::kFloat64Ceil);
278
279     ASSERT_TRUE(r.Changed());
280     EXPECT_THAT(r.replacement(), IsFloat64Ceil(p0));
281   }
282 }
283
284
285 TEST_F(JSBuiltinReducerTest, MathCeilUnavailable) {
286   Handle<JSFunction> f = MathFunction("ceil");
287
288   TRACED_FOREACH(Type*, t0, kNumberTypes) {
289     Node* p0 = Parameter(t0, 0);
290     Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
291     Node* call =
292         graph()->NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS),
293                          fun, UndefinedConstant(), p0);
294     Reduction r = Reduce(call, MachineOperatorBuilder::Flag::kNoFlags);
295
296     ASSERT_FALSE(r.Changed());
297   }
298 }
299 }  // namespace compiler
300 }  // namespace internal
301 }  // namespace v8