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/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"
19 using testing::Capture;
20 using testing::CaptureEq;
26 class ChangeLoweringTest : public GraphTest {
28 ChangeLoweringTest() : simplified_(zone()) {}
29 ~ChangeLoweringTest() OVERRIDE {}
31 virtual MachineType WordRepresentation() const = 0;
34 int HeapNumberValueOffset() const {
35 STATIC_ASSERT(HeapNumber::kValueOffset % kApiPointerSize == 0);
36 return (HeapNumber::kValueOffset / kApiPointerSize) * PointerSize() -
39 bool Is32() const { return WordRepresentation() == kRepWord32; }
40 int PointerSize() const {
41 switch (WordRepresentation()) {
52 int SmiMaxValue() const { return -(SmiMinValue() + 1); }
53 int SmiMinValue() const {
54 return static_cast<int>(0xffffffffu << (SmiValueSize() - 1));
56 int SmiShiftAmount() const { return kSmiTagSize + SmiShiftSize(); }
57 int SmiShiftSize() const {
58 return Is32() ? SmiTagging<4>::SmiShiftSize()
59 : SmiTagging<8>::SmiShiftSize();
61 int SmiValueSize() const {
62 return Is32() ? SmiTagging<4>::SmiValueSize()
63 : SmiTagging<8>::SmiValueSize();
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);
74 SimplifiedOperatorBuilder* simplified() { return &simplified_; }
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,
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(),
89 Matcher<Node*> IsIntPtrConstant(int value) {
90 return Is32() ? IsInt32Constant(value) : IsInt64Constant(value);
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);
99 SimplifiedOperatorBuilder simplified_;
103 // -----------------------------------------------------------------------------
107 class ChangeLoweringCommonTest
108 : public ChangeLoweringTest,
109 public ::testing::WithParamInterface<MachineType> {
111 ~ChangeLoweringCommonTest() OVERRIDE {}
113 MachineType WordRepresentation() const FINAL { return GetParam(); }
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()));
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());
134 EXPECT_THAT(reduction.replacement(), IsWordEqual(val, IsTrueConstant()));
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());
144 Node* finish = reduction.replacement();
145 Capture<Node*> heap_number;
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())));
158 TARGET_TEST_P(ChangeLoweringCommonTest, StringAdd) {
160 graph()->NewNode(simplified()->StringAdd(), Parameter(0), Parameter(1));
161 Reduction reduction = Reduce(node);
162 EXPECT_FALSE(reduction.Changed());
166 INSTANTIATE_TEST_CASE_P(ChangeLoweringTest, ChangeLoweringCommonTest,
167 ::testing::Values(kRepWord32, kRepWord64));
170 // -----------------------------------------------------------------------------
174 class ChangeLowering32Test : public ChangeLoweringTest {
176 ~ChangeLowering32Test() OVERRIDE {}
177 MachineType WordRepresentation() const FINAL { return kRepWord32; }
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());
188 Node* phi = reduction.replacement();
189 Capture<Node*> add, branch, heap_number, if_true;
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))),
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()))))));
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());
216 Node* change = reduction.replacement();
217 Capture<Node*> add, branch, heap_number, if_true;
218 EXPECT_THAT(change, IsWord32Shl(val, IsInt32Constant(SmiShiftAmount())));
222 TARGET_TEST_F(ChangeLowering32Test, ChangeTaggedToFloat64) {
223 STATIC_ASSERT(kSmiTag == 0);
224 STATIC_ASSERT(kSmiTagSize == 1);
226 Node* val = Parameter(0);
227 Node* node = graph()->NewNode(simplified()->ChangeTaggedToFloat64(), val);
228 Reduction reduction = Reduce(node);
229 ASSERT_TRUE(reduction.Changed());
231 Node* phi = reduction.replacement();
232 Capture<Node*> branch, if_true;
236 kMachFloat64, IsLoadHeapNumber(val, CaptureEq(&if_true)),
237 IsChangeInt32ToFloat64(
238 IsWord32Sar(val, IsInt32Constant(SmiShiftAmount()))),
240 AllOf(CaptureEq(&if_true),
243 IsBranch(IsWord32And(val, IsInt32Constant(kSmiTagMask)),
244 graph()->start())))),
245 IsIfFalse(CaptureEq(&branch)))));
249 TARGET_TEST_F(ChangeLowering32Test, ChangeTaggedToInt32) {
250 STATIC_ASSERT(kSmiTag == 0);
251 STATIC_ASSERT(kSmiTagSize == 1);
253 Node* val = Parameter(0);
254 Node* node = graph()->NewNode(simplified()->ChangeTaggedToInt32(), val);
255 Reduction reduction = Reduce(node);
256 ASSERT_TRUE(reduction.Changed());
258 Node* phi = reduction.replacement();
259 Capture<Node*> branch, if_true;
263 IsChangeFloat64ToInt32(IsLoadHeapNumber(val, CaptureEq(&if_true))),
264 IsWord32Sar(val, IsInt32Constant(SmiShiftAmount())),
265 IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))),
268 IsBranch(IsWord32And(val, IsInt32Constant(kSmiTagMask)),
269 graph()->start()))))));
273 TARGET_TEST_F(ChangeLowering32Test, ChangeTaggedToUint32) {
274 STATIC_ASSERT(kSmiTag == 0);
275 STATIC_ASSERT(kSmiTagSize == 1);
277 Node* val = Parameter(0);
278 Node* node = graph()->NewNode(simplified()->ChangeTaggedToUint32(), val);
279 Reduction reduction = Reduce(node);
280 ASSERT_TRUE(reduction.Changed());
282 Node* phi = reduction.replacement();
283 Capture<Node*> branch, if_true;
287 IsChangeFloat64ToUint32(IsLoadHeapNumber(val, CaptureEq(&if_true))),
288 IsWord32Sar(val, IsInt32Constant(SmiShiftAmount())),
289 IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))),
292 IsBranch(IsWord32And(val, IsInt32Constant(kSmiTagMask)),
293 graph()->start()))))));
297 TARGET_TEST_F(ChangeLowering32Test, ChangeUint32ToTagged) {
298 STATIC_ASSERT(kSmiTag == 0);
299 STATIC_ASSERT(kSmiTagSize == 1);
301 Node* val = Parameter(0);
302 Node* node = graph()->NewNode(simplified()->ChangeUint32ToTagged(), val);
303 Reduction reduction = Reduce(node);
304 ASSERT_TRUE(reduction.Changed());
306 Node* phi = reduction.replacement();
307 Capture<Node*> branch, heap_number, if_false;
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))),
320 IsIfTrue(AllOf(CaptureEq(&branch),
321 IsBranch(IsUint32LessThanOrEqual(
322 val, IsInt32Constant(SmiMaxValue())),
324 AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch))))));
328 // -----------------------------------------------------------------------------
332 class ChangeLowering64Test : public ChangeLoweringTest {
334 ~ChangeLowering64Test() OVERRIDE {}
335 MachineType WordRepresentation() const FINAL { return kRepWord64; }
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());
345 EXPECT_THAT(reduction.replacement(),
346 IsWord64Shl(IsChangeInt32ToInt64(val),
347 IsInt64Constant(SmiShiftAmount())));
351 TARGET_TEST_F(ChangeLowering64Test, ChangeTaggedToFloat64) {
352 STATIC_ASSERT(kSmiTag == 0);
353 STATIC_ASSERT(kSmiTagSize == 1);
355 Node* val = Parameter(0);
356 Node* node = graph()->NewNode(simplified()->ChangeTaggedToFloat64(), val);
357 Reduction reduction = Reduce(node);
358 ASSERT_TRUE(reduction.Changed());
360 Node* phi = reduction.replacement();
361 Capture<Node*> branch, if_true;
365 kMachFloat64, IsLoadHeapNumber(val, CaptureEq(&if_true)),
366 IsChangeInt32ToFloat64(IsTruncateInt64ToInt32(
367 IsWord64Sar(val, IsInt64Constant(SmiShiftAmount())))),
369 AllOf(CaptureEq(&if_true),
372 IsBranch(IsWord64And(val, IsInt64Constant(kSmiTagMask)),
373 graph()->start())))),
374 IsIfFalse(CaptureEq(&branch)))));
378 TARGET_TEST_F(ChangeLowering64Test, ChangeTaggedToInt32) {
379 STATIC_ASSERT(kSmiTag == 0);
380 STATIC_ASSERT(kSmiTagSize == 1);
382 Node* val = Parameter(0);
383 Node* node = graph()->NewNode(simplified()->ChangeTaggedToInt32(), val);
384 Reduction reduction = Reduce(node);
385 ASSERT_TRUE(reduction.Changed());
387 Node* phi = reduction.replacement();
388 Capture<Node*> branch, if_true;
392 IsChangeFloat64ToInt32(IsLoadHeapNumber(val, CaptureEq(&if_true))),
393 IsTruncateInt64ToInt32(
394 IsWord64Sar(val, IsInt64Constant(SmiShiftAmount()))),
395 IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))),
398 IsBranch(IsWord64And(val, IsInt64Constant(kSmiTagMask)),
399 graph()->start()))))));
403 TARGET_TEST_F(ChangeLowering64Test, ChangeTaggedToUint32) {
404 STATIC_ASSERT(kSmiTag == 0);
405 STATIC_ASSERT(kSmiTagSize == 1);
407 Node* val = Parameter(0);
408 Node* node = graph()->NewNode(simplified()->ChangeTaggedToUint32(), val);
409 Reduction reduction = Reduce(node);
410 ASSERT_TRUE(reduction.Changed());
412 Node* phi = reduction.replacement();
413 Capture<Node*> branch, if_true;
417 IsChangeFloat64ToUint32(IsLoadHeapNumber(val, CaptureEq(&if_true))),
418 IsTruncateInt64ToInt32(
419 IsWord64Sar(val, IsInt64Constant(SmiShiftAmount()))),
420 IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))),
423 IsBranch(IsWord64And(val, IsInt64Constant(kSmiTagMask)),
424 graph()->start()))))));
428 TARGET_TEST_F(ChangeLowering64Test, ChangeUint32ToTagged) {
429 STATIC_ASSERT(kSmiTag == 0);
430 STATIC_ASSERT(kSmiTagSize == 1);
432 Node* val = Parameter(0);
433 Node* node = graph()->NewNode(simplified()->ChangeUint32ToTagged(), val);
434 Reduction reduction = Reduce(node);
435 ASSERT_TRUE(reduction.Changed());
437 Node* phi = reduction.replacement();
438 Capture<Node*> branch, heap_number, if_false;
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))),
452 IsIfTrue(AllOf(CaptureEq(&branch),
453 IsBranch(IsUint32LessThanOrEqual(
454 val, IsInt32Constant(SmiMaxValue())),
456 AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch))))));
459 } // namespace compiler
460 } // namespace internal