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 TypedGraphTest {
28 ChangeLoweringTest() : simplified_(zone()) {}
30 virtual MachineType WordRepresentation() const = 0;
33 bool Is32() const { return WordRepresentation() == kRepWord32; }
34 bool Is64() const { return WordRepresentation() == kRepWord64; }
36 Reduction Reduce(Node* node) {
37 MachineOperatorBuilder machine(zone(), WordRepresentation());
38 JSOperatorBuilder javascript(zone());
39 JSGraph jsgraph(isolate(), graph(), common(), &javascript, &machine);
40 ChangeLowering reducer(&jsgraph);
41 return reducer.Reduce(node);
44 SimplifiedOperatorBuilder* simplified() { return &simplified_; }
46 Matcher<Node*> IsAllocateHeapNumber(const Matcher<Node*>& effect_matcher,
47 const Matcher<Node*>& control_matcher) {
48 return IsCall(_, IsHeapConstant(Unique<HeapObject>::CreateImmovable(
49 AllocateHeapNumberStub(isolate()).GetCode())),
50 IsNumberConstant(BitEq(0.0)), effect_matcher,
53 Matcher<Node*> IsChangeInt32ToSmi(const Matcher<Node*>& value_matcher) {
54 return Is64() ? IsWord64Shl(IsChangeInt32ToInt64(value_matcher),
55 IsSmiShiftBitsConstant())
56 : IsWord32Shl(value_matcher, IsSmiShiftBitsConstant());
58 Matcher<Node*> IsChangeSmiToInt32(const Matcher<Node*>& value_matcher) {
59 return Is64() ? IsTruncateInt64ToInt32(
60 IsWord64Sar(value_matcher, IsSmiShiftBitsConstant()))
61 : IsWord32Sar(value_matcher, IsSmiShiftBitsConstant());
63 Matcher<Node*> IsChangeUint32ToSmi(const Matcher<Node*>& value_matcher) {
64 return Is64() ? IsWord64Shl(IsChangeUint32ToUint64(value_matcher),
65 IsSmiShiftBitsConstant())
66 : IsWord32Shl(value_matcher, IsSmiShiftBitsConstant());
68 Matcher<Node*> IsLoadHeapNumber(const Matcher<Node*>& value_matcher,
69 const Matcher<Node*>& control_matcher) {
70 return IsLoad(kMachFloat64, value_matcher,
71 IsIntPtrConstant(HeapNumber::kValueOffset - kHeapObjectTag),
72 graph()->start(), control_matcher);
74 Matcher<Node*> IsIntPtrConstant(int value) {
75 return Is32() ? IsInt32Constant(value) : IsInt64Constant(value);
77 Matcher<Node*> IsSmiShiftBitsConstant() {
78 return IsIntPtrConstant(kSmiShiftSize + kSmiTagSize);
80 Matcher<Node*> IsWordEqual(const Matcher<Node*>& lhs_matcher,
81 const Matcher<Node*>& rhs_matcher) {
82 return Is32() ? IsWord32Equal(lhs_matcher, rhs_matcher)
83 : IsWord64Equal(lhs_matcher, rhs_matcher);
87 SimplifiedOperatorBuilder simplified_;
91 // -----------------------------------------------------------------------------
95 class ChangeLoweringCommonTest
96 : public ChangeLoweringTest,
97 public ::testing::WithParamInterface<MachineType> {
99 ~ChangeLoweringCommonTest() OVERRIDE {}
101 MachineType WordRepresentation() const FINAL { return GetParam(); }
105 TARGET_TEST_P(ChangeLoweringCommonTest, ChangeBitToBool) {
106 Node* value = Parameter(Type::Boolean());
108 Reduce(graph()->NewNode(simplified()->ChangeBitToBool(), value));
109 ASSERT_TRUE(r.Changed());
110 EXPECT_THAT(r.replacement(), IsSelect(kMachAnyTagged, value, IsTrueConstant(),
115 TARGET_TEST_P(ChangeLoweringCommonTest, ChangeBoolToBit) {
116 Node* value = Parameter(Type::Number());
118 Reduce(graph()->NewNode(simplified()->ChangeBoolToBit(), value));
119 ASSERT_TRUE(r.Changed());
120 EXPECT_THAT(r.replacement(), IsWordEqual(value, IsTrueConstant()));
124 TARGET_TEST_P(ChangeLoweringCommonTest, ChangeFloat64ToTagged) {
125 Node* value = Parameter(Type::Number());
127 Reduce(graph()->NewNode(simplified()->ChangeFloat64ToTagged(), value));
128 ASSERT_TRUE(r.Changed());
129 Capture<Node*> heap_number;
133 AllOf(CaptureEq(&heap_number),
134 IsAllocateHeapNumber(IsValueEffect(value), graph()->start())),
135 IsStore(StoreRepresentation(kMachFloat64, kNoWriteBarrier),
136 CaptureEq(&heap_number),
137 IsIntPtrConstant(HeapNumber::kValueOffset - kHeapObjectTag),
138 value, CaptureEq(&heap_number), graph()->start())));
142 TARGET_TEST_P(ChangeLoweringCommonTest, ChangeInt32ToTaggedWithSignedSmall) {
143 Node* value = Parameter(Type::SignedSmall());
145 Reduce(graph()->NewNode(simplified()->ChangeInt32ToTagged(), value));
146 ASSERT_TRUE(r.Changed());
147 EXPECT_THAT(r.replacement(), IsChangeInt32ToSmi(value));
151 TARGET_TEST_P(ChangeLoweringCommonTest, ChangeUint32ToTaggedWithUnsignedSmall) {
152 Node* value = Parameter(Type::UnsignedSmall());
154 Reduce(graph()->NewNode(simplified()->ChangeUint32ToTagged(), value));
155 ASSERT_TRUE(r.Changed());
156 EXPECT_THAT(r.replacement(), IsChangeUint32ToSmi(value));
160 TARGET_TEST_P(ChangeLoweringCommonTest, ChangeTaggedToInt32WithTaggedSigned) {
161 Node* value = Parameter(Type::TaggedSigned());
163 Reduce(graph()->NewNode(simplified()->ChangeTaggedToInt32(), value));
164 ASSERT_TRUE(r.Changed());
165 EXPECT_THAT(r.replacement(), IsChangeSmiToInt32(value));
169 TARGET_TEST_P(ChangeLoweringCommonTest, ChangeTaggedToInt32WithTaggedPointer) {
170 Node* value = Parameter(Type::TaggedPointer());
172 Reduce(graph()->NewNode(simplified()->ChangeTaggedToInt32(), value));
173 ASSERT_TRUE(r.Changed());
174 EXPECT_THAT(r.replacement(), IsChangeFloat64ToInt32(
175 IsLoadHeapNumber(value, graph()->start())));
179 TARGET_TEST_P(ChangeLoweringCommonTest, ChangeTaggedToUint32WithTaggedSigned) {
180 Node* value = Parameter(Type::TaggedSigned());
182 Reduce(graph()->NewNode(simplified()->ChangeTaggedToUint32(), value));
183 ASSERT_TRUE(r.Changed());
184 EXPECT_THAT(r.replacement(), IsChangeSmiToInt32(value));
188 TARGET_TEST_P(ChangeLoweringCommonTest, ChangeTaggedToUint32WithTaggedPointer) {
189 Node* value = Parameter(Type::TaggedPointer());
191 Reduce(graph()->NewNode(simplified()->ChangeTaggedToUint32(), value));
192 ASSERT_TRUE(r.Changed());
193 EXPECT_THAT(r.replacement(), IsChangeFloat64ToUint32(
194 IsLoadHeapNumber(value, graph()->start())));
198 INSTANTIATE_TEST_CASE_P(ChangeLoweringTest, ChangeLoweringCommonTest,
199 ::testing::Values(kRepWord32, kRepWord64));
202 // -----------------------------------------------------------------------------
206 class ChangeLowering32Test : public ChangeLoweringTest {
208 ~ChangeLowering32Test() OVERRIDE {}
209 MachineType WordRepresentation() const FINAL { return kRepWord32; }
213 TARGET_TEST_F(ChangeLowering32Test, ChangeInt32ToTagged) {
214 Node* value = Parameter(Type::Integral32());
215 Node* node = graph()->NewNode(simplified()->ChangeInt32ToTagged(), value);
216 Reduction r = Reduce(node);
217 ASSERT_TRUE(r.Changed());
218 Capture<Node*> add, branch, heap_number, if_true;
221 IsPhi(kMachAnyTagged,
222 IsFinish(AllOf(CaptureEq(&heap_number),
223 IsAllocateHeapNumber(_, CaptureEq(&if_true))),
224 IsStore(StoreRepresentation(kMachFloat64, kNoWriteBarrier),
225 CaptureEq(&heap_number),
226 IsIntPtrConstant(HeapNumber::kValueOffset -
228 IsChangeInt32ToFloat64(value),
229 CaptureEq(&heap_number), CaptureEq(&if_true))),
230 IsProjection(0, AllOf(CaptureEq(&add),
231 IsInt32AddWithOverflow(value, value))),
232 IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))),
233 IsIfFalse(AllOf(CaptureEq(&branch),
234 IsBranch(IsProjection(1, CaptureEq(&add)),
235 graph()->start()))))));
239 TARGET_TEST_F(ChangeLowering32Test, ChangeTaggedToFloat64) {
240 STATIC_ASSERT(kSmiTag == 0);
241 STATIC_ASSERT(kSmiTagSize == 1);
243 Node* value = Parameter(Type::Number());
244 Node* node = graph()->NewNode(simplified()->ChangeTaggedToFloat64(), value);
245 Reduction r = Reduce(node);
246 ASSERT_TRUE(r.Changed());
247 Capture<Node*> branch, if_true;
250 IsPhi(kMachFloat64, IsLoadHeapNumber(value, CaptureEq(&if_true)),
251 IsChangeInt32ToFloat64(IsWord32Sar(
252 value, IsInt32Constant(kSmiTagSize + kSmiShiftSize))),
253 IsMerge(AllOf(CaptureEq(&if_true),
256 IsBranch(IsWord32And(
257 value, IsInt32Constant(kSmiTagMask)),
258 graph()->start())))),
259 IsIfFalse(CaptureEq(&branch)))));
263 TARGET_TEST_F(ChangeLowering32Test, ChangeTaggedToInt32) {
264 STATIC_ASSERT(kSmiTag == 0);
265 STATIC_ASSERT(kSmiTagSize == 1);
267 Node* value = Parameter(Type::Signed32());
268 Node* node = graph()->NewNode(simplified()->ChangeTaggedToInt32(), value);
269 Reduction r = Reduce(node);
270 ASSERT_TRUE(r.Changed());
271 Capture<Node*> branch, if_true;
276 IsChangeFloat64ToInt32(IsLoadHeapNumber(value, CaptureEq(&if_true))),
277 IsWord32Sar(value, IsInt32Constant(kSmiTagSize + kSmiShiftSize)),
278 IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))),
281 IsBranch(IsWord32And(value, IsInt32Constant(kSmiTagMask)),
282 graph()->start()))))));
286 TARGET_TEST_F(ChangeLowering32Test, ChangeTaggedToUint32) {
287 STATIC_ASSERT(kSmiTag == 0);
288 STATIC_ASSERT(kSmiTagSize == 1);
290 Node* value = Parameter(Type::Unsigned32());
291 Node* node = graph()->NewNode(simplified()->ChangeTaggedToUint32(), value);
292 Reduction r = Reduce(node);
293 ASSERT_TRUE(r.Changed());
294 Capture<Node*> branch, if_true;
299 IsChangeFloat64ToUint32(IsLoadHeapNumber(value, CaptureEq(&if_true))),
300 IsWord32Sar(value, IsInt32Constant(kSmiTagSize + kSmiShiftSize)),
301 IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))),
304 IsBranch(IsWord32And(value, IsInt32Constant(kSmiTagMask)),
305 graph()->start()))))));
309 TARGET_TEST_F(ChangeLowering32Test, ChangeUint32ToTagged) {
310 STATIC_ASSERT(kSmiTag == 0);
311 STATIC_ASSERT(kSmiTagSize == 1);
313 Node* value = Parameter(Type::Number());
314 Node* node = graph()->NewNode(simplified()->ChangeUint32ToTagged(), value);
315 Reduction r = Reduce(node);
316 ASSERT_TRUE(r.Changed());
317 Capture<Node*> branch, heap_number, if_false;
322 IsWord32Shl(value, IsInt32Constant(kSmiTagSize + kSmiShiftSize)),
323 IsFinish(AllOf(CaptureEq(&heap_number),
324 IsAllocateHeapNumber(_, CaptureEq(&if_false))),
325 IsStore(StoreRepresentation(kMachFloat64, kNoWriteBarrier),
326 CaptureEq(&heap_number),
327 IsInt32Constant(HeapNumber::kValueOffset -
329 IsChangeUint32ToFloat64(value),
330 CaptureEq(&heap_number), CaptureEq(&if_false))),
331 IsMerge(IsIfTrue(AllOf(
333 IsBranch(IsUint32LessThanOrEqual(
334 value, IsInt32Constant(Smi::kMaxValue)),
336 AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch))))));
340 // -----------------------------------------------------------------------------
344 class ChangeLowering64Test : public ChangeLoweringTest {
346 ~ChangeLowering64Test() OVERRIDE {}
347 MachineType WordRepresentation() const FINAL { return kRepWord64; }
351 TARGET_TEST_F(ChangeLowering64Test, ChangeInt32ToTagged) {
352 Node* value = Parameter(Type::Signed32());
353 Node* node = graph()->NewNode(simplified()->ChangeInt32ToTagged(), value);
354 Reduction r = Reduce(node);
355 ASSERT_TRUE(r.Changed());
356 EXPECT_THAT(r.replacement(), IsChangeInt32ToSmi(value));
360 TARGET_TEST_F(ChangeLowering64Test, ChangeTaggedToFloat64) {
361 STATIC_ASSERT(kSmiTag == 0);
362 STATIC_ASSERT(kSmiTagSize == 1);
364 Node* value = Parameter(Type::Number());
365 Node* node = graph()->NewNode(simplified()->ChangeTaggedToFloat64(), value);
366 Reduction r = Reduce(node);
367 ASSERT_TRUE(r.Changed());
368 Capture<Node*> branch, if_true;
371 IsPhi(kMachFloat64, IsLoadHeapNumber(value, CaptureEq(&if_true)),
372 IsChangeInt32ToFloat64(IsTruncateInt64ToInt32(IsWord64Sar(
373 value, IsInt64Constant(kSmiTagSize + kSmiShiftSize)))),
374 IsMerge(AllOf(CaptureEq(&if_true),
377 IsBranch(IsWord64And(
378 value, IsInt64Constant(kSmiTagMask)),
379 graph()->start())))),
380 IsIfFalse(CaptureEq(&branch)))));
384 TARGET_TEST_F(ChangeLowering64Test, ChangeTaggedToInt32) {
385 STATIC_ASSERT(kSmiTag == 0);
386 STATIC_ASSERT(kSmiTagSize == 1);
388 Node* value = Parameter(Type::Signed32());
389 Node* node = graph()->NewNode(simplified()->ChangeTaggedToInt32(), value);
390 Reduction r = Reduce(node);
391 ASSERT_TRUE(r.Changed());
392 Capture<Node*> branch, if_true;
397 IsChangeFloat64ToInt32(IsLoadHeapNumber(value, CaptureEq(&if_true))),
398 IsTruncateInt64ToInt32(
399 IsWord64Sar(value, IsInt64Constant(kSmiTagSize + kSmiShiftSize))),
400 IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))),
403 IsBranch(IsWord64And(value, IsInt64Constant(kSmiTagMask)),
404 graph()->start()))))));
408 TARGET_TEST_F(ChangeLowering64Test, ChangeTaggedToUint32) {
409 STATIC_ASSERT(kSmiTag == 0);
410 STATIC_ASSERT(kSmiTagSize == 1);
412 Node* value = Parameter(Type::Unsigned32());
413 Node* node = graph()->NewNode(simplified()->ChangeTaggedToUint32(), value);
414 Reduction r = Reduce(node);
415 ASSERT_TRUE(r.Changed());
416 Capture<Node*> branch, if_true;
421 IsChangeFloat64ToUint32(IsLoadHeapNumber(value, CaptureEq(&if_true))),
422 IsTruncateInt64ToInt32(
423 IsWord64Sar(value, IsInt64Constant(kSmiTagSize + kSmiShiftSize))),
424 IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))),
427 IsBranch(IsWord64And(value, IsInt64Constant(kSmiTagMask)),
428 graph()->start()))))));
432 TARGET_TEST_F(ChangeLowering64Test, ChangeUint32ToTagged) {
433 STATIC_ASSERT(kSmiTag == 0);
434 STATIC_ASSERT(kSmiTagSize == 1);
436 Node* value = Parameter(Type::Number());
437 Node* node = graph()->NewNode(simplified()->ChangeUint32ToTagged(), value);
438 Reduction r = Reduce(node);
439 ASSERT_TRUE(r.Changed());
440 Capture<Node*> branch, heap_number, if_false;
445 IsWord64Shl(IsChangeUint32ToUint64(value),
446 IsInt64Constant(kSmiTagSize + kSmiShiftSize)),
447 IsFinish(AllOf(CaptureEq(&heap_number),
448 IsAllocateHeapNumber(_, CaptureEq(&if_false))),
449 IsStore(StoreRepresentation(kMachFloat64, kNoWriteBarrier),
450 CaptureEq(&heap_number),
451 IsInt64Constant(HeapNumber::kValueOffset -
453 IsChangeUint32ToFloat64(value),
454 CaptureEq(&heap_number), CaptureEq(&if_false))),
455 IsMerge(IsIfTrue(AllOf(
457 IsBranch(IsUint32LessThanOrEqual(
458 value, IsInt32Constant(Smi::kMaxValue)),
460 AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch))))));
463 } // namespace compiler
464 } // namespace internal