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/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"
15
16 using testing::_;
17 using testing::AllOf;
18 using testing::BitEq;
19 using testing::Capture;
20 using testing::CaptureEq;
21
22 namespace v8 {
23 namespace internal {
24 namespace compiler {
25
26 class ChangeLoweringTest : public TypedGraphTest {
27 public:
ChangeLoweringTest()28 ChangeLoweringTest() : simplified_(zone()) {}
29
30 virtual MachineRepresentation WordRepresentation() const = 0;
31
32 protected:
Is32() const33 bool Is32() const {
34 return WordRepresentation() == MachineRepresentation::kWord32;
35 }
Is64() const36 bool Is64() const {
37 return WordRepresentation() == MachineRepresentation::kWord64;
38 }
39
Reduce(Node * node)40 Reduction Reduce(Node* node) {
41 MachineOperatorBuilder machine(zone(), WordRepresentation());
42 JSOperatorBuilder javascript(zone());
43 JSGraph jsgraph(isolate(), graph(), common(), &javascript, nullptr,
44 &machine);
45 ChangeLowering reducer(&jsgraph);
46 return reducer.Reduce(node);
47 }
48
simplified()49 SimplifiedOperatorBuilder* simplified() { return &simplified_; }
50
IsAllocateHeapNumber(const Matcher<Node * > & effect_matcher,const Matcher<Node * > & control_matcher)51 Matcher<Node*> IsAllocateHeapNumber(const Matcher<Node*>& effect_matcher,
52 const Matcher<Node*>& control_matcher) {
53 return IsCall(
54 _, IsHeapConstant(AllocateHeapNumberStub(isolate()).GetCode()),
55 IsNumberConstant(BitEq(0.0)), effect_matcher, control_matcher);
56 }
IsChangeInt32ToSmi(const Matcher<Node * > & value_matcher)57 Matcher<Node*> IsChangeInt32ToSmi(const Matcher<Node*>& value_matcher) {
58 return Is64() ? IsWord64Shl(IsChangeInt32ToInt64(value_matcher),
59 IsSmiShiftBitsConstant())
60 : IsWord32Shl(value_matcher, IsSmiShiftBitsConstant());
61 }
IsChangeSmiToInt32(const Matcher<Node * > & value_matcher)62 Matcher<Node*> IsChangeSmiToInt32(const Matcher<Node*>& value_matcher) {
63 return Is64() ? IsTruncateInt64ToInt32(
64 IsWord64Sar(value_matcher, IsSmiShiftBitsConstant()))
65 : IsWord32Sar(value_matcher, IsSmiShiftBitsConstant());
66 }
IsChangeUint32ToSmi(const Matcher<Node * > & value_matcher)67 Matcher<Node*> IsChangeUint32ToSmi(const Matcher<Node*>& value_matcher) {
68 return Is64() ? IsWord64Shl(IsChangeUint32ToUint64(value_matcher),
69 IsSmiShiftBitsConstant())
70 : IsWord32Shl(value_matcher, IsSmiShiftBitsConstant());
71 }
IsLoadHeapNumber(const Matcher<Node * > & value_matcher,const Matcher<Node * > & control_matcher)72 Matcher<Node*> IsLoadHeapNumber(const Matcher<Node*>& value_matcher,
73 const Matcher<Node*>& control_matcher) {
74 return IsLoad(MachineType::Float64(), value_matcher,
75 IsIntPtrConstant(HeapNumber::kValueOffset - kHeapObjectTag),
76 graph()->start(), control_matcher);
77 }
IsIntPtrConstant(int value)78 Matcher<Node*> IsIntPtrConstant(int value) {
79 return Is32() ? IsInt32Constant(value) : IsInt64Constant(value);
80 }
IsSmiShiftBitsConstant()81 Matcher<Node*> IsSmiShiftBitsConstant() {
82 return IsIntPtrConstant(kSmiShiftSize + kSmiTagSize);
83 }
IsWordEqual(const Matcher<Node * > & lhs_matcher,const Matcher<Node * > & rhs_matcher)84 Matcher<Node*> IsWordEqual(const Matcher<Node*>& lhs_matcher,
85 const Matcher<Node*>& rhs_matcher) {
86 return Is32() ? IsWord32Equal(lhs_matcher, rhs_matcher)
87 : IsWord64Equal(lhs_matcher, rhs_matcher);
88 }
89
90 private:
91 SimplifiedOperatorBuilder simplified_;
92 };
93
94
95 // -----------------------------------------------------------------------------
96 // Common.
97
98
99 class ChangeLoweringCommonTest
100 : public ChangeLoweringTest,
101 public ::testing::WithParamInterface<MachineRepresentation> {
102 public:
~ChangeLoweringCommonTest()103 ~ChangeLoweringCommonTest() override {}
104
WordRepresentation() const105 MachineRepresentation WordRepresentation() const final { return GetParam(); }
106 };
107
108
TARGET_TEST_P(ChangeLoweringCommonTest,ChangeBitToBool)109 TARGET_TEST_P(ChangeLoweringCommonTest, ChangeBitToBool) {
110 Node* value = Parameter(Type::Boolean());
111 Reduction r =
112 Reduce(graph()->NewNode(simplified()->ChangeBitToBool(), value));
113 ASSERT_TRUE(r.Changed());
114 EXPECT_THAT(r.replacement(), IsSelect(MachineRepresentation::kTagged, value,
115 IsTrueConstant(), IsFalseConstant()));
116 }
117
118
TARGET_TEST_P(ChangeLoweringCommonTest,ChangeBoolToBit)119 TARGET_TEST_P(ChangeLoweringCommonTest, ChangeBoolToBit) {
120 Node* value = Parameter(Type::Number());
121 Reduction r =
122 Reduce(graph()->NewNode(simplified()->ChangeBoolToBit(), value));
123 ASSERT_TRUE(r.Changed());
124 EXPECT_THAT(r.replacement(), IsWordEqual(value, IsTrueConstant()));
125 }
126
127
TARGET_TEST_P(ChangeLoweringCommonTest,ChangeInt32ToTaggedWithSignedSmall)128 TARGET_TEST_P(ChangeLoweringCommonTest, ChangeInt32ToTaggedWithSignedSmall) {
129 Node* value = Parameter(Type::SignedSmall());
130 Reduction r =
131 Reduce(graph()->NewNode(simplified()->ChangeInt32ToTagged(), value));
132 ASSERT_TRUE(r.Changed());
133 EXPECT_THAT(r.replacement(), IsChangeInt32ToSmi(value));
134 }
135
136
TARGET_TEST_P(ChangeLoweringCommonTest,ChangeUint32ToTaggedWithUnsignedSmall)137 TARGET_TEST_P(ChangeLoweringCommonTest, ChangeUint32ToTaggedWithUnsignedSmall) {
138 Node* value = Parameter(Type::UnsignedSmall());
139 Reduction r =
140 Reduce(graph()->NewNode(simplified()->ChangeUint32ToTagged(), value));
141 ASSERT_TRUE(r.Changed());
142 EXPECT_THAT(r.replacement(), IsChangeUint32ToSmi(value));
143 }
144
145
TARGET_TEST_P(ChangeLoweringCommonTest,ChangeTaggedToInt32WithTaggedSigned)146 TARGET_TEST_P(ChangeLoweringCommonTest, ChangeTaggedToInt32WithTaggedSigned) {
147 Node* value = Parameter(Type::TaggedSigned());
148 Reduction r =
149 Reduce(graph()->NewNode(simplified()->ChangeTaggedToInt32(), value));
150 ASSERT_TRUE(r.Changed());
151 EXPECT_THAT(r.replacement(), IsChangeSmiToInt32(value));
152 }
153
154
TARGET_TEST_P(ChangeLoweringCommonTest,ChangeTaggedToInt32WithTaggedPointer)155 TARGET_TEST_P(ChangeLoweringCommonTest, ChangeTaggedToInt32WithTaggedPointer) {
156 Node* value = Parameter(Type::TaggedPointer());
157 Reduction r =
158 Reduce(graph()->NewNode(simplified()->ChangeTaggedToInt32(), value));
159 ASSERT_TRUE(r.Changed());
160 EXPECT_THAT(r.replacement(), IsChangeFloat64ToInt32(
161 IsLoadHeapNumber(value, graph()->start())));
162 }
163
164
TARGET_TEST_P(ChangeLoweringCommonTest,ChangeTaggedToUint32WithTaggedSigned)165 TARGET_TEST_P(ChangeLoweringCommonTest, ChangeTaggedToUint32WithTaggedSigned) {
166 Node* value = Parameter(Type::TaggedSigned());
167 Reduction r =
168 Reduce(graph()->NewNode(simplified()->ChangeTaggedToUint32(), value));
169 ASSERT_TRUE(r.Changed());
170 EXPECT_THAT(r.replacement(), IsChangeSmiToInt32(value));
171 }
172
173
TARGET_TEST_P(ChangeLoweringCommonTest,ChangeTaggedToUint32WithTaggedPointer)174 TARGET_TEST_P(ChangeLoweringCommonTest, ChangeTaggedToUint32WithTaggedPointer) {
175 Node* value = Parameter(Type::TaggedPointer());
176 Reduction r =
177 Reduce(graph()->NewNode(simplified()->ChangeTaggedToUint32(), value));
178 ASSERT_TRUE(r.Changed());
179 EXPECT_THAT(r.replacement(), IsChangeFloat64ToUint32(
180 IsLoadHeapNumber(value, graph()->start())));
181 }
182
183
TARGET_TEST_P(ChangeLoweringCommonTest,StoreFieldSmi)184 TARGET_TEST_P(ChangeLoweringCommonTest, StoreFieldSmi) {
185 FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
186 Handle<Name>::null(), Type::Any(),
187 MachineType::AnyTagged()};
188 Node* p0 = Parameter(Type::TaggedPointer());
189 Node* p1 = Parameter(Type::TaggedSigned());
190 Node* store = graph()->NewNode(simplified()->StoreField(access), p0, p1,
191 graph()->start(), graph()->start());
192 Reduction r = Reduce(store);
193
194 ASSERT_TRUE(r.Changed());
195 EXPECT_THAT(r.replacement(),
196 IsStore(StoreRepresentation(MachineRepresentation::kTagged,
197 kNoWriteBarrier),
198 p0, IsIntPtrConstant(access.offset - access.tag()), p1,
199 graph()->start(), graph()->start()));
200 }
201
202
TARGET_TEST_P(ChangeLoweringCommonTest,StoreFieldTagged)203 TARGET_TEST_P(ChangeLoweringCommonTest, StoreFieldTagged) {
204 FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
205 Handle<Name>::null(), Type::Any(),
206 MachineType::AnyTagged()};
207 Node* p0 = Parameter(Type::TaggedPointer());
208 Node* p1 = Parameter(Type::Tagged());
209 Node* store = graph()->NewNode(simplified()->StoreField(access), p0, p1,
210 graph()->start(), graph()->start());
211 Reduction r = Reduce(store);
212
213 ASSERT_TRUE(r.Changed());
214 EXPECT_THAT(r.replacement(),
215 IsStore(StoreRepresentation(MachineRepresentation::kTagged,
216 kFullWriteBarrier),
217 p0, IsIntPtrConstant(access.offset - access.tag()), p1,
218 graph()->start(), graph()->start()));
219 }
220
221
TARGET_TEST_P(ChangeLoweringCommonTest,LoadField)222 TARGET_TEST_P(ChangeLoweringCommonTest, LoadField) {
223 FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
224 Handle<Name>::null(), Type::Any(),
225 MachineType::AnyTagged()};
226 Node* p0 = Parameter(Type::TaggedPointer());
227 Node* load = graph()->NewNode(simplified()->LoadField(access), p0,
228 graph()->start(), graph()->start());
229 Reduction r = Reduce(load);
230
231 ASSERT_TRUE(r.Changed());
232 Matcher<Node*> index_match = IsIntPtrConstant(access.offset - access.tag());
233 EXPECT_THAT(r.replacement(),
234 IsLoad(MachineType::AnyTagged(), p0,
235 IsIntPtrConstant(access.offset - access.tag()),
236 graph()->start(), graph()->start()));
237 }
238
239
TARGET_TEST_P(ChangeLoweringCommonTest,StoreElementTagged)240 TARGET_TEST_P(ChangeLoweringCommonTest, StoreElementTagged) {
241 ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(),
242 MachineType::AnyTagged()};
243 Node* p0 = Parameter(Type::TaggedPointer());
244 Node* p1 = Parameter(Type::Signed32());
245 Node* p2 = Parameter(Type::Tagged());
246 Node* store = graph()->NewNode(simplified()->StoreElement(access), p0, p1, p2,
247 graph()->start(), graph()->start());
248 Reduction r = Reduce(store);
249
250 const int element_size_shift =
251 ElementSizeLog2Of(access.machine_type.representation());
252 ASSERT_TRUE(r.Changed());
253 Matcher<Node*> index_match =
254 IsInt32Add(IsWord32Shl(p1, IsInt32Constant(element_size_shift)),
255 IsInt32Constant(access.header_size - access.tag()));
256 if (!Is32()) {
257 index_match = IsChangeUint32ToUint64(index_match);
258 }
259
260 EXPECT_THAT(r.replacement(),
261 IsStore(StoreRepresentation(MachineRepresentation::kTagged,
262 kFullWriteBarrier),
263 p0, index_match, p2, graph()->start(), graph()->start()));
264 }
265
266
TARGET_TEST_P(ChangeLoweringCommonTest,StoreElementUint8)267 TARGET_TEST_P(ChangeLoweringCommonTest, StoreElementUint8) {
268 ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
269 Type::Signed32(), MachineType::Uint8()};
270 Node* p0 = Parameter(Type::TaggedPointer());
271 Node* p1 = Parameter(Type::Signed32());
272 Node* p2 = Parameter(Type::Signed32());
273 Node* store = graph()->NewNode(simplified()->StoreElement(access), p0, p1, p2,
274 graph()->start(), graph()->start());
275 Reduction r = Reduce(store);
276
277 ASSERT_TRUE(r.Changed());
278 Matcher<Node*> index_match =
279 IsInt32Add(p1, IsInt32Constant(access.header_size - access.tag()));
280 if (!Is32()) {
281 index_match = IsChangeUint32ToUint64(index_match);
282 }
283
284 EXPECT_THAT(r.replacement(),
285 IsStore(StoreRepresentation(MachineRepresentation::kWord8,
286 kNoWriteBarrier),
287 p0, index_match, p2, graph()->start(), graph()->start()));
288 }
289
290
TARGET_TEST_P(ChangeLoweringCommonTest,LoadElementTagged)291 TARGET_TEST_P(ChangeLoweringCommonTest, LoadElementTagged) {
292 ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(),
293 MachineType::AnyTagged()};
294 Node* p0 = Parameter(Type::TaggedPointer());
295 Node* p1 = Parameter(Type::Signed32());
296 Node* load = graph()->NewNode(simplified()->LoadElement(access), p0, p1,
297 graph()->start(), graph()->start());
298 Reduction r = Reduce(load);
299
300 const int element_size_shift =
301 ElementSizeLog2Of(access.machine_type.representation());
302 ASSERT_TRUE(r.Changed());
303 Matcher<Node*> index_match =
304 IsInt32Add(IsWord32Shl(p1, IsInt32Constant(element_size_shift)),
305 IsInt32Constant(access.header_size - access.tag()));
306 if (!Is32()) {
307 index_match = IsChangeUint32ToUint64(index_match);
308 }
309
310 EXPECT_THAT(r.replacement(), IsLoad(MachineType::AnyTagged(), p0, index_match,
311 graph()->start(), graph()->start()));
312 }
313
314
TARGET_TEST_P(ChangeLoweringCommonTest,LoadElementInt8)315 TARGET_TEST_P(ChangeLoweringCommonTest, LoadElementInt8) {
316 ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
317 Type::Signed32(), MachineType::Int8()};
318 Node* p0 = Parameter(Type::TaggedPointer());
319 Node* p1 = Parameter(Type::Signed32());
320 Node* load = graph()->NewNode(simplified()->LoadElement(access), p0, p1,
321 graph()->start(), graph()->start());
322 Reduction r = Reduce(load);
323
324 ASSERT_TRUE(r.Changed());
325 Matcher<Node*> index_match =
326 IsInt32Add(p1, IsInt32Constant(access.header_size - access.tag()));
327 if (!Is32()) {
328 index_match = IsChangeUint32ToUint64(index_match);
329 }
330
331 EXPECT_THAT(r.replacement(), IsLoad(MachineType::Int8(), p0, index_match,
332 graph()->start(), graph()->start()));
333 }
334
335
TARGET_TEST_P(ChangeLoweringCommonTest,Allocate)336 TARGET_TEST_P(ChangeLoweringCommonTest, Allocate) {
337 Node* p0 = Parameter(Type::Signed32());
338 Node* alloc = graph()->NewNode(simplified()->Allocate(TENURED), p0,
339 graph()->start(), graph()->start());
340 Reduction r = Reduce(alloc);
341
342 // Only check that we lowered, but do not specify the exact form since
343 // this is subject to change.
344 ASSERT_TRUE(r.Changed());
345 }
346
347
348 INSTANTIATE_TEST_CASE_P(ChangeLoweringTest, ChangeLoweringCommonTest,
349 ::testing::Values(MachineRepresentation::kWord32,
350 MachineRepresentation::kWord64));
351
352
353 // -----------------------------------------------------------------------------
354 // 32-bit
355
356
357 class ChangeLowering32Test : public ChangeLoweringTest {
358 public:
~ChangeLowering32Test()359 ~ChangeLowering32Test() override {}
WordRepresentation() const360 MachineRepresentation WordRepresentation() const final {
361 return MachineRepresentation::kWord32;
362 }
363 };
364
365
TARGET_TEST_F(ChangeLowering32Test,ChangeInt32ToTagged)366 TARGET_TEST_F(ChangeLowering32Test, ChangeInt32ToTagged) {
367 Node* value = Parameter(Type::Integral32());
368 Node* node = graph()->NewNode(simplified()->ChangeInt32ToTagged(), value);
369 Reduction r = Reduce(node);
370 ASSERT_TRUE(r.Changed());
371 Capture<Node*> add, branch, heap_number, if_true;
372 EXPECT_THAT(
373 r.replacement(),
374 IsPhi(MachineRepresentation::kTagged,
375 IsFinishRegion(
376 AllOf(CaptureEq(&heap_number),
377 IsAllocateHeapNumber(_, CaptureEq(&if_true))),
378 IsStore(
379 StoreRepresentation(MachineRepresentation::kFloat64,
380 kNoWriteBarrier),
381 CaptureEq(&heap_number),
382 IsIntPtrConstant(HeapNumber::kValueOffset - kHeapObjectTag),
383 IsChangeInt32ToFloat64(value), CaptureEq(&heap_number),
384 CaptureEq(&if_true))),
385 IsProjection(0, AllOf(CaptureEq(&add),
386 IsInt32AddWithOverflow(value, value))),
387 IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))),
388 IsIfFalse(AllOf(CaptureEq(&branch),
389 IsBranch(IsProjection(1, CaptureEq(&add)),
390 graph()->start()))))));
391 }
392
393
TARGET_TEST_F(ChangeLowering32Test,ChangeTaggedToFloat64)394 TARGET_TEST_F(ChangeLowering32Test, ChangeTaggedToFloat64) {
395 STATIC_ASSERT(kSmiTag == 0);
396 STATIC_ASSERT(kSmiTagSize == 1);
397
398 Node* value = Parameter(Type::Number());
399 Node* node = graph()->NewNode(simplified()->ChangeTaggedToFloat64(), value);
400 Reduction r = Reduce(node);
401 ASSERT_TRUE(r.Changed());
402 Capture<Node*> branch, if_true;
403 EXPECT_THAT(
404 r.replacement(),
405 IsPhi(MachineRepresentation::kFloat64,
406 IsLoadHeapNumber(value, CaptureEq(&if_true)),
407 IsChangeInt32ToFloat64(IsWord32Sar(
408 value, IsInt32Constant(kSmiTagSize + kSmiShiftSize))),
409 IsMerge(AllOf(CaptureEq(&if_true),
410 IsIfTrue(AllOf(
411 CaptureEq(&branch),
412 IsBranch(IsWord32And(
413 value, IsInt32Constant(kSmiTagMask)),
414 graph()->start())))),
415 IsIfFalse(CaptureEq(&branch)))));
416 }
417
418
TARGET_TEST_F(ChangeLowering32Test,ChangeTaggedToInt32)419 TARGET_TEST_F(ChangeLowering32Test, ChangeTaggedToInt32) {
420 STATIC_ASSERT(kSmiTag == 0);
421 STATIC_ASSERT(kSmiTagSize == 1);
422
423 Node* value = Parameter(Type::Signed32());
424 Node* node = graph()->NewNode(simplified()->ChangeTaggedToInt32(), value);
425 Reduction r = Reduce(node);
426 ASSERT_TRUE(r.Changed());
427 Capture<Node*> branch, if_true;
428 EXPECT_THAT(
429 r.replacement(),
430 IsPhi(
431 MachineRepresentation::kWord32,
432 IsChangeFloat64ToInt32(IsLoadHeapNumber(value, CaptureEq(&if_true))),
433 IsWord32Sar(value, IsInt32Constant(kSmiTagSize + kSmiShiftSize)),
434 IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))),
435 IsIfFalse(AllOf(
436 CaptureEq(&branch),
437 IsBranch(IsWord32And(value, IsInt32Constant(kSmiTagMask)),
438 graph()->start()))))));
439 }
440
441
TARGET_TEST_F(ChangeLowering32Test,ChangeTaggedToUint32)442 TARGET_TEST_F(ChangeLowering32Test, ChangeTaggedToUint32) {
443 STATIC_ASSERT(kSmiTag == 0);
444 STATIC_ASSERT(kSmiTagSize == 1);
445
446 Node* value = Parameter(Type::Unsigned32());
447 Node* node = graph()->NewNode(simplified()->ChangeTaggedToUint32(), value);
448 Reduction r = Reduce(node);
449 ASSERT_TRUE(r.Changed());
450 Capture<Node*> branch, if_true;
451 EXPECT_THAT(
452 r.replacement(),
453 IsPhi(
454 MachineRepresentation::kWord32,
455 IsChangeFloat64ToUint32(IsLoadHeapNumber(value, CaptureEq(&if_true))),
456 IsWord32Sar(value, IsInt32Constant(kSmiTagSize + kSmiShiftSize)),
457 IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))),
458 IsIfFalse(AllOf(
459 CaptureEq(&branch),
460 IsBranch(IsWord32And(value, IsInt32Constant(kSmiTagMask)),
461 graph()->start()))))));
462 }
463
464
TARGET_TEST_F(ChangeLowering32Test,ChangeUint32ToTagged)465 TARGET_TEST_F(ChangeLowering32Test, ChangeUint32ToTagged) {
466 STATIC_ASSERT(kSmiTag == 0);
467 STATIC_ASSERT(kSmiTagSize == 1);
468
469 Node* value = Parameter(Type::Number());
470 Node* node = graph()->NewNode(simplified()->ChangeUint32ToTagged(), value);
471 Reduction r = Reduce(node);
472 ASSERT_TRUE(r.Changed());
473 Capture<Node*> branch, heap_number, if_false;
474 EXPECT_THAT(
475 r.replacement(),
476 IsPhi(
477 MachineRepresentation::kTagged,
478 IsWord32Shl(value, IsInt32Constant(kSmiTagSize + kSmiShiftSize)),
479 IsFinishRegion(
480 AllOf(CaptureEq(&heap_number),
481 IsAllocateHeapNumber(_, CaptureEq(&if_false))),
482 IsStore(
483 StoreRepresentation(MachineRepresentation::kFloat64,
484 kNoWriteBarrier),
485 CaptureEq(&heap_number),
486 IsInt32Constant(HeapNumber::kValueOffset - kHeapObjectTag),
487 IsChangeUint32ToFloat64(value), CaptureEq(&heap_number),
488 CaptureEq(&if_false))),
489 IsMerge(IsIfTrue(AllOf(
490 CaptureEq(&branch),
491 IsBranch(IsUint32LessThanOrEqual(
492 value, IsInt32Constant(Smi::kMaxValue)),
493 graph()->start()))),
494 AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch))))));
495 }
496
497
498 // -----------------------------------------------------------------------------
499 // 64-bit
500
501
502 class ChangeLowering64Test : public ChangeLoweringTest {
503 public:
~ChangeLowering64Test()504 ~ChangeLowering64Test() override {}
WordRepresentation() const505 MachineRepresentation WordRepresentation() const final {
506 return MachineRepresentation::kWord64;
507 }
508 };
509
510
TARGET_TEST_F(ChangeLowering64Test,ChangeInt32ToTagged)511 TARGET_TEST_F(ChangeLowering64Test, ChangeInt32ToTagged) {
512 Node* value = Parameter(Type::Signed32());
513 Node* node = graph()->NewNode(simplified()->ChangeInt32ToTagged(), value);
514 Reduction r = Reduce(node);
515 ASSERT_TRUE(r.Changed());
516 EXPECT_THAT(r.replacement(), IsChangeInt32ToSmi(value));
517 }
518
519
TARGET_TEST_F(ChangeLowering64Test,ChangeTaggedToFloat64)520 TARGET_TEST_F(ChangeLowering64Test, ChangeTaggedToFloat64) {
521 STATIC_ASSERT(kSmiTag == 0);
522 STATIC_ASSERT(kSmiTagSize == 1);
523
524 Node* value = Parameter(Type::Number());
525 Node* node = graph()->NewNode(simplified()->ChangeTaggedToFloat64(), value);
526 Reduction r = Reduce(node);
527 ASSERT_TRUE(r.Changed());
528 Capture<Node*> branch, if_true;
529 EXPECT_THAT(
530 r.replacement(),
531 IsPhi(MachineRepresentation::kFloat64,
532 IsLoadHeapNumber(value, CaptureEq(&if_true)),
533 IsChangeInt32ToFloat64(IsTruncateInt64ToInt32(IsWord64Sar(
534 value, IsInt64Constant(kSmiTagSize + kSmiShiftSize)))),
535 IsMerge(AllOf(CaptureEq(&if_true),
536 IsIfTrue(AllOf(
537 CaptureEq(&branch),
538 IsBranch(IsWord64And(
539 value, IsInt64Constant(kSmiTagMask)),
540 graph()->start())))),
541 IsIfFalse(CaptureEq(&branch)))));
542 }
543
544
TARGET_TEST_F(ChangeLowering64Test,ChangeTaggedToInt32)545 TARGET_TEST_F(ChangeLowering64Test, ChangeTaggedToInt32) {
546 STATIC_ASSERT(kSmiTag == 0);
547 STATIC_ASSERT(kSmiTagSize == 1);
548
549 Node* value = Parameter(Type::Signed32());
550 Node* node = graph()->NewNode(simplified()->ChangeTaggedToInt32(), value);
551 Reduction r = Reduce(node);
552 ASSERT_TRUE(r.Changed());
553 Capture<Node*> branch, if_true;
554 EXPECT_THAT(
555 r.replacement(),
556 IsPhi(
557 MachineRepresentation::kWord32,
558 IsChangeFloat64ToInt32(IsLoadHeapNumber(value, CaptureEq(&if_true))),
559 IsTruncateInt64ToInt32(
560 IsWord64Sar(value, IsInt64Constant(kSmiTagSize + kSmiShiftSize))),
561 IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))),
562 IsIfFalse(AllOf(
563 CaptureEq(&branch),
564 IsBranch(IsWord64And(value, IsInt64Constant(kSmiTagMask)),
565 graph()->start()))))));
566 }
567
568
TARGET_TEST_F(ChangeLowering64Test,ChangeTaggedToUint32)569 TARGET_TEST_F(ChangeLowering64Test, ChangeTaggedToUint32) {
570 STATIC_ASSERT(kSmiTag == 0);
571 STATIC_ASSERT(kSmiTagSize == 1);
572
573 Node* value = Parameter(Type::Unsigned32());
574 Node* node = graph()->NewNode(simplified()->ChangeTaggedToUint32(), value);
575 Reduction r = Reduce(node);
576 ASSERT_TRUE(r.Changed());
577 Capture<Node*> branch, if_true;
578 EXPECT_THAT(
579 r.replacement(),
580 IsPhi(
581 MachineRepresentation::kWord32,
582 IsChangeFloat64ToUint32(IsLoadHeapNumber(value, CaptureEq(&if_true))),
583 IsTruncateInt64ToInt32(
584 IsWord64Sar(value, IsInt64Constant(kSmiTagSize + kSmiShiftSize))),
585 IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))),
586 IsIfFalse(AllOf(
587 CaptureEq(&branch),
588 IsBranch(IsWord64And(value, IsInt64Constant(kSmiTagMask)),
589 graph()->start()))))));
590 }
591
592
TARGET_TEST_F(ChangeLowering64Test,ChangeUint32ToTagged)593 TARGET_TEST_F(ChangeLowering64Test, ChangeUint32ToTagged) {
594 STATIC_ASSERT(kSmiTag == 0);
595 STATIC_ASSERT(kSmiTagSize == 1);
596
597 Node* value = Parameter(Type::Number());
598 Node* node = graph()->NewNode(simplified()->ChangeUint32ToTagged(), value);
599 Reduction r = Reduce(node);
600 ASSERT_TRUE(r.Changed());
601 Capture<Node*> branch, heap_number, if_false;
602 EXPECT_THAT(
603 r.replacement(),
604 IsPhi(
605 MachineRepresentation::kTagged,
606 IsWord64Shl(IsChangeUint32ToUint64(value),
607 IsInt64Constant(kSmiTagSize + kSmiShiftSize)),
608 IsFinishRegion(
609 AllOf(CaptureEq(&heap_number),
610 IsAllocateHeapNumber(_, CaptureEq(&if_false))),
611 IsStore(
612 StoreRepresentation(MachineRepresentation::kFloat64,
613 kNoWriteBarrier),
614 CaptureEq(&heap_number),
615 IsInt64Constant(HeapNumber::kValueOffset - kHeapObjectTag),
616 IsChangeUint32ToFloat64(value), CaptureEq(&heap_number),
617 CaptureEq(&if_false))),
618 IsMerge(IsIfTrue(AllOf(
619 CaptureEq(&branch),
620 IsBranch(IsUint32LessThanOrEqual(
621 value, IsInt32Constant(Smi::kMaxValue)),
622 graph()->start()))),
623 AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch))))));
624 }
625
626 } // namespace compiler
627 } // namespace internal
628 } // namespace v8
629