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