blob: 919c1b2237a1820d260d0d76fb11147fe321282e [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"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010#include "test/unittests/compiler/graph-unittest.h"
11#include "test/unittests/compiler/node-test-utils.h"
12#include "testing/gmock-support.h"
13
14
15using testing::_;
16using testing::AllOf;
17using testing::BitEq;
18using testing::Capture;
19using testing::CaptureEq;
20
21
22namespace v8 {
23namespace internal {
24namespace compiler {
25
Ben Murdoch097c5b22016-05-18 11:27:45 +010026class JSIntrinsicLoweringTest : public GraphTest {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000027 public:
Ben Murdoch097c5b22016-05-18 11:27:45 +010028 JSIntrinsicLoweringTest() : GraphTest(3), javascript_(zone()) {}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000029 ~JSIntrinsicLoweringTest() override {}
30
31 protected:
32 Reduction Reduce(Node* node, MachineOperatorBuilder::Flags flags =
33 MachineOperatorBuilder::kNoFlags) {
34 MachineOperatorBuilder machine(zone(), MachineType::PointerRepresentation(),
35 flags);
36 SimplifiedOperatorBuilder simplified(zone());
37 JSGraph jsgraph(isolate(), graph(), common(), javascript(), &simplified,
38 &machine);
39 // TODO(titzer): mock the GraphReducer here for better unit testing.
40 GraphReducer graph_reducer(zone(), graph());
41 JSIntrinsicLowering reducer(&graph_reducer, &jsgraph,
42 JSIntrinsicLowering::kDeoptimizationEnabled);
43 return reducer.Reduce(node);
44 }
45
46 Node* EmptyFrameState() {
47 MachineOperatorBuilder machine(zone());
48 JSGraph jsgraph(isolate(), graph(), common(), javascript(), nullptr,
49 &machine);
50 return jsgraph.EmptyFrameState();
51 }
52
53 JSOperatorBuilder* javascript() { return &javascript_; }
54
55 private:
56 JSOperatorBuilder javascript_;
57};
58
59
60// -----------------------------------------------------------------------------
61// %_ConstructDouble
62
63
64TEST_F(JSIntrinsicLoweringTest, InlineOptimizedConstructDouble) {
65 Node* const input0 = Parameter(0);
66 Node* const input1 = Parameter(1);
67 Node* const context = Parameter(2);
68 Node* const effect = graph()->start();
69 Node* const control = graph()->start();
70 Reduction const r = Reduce(graph()->NewNode(
71 javascript()->CallRuntime(Runtime::kInlineConstructDouble, 2), input0,
72 input1, context, effect, control));
73 ASSERT_TRUE(r.Changed());
74 EXPECT_THAT(r.replacement(), IsFloat64InsertHighWord32(
75 IsFloat64InsertLowWord32(
76 IsNumberConstant(BitEq(0.0)), input1),
77 input0));
78}
79
80
81// -----------------------------------------------------------------------------
82// %_DoubleLo
83
84
85TEST_F(JSIntrinsicLoweringTest, InlineOptimizedDoubleLo) {
86 Node* const input = Parameter(0);
87 Node* const context = Parameter(1);
88 Node* const effect = graph()->start();
89 Node* const control = graph()->start();
90 Reduction const r = Reduce(
91 graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineDoubleLo, 1),
92 input, context, effect, control));
93 ASSERT_TRUE(r.Changed());
94 EXPECT_THAT(r.replacement(), IsFloat64ExtractLowWord32(input));
95}
96
97
98// -----------------------------------------------------------------------------
99// %_DoubleHi
100
101
102TEST_F(JSIntrinsicLoweringTest, InlineOptimizedDoubleHi) {
103 Node* const input = Parameter(0);
104 Node* const context = Parameter(1);
105 Node* const effect = graph()->start();
106 Node* const control = graph()->start();
107 Reduction const r = Reduce(
108 graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineDoubleHi, 1),
109 input, context, effect, control));
110 ASSERT_TRUE(r.Changed());
111 EXPECT_THAT(r.replacement(), IsFloat64ExtractHighWord32(input));
112}
113
114
115// -----------------------------------------------------------------------------
116// %_IsSmi
117
118
119TEST_F(JSIntrinsicLoweringTest, InlineIsSmi) {
120 Node* const input = Parameter(0);
121 Node* const context = Parameter(1);
122 Node* const effect = graph()->start();
123 Node* const control = graph()->start();
124 Reduction const r = Reduce(
125 graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineIsSmi, 1),
126 input, context, effect, control));
127 ASSERT_TRUE(r.Changed());
128 EXPECT_THAT(r.replacement(), IsObjectIsSmi(input));
129}
130
131
132// -----------------------------------------------------------------------------
133// %_IsArray
134
135
136TEST_F(JSIntrinsicLoweringTest, InlineIsArray) {
137 Node* const input = Parameter(0);
138 Node* const context = Parameter(1);
139 Node* const effect = graph()->start();
140 Node* const control = graph()->start();
141 Reduction const r = Reduce(
142 graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineIsArray, 1),
143 input, context, effect, control));
144 ASSERT_TRUE(r.Changed());
145
146 Node* phi = r.replacement();
147 Capture<Node*> branch, if_false;
148 EXPECT_THAT(
149 phi,
150 IsPhi(
151 MachineRepresentation::kTagged, IsFalseConstant(),
152 IsWord32Equal(IsLoadField(AccessBuilder::ForMapInstanceType(),
153 IsLoadField(AccessBuilder::ForMap(), input,
154 effect, CaptureEq(&if_false)),
155 effect, _),
156 IsInt32Constant(JS_ARRAY_TYPE)),
157 IsMerge(IsIfTrue(AllOf(CaptureEq(&branch),
158 IsBranch(IsObjectIsSmi(input), control))),
159 AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch))))));
160}
161
162
163// -----------------------------------------------------------------------------
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000164// %_IsTypedArray
165
166
167TEST_F(JSIntrinsicLoweringTest, InlineIsTypedArray) {
168 Node* const input = Parameter(0);
169 Node* const context = Parameter(1);
170 Node* const effect = graph()->start();
171 Node* const control = graph()->start();
172 Reduction const r = Reduce(graph()->NewNode(
173 javascript()->CallRuntime(Runtime::kInlineIsTypedArray, 1), input,
174 context, effect, control));
175 ASSERT_TRUE(r.Changed());
176
177 Node* phi = r.replacement();
178 Capture<Node*> branch, if_false;
179 EXPECT_THAT(
180 phi,
181 IsPhi(
182 MachineRepresentation::kTagged, IsFalseConstant(),
183 IsWord32Equal(IsLoadField(AccessBuilder::ForMapInstanceType(),
184 IsLoadField(AccessBuilder::ForMap(), input,
185 effect, CaptureEq(&if_false)),
186 effect, _),
187 IsInt32Constant(JS_TYPED_ARRAY_TYPE)),
188 IsMerge(IsIfTrue(AllOf(CaptureEq(&branch),
189 IsBranch(IsObjectIsSmi(input), control))),
190 AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch))))));
191}
192
193
194// -----------------------------------------------------------------------------
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000195// %_IsRegExp
196
197
198TEST_F(JSIntrinsicLoweringTest, InlineIsRegExp) {
199 Node* const input = Parameter(0);
200 Node* const context = Parameter(1);
201 Node* const effect = graph()->start();
202 Node* const control = graph()->start();
203 Reduction const r = Reduce(
204 graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineIsRegExp, 1),
205 input, context, effect, control));
206 ASSERT_TRUE(r.Changed());
207
208 Node* phi = r.replacement();
209 Capture<Node*> branch, if_false;
210 EXPECT_THAT(
211 phi,
212 IsPhi(
213 MachineRepresentation::kTagged, IsFalseConstant(),
214 IsWord32Equal(IsLoadField(AccessBuilder::ForMapInstanceType(),
215 IsLoadField(AccessBuilder::ForMap(), input,
216 effect, CaptureEq(&if_false)),
217 effect, _),
218 IsInt32Constant(JS_REGEXP_TYPE)),
219 IsMerge(IsIfTrue(AllOf(CaptureEq(&branch),
220 IsBranch(IsObjectIsSmi(input), control))),
221 AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch))))));
222}
223
224
225// -----------------------------------------------------------------------------
226// %_IsJSReceiver
227
228
Ben Murdoch097c5b22016-05-18 11:27:45 +0100229TEST_F(JSIntrinsicLoweringTest, InlineIsJSReceiver) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000230 Node* const input = Parameter(0);
231 Node* const context = Parameter(1);
232 Node* const effect = graph()->start();
233 Node* const control = graph()->start();
234 Reduction const r = Reduce(graph()->NewNode(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100235 javascript()->CallRuntime(Runtime::kInlineIsJSReceiver, 1), input,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000236 context, effect, control));
237 ASSERT_TRUE(r.Changed());
Ben Murdoch097c5b22016-05-18 11:27:45 +0100238 EXPECT_THAT(r.replacement(), IsObjectIsReceiver(input));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000239}
240
241
242// -----------------------------------------------------------------------------
243// %_MathFloor
244
245
246TEST_F(JSIntrinsicLoweringTest, InlineMathFloor) {
247 Node* const input = Parameter(0);
248 Node* const context = Parameter(1);
249 Node* const effect = graph()->start();
250 Node* const control = graph()->start();
251 Reduction const r = Reduce(
252 graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineMathFloor, 1),
253 input, context, effect, control),
254 MachineOperatorBuilder::kFloat64RoundDown);
255 ASSERT_TRUE(r.Changed());
256 EXPECT_THAT(r.replacement(), IsFloat64RoundDown(input));
257}
258
259
260// -----------------------------------------------------------------------------
261// %_MathSqrt
262
263
264TEST_F(JSIntrinsicLoweringTest, InlineMathSqrt) {
265 Node* const input = Parameter(0);
266 Node* const context = Parameter(1);
267 Node* const effect = graph()->start();
268 Node* const control = graph()->start();
269 Reduction const r = Reduce(
270 graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineMathSqrt, 1),
271 input, context, effect, control));
272 ASSERT_TRUE(r.Changed());
273 EXPECT_THAT(r.replacement(), IsFloat64Sqrt(input));
274}
275
276
277// -----------------------------------------------------------------------------
278// %_MathClz32
279
280
281TEST_F(JSIntrinsicLoweringTest, InlineMathClz32) {
282 Node* const input = Parameter(0);
283 Node* const context = Parameter(1);
284 Node* const effect = graph()->start();
285 Node* const control = graph()->start();
286 Reduction const r = Reduce(
287 graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineMathClz32, 1),
288 input, context, effect, control));
289 ASSERT_TRUE(r.Changed());
290 EXPECT_THAT(r.replacement(), IsWord32Clz(input));
291}
292
293
294// -----------------------------------------------------------------------------
295// %_ValueOf
296
297
298TEST_F(JSIntrinsicLoweringTest, InlineValueOf) {
299 Node* const input = Parameter(0);
300 Node* const context = Parameter(1);
301 Node* const effect = graph()->start();
302 Node* const control = graph()->start();
303 Reduction const r = Reduce(
304 graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineValueOf, 1),
305 input, context, effect, control));
306 ASSERT_TRUE(r.Changed());
307
308 Node* phi = r.replacement();
309 Capture<Node*> branch0, if_false0, branch1, if_true1;
310 EXPECT_THAT(
311 phi,
312 IsPhi(
313 MachineRepresentation::kTagged, input,
314 IsPhi(MachineRepresentation::kTagged,
315 IsLoadField(AccessBuilder::ForValue(), input, effect,
316 CaptureEq(&if_true1)),
317 input,
318 IsMerge(
319 AllOf(CaptureEq(&if_true1), IsIfTrue(CaptureEq(&branch1))),
320 IsIfFalse(AllOf(
321 CaptureEq(&branch1),
322 IsBranch(
323 IsWord32Equal(
324 IsLoadField(
325 AccessBuilder::ForMapInstanceType(),
326 IsLoadField(AccessBuilder::ForMap(), input,
327 effect, CaptureEq(&if_false0)),
328 effect, _),
329 IsInt32Constant(JS_VALUE_TYPE)),
330 CaptureEq(&if_false0)))))),
331 IsMerge(
332 IsIfTrue(AllOf(CaptureEq(&branch0),
333 IsBranch(IsObjectIsSmi(input), control))),
334 AllOf(CaptureEq(&if_false0), IsIfFalse(CaptureEq(&branch0))))));
335}
336
337} // namespace compiler
338} // namespace internal
339} // namespace v8