blob: 9c572820e7131e475370c3e31110aa28ad502938 [file] [log] [blame]
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001// 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-inl.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
13using testing::BitEq;
14using testing::Capture;
15
16namespace v8 {
17namespace internal {
18namespace compiler {
19
20class 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(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
52namespace {
53
54// TODO(mstarzinger): Find a common place and unify with test-js-typed-lowering.
55Type* const kNumberTypes[] = {
56 Type::UnsignedSmall(), Type::NegativeSigned32(),
57 Type::NonNegativeSigned32(), Type::SignedSmall(),
58 Type::Signed32(), Type::Unsigned32(),
59 Type::Integral32(), Type::MinusZero(),
60 Type::NaN(), Type::OrderedNumber(),
61 Type::PlainNumber(), Type::Number()};
62
63} // namespace
64
65
66// -----------------------------------------------------------------------------
67// Math.abs
68
69
70TEST_F(JSBuiltinReducerTest, MathAbs) {
71 Handle<JSFunction> f = MathFunction("abs");
72
73 TRACED_FOREACH(Type*, t0, kNumberTypes) {
74 Node* p0 = Parameter(t0, 0);
75 Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
76 Node* call =
77 graph()->NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS),
78 fun, UndefinedConstant(), p0);
79 Reduction r = Reduce(call);
80
81 if (t0->Is(Type::Unsigned32())) {
82 ASSERT_TRUE(r.Changed());
83 EXPECT_THAT(r.replacement(), p0);
84 } else {
85 Capture<Node*> branch;
86 ASSERT_TRUE(r.Changed());
87 EXPECT_THAT(
88 r.replacement(),
89 IsSelect(kMachNone,
90 IsNumberLessThan(IsNumberConstant(BitEq(0.0)), p0), p0,
91 IsNumberSubtract(IsNumberConstant(BitEq(0.0)), p0)));
92 }
93 }
94}
95
96
97// -----------------------------------------------------------------------------
98// Math.sqrt
99
100
101TEST_F(JSBuiltinReducerTest, MathSqrt) {
102 Handle<JSFunction> f = MathFunction("sqrt");
103
104 TRACED_FOREACH(Type*, t0, kNumberTypes) {
105 Node* p0 = Parameter(t0, 0);
106 Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
107 Node* call =
108 graph()->NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS),
109 fun, UndefinedConstant(), p0);
110 Reduction r = Reduce(call);
111
112 ASSERT_TRUE(r.Changed());
113 EXPECT_THAT(r.replacement(), IsFloat64Sqrt(p0));
114 }
115}
116
117
118// -----------------------------------------------------------------------------
119// Math.max
120
121
122TEST_F(JSBuiltinReducerTest, MathMax0) {
123 Handle<JSFunction> f = MathFunction("max");
124
125 Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
126 Node* call =
127 graph()->NewNode(javascript()->CallFunction(2, NO_CALL_FUNCTION_FLAGS),
128 fun, UndefinedConstant());
129 Reduction r = Reduce(call);
130
131 ASSERT_TRUE(r.Changed());
132 EXPECT_THAT(r.replacement(), IsNumberConstant(-V8_INFINITY));
133}
134
135
136TEST_F(JSBuiltinReducerTest, MathMax1) {
137 Handle<JSFunction> f = MathFunction("max");
138
139 TRACED_FOREACH(Type*, t0, kNumberTypes) {
140 Node* p0 = Parameter(t0, 0);
141 Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
142 Node* call =
143 graph()->NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS),
144 fun, UndefinedConstant(), p0);
145 Reduction r = Reduce(call);
146
147 ASSERT_TRUE(r.Changed());
148 EXPECT_THAT(r.replacement(), p0);
149 }
150}
151
152
153TEST_F(JSBuiltinReducerTest, MathMax2) {
154 Handle<JSFunction> f = MathFunction("max");
155
156 TRACED_FOREACH(Type*, t0, kNumberTypes) {
157 TRACED_FOREACH(Type*, t1, kNumberTypes) {
158 Node* p0 = Parameter(t0, 0);
159 Node* p1 = Parameter(t1, 1);
160 Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
161 Node* call = graph()->NewNode(
162 javascript()->CallFunction(4, NO_CALL_FUNCTION_FLAGS), fun,
163 UndefinedConstant(), p0, p1);
164 Reduction r = Reduce(call);
165
166 if (t0->Is(Type::Integral32()) && t1->Is(Type::Integral32())) {
167 ASSERT_TRUE(r.Changed());
168 EXPECT_THAT(r.replacement(),
169 IsSelect(kMachNone, IsNumberLessThan(p1, p0), p1, p0));
170 } else {
171 ASSERT_FALSE(r.Changed());
172 EXPECT_EQ(IrOpcode::kJSCallFunction, call->opcode());
173 }
174 }
175 }
176}
177
178
179// -----------------------------------------------------------------------------
180// Math.imul
181
182
183TEST_F(JSBuiltinReducerTest, MathImul) {
184 Handle<JSFunction> f = MathFunction("imul");
185
186 TRACED_FOREACH(Type*, t0, kNumberTypes) {
187 TRACED_FOREACH(Type*, t1, kNumberTypes) {
188 Node* p0 = Parameter(t0, 0);
189 Node* p1 = Parameter(t1, 1);
190 Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
191 Node* call = graph()->NewNode(
192 javascript()->CallFunction(4, NO_CALL_FUNCTION_FLAGS), fun,
193 UndefinedConstant(), p0, p1);
194 Reduction r = Reduce(call);
195
196 if (t0->Is(Type::Integral32()) && t1->Is(Type::Integral32())) {
197 ASSERT_TRUE(r.Changed());
198 EXPECT_THAT(r.replacement(), IsInt32Mul(p0, p1));
199 } else {
200 ASSERT_FALSE(r.Changed());
201 EXPECT_EQ(IrOpcode::kJSCallFunction, call->opcode());
202 }
203 }
204 }
205}
206
207
208// -----------------------------------------------------------------------------
209// Math.fround
210
211
212TEST_F(JSBuiltinReducerTest, MathFround) {
213 Handle<JSFunction> f = MathFunction("fround");
214
215 TRACED_FOREACH(Type*, t0, kNumberTypes) {
216 Node* p0 = Parameter(t0, 0);
217 Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
218 Node* call =
219 graph()->NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS),
220 fun, UndefinedConstant(), p0);
221 Reduction r = Reduce(call);
222
223 ASSERT_TRUE(r.Changed());
224 EXPECT_THAT(r.replacement(), IsTruncateFloat64ToFloat32(p0));
225 }
226}
227
228
229// -----------------------------------------------------------------------------
230// Math.floor
231
232
233TEST_F(JSBuiltinReducerTest, MathFloorAvailable) {
234 Handle<JSFunction> f = MathFunction("floor");
235
236 TRACED_FOREACH(Type*, t0, kNumberTypes) {
237 Node* p0 = Parameter(t0, 0);
238 Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
239 Node* call =
240 graph()->NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS),
241 fun, UndefinedConstant(), p0);
242 Reduction r = Reduce(call, MachineOperatorBuilder::Flag::kFloat64Floor);
243
244 ASSERT_TRUE(r.Changed());
245 EXPECT_THAT(r.replacement(), IsFloat64Floor(p0));
246 }
247}
248
249
250TEST_F(JSBuiltinReducerTest, MathFloorUnavailable) {
251 Handle<JSFunction> f = MathFunction("floor");
252
253 TRACED_FOREACH(Type*, t0, kNumberTypes) {
254 Node* p0 = Parameter(t0, 0);
255 Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
256 Node* call =
257 graph()->NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS),
258 fun, UndefinedConstant(), p0);
259 Reduction r = Reduce(call, MachineOperatorBuilder::Flag::kNoFlags);
260
261 ASSERT_FALSE(r.Changed());
262 }
263}
264
265
266// -----------------------------------------------------------------------------
267// Math.ceil
268
269
270TEST_F(JSBuiltinReducerTest, MathCeilAvailable) {
271 Handle<JSFunction> f = MathFunction("ceil");
272
273 TRACED_FOREACH(Type*, t0, kNumberTypes) {
274 Node* p0 = Parameter(t0, 0);
275 Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
276 Node* call =
277 graph()->NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS),
278 fun, UndefinedConstant(), p0);
279 Reduction r = Reduce(call, MachineOperatorBuilder::Flag::kFloat64Ceil);
280
281 ASSERT_TRUE(r.Changed());
282 EXPECT_THAT(r.replacement(), IsFloat64Ceil(p0));
283 }
284}
285
286
287TEST_F(JSBuiltinReducerTest, MathCeilUnavailable) {
288 Handle<JSFunction> f = MathFunction("ceil");
289
290 TRACED_FOREACH(Type*, t0, kNumberTypes) {
291 Node* p0 = Parameter(t0, 0);
292 Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
293 Node* call =
294 graph()->NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS),
295 fun, UndefinedConstant(), p0);
296 Reduction r = Reduce(call, MachineOperatorBuilder::Flag::kNoFlags);
297
298 ASSERT_FALSE(r.Changed());
299 }
300}
301} // namespace compiler
302} // namespace internal
303} // namespace v8