1 // 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.
5 #include "src/compiler/access-builder.h"
6 #include "src/compiler/js-graph.h"
7 #include "src/compiler/js-intrinsic-lowering.h"
8 #include "src/compiler/js-operator.h"
9 #include "test/unittests/compiler/graph-unittest.h"
10 #include "test/unittests/compiler/node-test-utils.h"
11 #include "testing/gmock-support.h"
16 using testing::Capture;
17 using testing::CaptureEq;
24 class JSIntrinsicLoweringTest : public GraphTest {
26 JSIntrinsicLoweringTest() : GraphTest(3), javascript_(zone()) {}
27 ~JSIntrinsicLoweringTest() OVERRIDE {}
30 Reduction Reduce(Node* node, MachineOperatorBuilder::Flags flags =
31 MachineOperatorBuilder::kNoFlags) {
32 MachineOperatorBuilder machine(zone(), kMachPtr, flags);
33 JSGraph jsgraph(isolate(), graph(), common(), javascript(), &machine);
34 JSIntrinsicLowering reducer(&jsgraph);
35 return reducer.Reduce(node);
38 JSOperatorBuilder* javascript() { return &javascript_; }
41 JSOperatorBuilder javascript_;
45 // -----------------------------------------------------------------------------
49 TEST_F(JSIntrinsicLoweringTest, InlineOptimizedConstructDouble) {
50 Node* const input0 = Parameter(0);
51 Node* const input1 = Parameter(1);
52 Node* const context = Parameter(2);
53 Node* const effect = graph()->start();
54 Node* const control = graph()->start();
55 Reduction const r = Reduce(graph()->NewNode(
56 javascript()->CallRuntime(Runtime::kInlineConstructDouble, 2), input0,
57 input1, context, effect, control));
58 ASSERT_TRUE(r.Changed());
59 EXPECT_THAT(r.replacement(), IsFloat64InsertHighWord32(
60 IsFloat64InsertLowWord32(
61 IsNumberConstant(BitEq(0.0)), input1),
66 // -----------------------------------------------------------------------------
70 TEST_F(JSIntrinsicLoweringTest, InlineOptimizedDoubleLo) {
71 Node* const input = Parameter(0);
72 Node* const context = Parameter(1);
73 Node* const effect = graph()->start();
74 Node* const control = graph()->start();
75 Reduction const r = Reduce(
76 graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineDoubleLo, 1),
77 input, context, effect, control));
78 ASSERT_TRUE(r.Changed());
79 EXPECT_THAT(r.replacement(), IsFloat64ExtractLowWord32(input));
83 // -----------------------------------------------------------------------------
87 TEST_F(JSIntrinsicLoweringTest, InlineOptimizedDoubleHi) {
88 Node* const input = Parameter(0);
89 Node* const context = Parameter(1);
90 Node* const effect = graph()->start();
91 Node* const control = graph()->start();
92 Reduction const r = Reduce(
93 graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineDoubleHi, 1),
94 input, context, effect, control));
95 ASSERT_TRUE(r.Changed());
96 EXPECT_THAT(r.replacement(), IsFloat64ExtractHighWord32(input));
100 // -----------------------------------------------------------------------------
104 TEST_F(JSIntrinsicLoweringTest, InlineIsSmi) {
105 Node* const input = Parameter(0);
106 Node* const context = Parameter(1);
107 Node* const effect = graph()->start();
108 Node* const control = graph()->start();
109 Reduction const r = Reduce(
110 graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineIsSmi, 1),
111 input, context, effect, control));
112 ASSERT_TRUE(r.Changed());
113 EXPECT_THAT(r.replacement(), IsObjectIsSmi(input));
117 // -----------------------------------------------------------------------------
118 // %_IsNonNegativeSmi
121 TEST_F(JSIntrinsicLoweringTest, InlineIsNonNegativeSmi) {
122 Node* const input = Parameter(0);
123 Node* const context = Parameter(1);
124 Node* const effect = graph()->start();
125 Node* const control = graph()->start();
126 Reduction const r = Reduce(graph()->NewNode(
127 javascript()->CallRuntime(Runtime::kInlineIsNonNegativeSmi, 1), input,
128 context, effect, control));
129 ASSERT_TRUE(r.Changed());
130 EXPECT_THAT(r.replacement(), IsObjectIsNonNegativeSmi(input));
134 // -----------------------------------------------------------------------------
138 TEST_F(JSIntrinsicLoweringTest, InlineIsArray) {
139 Node* const input = Parameter(0);
140 Node* const context = Parameter(1);
141 Node* const effect = graph()->start();
142 Node* const control = graph()->start();
143 Reduction const r = Reduce(
144 graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineIsArray, 1),
145 input, context, effect, control));
146 ASSERT_TRUE(r.Changed());
148 Node* phi = r.replacement();
149 Capture<Node*> branch, if_false;
153 static_cast<MachineType>(kTypeBool | kRepTagged), IsFalseConstant(),
154 IsWord32Equal(IsLoadField(AccessBuilder::ForMapInstanceType(),
155 IsLoadField(AccessBuilder::ForMap(), input,
156 effect, CaptureEq(&if_false)),
158 IsInt32Constant(JS_ARRAY_TYPE)),
159 IsMerge(IsIfTrue(AllOf(CaptureEq(&branch),
160 IsBranch(IsObjectIsSmi(input), control))),
161 AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch))))));
165 // -----------------------------------------------------------------------------
169 TEST_F(JSIntrinsicLoweringTest, InlineIsFunction) {
170 Node* const input = Parameter(0);
171 Node* const context = Parameter(1);
172 Node* const effect = graph()->start();
173 Node* const control = graph()->start();
174 Reduction const r = Reduce(
175 graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineIsFunction, 1),
176 input, context, effect, control));
177 ASSERT_TRUE(r.Changed());
179 Node* phi = r.replacement();
180 Capture<Node*> branch, if_false;
184 static_cast<MachineType>(kTypeBool | kRepTagged), IsFalseConstant(),
185 IsWord32Equal(IsLoadField(AccessBuilder::ForMapInstanceType(),
186 IsLoadField(AccessBuilder::ForMap(), input,
187 effect, CaptureEq(&if_false)),
189 IsInt32Constant(JS_FUNCTION_TYPE)),
190 IsMerge(IsIfTrue(AllOf(CaptureEq(&branch),
191 IsBranch(IsObjectIsSmi(input), control))),
192 AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch))))));
196 // -----------------------------------------------------------------------------
200 TEST_F(JSIntrinsicLoweringTest, InlineIsRegExp) {
201 Node* const input = Parameter(0);
202 Node* const context = Parameter(1);
203 Node* const effect = graph()->start();
204 Node* const control = graph()->start();
205 Reduction const r = Reduce(
206 graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineIsRegExp, 1),
207 input, context, effect, control));
208 ASSERT_TRUE(r.Changed());
210 Node* phi = r.replacement();
211 Capture<Node*> branch, if_false;
215 static_cast<MachineType>(kTypeBool | kRepTagged), IsFalseConstant(),
216 IsWord32Equal(IsLoadField(AccessBuilder::ForMapInstanceType(),
217 IsLoadField(AccessBuilder::ForMap(), input,
218 effect, CaptureEq(&if_false)),
220 IsInt32Constant(JS_REGEXP_TYPE)),
221 IsMerge(IsIfTrue(AllOf(CaptureEq(&branch),
222 IsBranch(IsObjectIsSmi(input), control))),
223 AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch))))));
227 // -----------------------------------------------------------------------------
231 TEST_F(JSIntrinsicLoweringTest, InlineJSValueGetValue) {
232 Node* const input = Parameter(0);
233 Node* const context = Parameter(1);
234 Node* const effect = graph()->start();
235 Node* const control = graph()->start();
236 Reduction const r = Reduce(graph()->NewNode(
237 javascript()->CallRuntime(Runtime::kInlineJSValueGetValue, 1), input,
238 context, effect, control));
239 ASSERT_TRUE(r.Changed());
240 EXPECT_THAT(r.replacement(),
241 IsLoadField(AccessBuilder::ForValue(), input, effect, control));
245 // -----------------------------------------------------------------------------
249 TEST_F(JSIntrinsicLoweringTest, InlineMathFloor) {
250 Node* const input = Parameter(0);
251 Node* const context = Parameter(1);
252 Node* const effect = graph()->start();
253 Node* const control = graph()->start();
254 Reduction const r = Reduce(
255 graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineMathFloor, 1),
256 input, context, effect, control),
257 MachineOperatorBuilder::kFloat64RoundDown);
258 ASSERT_TRUE(r.Changed());
259 EXPECT_THAT(r.replacement(), IsFloat64RoundDown(input));
263 // -----------------------------------------------------------------------------
267 TEST_F(JSIntrinsicLoweringTest, InlineMathSqrt) {
268 Node* const input = Parameter(0);
269 Node* const context = Parameter(1);
270 Node* const effect = graph()->start();
271 Node* const control = graph()->start();
272 Reduction const r = Reduce(
273 graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineMathSqrt, 1),
274 input, context, effect, control));
275 ASSERT_TRUE(r.Changed());
276 EXPECT_THAT(r.replacement(), IsFloat64Sqrt(input));
280 // -----------------------------------------------------------------------------
284 TEST_F(JSIntrinsicLoweringTest, InlineStringGetLength) {
285 Node* const input = Parameter(0);
286 Node* const context = Parameter(1);
287 Node* const effect = graph()->start();
288 Node* const control = graph()->start();
289 Reduction const r = Reduce(graph()->NewNode(
290 javascript()->CallRuntime(Runtime::kInlineStringGetLength, 1), input,
291 context, effect, control));
292 ASSERT_TRUE(r.Changed());
293 EXPECT_THAT(r.replacement(), IsLoadField(AccessBuilder::ForStringLength(),
294 input, effect, control));
298 // -----------------------------------------------------------------------------
302 TEST_F(JSIntrinsicLoweringTest, InlineMathClz32) {
303 Node* const input = Parameter(0);
304 Node* const context = Parameter(1);
305 Node* const effect = graph()->start();
306 Node* const control = graph()->start();
307 Reduction const r = Reduce(
308 graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineMathClz32, 1),
309 input, context, effect, control));
310 ASSERT_TRUE(r.Changed());
311 EXPECT_THAT(r.replacement(), IsWord32Clz(input));
315 // -----------------------------------------------------------------------------
319 TEST_F(JSIntrinsicLoweringTest, InlineValueOf) {
320 Node* const input = Parameter(0);
321 Node* const context = Parameter(1);
322 Node* const effect = graph()->start();
323 Node* const control = graph()->start();
324 Reduction const r = Reduce(
325 graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineValueOf, 1),
326 input, context, effect, control));
327 ASSERT_TRUE(r.Changed());
329 Node* phi = r.replacement();
330 Capture<Node*> branch0, if_false0, branch1, if_true1;
334 kMachAnyTagged, input,
335 IsPhi(kMachAnyTagged, IsLoadField(AccessBuilder::ForValue(), input,
336 effect, CaptureEq(&if_true1)),
339 AllOf(CaptureEq(&if_true1), IsIfTrue(CaptureEq(&branch1))),
345 AccessBuilder::ForMapInstanceType(),
346 IsLoadField(AccessBuilder::ForMap(), input,
347 effect, CaptureEq(&if_false0)),
349 IsInt32Constant(JS_VALUE_TYPE)),
350 CaptureEq(&if_false0)))))),
352 IsIfTrue(AllOf(CaptureEq(&branch0),
353 IsBranch(IsObjectIsSmi(input), control))),
354 AllOf(CaptureEq(&if_false0), IsIfFalse(CaptureEq(&branch0))))));
357 } // namespace compiler
358 } // namespace internal