blob: f38f8eaac7b3789f0155e971812214afdd90fa72 [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// Copyright 2015 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/access-builder.h"
6#include "src/compiler/diamond.h"
7#include "src/compiler/js-graph.h"
8#include "src/compiler/js-intrinsic-lowering.h"
9#include "src/compiler/js-operator.h"
10#include "src/types-inl.h"
11#include "test/unittests/compiler/graph-unittest.h"
12#include "test/unittests/compiler/node-test-utils.h"
13#include "testing/gmock-support.h"
14
15
16using testing::_;
17using testing::AllOf;
18using testing::BitEq;
19using testing::Capture;
20using testing::CaptureEq;
21
22
23namespace v8 {
24namespace internal {
25namespace compiler {
26
27class JSIntrinsicLoweringTest : public TypedGraphTest {
28 public:
29 JSIntrinsicLoweringTest() : TypedGraphTest(3), javascript_(zone()) {}
30 ~JSIntrinsicLoweringTest() override {}
31
32 protected:
33 Reduction Reduce(Node* node, MachineOperatorBuilder::Flags flags =
34 MachineOperatorBuilder::kNoFlags) {
35 MachineOperatorBuilder machine(zone(), MachineType::PointerRepresentation(),
36 flags);
37 SimplifiedOperatorBuilder simplified(zone());
38 JSGraph jsgraph(isolate(), graph(), common(), javascript(), &simplified,
39 &machine);
40 // TODO(titzer): mock the GraphReducer here for better unit testing.
41 GraphReducer graph_reducer(zone(), graph());
42 JSIntrinsicLowering reducer(&graph_reducer, &jsgraph,
43 JSIntrinsicLowering::kDeoptimizationEnabled);
44 return reducer.Reduce(node);
45 }
46
47 Node* EmptyFrameState() {
48 MachineOperatorBuilder machine(zone());
49 JSGraph jsgraph(isolate(), graph(), common(), javascript(), nullptr,
50 &machine);
51 return jsgraph.EmptyFrameState();
52 }
53
54 JSOperatorBuilder* javascript() { return &javascript_; }
55
56 private:
57 JSOperatorBuilder javascript_;
58};
59
60
61// -----------------------------------------------------------------------------
62// %_ConstructDouble
63
64
65TEST_F(JSIntrinsicLoweringTest, InlineOptimizedConstructDouble) {
66 Node* const input0 = Parameter(0);
67 Node* const input1 = Parameter(1);
68 Node* const context = Parameter(2);
69 Node* const effect = graph()->start();
70 Node* const control = graph()->start();
71 Reduction const r = Reduce(graph()->NewNode(
72 javascript()->CallRuntime(Runtime::kInlineConstructDouble, 2), input0,
73 input1, context, effect, control));
74 ASSERT_TRUE(r.Changed());
75 EXPECT_THAT(r.replacement(), IsFloat64InsertHighWord32(
76 IsFloat64InsertLowWord32(
77 IsNumberConstant(BitEq(0.0)), input1),
78 input0));
79}
80
81
82// -----------------------------------------------------------------------------
83// %_DoubleLo
84
85
86TEST_F(JSIntrinsicLoweringTest, InlineOptimizedDoubleLo) {
87 Node* const input = Parameter(0);
88 Node* const context = Parameter(1);
89 Node* const effect = graph()->start();
90 Node* const control = graph()->start();
91 Reduction const r = Reduce(
92 graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineDoubleLo, 1),
93 input, context, effect, control));
94 ASSERT_TRUE(r.Changed());
95 EXPECT_THAT(r.replacement(), IsFloat64ExtractLowWord32(input));
96}
97
98
99// -----------------------------------------------------------------------------
100// %_DoubleHi
101
102
103TEST_F(JSIntrinsicLoweringTest, InlineOptimizedDoubleHi) {
104 Node* const input = Parameter(0);
105 Node* const context = Parameter(1);
106 Node* const effect = graph()->start();
107 Node* const control = graph()->start();
108 Reduction const r = Reduce(
109 graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineDoubleHi, 1),
110 input, context, effect, control));
111 ASSERT_TRUE(r.Changed());
112 EXPECT_THAT(r.replacement(), IsFloat64ExtractHighWord32(input));
113}
114
115
116// -----------------------------------------------------------------------------
117// %_IsSmi
118
119
120TEST_F(JSIntrinsicLoweringTest, InlineIsSmi) {
121 Node* const input = Parameter(0);
122 Node* const context = Parameter(1);
123 Node* const effect = graph()->start();
124 Node* const control = graph()->start();
125 Reduction const r = Reduce(
126 graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineIsSmi, 1),
127 input, context, effect, control));
128 ASSERT_TRUE(r.Changed());
129 EXPECT_THAT(r.replacement(), IsObjectIsSmi(input));
130}
131
132
133// -----------------------------------------------------------------------------
134// %_IsArray
135
136
137TEST_F(JSIntrinsicLoweringTest, InlineIsArray) {
138 Node* const input = Parameter(0);
139 Node* const context = Parameter(1);
140 Node* const effect = graph()->start();
141 Node* const control = graph()->start();
142 Reduction const r = Reduce(
143 graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineIsArray, 1),
144 input, context, effect, control));
145 ASSERT_TRUE(r.Changed());
146
147 Node* phi = r.replacement();
148 Capture<Node*> branch, if_false;
149 EXPECT_THAT(
150 phi,
151 IsPhi(
152 MachineRepresentation::kTagged, IsFalseConstant(),
153 IsWord32Equal(IsLoadField(AccessBuilder::ForMapInstanceType(),
154 IsLoadField(AccessBuilder::ForMap(), input,
155 effect, CaptureEq(&if_false)),
156 effect, _),
157 IsInt32Constant(JS_ARRAY_TYPE)),
158 IsMerge(IsIfTrue(AllOf(CaptureEq(&branch),
159 IsBranch(IsObjectIsSmi(input), control))),
160 AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch))))));
161}
162
163
164// -----------------------------------------------------------------------------
165// %_IsDate
166
167
168TEST_F(JSIntrinsicLoweringTest, InlineIsDate) {
169 Node* const input = Parameter(0);
170 Node* const context = Parameter(1);
171 Node* const effect = graph()->start();
172 Node* const control = graph()->start();
173 Reduction const r = Reduce(
174 graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineIsDate, 1),
175 input, context, effect, control));
176 ASSERT_TRUE(r.Changed());
177
178 Node* phi = r.replacement();
179 Capture<Node*> branch, if_false;
180 EXPECT_THAT(
181 phi,
182 IsPhi(
183 MachineRepresentation::kTagged, IsFalseConstant(),
184 IsWord32Equal(IsLoadField(AccessBuilder::ForMapInstanceType(),
185 IsLoadField(AccessBuilder::ForMap(), input,
186 effect, CaptureEq(&if_false)),
187 effect, _),
188 IsInt32Constant(JS_DATE_TYPE)),
189 IsMerge(IsIfTrue(AllOf(CaptureEq(&branch),
190 IsBranch(IsObjectIsSmi(input), control))),
191 AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch))))));
192}
193
194
195// -----------------------------------------------------------------------------
196// %_IsTypedArray
197
198
199TEST_F(JSIntrinsicLoweringTest, InlineIsTypedArray) {
200 Node* const input = Parameter(0);
201 Node* const context = Parameter(1);
202 Node* const effect = graph()->start();
203 Node* const control = graph()->start();
204 Reduction const r = Reduce(graph()->NewNode(
205 javascript()->CallRuntime(Runtime::kInlineIsTypedArray, 1), input,
206 context, effect, control));
207 ASSERT_TRUE(r.Changed());
208
209 Node* phi = r.replacement();
210 Capture<Node*> branch, if_false;
211 EXPECT_THAT(
212 phi,
213 IsPhi(
214 MachineRepresentation::kTagged, IsFalseConstant(),
215 IsWord32Equal(IsLoadField(AccessBuilder::ForMapInstanceType(),
216 IsLoadField(AccessBuilder::ForMap(), input,
217 effect, CaptureEq(&if_false)),
218 effect, _),
219 IsInt32Constant(JS_TYPED_ARRAY_TYPE)),
220 IsMerge(IsIfTrue(AllOf(CaptureEq(&branch),
221 IsBranch(IsObjectIsSmi(input), control))),
222 AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch))))));
223}
224
225
226// -----------------------------------------------------------------------------
227// %_IsFunction
228
229
230TEST_F(JSIntrinsicLoweringTest, InlineIsFunction) {
231 Node* const input = Parameter(Type::Any());
232 Node* const context = Parameter(Type::Any());
233 Node* const effect = graph()->start();
234 Node* const control = graph()->start();
235 Reduction const r = Reduce(
236 graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineIsFunction, 1),
237 input, context, effect, control));
238 ASSERT_TRUE(r.Changed());
239
240 Node* phi = r.replacement();
241 Capture<Node*> branch, if_false;
242 EXPECT_THAT(
243 phi,
244 IsPhi(
245 MachineRepresentation::kTagged, IsFalseConstant(),
246 IsUint32LessThanOrEqual(
247 IsInt32Constant(FIRST_FUNCTION_TYPE),
248 IsLoadField(AccessBuilder::ForMapInstanceType(),
249 IsLoadField(AccessBuilder::ForMap(), input, effect,
250 CaptureEq(&if_false)),
251 effect, _)),
252 IsMerge(IsIfTrue(AllOf(CaptureEq(&branch),
253 IsBranch(IsObjectIsSmi(input), control))),
254 AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch))))));
255}
256
257
258// -----------------------------------------------------------------------------
259// %_IsRegExp
260
261
262TEST_F(JSIntrinsicLoweringTest, InlineIsRegExp) {
263 Node* const input = Parameter(0);
264 Node* const context = Parameter(1);
265 Node* const effect = graph()->start();
266 Node* const control = graph()->start();
267 Reduction const r = Reduce(
268 graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineIsRegExp, 1),
269 input, context, effect, control));
270 ASSERT_TRUE(r.Changed());
271
272 Node* phi = r.replacement();
273 Capture<Node*> branch, if_false;
274 EXPECT_THAT(
275 phi,
276 IsPhi(
277 MachineRepresentation::kTagged, IsFalseConstant(),
278 IsWord32Equal(IsLoadField(AccessBuilder::ForMapInstanceType(),
279 IsLoadField(AccessBuilder::ForMap(), input,
280 effect, CaptureEq(&if_false)),
281 effect, _),
282 IsInt32Constant(JS_REGEXP_TYPE)),
283 IsMerge(IsIfTrue(AllOf(CaptureEq(&branch),
284 IsBranch(IsObjectIsSmi(input), control))),
285 AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch))))));
286}
287
288
289// -----------------------------------------------------------------------------
290// %_IsJSReceiver
291
292
293TEST_F(JSIntrinsicLoweringTest, InlineIsJSReceiverWithAny) {
294 Node* const input = Parameter(Type::Any());
295 Node* const context = Parameter(Type::Any());
296 Node* const effect = graph()->start();
297 Node* const control = graph()->start();
298 Reduction const r = Reduce(graph()->NewNode(
299 javascript()->CallRuntime(Runtime::kInlineIsJSReceiver, 1), input,
300 context, effect, control));
301 ASSERT_TRUE(r.Changed());
302
303 Node* phi = r.replacement();
304 Capture<Node *> branch, if_false;
305 EXPECT_THAT(
306 phi,
307 IsPhi(
308 MachineRepresentation::kTagged, IsFalseConstant(),
309 IsUint32LessThanOrEqual(
310 IsInt32Constant(FIRST_JS_RECEIVER_TYPE),
311 IsLoadField(AccessBuilder::ForMapInstanceType(),
312 IsLoadField(AccessBuilder::ForMap(), input, effect,
313 CaptureEq(&if_false)),
314 effect, _)),
315 IsMerge(IsIfTrue(AllOf(CaptureEq(&branch),
316 IsBranch(IsObjectIsSmi(input), control))),
317 AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch))))));
318}
319
320
321TEST_F(JSIntrinsicLoweringTest, InlineIsJSReceiverWithReceiver) {
322 Node* const input = Parameter(Type::Receiver());
323 Node* const context = Parameter(Type::Any());
324 Node* const effect = graph()->start();
325 Node* const control = graph()->start();
326 Reduction const r = Reduce(graph()->NewNode(
327 javascript()->CallRuntime(Runtime::kInlineIsJSReceiver, 1), input,
328 context, effect, control));
329 ASSERT_TRUE(r.Changed());
330 EXPECT_THAT(r.replacement(), IsTrueConstant());
331}
332
333
334TEST_F(JSIntrinsicLoweringTest, InlineIsJSReceiverWithUndefined) {
335 Node* const input = Parameter(Type::Undefined());
336 Node* const context = Parameter(Type::Any());
337 Node* const effect = graph()->start();
338 Node* const control = graph()->start();
339 Reduction const r = Reduce(graph()->NewNode(
340 javascript()->CallRuntime(Runtime::kInlineIsJSReceiver, 1), input,
341 context, effect, control));
342 ASSERT_TRUE(r.Changed());
343 EXPECT_THAT(r.replacement(), IsFalseConstant());
344}
345
346
347// -----------------------------------------------------------------------------
348// %_JSValueGetValue
349
350
351TEST_F(JSIntrinsicLoweringTest, InlineJSValueGetValue) {
352 Node* const input = Parameter(0);
353 Node* const context = Parameter(1);
354 Node* const effect = graph()->start();
355 Node* const control = graph()->start();
356 Reduction const r = Reduce(graph()->NewNode(
357 javascript()->CallRuntime(Runtime::kInlineJSValueGetValue, 1), input,
358 context, effect, control));
359 ASSERT_TRUE(r.Changed());
360 EXPECT_THAT(r.replacement(),
361 IsLoadField(AccessBuilder::ForValue(), input, effect, control));
362}
363
364
365// -----------------------------------------------------------------------------
366// %_MathFloor
367
368
369TEST_F(JSIntrinsicLoweringTest, InlineMathFloor) {
370 Node* const input = Parameter(0);
371 Node* const context = Parameter(1);
372 Node* const effect = graph()->start();
373 Node* const control = graph()->start();
374 Reduction const r = Reduce(
375 graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineMathFloor, 1),
376 input, context, effect, control),
377 MachineOperatorBuilder::kFloat64RoundDown);
378 ASSERT_TRUE(r.Changed());
379 EXPECT_THAT(r.replacement(), IsFloat64RoundDown(input));
380}
381
382
383// -----------------------------------------------------------------------------
384// %_MathSqrt
385
386
387TEST_F(JSIntrinsicLoweringTest, InlineMathSqrt) {
388 Node* const input = Parameter(0);
389 Node* const context = Parameter(1);
390 Node* const effect = graph()->start();
391 Node* const control = graph()->start();
392 Reduction const r = Reduce(
393 graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineMathSqrt, 1),
394 input, context, effect, control));
395 ASSERT_TRUE(r.Changed());
396 EXPECT_THAT(r.replacement(), IsFloat64Sqrt(input));
397}
398
399
400// -----------------------------------------------------------------------------
401// %_MathClz32
402
403
404TEST_F(JSIntrinsicLoweringTest, InlineMathClz32) {
405 Node* const input = Parameter(0);
406 Node* const context = Parameter(1);
407 Node* const effect = graph()->start();
408 Node* const control = graph()->start();
409 Reduction const r = Reduce(
410 graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineMathClz32, 1),
411 input, context, effect, control));
412 ASSERT_TRUE(r.Changed());
413 EXPECT_THAT(r.replacement(), IsWord32Clz(input));
414}
415
416
417// -----------------------------------------------------------------------------
418// %_ValueOf
419
420
421TEST_F(JSIntrinsicLoweringTest, InlineValueOf) {
422 Node* const input = Parameter(0);
423 Node* const context = Parameter(1);
424 Node* const effect = graph()->start();
425 Node* const control = graph()->start();
426 Reduction const r = Reduce(
427 graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineValueOf, 1),
428 input, context, effect, control));
429 ASSERT_TRUE(r.Changed());
430
431 Node* phi = r.replacement();
432 Capture<Node*> branch0, if_false0, branch1, if_true1;
433 EXPECT_THAT(
434 phi,
435 IsPhi(
436 MachineRepresentation::kTagged, input,
437 IsPhi(MachineRepresentation::kTagged,
438 IsLoadField(AccessBuilder::ForValue(), input, effect,
439 CaptureEq(&if_true1)),
440 input,
441 IsMerge(
442 AllOf(CaptureEq(&if_true1), IsIfTrue(CaptureEq(&branch1))),
443 IsIfFalse(AllOf(
444 CaptureEq(&branch1),
445 IsBranch(
446 IsWord32Equal(
447 IsLoadField(
448 AccessBuilder::ForMapInstanceType(),
449 IsLoadField(AccessBuilder::ForMap(), input,
450 effect, CaptureEq(&if_false0)),
451 effect, _),
452 IsInt32Constant(JS_VALUE_TYPE)),
453 CaptureEq(&if_false0)))))),
454 IsMerge(
455 IsIfTrue(AllOf(CaptureEq(&branch0),
456 IsBranch(IsObjectIsSmi(input), control))),
457 AllOf(CaptureEq(&if_false0), IsIfFalse(CaptureEq(&branch0))))));
458}
459
460} // namespace compiler
461} // namespace internal
462} // namespace v8