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