1513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org// Copyright 2014 the V8 project authors. All rights reserved.
2513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org// Use of this source code is governed by a BSD-style license that can be
3513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org// found in the LICENSE file.
4513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org
5513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org#include "src/compiler/change-lowering.h"
6513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org#include "src/compiler/compiler-test-utils.h"
7513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org#include "src/compiler/graph-unittest.h"
8513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org#include "src/compiler/js-graph.h"
9513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org#include "src/compiler/node-properties-inl.h"
10513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org#include "src/compiler/simplified-operator.h"
11513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org#include "src/compiler/typer.h"
12513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org#include "testing/gmock-support.h"
13513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org
14513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.orgusing testing::_;
15513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.orgusing testing::AllOf;
16513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.orgusing testing::Capture;
17513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.orgusing testing::CaptureEq;
18513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org
19513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.orgnamespace v8 {
20513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.orgnamespace internal {
21513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.orgnamespace compiler {
22513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org
23513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org// TODO(bmeurer): Find a new home for these functions.
24513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.orginline std::ostream& operator<<(std::ostream& os, const MachineType& type) {
25513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org  OStringStream ost;
26513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org  ost << type;
27513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org  return os << ost.c_str();
28513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org}
29513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org
30513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org
31513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.orgclass ChangeLoweringTest : public GraphTest {
32513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org public:
33513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org  ChangeLoweringTest() : simplified_(zone()) {}
34513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org  virtual ~ChangeLoweringTest() {}
35513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org
36513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org  virtual MachineType WordRepresentation() const = 0;
37513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org
38513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org protected:
39513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org  int HeapNumberValueOffset() const {
40513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org    STATIC_ASSERT(HeapNumber::kValueOffset % kApiPointerSize == 0);
41513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org    return (HeapNumber::kValueOffset / kApiPointerSize) * PointerSize() -
42513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org           kHeapObjectTag;
43513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org  }
44513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org  bool Is32() const { return WordRepresentation() == kRepWord32; }
45513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org  int PointerSize() const {
46513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org    switch (WordRepresentation()) {
47513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org      case kRepWord32:
48513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org        return 4;
49513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org      case kRepWord64:
50513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org        return 8;
51513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org      default:
52513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org        break;
53513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org    }
54513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org    UNREACHABLE();
55513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org    return 0;
56513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org  }
57513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org  int SmiMaxValue() const { return -(SmiMinValue() + 1); }
58513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org  int SmiMinValue() const {
59513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org    return static_cast<int>(0xffffffffu << (SmiValueSize() - 1));
60513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org  }
61513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org  int SmiShiftAmount() const { return kSmiTagSize + SmiShiftSize(); }
62513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org  int SmiShiftSize() const {
63513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org    return Is32() ? SmiTagging<4>::SmiShiftSize()
64513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org                  : SmiTagging<8>::SmiShiftSize();
65513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org  }
66513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org  int SmiValueSize() const {
67513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org    return Is32() ? SmiTagging<4>::SmiValueSize()
68513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org                  : SmiTagging<8>::SmiValueSize();
69513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org  }
70513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org
71513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org  Node* Parameter(int32_t index = 0) {
72513246162767bca05d2ceb8f2cf9b28e6f67f6facommit-bot@chromium.org    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(
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,
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
113class ChangeLoweringCommonTest
114    : public ChangeLoweringTest,
115      public ::testing::WithParamInterface<MachineType> {
116 public:
117  virtual ~ChangeLoweringCommonTest() {}
118
119  virtual MachineType WordRepresentation() const FINAL OVERRIDE {
120    return GetParam();
121  }
122};
123
124
125TARGET_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());
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
142TARGET_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());
147
148  EXPECT_THAT(reduction.replacement(), IsWordEqual(val, IsTrueConstant()));
149}
150
151
152TARGET_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
171TARGET_TEST_P(ChangeLoweringCommonTest, StringAdd) {
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
179INSTANTIATE_TEST_CASE_P(ChangeLoweringTest, ChangeLoweringCommonTest,
180                        ::testing::Values(kRepWord32, kRepWord64));
181
182
183// -----------------------------------------------------------------------------
184// 32-bit
185
186
187class ChangeLowering32Test : public ChangeLoweringTest {
188 public:
189  virtual ~ChangeLowering32Test() {}
190  virtual MachineType WordRepresentation() const FINAL OVERRIDE {
191    return kRepWord32;
192  }
193};
194
195
196TARGET_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,
206      IsPhi(kMachAnyTagged,
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
223TARGET_TEST_F(ChangeLowering32Test, ChangeTaggedToFloat64) {
224  STATIC_ASSERT(kSmiTag == 0);
225  STATIC_ASSERT(kSmiTagSize == 1);
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))),
240          IsChangeInt32ToFloat64(
241              IsWord32Sar(val, IsInt32Constant(SmiShiftAmount()))),
242          IsMerge(
243              AllOf(CaptureEq(&if_true),
244                    IsIfTrue(AllOf(
245                        CaptureEq(&branch),
246                        IsBranch(IsWord32And(val, IsInt32Constant(kSmiTagMask)),
247                                 graph()->start())))),
248              IsIfFalse(CaptureEq(&branch)))));
249}
250
251
252TARGET_TEST_F(ChangeLowering32Test, ChangeTaggedToInt32) {
253  STATIC_ASSERT(kSmiTag == 0);
254  STATIC_ASSERT(kSmiTagSize == 1);
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,
265      IsPhi(kMachInt32,
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))),
271                    IsIfFalse(AllOf(
272                        CaptureEq(&branch),
273                        IsBranch(IsWord32And(val, IsInt32Constant(kSmiTagMask)),
274                                 graph()->start()))))));
275}
276
277
278TARGET_TEST_F(ChangeLowering32Test, ChangeTaggedToUint32) {
279  STATIC_ASSERT(kSmiTag == 0);
280  STATIC_ASSERT(kSmiTagSize == 1);
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,
291      IsPhi(kMachUint32,
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))),
297                    IsIfFalse(AllOf(
298                        CaptureEq(&branch),
299                        IsBranch(IsWord32And(val, IsInt32Constant(kSmiTagMask)),
300                                 graph()->start()))))));
301}
302
303
304TARGET_TEST_F(ChangeLowering32Test, ChangeUint32ToTagged) {
305  STATIC_ASSERT(kSmiTag == 0);
306  STATIC_ASSERT(kSmiTagSize == 1);
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),
328                             IsBranch(IsUint32LessThanOrEqual(
329                                          val, IsInt32Constant(SmiMaxValue())),
330                                      graph()->start()))),
331              AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch))))));
332}
333
334
335// -----------------------------------------------------------------------------
336// 64-bit
337
338
339class ChangeLowering64Test : public ChangeLoweringTest {
340 public:
341  virtual ~ChangeLowering64Test() {}
342  virtual MachineType WordRepresentation() const FINAL OVERRIDE {
343    return kRepWord64;
344  }
345};
346
347
348TARGET_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(),
355              IsWord64Shl(IsChangeInt32ToInt64(val),
356                          IsInt32Constant(SmiShiftAmount())));
357}
358
359
360TARGET_TEST_F(ChangeLowering64Test, ChangeTaggedToFloat64) {
361  STATIC_ASSERT(kSmiTag == 0);
362  STATIC_ASSERT(kSmiTagSize == 1);
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))),
377          IsChangeInt32ToFloat64(IsTruncateInt64ToInt32(
378              IsWord64Sar(val, IsInt32Constant(SmiShiftAmount())))),
379          IsMerge(
380              AllOf(CaptureEq(&if_true),
381                    IsIfTrue(AllOf(
382                        CaptureEq(&branch),
383                        IsBranch(IsWord64And(val, IsInt32Constant(kSmiTagMask)),
384                                 graph()->start())))),
385              IsIfFalse(CaptureEq(&branch)))));
386}
387
388
389TARGET_TEST_F(ChangeLowering64Test, ChangeTaggedToInt32) {
390  STATIC_ASSERT(kSmiTag == 0);
391  STATIC_ASSERT(kSmiTagSize == 1);
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,
402      IsPhi(kMachInt32,
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))),
409                    IsIfFalse(AllOf(
410                        CaptureEq(&branch),
411                        IsBranch(IsWord64And(val, IsInt32Constant(kSmiTagMask)),
412                                 graph()->start()))))));
413}
414
415
416TARGET_TEST_F(ChangeLowering64Test, ChangeTaggedToUint32) {
417  STATIC_ASSERT(kSmiTag == 0);
418  STATIC_ASSERT(kSmiTagSize == 1);
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,
429      IsPhi(kMachUint32,
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))),
436                    IsIfFalse(AllOf(
437                        CaptureEq(&branch),
438                        IsBranch(IsWord64And(val, IsInt32Constant(kSmiTagMask)),
439                                 graph()->start()))))));
440}
441
442
443TARGET_TEST_F(ChangeLowering64Test, ChangeUint32ToTagged) {
444  STATIC_ASSERT(kSmiTag == 0);
445  STATIC_ASSERT(kSmiTagSize == 1);
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(
457          kMachAnyTagged, IsWord64Shl(IsChangeUint32ToUint64(val),
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),
468                             IsBranch(IsUint32LessThanOrEqual(
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
477