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/compiler/graph-unittest.h"
6#include "src/compiler/js-graph.h"
7#include "src/compiler/simplified-operator.h"
8#include "src/compiler/simplified-operator-reducer.h"
9#include "src/compiler/typer.h"
10#include "src/conversions.h"
11
12namespace v8 {
13namespace internal {
14namespace compiler {
15
16class SimplifiedOperatorReducerTest : public GraphTest {
17 public:
18  explicit SimplifiedOperatorReducerTest(int num_parameters = 1)
19      : GraphTest(num_parameters), simplified_(zone()) {}
20  virtual ~SimplifiedOperatorReducerTest() {}
21
22 protected:
23  Reduction Reduce(Node* node) {
24    Typer typer(zone());
25    MachineOperatorBuilder machine;
26    JSOperatorBuilder javascript(zone());
27    JSGraph jsgraph(graph(), common(), &javascript, &typer, &machine);
28    SimplifiedOperatorReducer reducer(&jsgraph);
29    return reducer.Reduce(node);
30  }
31
32  SimplifiedOperatorBuilder* simplified() { return &simplified_; }
33
34 private:
35  SimplifiedOperatorBuilder simplified_;
36};
37
38
39template <typename T>
40class SimplifiedOperatorReducerTestWithParam
41    : public SimplifiedOperatorReducerTest,
42      public ::testing::WithParamInterface<T> {
43 public:
44  explicit SimplifiedOperatorReducerTestWithParam(int num_parameters = 1)
45      : SimplifiedOperatorReducerTest(num_parameters) {}
46  virtual ~SimplifiedOperatorReducerTestWithParam() {}
47};
48
49
50namespace {
51
52static const double kFloat64Values[] = {
53    -V8_INFINITY,  -6.52696e+290, -1.05768e+290, -5.34203e+268, -1.01997e+268,
54    -8.22758e+266, -1.58402e+261, -5.15246e+241, -5.92107e+226, -1.21477e+226,
55    -1.67913e+188, -1.6257e+184,  -2.60043e+170, -2.52941e+168, -3.06033e+116,
56    -4.56201e+52,  -3.56788e+50,  -9.9066e+38,   -3.07261e+31,  -2.1271e+09,
57    -1.91489e+09,  -1.73053e+09,  -9.30675e+08,  -26030,        -20453,
58    -15790,        -11699,        -111,          -97,           -78,
59    -63,           -58,           -1.53858e-06,  -2.98914e-12,  -1.14741e-39,
60    -8.20347e-57,  -1.48932e-59,  -3.17692e-66,  -8.93103e-81,  -3.91337e-83,
61    -6.0489e-92,   -8.83291e-113, -4.28266e-117, -1.92058e-178, -2.0567e-192,
62    -1.68167e-194, -1.51841e-214, -3.98738e-234, -7.31851e-242, -2.21875e-253,
63    -1.11612e-293, -0.0,          0.0,           2.22507e-308,  1.06526e-307,
64    4.16643e-227,  6.76624e-223,  2.0432e-197,   3.16254e-184,  1.37315e-173,
65    2.88603e-172,  1.54155e-99,   4.42923e-81,   1.40539e-73,   5.4462e-73,
66    1.24064e-58,   3.11167e-58,   2.75826e-39,   0.143815,      58,
67    67,            601,           7941,          11644,         13697,
68    25680,         29882,         1.32165e+08,   1.62439e+08,   4.16837e+08,
69    9.59097e+08,   1.32491e+09,   1.8728e+09,    1.0672e+17,    2.69606e+46,
70    1.98285e+79,   1.0098e+82,    7.93064e+88,   3.67444e+121,  9.36506e+123,
71    7.27954e+162,  3.05316e+168,  1.16171e+175,  1.64771e+189,  1.1622e+202,
72    2.00748e+239,  2.51778e+244,  3.90282e+306,  1.79769e+308,  V8_INFINITY};
73
74
75static const int32_t kInt32Values[] = {
76    -2147483647 - 1, -2104508227, -2103151830, -1435284490, -1378926425,
77    -1318814539,     -1289388009, -1287537572, -1279026536, -1241605942,
78    -1226046939,     -941837148,  -779818051,  -413830641,  -245798087,
79    -184657557,      -127145950,  -105483328,  -32325,      -26653,
80    -23858,          -23834,      -22363,      -19858,      -19044,
81    -18744,          -15528,      -5309,       -3372,       -2093,
82    -104,            -98,         -97,         -93,         -84,
83    -80,             -78,         -76,         -72,         -58,
84    -57,             -56,         -55,         -45,         -40,
85    -34,             -32,         -25,         -24,         -5,
86    -2,              0,           3,           10,          24,
87    34,              42,          46,          47,          48,
88    52,              56,          64,          65,          71,
89    76,              79,          81,          82,          97,
90    102,             103,         104,         106,         107,
91    109,             116,         122,         3653,        4485,
92    12405,           16504,       26262,       28704,       29755,
93    30554,           16476817,    605431957,   832401070,   873617242,
94    914205764,       1062628108,  1087581664,  1488498068,  1534668023,
95    1661587028,      1696896187,  1866841746,  2032089723,  2147483647};
96
97
98static const uint32_t kUint32Values[] = {
99    0x0,        0x5,        0x8,        0xc,        0xd,        0x26,
100    0x28,       0x29,       0x30,       0x34,       0x3e,       0x42,
101    0x50,       0x5b,       0x63,       0x71,       0x77,       0x7c,
102    0x83,       0x88,       0x96,       0x9c,       0xa3,       0xfa,
103    0x7a7,      0x165d,     0x234d,     0x3acb,     0x43a5,     0x4573,
104    0x5b4f,     0x5f14,     0x6996,     0x6c6e,     0x7289,     0x7b9a,
105    0x7bc9,     0x86bb,     0xa839,     0xaa41,     0xb03b,     0xc942,
106    0xce68,     0xcf4c,     0xd3ad,     0xdea3,     0xe90c,     0xed86,
107    0xfba5,     0x172dcc6,  0x114d8fc1, 0x182d6c9d, 0x1b1e3fad, 0x1db033bf,
108    0x1e1de755, 0x1f625c80, 0x28f6cf00, 0x2acb6a94, 0x2c20240e, 0x2f0fe54e,
109    0x31863a7c, 0x33325474, 0x3532fae3, 0x3bab82ea, 0x4c4b83a2, 0x4cd93d1e,
110    0x4f7331d4, 0x5491b09b, 0x57cc6ff9, 0x60d3b4dc, 0x653f5904, 0x690ae256,
111    0x69fe3276, 0x6bebf0ba, 0x6e2c69a3, 0x73b84ff7, 0x7b3a1924, 0x7ed032d9,
112    0x84dd734b, 0x8552ea53, 0x8680754f, 0x8e9660eb, 0x94fe2b9c, 0x972d30cf,
113    0x9b98c482, 0xb158667e, 0xb432932c, 0xb5b70989, 0xb669971a, 0xb7c359d1,
114    0xbeb15c0d, 0xc171c53d, 0xc743dd38, 0xc8e2af50, 0xc98e2df0, 0xd9d1cdf9,
115    0xdcc91049, 0xe46f396d, 0xee991950, 0xef64e521, 0xf7aeefc9, 0xffffffff};
116
117
118MATCHER(IsNaN, std::string(negation ? "isn't" : "is") + " NaN") {
119  return std::isnan(arg);
120}
121
122}  // namespace
123
124
125// -----------------------------------------------------------------------------
126// Unary operators
127
128
129namespace {
130
131struct UnaryOperator {
132  const Operator* (SimplifiedOperatorBuilder::*constructor)();
133  const char* constructor_name;
134};
135
136
137std::ostream& operator<<(std::ostream& os, const UnaryOperator& unop) {
138  return os << unop.constructor_name;
139}
140
141
142static const UnaryOperator kUnaryOperators[] = {
143    {&SimplifiedOperatorBuilder::BooleanNot, "BooleanNot"},
144    {&SimplifiedOperatorBuilder::ChangeBitToBool, "ChangeBitToBool"},
145    {&SimplifiedOperatorBuilder::ChangeBoolToBit, "ChangeBoolToBit"},
146    {&SimplifiedOperatorBuilder::ChangeFloat64ToTagged,
147     "ChangeFloat64ToTagged"},
148    {&SimplifiedOperatorBuilder::ChangeInt32ToTagged, "ChangeInt32ToTagged"},
149    {&SimplifiedOperatorBuilder::ChangeTaggedToFloat64,
150     "ChangeTaggedToFloat64"},
151    {&SimplifiedOperatorBuilder::ChangeTaggedToInt32, "ChangeTaggedToInt32"},
152    {&SimplifiedOperatorBuilder::ChangeTaggedToUint32, "ChangeTaggedToUint32"},
153    {&SimplifiedOperatorBuilder::ChangeUint32ToTagged, "ChangeUint32ToTagged"}};
154
155}  // namespace
156
157
158typedef SimplifiedOperatorReducerTestWithParam<UnaryOperator>
159    SimplifiedUnaryOperatorTest;
160
161
162TEST_P(SimplifiedUnaryOperatorTest, Parameter) {
163  const UnaryOperator& unop = GetParam();
164  Reduction reduction = Reduce(
165      graph()->NewNode((simplified()->*unop.constructor)(), Parameter(0)));
166  EXPECT_FALSE(reduction.Changed());
167}
168
169
170INSTANTIATE_TEST_CASE_P(SimplifiedOperatorReducerTest,
171                        SimplifiedUnaryOperatorTest,
172                        ::testing::ValuesIn(kUnaryOperators));
173
174
175// -----------------------------------------------------------------------------
176// BooleanNot
177
178
179TEST_F(SimplifiedOperatorReducerTest, BooleanNotWithBooleanNot) {
180  Node* param0 = Parameter(0);
181  Reduction reduction = Reduce(
182      graph()->NewNode(simplified()->BooleanNot(),
183                       graph()->NewNode(simplified()->BooleanNot(), param0)));
184  ASSERT_TRUE(reduction.Changed());
185  EXPECT_EQ(param0, reduction.replacement());
186}
187
188
189TEST_F(SimplifiedOperatorReducerTest, BooleanNotWithFalseConstant) {
190  Reduction reduction0 =
191      Reduce(graph()->NewNode(simplified()->BooleanNot(), FalseConstant()));
192  ASSERT_TRUE(reduction0.Changed());
193  EXPECT_THAT(reduction0.replacement(), IsTrueConstant());
194}
195
196
197TEST_F(SimplifiedOperatorReducerTest, BooleanNotWithTrueConstant) {
198  Reduction reduction1 =
199      Reduce(graph()->NewNode(simplified()->BooleanNot(), TrueConstant()));
200  ASSERT_TRUE(reduction1.Changed());
201  EXPECT_THAT(reduction1.replacement(), IsFalseConstant());
202}
203
204
205// -----------------------------------------------------------------------------
206// ChangeBoolToBit
207
208
209TEST_F(SimplifiedOperatorReducerTest, ChangeBitToBoolWithChangeBoolToBit) {
210  Node* param0 = Parameter(0);
211  Reduction reduction = Reduce(graph()->NewNode(
212      simplified()->ChangeBitToBool(),
213      graph()->NewNode(simplified()->ChangeBoolToBit(), param0)));
214  ASSERT_TRUE(reduction.Changed());
215  EXPECT_EQ(param0, reduction.replacement());
216}
217
218
219TEST_F(SimplifiedOperatorReducerTest, ChangeBitToBoolWithZeroConstant) {
220  Reduction reduction = Reduce(
221      graph()->NewNode(simplified()->ChangeBitToBool(), Int32Constant(0)));
222  ASSERT_TRUE(reduction.Changed());
223  EXPECT_THAT(reduction.replacement(), IsFalseConstant());
224}
225
226
227TEST_F(SimplifiedOperatorReducerTest, ChangeBitToBoolWithOneConstant) {
228  Reduction reduction = Reduce(
229      graph()->NewNode(simplified()->ChangeBitToBool(), Int32Constant(1)));
230  ASSERT_TRUE(reduction.Changed());
231  EXPECT_THAT(reduction.replacement(), IsTrueConstant());
232}
233
234
235// -----------------------------------------------------------------------------
236// ChangeBoolToBit
237
238
239TEST_F(SimplifiedOperatorReducerTest, ChangeBoolToBitWithFalseConstant) {
240  Reduction reduction = Reduce(
241      graph()->NewNode(simplified()->ChangeBoolToBit(), FalseConstant()));
242  ASSERT_TRUE(reduction.Changed());
243  EXPECT_THAT(reduction.replacement(), IsInt32Constant(0));
244}
245
246
247TEST_F(SimplifiedOperatorReducerTest, ChangeBoolToBitWithTrueConstant) {
248  Reduction reduction =
249      Reduce(graph()->NewNode(simplified()->ChangeBoolToBit(), TrueConstant()));
250  ASSERT_TRUE(reduction.Changed());
251  EXPECT_THAT(reduction.replacement(), IsInt32Constant(1));
252}
253
254
255TEST_F(SimplifiedOperatorReducerTest, ChangeBoolToBitWithChangeBitToBool) {
256  Node* param0 = Parameter(0);
257  Reduction reduction = Reduce(graph()->NewNode(
258      simplified()->ChangeBoolToBit(),
259      graph()->NewNode(simplified()->ChangeBitToBool(), param0)));
260  ASSERT_TRUE(reduction.Changed());
261  EXPECT_EQ(param0, reduction.replacement());
262}
263
264
265// -----------------------------------------------------------------------------
266// ChangeFloat64ToTagged
267
268
269TEST_F(SimplifiedOperatorReducerTest, ChangeFloat64ToTaggedWithConstant) {
270  TRACED_FOREACH(double, n, kFloat64Values) {
271    Reduction reduction = Reduce(graph()->NewNode(
272        simplified()->ChangeFloat64ToTagged(), Float64Constant(n)));
273    ASSERT_TRUE(reduction.Changed());
274    EXPECT_THAT(reduction.replacement(), IsNumberConstant(n));
275  }
276}
277
278
279// -----------------------------------------------------------------------------
280// ChangeInt32ToTagged
281
282
283TEST_F(SimplifiedOperatorReducerTest, ChangeInt32ToTaggedWithConstant) {
284  TRACED_FOREACH(int32_t, n, kInt32Values) {
285    Reduction reduction = Reduce(graph()->NewNode(
286        simplified()->ChangeInt32ToTagged(), Int32Constant(n)));
287    ASSERT_TRUE(reduction.Changed());
288    EXPECT_THAT(reduction.replacement(), IsNumberConstant(FastI2D(n)));
289  }
290}
291
292
293// -----------------------------------------------------------------------------
294// ChangeTaggedToFloat64
295
296
297TEST_F(SimplifiedOperatorReducerTest,
298       ChangeTaggedToFloat64WithChangeFloat64ToTagged) {
299  Node* param0 = Parameter(0);
300  Reduction reduction = Reduce(graph()->NewNode(
301      simplified()->ChangeTaggedToFloat64(),
302      graph()->NewNode(simplified()->ChangeFloat64ToTagged(), param0)));
303  ASSERT_TRUE(reduction.Changed());
304  EXPECT_EQ(param0, reduction.replacement());
305}
306
307
308TEST_F(SimplifiedOperatorReducerTest,
309       ChangeTaggedToFloat64WithChangeInt32ToTagged) {
310  Node* param0 = Parameter(0);
311  Reduction reduction = Reduce(graph()->NewNode(
312      simplified()->ChangeTaggedToFloat64(),
313      graph()->NewNode(simplified()->ChangeInt32ToTagged(), param0)));
314  ASSERT_TRUE(reduction.Changed());
315  EXPECT_THAT(reduction.replacement(), IsChangeInt32ToFloat64(param0));
316}
317
318
319TEST_F(SimplifiedOperatorReducerTest,
320       ChangeTaggedToFloat64WithChangeUint32ToTagged) {
321  Node* param0 = Parameter(0);
322  Reduction reduction = Reduce(graph()->NewNode(
323      simplified()->ChangeTaggedToFloat64(),
324      graph()->NewNode(simplified()->ChangeUint32ToTagged(), param0)));
325  ASSERT_TRUE(reduction.Changed());
326  EXPECT_THAT(reduction.replacement(), IsChangeUint32ToFloat64(param0));
327}
328
329
330TEST_F(SimplifiedOperatorReducerTest, ChangeTaggedToFloat64WithConstant) {
331  TRACED_FOREACH(double, n, kFloat64Values) {
332    Reduction reduction = Reduce(graph()->NewNode(
333        simplified()->ChangeTaggedToFloat64(), NumberConstant(n)));
334    ASSERT_TRUE(reduction.Changed());
335    EXPECT_THAT(reduction.replacement(), IsFloat64Constant(n));
336  }
337}
338
339
340TEST_F(SimplifiedOperatorReducerTest, ChangeTaggedToFloat64WithNaNConstant1) {
341  Reduction reduction =
342      Reduce(graph()->NewNode(simplified()->ChangeTaggedToFloat64(),
343                              NumberConstant(-base::OS::nan_value())));
344  ASSERT_TRUE(reduction.Changed());
345  EXPECT_THAT(reduction.replacement(), IsFloat64Constant(IsNaN()));
346}
347
348
349TEST_F(SimplifiedOperatorReducerTest, ChangeTaggedToFloat64WithNaNConstant2) {
350  Reduction reduction =
351      Reduce(graph()->NewNode(simplified()->ChangeTaggedToFloat64(),
352                              NumberConstant(base::OS::nan_value())));
353  ASSERT_TRUE(reduction.Changed());
354  EXPECT_THAT(reduction.replacement(), IsFloat64Constant(IsNaN()));
355}
356
357
358// -----------------------------------------------------------------------------
359// ChangeTaggedToInt32
360
361
362TEST_F(SimplifiedOperatorReducerTest,
363       ChangeTaggedToInt32WithChangeFloat64ToTagged) {
364  Node* param0 = Parameter(0);
365  Reduction reduction = Reduce(graph()->NewNode(
366      simplified()->ChangeTaggedToInt32(),
367      graph()->NewNode(simplified()->ChangeFloat64ToTagged(), param0)));
368  ASSERT_TRUE(reduction.Changed());
369  EXPECT_THAT(reduction.replacement(), IsChangeFloat64ToInt32(param0));
370}
371
372
373TEST_F(SimplifiedOperatorReducerTest,
374       ChangeTaggedToInt32WithChangeInt32ToTagged) {
375  Node* param0 = Parameter(0);
376  Reduction reduction = Reduce(graph()->NewNode(
377      simplified()->ChangeTaggedToInt32(),
378      graph()->NewNode(simplified()->ChangeInt32ToTagged(), param0)));
379  ASSERT_TRUE(reduction.Changed());
380  EXPECT_EQ(param0, reduction.replacement());
381}
382
383
384TEST_F(SimplifiedOperatorReducerTest, ChangeTaggedToInt32WithConstant) {
385  TRACED_FOREACH(double, n, kFloat64Values) {
386    Reduction reduction = Reduce(graph()->NewNode(
387        simplified()->ChangeTaggedToInt32(), NumberConstant(n)));
388    ASSERT_TRUE(reduction.Changed());
389    EXPECT_THAT(reduction.replacement(), IsInt32Constant(DoubleToInt32(n)));
390  }
391}
392
393
394TEST_F(SimplifiedOperatorReducerTest, ChangeTaggedToInt32WithNaNConstant1) {
395  Reduction reduction =
396      Reduce(graph()->NewNode(simplified()->ChangeTaggedToInt32(),
397                              NumberConstant(-base::OS::nan_value())));
398  ASSERT_TRUE(reduction.Changed());
399  EXPECT_THAT(reduction.replacement(), IsInt32Constant(0));
400}
401
402
403TEST_F(SimplifiedOperatorReducerTest, ChangeTaggedToInt32WithNaNConstant2) {
404  Reduction reduction =
405      Reduce(graph()->NewNode(simplified()->ChangeTaggedToInt32(),
406                              NumberConstant(base::OS::nan_value())));
407  ASSERT_TRUE(reduction.Changed());
408  EXPECT_THAT(reduction.replacement(), IsInt32Constant(0));
409}
410
411
412// -----------------------------------------------------------------------------
413// ChangeTaggedToUint32
414
415
416TEST_F(SimplifiedOperatorReducerTest,
417       ChangeTaggedToUint32WithChangeFloat64ToTagged) {
418  Node* param0 = Parameter(0);
419  Reduction reduction = Reduce(graph()->NewNode(
420      simplified()->ChangeTaggedToUint32(),
421      graph()->NewNode(simplified()->ChangeFloat64ToTagged(), param0)));
422  ASSERT_TRUE(reduction.Changed());
423  EXPECT_THAT(reduction.replacement(), IsChangeFloat64ToUint32(param0));
424}
425
426
427TEST_F(SimplifiedOperatorReducerTest,
428       ChangeTaggedToUint32WithChangeUint32ToTagged) {
429  Node* param0 = Parameter(0);
430  Reduction reduction = Reduce(graph()->NewNode(
431      simplified()->ChangeTaggedToUint32(),
432      graph()->NewNode(simplified()->ChangeUint32ToTagged(), param0)));
433  ASSERT_TRUE(reduction.Changed());
434  EXPECT_EQ(param0, reduction.replacement());
435}
436
437
438TEST_F(SimplifiedOperatorReducerTest, ChangeTaggedToUint32WithConstant) {
439  TRACED_FOREACH(double, n, kFloat64Values) {
440    Reduction reduction = Reduce(graph()->NewNode(
441        simplified()->ChangeTaggedToUint32(), NumberConstant(n)));
442    ASSERT_TRUE(reduction.Changed());
443    EXPECT_THAT(reduction.replacement(),
444                IsInt32Constant(bit_cast<int32_t>(DoubleToUint32(n))));
445  }
446}
447
448
449TEST_F(SimplifiedOperatorReducerTest, ChangeTaggedToUint32WithNaNConstant1) {
450  Reduction reduction =
451      Reduce(graph()->NewNode(simplified()->ChangeTaggedToUint32(),
452                              NumberConstant(-base::OS::nan_value())));
453  ASSERT_TRUE(reduction.Changed());
454  EXPECT_THAT(reduction.replacement(), IsInt32Constant(0));
455}
456
457
458TEST_F(SimplifiedOperatorReducerTest, ChangeTaggedToUint32WithNaNConstant2) {
459  Reduction reduction =
460      Reduce(graph()->NewNode(simplified()->ChangeTaggedToUint32(),
461                              NumberConstant(base::OS::nan_value())));
462  ASSERT_TRUE(reduction.Changed());
463  EXPECT_THAT(reduction.replacement(), IsInt32Constant(0));
464}
465
466
467// -----------------------------------------------------------------------------
468// ChangeUint32ToTagged
469
470
471TEST_F(SimplifiedOperatorReducerTest, ChangeUint32ToTagged) {
472  TRACED_FOREACH(uint32_t, n, kUint32Values) {
473    Reduction reduction =
474        Reduce(graph()->NewNode(simplified()->ChangeUint32ToTagged(),
475                                Int32Constant(bit_cast<int32_t>(n))));
476    ASSERT_TRUE(reduction.Changed());
477    EXPECT_THAT(reduction.replacement(), IsNumberConstant(FastUI2D(n)));
478  }
479}
480
481}  // namespace compiler
482}  // namespace internal
483}  // namespace v8
484