V8 Project
change-lowering-unittest.cc
Go to the documentation of this file.
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 
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.
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:
34  virtual ~ChangeLoweringTest() {}
35 
36  virtual MachineType WordRepresentation() const = 0;
37 
38  protected:
39  int HeapNumberValueOffset() const {
43  }
44  bool Is32() const { return WordRepresentation() == kRepWord32; }
45  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  }
57  int SmiMaxValue() const { return -(SmiMinValue() + 1); }
58  int SmiMinValue() const {
59  return static_cast<int>(0xffffffffu << (SmiValueSize() - 1));
60  }
61  int SmiShiftAmount() const { return kSmiTagSize + SmiShiftSize(); }
62  int SmiShiftSize() const {
65  }
66  int SmiValueSize() const {
69  }
70 
71  Node* Parameter(int32_t index = 0) {
72  return graph()->NewNode(common()->Parameter(index), graph()->start());
73  }
74 
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 
86  SimplifiedOperatorBuilder* simplified() { return &simplified_; }
87 
88  Matcher<Node*> IsAllocateHeapNumber(const Matcher<Node*>& effect_matcher,
89  const Matcher<Node*>& control_matcher) {
90  return IsCall(
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  }
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 
114  : public ChangeLoweringTest,
115  public ::testing::WithParamInterface<MachineType> {
116  public:
118 
120  return GetParam();
121  }
122 };
123 
124 
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 
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 
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 
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 
180  ::testing::Values(kRepWord32, kRepWord64));
181 
182 
183 // -----------------------------------------------------------------------------
184 // 32-bit
185 
186 
188  public:
191  return kRepWord32;
192  }
193 };
194 
195 
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,
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 
223 TARGET_TEST_F(ChangeLowering32Test, ChangeTaggedToFloat64) {
224  STATIC_ASSERT(kSmiTag == 0);
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))),
241  IsWord32Sar(val, IsInt32Constant(SmiShiftAmount()))),
242  IsMerge(
243  AllOf(CaptureEq(&if_true),
244  IsIfTrue(AllOf(
245  CaptureEq(&branch),
247  graph()->start())))),
248  IsIfFalse(CaptureEq(&branch)))));
249 }
250 
251 
252 TARGET_TEST_F(ChangeLowering32Test, ChangeTaggedToInt32) {
253  STATIC_ASSERT(kSmiTag == 0);
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,
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),
274  graph()->start()))))));
275 }
276 
277 
278 TARGET_TEST_F(ChangeLowering32Test, ChangeTaggedToUint32) {
279  STATIC_ASSERT(kSmiTag == 0);
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,
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),
300  graph()->start()))))));
301 }
302 
303 
304 TARGET_TEST_F(ChangeLowering32Test, ChangeUint32ToTagged) {
305  STATIC_ASSERT(kSmiTag == 0);
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),
329  val, IsInt32Constant(SmiMaxValue())),
330  graph()->start()))),
331  AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch))))));
332 }
333 
334 
335 // -----------------------------------------------------------------------------
336 // 64-bit
337 
338 
340  public:
343  return kRepWord64;
344  }
345 };
346 
347 
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(),
356  IsInt32Constant(SmiShiftAmount())));
357 }
358 
359 
360 TARGET_TEST_F(ChangeLowering64Test, ChangeTaggedToFloat64) {
361  STATIC_ASSERT(kSmiTag == 0);
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))),
378  IsWord64Sar(val, IsInt32Constant(SmiShiftAmount())))),
379  IsMerge(
380  AllOf(CaptureEq(&if_true),
381  IsIfTrue(AllOf(
382  CaptureEq(&branch),
384  graph()->start())))),
385  IsIfFalse(CaptureEq(&branch)))));
386 }
387 
388 
389 TARGET_TEST_F(ChangeLowering64Test, ChangeTaggedToInt32) {
390  STATIC_ASSERT(kSmiTag == 0);
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,
404  kMachFloat64, val, IsInt32Constant(HeapNumberValueOffset()),
405  IsControlEffect(CaptureEq(&if_true)))),
407  IsWord64Sar(val, IsInt32Constant(SmiShiftAmount()))),
408  IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))),
409  IsIfFalse(AllOf(
410  CaptureEq(&branch),
412  graph()->start()))))));
413 }
414 
415 
416 TARGET_TEST_F(ChangeLowering64Test, ChangeTaggedToUint32) {
417  STATIC_ASSERT(kSmiTag == 0);
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,
431  kMachFloat64, val, IsInt32Constant(HeapNumberValueOffset()),
432  IsControlEffect(CaptureEq(&if_true)))),
434  IsWord64Sar(val, IsInt32Constant(SmiShiftAmount()))),
435  IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))),
436  IsIfFalse(AllOf(
437  CaptureEq(&branch),
439  graph()->start()))))));
440 }
441 
442 
443 TARGET_TEST_F(ChangeLowering64Test, ChangeUint32ToTagged) {
444  STATIC_ASSERT(kSmiTag == 0);
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(
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),
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
Isolate * isolate() const
Definition: test-utils.h:20
static const int kValueOffset
Definition: objects.h:1506
const char * c_str() const
Definition: ostreams.h:84
static const Function * FunctionForId(FunctionId id)
Definition: runtime.cc:9312
virtual MachineType WordRepresentation() const FINAL OVERRIDE
virtual MachineType WordRepresentation() const FINAL OVERRIDE
virtual MachineType WordRepresentation() const FINAL OVERRIDE
Matcher< Node * > IsAllocateHeapNumber(const Matcher< Node * > &effect_matcher, const Matcher< Node * > &control_matcher)
virtual MachineType WordRepresentation() const =0
Matcher< Node * > IsWordEqual(const Matcher< Node * > &lhs_matcher, const Matcher< Node * > &rhs_matcher)
CommonOperatorBuilder * common()
Node * NewNode(const Operator *op, int input_count, Node **inputs)
Definition: graph.cc:24
#define OVERRIDE
#define UNREACHABLE()
Definition: logging.h:30
#define _
int int32_t
Definition: unicode.cc:24
Matcher< Node * > IsChangeInt32ToInt64(const Matcher< Node * > &input_matcher)
Matcher< Node * > IsChangeUint32ToFloat64(const Matcher< Node * > &input_matcher)
Matcher< Node * > IsWord32Equal(const Matcher< Node * > &lhs_matcher, const Matcher< Node * > &rhs_matcher)
Matcher< Node * > IsMerge(const Matcher< Node * > &control0_matcher, const Matcher< Node * > &control1_matcher)
Matcher< Node * > IsUint32LessThanOrEqual(const Matcher< Node * > &lhs_matcher, const Matcher< Node * > &rhs_matcher)
Matcher< Node * > IsIfFalse(const Matcher< Node * > &control_matcher)
Matcher< Node * > IsBranch(const Matcher< Node * > &value_matcher, const Matcher< Node * > &control_matcher)
std::ostream & operator<<(std::ostream &os, const MachineType &type)
Matcher< Node * > IsTruncateInt64ToInt32(const Matcher< Node * > &input_matcher)
Matcher< Node * > IsNumberConstant(const Matcher< double > &value_matcher)
Matcher< Node * > IsIfTrue(const Matcher< Node * > &control_matcher)
TARGET_TEST_F(ChangeLowering32Test, ChangeInt32ToTagged)
STATIC_ASSERT(DoubleRegister::kMaxNumAllocatableRegisters >=Register::kMaxNumAllocatableRegisters)
Matcher< Node * > IsControlEffect(const Matcher< Node * > &control_matcher)
Matcher< Node * > IsFinish(const Matcher< Node * > &value_matcher, const Matcher< Node * > &effect_matcher)
TARGET_TEST_P(ChangeLoweringCommonTest, ChangeBitToBool)
Matcher< Node * > IsWord32Shl(const Matcher< Node * > &lhs_matcher, const Matcher< Node * > &rhs_matcher)
Matcher< Node * > IsChangeUint32ToUint64(const Matcher< Node * > &input_matcher)
Matcher< Node * > IsChangeInt32ToFloat64(const Matcher< Node * > &input_matcher)
Matcher< Node * > IsInt32Constant(const Matcher< int32_t > &value_matcher)
Matcher< Node * > IsWord32And(const Matcher< Node * > &lhs_matcher, const Matcher< Node * > &rhs_matcher)
Matcher< Node * > IsCall(const Matcher< CallDescriptor * > &descriptor_matcher, const Matcher< Node * > &value0_matcher, const Matcher< Node * > &value1_matcher, const Matcher< Node * > &value2_matcher, const Matcher< Node * > &value3_matcher, const Matcher< Node * > &effect_matcher, const Matcher< Node * > &control_matcher)
Matcher< Node * > IsWord64Sar(const Matcher< Node * > &lhs_matcher, const Matcher< Node * > &rhs_matcher)
Matcher< Node * > IsExternalConstant(const Matcher< ExternalReference > &value_matcher)
INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorDPITest, ::testing::ValuesIn(kDPIs))
Matcher< Node * > IsPhi(const Matcher< MachineType > &type_matcher, const Matcher< Node * > &value0_matcher, const Matcher< Node * > &value1_matcher, const Matcher< Node * > &merge_matcher)
Matcher< Node * > IsStore(const Matcher< MachineType > &type_matcher, const Matcher< WriteBarrierKind > &write_barrier_matcher, const Matcher< Node * > &base_matcher, const Matcher< Node * > &index_matcher, const Matcher< Node * > &value_matcher, const Matcher< Node * > &effect_matcher, const Matcher< Node * > &control_matcher)
Matcher< Node * > IsValueEffect(const Matcher< Node * > &value_matcher)
Matcher< Node * > IsLoad(const Matcher< LoadRepresentation > &rep_matcher, const Matcher< Node * > &base_matcher, const Matcher< Node * > &index_matcher, const Matcher< Node * > &effect_matcher)
Matcher< Node * > IsProjection(const Matcher< size_t > &index_matcher, const Matcher< Node * > &base_matcher)
Matcher< Node * > IsChangeFloat64ToUint32(const Matcher< Node * > &input_matcher)
Matcher< Node * > IsHeapConstant(const Matcher< Unique< HeapObject > > &value_matcher)
Matcher< Node * > IsChangeFloat64ToInt32(const Matcher< Node * > &input_matcher)
Matcher< Node * > IsWord64Shl(const Matcher< Node * > &lhs_matcher, const Matcher< Node * > &rhs_matcher)
Matcher< Node * > IsWord64Equal(const Matcher< Node * > &lhs_matcher, const Matcher< Node * > &rhs_matcher)
Matcher< Node * > IsInt32AddWithOverflow(const Matcher< Node * > &lhs_matcher, const Matcher< Node * > &rhs_matcher)
Matcher< Node * > IsWord64And(const Matcher< Node * > &lhs_matcher, const Matcher< Node * > &rhs_matcher)
Matcher< Node * > IsWord32Sar(const Matcher< Node * > &lhs_matcher, const Matcher< Node * > &rhs_matcher)
const int kSmiTagSize
Definition: v8.h:5743
const int kApiPointerSize
Definition: v8.h:5732
const int kHeapObjectTag
Definition: v8.h:5737
const intptr_t kSmiTagMask
Definition: v8.h:5744
const int kSmiTag
Definition: v8.h:5742
Debugger support for the V8 JavaScript engine.
Definition: accessors.cc:20