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.
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"
16 using testing::Capture;
17 using testing::CaptureEq;
23 // TODO(bmeurer): Find a new home for these functions.
24 inline std::ostream& operator<<(std::ostream& os, const MachineType& type) {
27 return os << ost.c_str();
31 class ChangeLoweringTest : public GraphTest {
33 ChangeLoweringTest() : simplified_(zone()) {}
34 virtual ~ChangeLoweringTest() {}
36 virtual MachineType WordRepresentation() const = 0;
39 int HeapNumberValueOffset() const {
40 STATIC_ASSERT(HeapNumber::kValueOffset % kApiPointerSize == 0);
41 return (HeapNumber::kValueOffset / kApiPointerSize) * PointerSize() -
44 bool Is32() const { return WordRepresentation() == kRepWord32; }
45 int PointerSize() const {
46 switch (WordRepresentation()) {
57 int SmiMaxValue() const { return -(SmiMinValue() + 1); }
58 int SmiMinValue() const {
59 return static_cast<int>(0xffffffffu << (SmiValueSize() - 1));
61 int SmiShiftAmount() const { return kSmiTagSize + SmiShiftSize(); }
62 int SmiShiftSize() const {
63 return Is32() ? SmiTagging<4>::SmiShiftSize()
64 : SmiTagging<8>::SmiShiftSize();
66 int SmiValueSize() const {
67 return Is32() ? SmiTagging<4>::SmiValueSize()
68 : SmiTagging<8>::SmiValueSize();
71 Node* Parameter(int32_t index = 0) {
72 return graph()->NewNode(common()->Parameter(index), graph()->start());
75 Reduction Reduce(Node* node) {
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);
86 SimplifiedOperatorBuilder* simplified() { return &simplified_; }
88 Matcher<Node*> IsAllocateHeapNumber(const Matcher<Node*>& effect_matcher,
89 const Matcher<Node*>& control_matcher) {
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,
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);
105 SimplifiedOperatorBuilder simplified_;
109 // -----------------------------------------------------------------------------
113 class ChangeLoweringCommonTest
114 : public ChangeLoweringTest,
115 public ::testing::WithParamInterface<MachineType> {
117 virtual ~ChangeLoweringCommonTest() {}
119 virtual MachineType WordRepresentation() const FINAL OVERRIDE {
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());
131 Node* phi = reduction.replacement();
132 Capture<Node*> branch;
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)))));
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());
148 EXPECT_THAT(reduction.replacement(), IsWordEqual(val, IsTrueConstant()));
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());
158 Node* finish = reduction.replacement();
159 Capture<Node*> heap_number;
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())));
171 TARGET_TEST_P(ChangeLoweringCommonTest, StringAdd) {
173 graph()->NewNode(simplified()->StringAdd(), Parameter(0), Parameter(1));
174 Reduction reduction = Reduce(node);
175 EXPECT_FALSE(reduction.Changed());
179 INSTANTIATE_TEST_CASE_P(ChangeLoweringTest, ChangeLoweringCommonTest,
180 ::testing::Values(kRepWord32, kRepWord64));
183 // -----------------------------------------------------------------------------
187 class ChangeLowering32Test : public ChangeLoweringTest {
189 virtual ~ChangeLowering32Test() {}
190 virtual MachineType WordRepresentation() const FINAL OVERRIDE {
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());
202 Node* phi = reduction.replacement();
203 Capture<Node*> add, branch, heap_number, if_true;
206 IsPhi(kMachAnyTagged,
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))),
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()))))));
223 TARGET_TEST_F(ChangeLowering32Test, ChangeTaggedToFloat64) {
224 STATIC_ASSERT(kSmiTag == 0);
225 STATIC_ASSERT(kSmiTagSize == 1);
227 Node* val = Parameter(0);
228 Node* node = graph()->NewNode(simplified()->ChangeTaggedToFloat64(), val);
229 Reduction reduction = Reduce(node);
230 ASSERT_TRUE(reduction.Changed());
232 Node* phi = reduction.replacement();
233 Capture<Node*> branch, if_true;
238 IsLoad(kMachFloat64, val, IsInt32Constant(HeapNumberValueOffset()),
239 IsControlEffect(CaptureEq(&if_true))),
240 IsChangeInt32ToFloat64(
241 IsWord32Sar(val, IsInt32Constant(SmiShiftAmount()))),
243 AllOf(CaptureEq(&if_true),
246 IsBranch(IsWord32And(val, IsInt32Constant(kSmiTagMask)),
247 graph()->start())))),
248 IsIfFalse(CaptureEq(&branch)))));
252 TARGET_TEST_F(ChangeLowering32Test, ChangeTaggedToInt32) {
253 STATIC_ASSERT(kSmiTag == 0);
254 STATIC_ASSERT(kSmiTagSize == 1);
256 Node* val = Parameter(0);
257 Node* node = graph()->NewNode(simplified()->ChangeTaggedToInt32(), val);
258 Reduction reduction = Reduce(node);
259 ASSERT_TRUE(reduction.Changed());
261 Node* phi = reduction.replacement();
262 Capture<Node*> branch, if_true;
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))),
273 IsBranch(IsWord32And(val, IsInt32Constant(kSmiTagMask)),
274 graph()->start()))))));
278 TARGET_TEST_F(ChangeLowering32Test, ChangeTaggedToUint32) {
279 STATIC_ASSERT(kSmiTag == 0);
280 STATIC_ASSERT(kSmiTagSize == 1);
282 Node* val = Parameter(0);
283 Node* node = graph()->NewNode(simplified()->ChangeTaggedToUint32(), val);
284 Reduction reduction = Reduce(node);
285 ASSERT_TRUE(reduction.Changed());
287 Node* phi = reduction.replacement();
288 Capture<Node*> branch, if_true;
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))),
299 IsBranch(IsWord32And(val, IsInt32Constant(kSmiTagMask)),
300 graph()->start()))))));
304 TARGET_TEST_F(ChangeLowering32Test, ChangeUint32ToTagged) {
305 STATIC_ASSERT(kSmiTag == 0);
306 STATIC_ASSERT(kSmiTagSize == 1);
308 Node* val = Parameter(0);
309 Node* node = graph()->NewNode(simplified()->ChangeUint32ToTagged(), val);
310 Reduction reduction = Reduce(node);
311 ASSERT_TRUE(reduction.Changed());
313 Node* phi = reduction.replacement();
314 Capture<Node*> branch, heap_number, if_false;
318 kMachAnyTagged, IsWord32Shl(val, IsInt32Constant(SmiShiftAmount())),
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))),
327 IsIfTrue(AllOf(CaptureEq(&branch),
328 IsBranch(IsUint32LessThanOrEqual(
329 val, IsInt32Constant(SmiMaxValue())),
331 AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch))))));
335 // -----------------------------------------------------------------------------
339 class ChangeLowering64Test : public ChangeLoweringTest {
341 virtual ~ChangeLowering64Test() {}
342 virtual MachineType WordRepresentation() const FINAL OVERRIDE {
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());
354 EXPECT_THAT(reduction.replacement(),
355 IsWord64Shl(IsChangeInt32ToInt64(val),
356 IsInt32Constant(SmiShiftAmount())));
360 TARGET_TEST_F(ChangeLowering64Test, ChangeTaggedToFloat64) {
361 STATIC_ASSERT(kSmiTag == 0);
362 STATIC_ASSERT(kSmiTagSize == 1);
364 Node* val = Parameter(0);
365 Node* node = graph()->NewNode(simplified()->ChangeTaggedToFloat64(), val);
366 Reduction reduction = Reduce(node);
367 ASSERT_TRUE(reduction.Changed());
369 Node* phi = reduction.replacement();
370 Capture<Node*> branch, if_true;
375 IsLoad(kMachFloat64, val, IsInt32Constant(HeapNumberValueOffset()),
376 IsControlEffect(CaptureEq(&if_true))),
377 IsChangeInt32ToFloat64(IsTruncateInt64ToInt32(
378 IsWord64Sar(val, IsInt32Constant(SmiShiftAmount())))),
380 AllOf(CaptureEq(&if_true),
383 IsBranch(IsWord64And(val, IsInt32Constant(kSmiTagMask)),
384 graph()->start())))),
385 IsIfFalse(CaptureEq(&branch)))));
389 TARGET_TEST_F(ChangeLowering64Test, ChangeTaggedToInt32) {
390 STATIC_ASSERT(kSmiTag == 0);
391 STATIC_ASSERT(kSmiTagSize == 1);
393 Node* val = Parameter(0);
394 Node* node = graph()->NewNode(simplified()->ChangeTaggedToInt32(), val);
395 Reduction reduction = Reduce(node);
396 ASSERT_TRUE(reduction.Changed());
398 Node* phi = reduction.replacement();
399 Capture<Node*> branch, if_true;
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))),
411 IsBranch(IsWord64And(val, IsInt32Constant(kSmiTagMask)),
412 graph()->start()))))));
416 TARGET_TEST_F(ChangeLowering64Test, ChangeTaggedToUint32) {
417 STATIC_ASSERT(kSmiTag == 0);
418 STATIC_ASSERT(kSmiTagSize == 1);
420 Node* val = Parameter(0);
421 Node* node = graph()->NewNode(simplified()->ChangeTaggedToUint32(), val);
422 Reduction reduction = Reduce(node);
423 ASSERT_TRUE(reduction.Changed());
425 Node* phi = reduction.replacement();
426 Capture<Node*> branch, if_true;
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))),
438 IsBranch(IsWord64And(val, IsInt32Constant(kSmiTagMask)),
439 graph()->start()))))));
443 TARGET_TEST_F(ChangeLowering64Test, ChangeUint32ToTagged) {
444 STATIC_ASSERT(kSmiTag == 0);
445 STATIC_ASSERT(kSmiTagSize == 1);
447 Node* val = Parameter(0);
448 Node* node = graph()->NewNode(simplified()->ChangeUint32ToTagged(), val);
449 Reduction reduction = Reduce(node);
450 ASSERT_TRUE(reduction.Changed());
452 Node* phi = reduction.replacement();
453 Capture<Node*> branch, heap_number, if_false;
457 kMachAnyTagged, IsWord64Shl(IsChangeUint32ToUint64(val),
458 IsInt32Constant(SmiShiftAmount())),
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))),
467 IsIfTrue(AllOf(CaptureEq(&branch),
468 IsBranch(IsUint32LessThanOrEqual(
469 val, IsInt32Constant(SmiMaxValue())),
471 AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch))))));
474 } // namespace compiler
475 } // namespace internal