OLD | NEW |
| (Empty) |
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/change-lowering.h" | |
6 #include "src/compiler/compiler-test-utils.h" | |
7 #include "src/compiler/graph-unittest.h" | |
8 #include "src/compiler/js-graph.h" | |
9 #include "src/compiler/node-properties-inl.h" | |
10 #include "src/compiler/simplified-operator.h" | |
11 #include "src/compiler/typer.h" | |
12 #include "testing/gmock-support.h" | |
13 | |
14 using testing::_; | |
15 using testing::AllOf; | |
16 using testing::Capture; | |
17 using testing::CaptureEq; | |
18 | |
19 namespace v8 { | |
20 namespace internal { | |
21 namespace compiler { | |
22 | |
23 class ChangeLoweringTest : public GraphTest { | |
24 public: | |
25 ChangeLoweringTest() : simplified_(zone()) {} | |
26 virtual ~ChangeLoweringTest() {} | |
27 | |
28 virtual MachineType WordRepresentation() const = 0; | |
29 | |
30 protected: | |
31 int HeapNumberValueOffset() const { | |
32 STATIC_ASSERT(HeapNumber::kValueOffset % kApiPointerSize == 0); | |
33 return (HeapNumber::kValueOffset / kApiPointerSize) * PointerSize() - | |
34 kHeapObjectTag; | |
35 } | |
36 bool Is32() const { return WordRepresentation() == kRepWord32; } | |
37 int PointerSize() const { | |
38 switch (WordRepresentation()) { | |
39 case kRepWord32: | |
40 return 4; | |
41 case kRepWord64: | |
42 return 8; | |
43 default: | |
44 break; | |
45 } | |
46 UNREACHABLE(); | |
47 return 0; | |
48 } | |
49 int SmiMaxValue() const { return -(SmiMinValue() + 1); } | |
50 int SmiMinValue() const { | |
51 return static_cast<int>(0xffffffffu << (SmiValueSize() - 1)); | |
52 } | |
53 int SmiShiftAmount() const { return kSmiTagSize + SmiShiftSize(); } | |
54 int SmiShiftSize() const { | |
55 return Is32() ? SmiTagging<4>::SmiShiftSize() | |
56 : SmiTagging<8>::SmiShiftSize(); | |
57 } | |
58 int SmiValueSize() const { | |
59 return Is32() ? SmiTagging<4>::SmiValueSize() | |
60 : SmiTagging<8>::SmiValueSize(); | |
61 } | |
62 | |
63 Node* Parameter(int32_t index = 0) { | |
64 return graph()->NewNode(common()->Parameter(index), graph()->start()); | |
65 } | |
66 | |
67 Reduction Reduce(Node* node) { | |
68 Typer typer(zone()); | |
69 MachineOperatorBuilder machine(WordRepresentation()); | |
70 JSOperatorBuilder javascript(zone()); | |
71 JSGraph jsgraph(graph(), common(), &javascript, &typer, &machine); | |
72 CompilationInfo info(isolate(), zone()); | |
73 Linkage linkage(&info); | |
74 ChangeLowering reducer(&jsgraph, &linkage); | |
75 return reducer.Reduce(node); | |
76 } | |
77 | |
78 SimplifiedOperatorBuilder* simplified() { return &simplified_; } | |
79 | |
80 Matcher<Node*> IsAllocateHeapNumber(const Matcher<Node*>& effect_matcher, | |
81 const Matcher<Node*>& control_matcher) { | |
82 return IsCall( | |
83 _, IsHeapConstant(Unique<HeapObject>::CreateImmovable( | |
84 CEntryStub(isolate(), 1).GetCode())), | |
85 IsExternalConstant(ExternalReference( | |
86 Runtime::FunctionForId(Runtime::kAllocateHeapNumber), isolate())), | |
87 IsInt32Constant(0), IsNumberConstant(0.0), effect_matcher, | |
88 control_matcher); | |
89 } | |
90 Matcher<Node*> IsWordEqual(const Matcher<Node*>& lhs_matcher, | |
91 const Matcher<Node*>& rhs_matcher) { | |
92 return Is32() ? IsWord32Equal(lhs_matcher, rhs_matcher) | |
93 : IsWord64Equal(lhs_matcher, rhs_matcher); | |
94 } | |
95 | |
96 private: | |
97 SimplifiedOperatorBuilder simplified_; | |
98 }; | |
99 | |
100 | |
101 // ----------------------------------------------------------------------------- | |
102 // Common. | |
103 | |
104 | |
105 class ChangeLoweringCommonTest | |
106 : public ChangeLoweringTest, | |
107 public ::testing::WithParamInterface<MachineType> { | |
108 public: | |
109 virtual ~ChangeLoweringCommonTest() {} | |
110 | |
111 virtual MachineType WordRepresentation() const FINAL OVERRIDE { | |
112 return GetParam(); | |
113 } | |
114 }; | |
115 | |
116 | |
117 TARGET_TEST_P(ChangeLoweringCommonTest, ChangeBitToBool) { | |
118 Node* val = Parameter(0); | |
119 Node* node = graph()->NewNode(simplified()->ChangeBitToBool(), val); | |
120 Reduction reduction = Reduce(node); | |
121 ASSERT_TRUE(reduction.Changed()); | |
122 | |
123 Node* phi = reduction.replacement(); | |
124 Capture<Node*> branch; | |
125 EXPECT_THAT(phi, | |
126 IsPhi(static_cast<MachineType>(kTypeBool | kRepTagged), | |
127 IsTrueConstant(), IsFalseConstant(), | |
128 IsMerge(IsIfTrue(AllOf(CaptureEq(&branch), | |
129 IsBranch(val, graph()->start()))), | |
130 IsIfFalse(CaptureEq(&branch))))); | |
131 } | |
132 | |
133 | |
134 TARGET_TEST_P(ChangeLoweringCommonTest, ChangeBoolToBit) { | |
135 Node* val = Parameter(0); | |
136 Node* node = graph()->NewNode(simplified()->ChangeBoolToBit(), val); | |
137 Reduction reduction = Reduce(node); | |
138 ASSERT_TRUE(reduction.Changed()); | |
139 | |
140 EXPECT_THAT(reduction.replacement(), IsWordEqual(val, IsTrueConstant())); | |
141 } | |
142 | |
143 | |
144 TARGET_TEST_P(ChangeLoweringCommonTest, ChangeFloat64ToTagged) { | |
145 Node* val = Parameter(0); | |
146 Node* node = graph()->NewNode(simplified()->ChangeFloat64ToTagged(), val); | |
147 Reduction reduction = Reduce(node); | |
148 ASSERT_TRUE(reduction.Changed()); | |
149 | |
150 Node* finish = reduction.replacement(); | |
151 Capture<Node*> heap_number; | |
152 EXPECT_THAT( | |
153 finish, | |
154 IsFinish( | |
155 AllOf(CaptureEq(&heap_number), | |
156 IsAllocateHeapNumber(IsValueEffect(val), graph()->start())), | |
157 IsStore(kMachFloat64, kNoWriteBarrier, CaptureEq(&heap_number), | |
158 IsInt32Constant(HeapNumberValueOffset()), val, | |
159 CaptureEq(&heap_number), graph()->start()))); | |
160 } | |
161 | |
162 | |
163 TARGET_TEST_P(ChangeLoweringCommonTest, StringAdd) { | |
164 Node* node = | |
165 graph()->NewNode(simplified()->StringAdd(), Parameter(0), Parameter(1)); | |
166 Reduction reduction = Reduce(node); | |
167 EXPECT_FALSE(reduction.Changed()); | |
168 } | |
169 | |
170 | |
171 INSTANTIATE_TEST_CASE_P(ChangeLoweringTest, ChangeLoweringCommonTest, | |
172 ::testing::Values(kRepWord32, kRepWord64)); | |
173 | |
174 | |
175 // ----------------------------------------------------------------------------- | |
176 // 32-bit | |
177 | |
178 | |
179 class ChangeLowering32Test : public ChangeLoweringTest { | |
180 public: | |
181 virtual ~ChangeLowering32Test() {} | |
182 virtual MachineType WordRepresentation() const FINAL OVERRIDE { | |
183 return kRepWord32; | |
184 } | |
185 }; | |
186 | |
187 | |
188 TARGET_TEST_F(ChangeLowering32Test, ChangeInt32ToTagged) { | |
189 Node* val = Parameter(0); | |
190 Node* node = graph()->NewNode(simplified()->ChangeInt32ToTagged(), val); | |
191 Reduction reduction = Reduce(node); | |
192 ASSERT_TRUE(reduction.Changed()); | |
193 | |
194 Node* phi = reduction.replacement(); | |
195 Capture<Node*> add, branch, heap_number, if_true; | |
196 EXPECT_THAT( | |
197 phi, | |
198 IsPhi(kMachAnyTagged, | |
199 IsFinish( | |
200 AllOf(CaptureEq(&heap_number), | |
201 IsAllocateHeapNumber(_, CaptureEq(&if_true))), | |
202 IsStore(kMachFloat64, kNoWriteBarrier, CaptureEq(&heap_number), | |
203 IsInt32Constant(HeapNumberValueOffset()), | |
204 IsChangeInt32ToFloat64(val), CaptureEq(&heap_number), | |
205 CaptureEq(&if_true))), | |
206 IsProjection( | |
207 0, AllOf(CaptureEq(&add), IsInt32AddWithOverflow(val, val))), | |
208 IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))), | |
209 IsIfFalse(AllOf(CaptureEq(&branch), | |
210 IsBranch(IsProjection(1, CaptureEq(&add)), | |
211 graph()->start())))))); | |
212 } | |
213 | |
214 | |
215 TARGET_TEST_F(ChangeLowering32Test, ChangeTaggedToFloat64) { | |
216 STATIC_ASSERT(kSmiTag == 0); | |
217 STATIC_ASSERT(kSmiTagSize == 1); | |
218 | |
219 Node* val = Parameter(0); | |
220 Node* node = graph()->NewNode(simplified()->ChangeTaggedToFloat64(), val); | |
221 Reduction reduction = Reduce(node); | |
222 ASSERT_TRUE(reduction.Changed()); | |
223 | |
224 Node* phi = reduction.replacement(); | |
225 Capture<Node*> branch, if_true; | |
226 EXPECT_THAT( | |
227 phi, | |
228 IsPhi( | |
229 kMachFloat64, | |
230 IsLoad(kMachFloat64, val, IsInt32Constant(HeapNumberValueOffset()), | |
231 IsControlEffect(CaptureEq(&if_true))), | |
232 IsChangeInt32ToFloat64( | |
233 IsWord32Sar(val, IsInt32Constant(SmiShiftAmount()))), | |
234 IsMerge( | |
235 AllOf(CaptureEq(&if_true), | |
236 IsIfTrue(AllOf( | |
237 CaptureEq(&branch), | |
238 IsBranch(IsWord32And(val, IsInt32Constant(kSmiTagMask)), | |
239 graph()->start())))), | |
240 IsIfFalse(CaptureEq(&branch))))); | |
241 } | |
242 | |
243 | |
244 TARGET_TEST_F(ChangeLowering32Test, ChangeTaggedToInt32) { | |
245 STATIC_ASSERT(kSmiTag == 0); | |
246 STATIC_ASSERT(kSmiTagSize == 1); | |
247 | |
248 Node* val = Parameter(0); | |
249 Node* node = graph()->NewNode(simplified()->ChangeTaggedToInt32(), val); | |
250 Reduction reduction = Reduce(node); | |
251 ASSERT_TRUE(reduction.Changed()); | |
252 | |
253 Node* phi = reduction.replacement(); | |
254 Capture<Node*> branch, if_true; | |
255 EXPECT_THAT( | |
256 phi, | |
257 IsPhi(kMachInt32, | |
258 IsChangeFloat64ToInt32(IsLoad( | |
259 kMachFloat64, val, IsInt32Constant(HeapNumberValueOffset()), | |
260 IsControlEffect(CaptureEq(&if_true)))), | |
261 IsWord32Sar(val, IsInt32Constant(SmiShiftAmount())), | |
262 IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))), | |
263 IsIfFalse(AllOf( | |
264 CaptureEq(&branch), | |
265 IsBranch(IsWord32And(val, IsInt32Constant(kSmiTagMask)), | |
266 graph()->start())))))); | |
267 } | |
268 | |
269 | |
270 TARGET_TEST_F(ChangeLowering32Test, ChangeTaggedToUint32) { | |
271 STATIC_ASSERT(kSmiTag == 0); | |
272 STATIC_ASSERT(kSmiTagSize == 1); | |
273 | |
274 Node* val = Parameter(0); | |
275 Node* node = graph()->NewNode(simplified()->ChangeTaggedToUint32(), val); | |
276 Reduction reduction = Reduce(node); | |
277 ASSERT_TRUE(reduction.Changed()); | |
278 | |
279 Node* phi = reduction.replacement(); | |
280 Capture<Node*> branch, if_true; | |
281 EXPECT_THAT( | |
282 phi, | |
283 IsPhi(kMachUint32, | |
284 IsChangeFloat64ToUint32(IsLoad( | |
285 kMachFloat64, val, IsInt32Constant(HeapNumberValueOffset()), | |
286 IsControlEffect(CaptureEq(&if_true)))), | |
287 IsWord32Sar(val, IsInt32Constant(SmiShiftAmount())), | |
288 IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))), | |
289 IsIfFalse(AllOf( | |
290 CaptureEq(&branch), | |
291 IsBranch(IsWord32And(val, IsInt32Constant(kSmiTagMask)), | |
292 graph()->start())))))); | |
293 } | |
294 | |
295 | |
296 TARGET_TEST_F(ChangeLowering32Test, ChangeUint32ToTagged) { | |
297 STATIC_ASSERT(kSmiTag == 0); | |
298 STATIC_ASSERT(kSmiTagSize == 1); | |
299 | |
300 Node* val = Parameter(0); | |
301 Node* node = graph()->NewNode(simplified()->ChangeUint32ToTagged(), val); | |
302 Reduction reduction = Reduce(node); | |
303 ASSERT_TRUE(reduction.Changed()); | |
304 | |
305 Node* phi = reduction.replacement(); | |
306 Capture<Node*> branch, heap_number, if_false; | |
307 EXPECT_THAT( | |
308 phi, | |
309 IsPhi( | |
310 kMachAnyTagged, IsWord32Shl(val, IsInt32Constant(SmiShiftAmount())), | |
311 IsFinish( | |
312 AllOf(CaptureEq(&heap_number), | |
313 IsAllocateHeapNumber(_, CaptureEq(&if_false))), | |
314 IsStore(kMachFloat64, kNoWriteBarrier, CaptureEq(&heap_number), | |
315 IsInt32Constant(HeapNumberValueOffset()), | |
316 IsChangeUint32ToFloat64(val), CaptureEq(&heap_number), | |
317 CaptureEq(&if_false))), | |
318 IsMerge( | |
319 IsIfTrue(AllOf(CaptureEq(&branch), | |
320 IsBranch(IsUint32LessThanOrEqual( | |
321 val, IsInt32Constant(SmiMaxValue())), | |
322 graph()->start()))), | |
323 AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch)))))); | |
324 } | |
325 | |
326 | |
327 // ----------------------------------------------------------------------------- | |
328 // 64-bit | |
329 | |
330 | |
331 class ChangeLowering64Test : public ChangeLoweringTest { | |
332 public: | |
333 virtual ~ChangeLowering64Test() {} | |
334 virtual MachineType WordRepresentation() const FINAL OVERRIDE { | |
335 return kRepWord64; | |
336 } | |
337 }; | |
338 | |
339 | |
340 TARGET_TEST_F(ChangeLowering64Test, ChangeInt32ToTagged) { | |
341 Node* val = Parameter(0); | |
342 Node* node = graph()->NewNode(simplified()->ChangeInt32ToTagged(), val); | |
343 Reduction reduction = Reduce(node); | |
344 ASSERT_TRUE(reduction.Changed()); | |
345 | |
346 EXPECT_THAT(reduction.replacement(), | |
347 IsWord64Shl(IsChangeInt32ToInt64(val), | |
348 IsInt32Constant(SmiShiftAmount()))); | |
349 } | |
350 | |
351 | |
352 TARGET_TEST_F(ChangeLowering64Test, ChangeTaggedToFloat64) { | |
353 STATIC_ASSERT(kSmiTag == 0); | |
354 STATIC_ASSERT(kSmiTagSize == 1); | |
355 | |
356 Node* val = Parameter(0); | |
357 Node* node = graph()->NewNode(simplified()->ChangeTaggedToFloat64(), val); | |
358 Reduction reduction = Reduce(node); | |
359 ASSERT_TRUE(reduction.Changed()); | |
360 | |
361 Node* phi = reduction.replacement(); | |
362 Capture<Node*> branch, if_true; | |
363 EXPECT_THAT( | |
364 phi, | |
365 IsPhi( | |
366 kMachFloat64, | |
367 IsLoad(kMachFloat64, val, IsInt32Constant(HeapNumberValueOffset()), | |
368 IsControlEffect(CaptureEq(&if_true))), | |
369 IsChangeInt32ToFloat64(IsTruncateInt64ToInt32( | |
370 IsWord64Sar(val, IsInt32Constant(SmiShiftAmount())))), | |
371 IsMerge( | |
372 AllOf(CaptureEq(&if_true), | |
373 IsIfTrue(AllOf( | |
374 CaptureEq(&branch), | |
375 IsBranch(IsWord64And(val, IsInt32Constant(kSmiTagMask)), | |
376 graph()->start())))), | |
377 IsIfFalse(CaptureEq(&branch))))); | |
378 } | |
379 | |
380 | |
381 TARGET_TEST_F(ChangeLowering64Test, ChangeTaggedToInt32) { | |
382 STATIC_ASSERT(kSmiTag == 0); | |
383 STATIC_ASSERT(kSmiTagSize == 1); | |
384 | |
385 Node* val = Parameter(0); | |
386 Node* node = graph()->NewNode(simplified()->ChangeTaggedToInt32(), val); | |
387 Reduction reduction = Reduce(node); | |
388 ASSERT_TRUE(reduction.Changed()); | |
389 | |
390 Node* phi = reduction.replacement(); | |
391 Capture<Node*> branch, if_true; | |
392 EXPECT_THAT( | |
393 phi, | |
394 IsPhi(kMachInt32, | |
395 IsChangeFloat64ToInt32(IsLoad( | |
396 kMachFloat64, val, IsInt32Constant(HeapNumberValueOffset()), | |
397 IsControlEffect(CaptureEq(&if_true)))), | |
398 IsTruncateInt64ToInt32( | |
399 IsWord64Sar(val, IsInt32Constant(SmiShiftAmount()))), | |
400 IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))), | |
401 IsIfFalse(AllOf( | |
402 CaptureEq(&branch), | |
403 IsBranch(IsWord64And(val, IsInt32Constant(kSmiTagMask)), | |
404 graph()->start())))))); | |
405 } | |
406 | |
407 | |
408 TARGET_TEST_F(ChangeLowering64Test, ChangeTaggedToUint32) { | |
409 STATIC_ASSERT(kSmiTag == 0); | |
410 STATIC_ASSERT(kSmiTagSize == 1); | |
411 | |
412 Node* val = Parameter(0); | |
413 Node* node = graph()->NewNode(simplified()->ChangeTaggedToUint32(), val); | |
414 Reduction reduction = Reduce(node); | |
415 ASSERT_TRUE(reduction.Changed()); | |
416 | |
417 Node* phi = reduction.replacement(); | |
418 Capture<Node*> branch, if_true; | |
419 EXPECT_THAT( | |
420 phi, | |
421 IsPhi(kMachUint32, | |
422 IsChangeFloat64ToUint32(IsLoad( | |
423 kMachFloat64, val, IsInt32Constant(HeapNumberValueOffset()), | |
424 IsControlEffect(CaptureEq(&if_true)))), | |
425 IsTruncateInt64ToInt32( | |
426 IsWord64Sar(val, IsInt32Constant(SmiShiftAmount()))), | |
427 IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))), | |
428 IsIfFalse(AllOf( | |
429 CaptureEq(&branch), | |
430 IsBranch(IsWord64And(val, IsInt32Constant(kSmiTagMask)), | |
431 graph()->start())))))); | |
432 } | |
433 | |
434 | |
435 TARGET_TEST_F(ChangeLowering64Test, ChangeUint32ToTagged) { | |
436 STATIC_ASSERT(kSmiTag == 0); | |
437 STATIC_ASSERT(kSmiTagSize == 1); | |
438 | |
439 Node* val = Parameter(0); | |
440 Node* node = graph()->NewNode(simplified()->ChangeUint32ToTagged(), val); | |
441 Reduction reduction = Reduce(node); | |
442 ASSERT_TRUE(reduction.Changed()); | |
443 | |
444 Node* phi = reduction.replacement(); | |
445 Capture<Node*> branch, heap_number, if_false; | |
446 EXPECT_THAT( | |
447 phi, | |
448 IsPhi( | |
449 kMachAnyTagged, IsWord64Shl(IsChangeUint32ToUint64(val), | |
450 IsInt32Constant(SmiShiftAmount())), | |
451 IsFinish( | |
452 AllOf(CaptureEq(&heap_number), | |
453 IsAllocateHeapNumber(_, CaptureEq(&if_false))), | |
454 IsStore(kMachFloat64, kNoWriteBarrier, CaptureEq(&heap_number), | |
455 IsInt32Constant(HeapNumberValueOffset()), | |
456 IsChangeUint32ToFloat64(val), CaptureEq(&heap_number), | |
457 CaptureEq(&if_false))), | |
458 IsMerge( | |
459 IsIfTrue(AllOf(CaptureEq(&branch), | |
460 IsBranch(IsUint32LessThanOrEqual( | |
461 val, IsInt32Constant(SmiMaxValue())), | |
462 graph()->start()))), | |
463 AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch)))))); | |
464 } | |
465 | |
466 } // namespace compiler | |
467 } // namespace internal | |
468 } // namespace v8 | |
OLD | NEW |