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/base/utils/random-number-generator.h"
6#include "src/codegen.h"
7#include "src/compiler/js-graph.h"
8#include "src/compiler/machine-operator-reducer.h"
9#include "src/compiler/operator-properties.h"
10#include "src/compiler/typer.h"
11#include "test/cctest/cctest.h"
12#include "test/cctest/compiler/value-helper.h"
13
14namespace v8 {
15namespace internal {
16namespace compiler {
17
18template <typename T>
19const Operator* NewConstantOperator(CommonOperatorBuilder* common,
20                                    volatile T value);
21
22template <>
23const Operator* NewConstantOperator<int32_t>(CommonOperatorBuilder* common,
24                                             volatile int32_t value) {
25  return common->Int32Constant(value);
26}
27
28template <>
29const Operator* NewConstantOperator<double>(CommonOperatorBuilder* common,
30                                            volatile double value) {
31  return common->Float64Constant(value);
32}
33
34
35template <typename T>
36T ValueOfOperator(const Operator* op);
37
38template <>
39int32_t ValueOfOperator<int32_t>(const Operator* op) {
40  CHECK_EQ(IrOpcode::kInt32Constant, op->opcode());
41  return OpParameter<int32_t>(op);
42}
43
44template <>
45double ValueOfOperator<double>(const Operator* op) {
46  CHECK_EQ(IrOpcode::kFloat64Constant, op->opcode());
47  return OpParameter<double>(op);
48}
49
50
51class ReducerTester : public HandleAndZoneScope {
52 public:
53  explicit ReducerTester(
54      int num_parameters = 0,
55      MachineOperatorBuilder::Flags flags = MachineOperatorBuilder::kNoFlags)
56      : isolate(main_isolate()),
57        binop(NULL),
58        unop(NULL),
59        machine(main_zone(), MachineType::PointerRepresentation(), flags),
60        common(main_zone()),
61        graph(main_zone()),
62        javascript(main_zone()),
63        typer(isolate, &graph),
64        jsgraph(isolate, &graph, &common, &javascript, nullptr, &machine),
65        maxuint32(Constant<int32_t>(kMaxUInt32)) {
66    Node* s = graph.NewNode(common.Start(num_parameters));
67    graph.SetStart(s);
68  }
69
70  Isolate* isolate;
71  const Operator* binop;
72  const Operator* unop;
73  MachineOperatorBuilder machine;
74  CommonOperatorBuilder common;
75  Graph graph;
76  JSOperatorBuilder javascript;
77  Typer typer;
78  JSGraph jsgraph;
79  Node* maxuint32;
80
81  template <typename T>
82  Node* Constant(volatile T value) {
83    return graph.NewNode(NewConstantOperator<T>(&common, value));
84  }
85
86  template <typename T>
87  const T ValueOf(const Operator* op) {
88    return ValueOfOperator<T>(op);
89  }
90
91  // Check that the reduction of this binop applied to constants {a} and {b}
92  // yields the {expect} value.
93  template <typename T>
94  void CheckFoldBinop(volatile T expect, volatile T a, volatile T b) {
95    CheckFoldBinop<T>(expect, Constant<T>(a), Constant<T>(b));
96  }
97
98  // Check that the reduction of this binop applied to {a} and {b} yields
99  // the {expect} value.
100  template <typename T>
101  void CheckFoldBinop(volatile T expect, Node* a, Node* b) {
102    CHECK(binop);
103    Node* n = CreateBinopNode(a, b);
104    MachineOperatorReducer reducer(&jsgraph);
105    Reduction reduction = reducer.Reduce(n);
106    CHECK(reduction.Changed());
107    CHECK_NE(n, reduction.replacement());
108    CHECK_EQ(expect, ValueOf<T>(reduction.replacement()->op()));
109  }
110
111  // Check that the reduction of this binop applied to {a} and {b} yields
112  // the {expect} node.
113  void CheckBinop(Node* expect, Node* a, Node* b) {
114    CHECK(binop);
115    Node* n = CreateBinopNode(a, b);
116    MachineOperatorReducer reducer(&jsgraph);
117    Reduction reduction = reducer.Reduce(n);
118    CHECK(reduction.Changed());
119    CHECK_EQ(expect, reduction.replacement());
120  }
121
122  // Check that the reduction of this binop applied to {left} and {right} yields
123  // this binop applied to {left_expect} and {right_expect}.
124  void CheckFoldBinop(Node* left_expect, Node* right_expect, Node* left,
125                      Node* right) {
126    CHECK(binop);
127    Node* n = CreateBinopNode(left, right);
128    MachineOperatorReducer reducer(&jsgraph);
129    Reduction reduction = reducer.Reduce(n);
130    CHECK(reduction.Changed());
131    CHECK_EQ(binop, reduction.replacement()->op());
132    CHECK_EQ(left_expect, reduction.replacement()->InputAt(0));
133    CHECK_EQ(right_expect, reduction.replacement()->InputAt(1));
134  }
135
136  // Check that the reduction of this binop applied to {left} and {right} yields
137  // the {op_expect} applied to {left_expect} and {right_expect}.
138  template <typename T>
139  void CheckFoldBinop(volatile T left_expect, const Operator* op_expect,
140                      Node* right_expect, Node* left, Node* right) {
141    CHECK(binop);
142    Node* n = CreateBinopNode(left, right);
143    MachineOperatorReducer reducer(&jsgraph);
144    Reduction r = reducer.Reduce(n);
145    CHECK(r.Changed());
146    CHECK_EQ(op_expect->opcode(), r.replacement()->op()->opcode());
147    CHECK_EQ(left_expect, ValueOf<T>(r.replacement()->InputAt(0)->op()));
148    CHECK_EQ(right_expect, r.replacement()->InputAt(1));
149  }
150
151  // Check that the reduction of this binop applied to {left} and {right} yields
152  // the {op_expect} applied to {left_expect} and {right_expect}.
153  template <typename T>
154  void CheckFoldBinop(Node* left_expect, const Operator* op_expect,
155                      volatile T right_expect, Node* left, Node* right) {
156    CHECK(binop);
157    Node* n = CreateBinopNode(left, right);
158    MachineOperatorReducer reducer(&jsgraph);
159    Reduction r = reducer.Reduce(n);
160    CHECK(r.Changed());
161    CHECK_EQ(op_expect->opcode(), r.replacement()->op()->opcode());
162    CHECK_EQ(OperatorProperties::GetTotalInputCount(op_expect),
163             r.replacement()->InputCount());
164    CHECK_EQ(left_expect, r.replacement()->InputAt(0));
165    CHECK_EQ(right_expect, ValueOf<T>(r.replacement()->InputAt(1)->op()));
166  }
167
168  // Check that if the given constant appears on the left, the reducer will
169  // swap it to be on the right.
170  template <typename T>
171  void CheckPutConstantOnRight(volatile T constant) {
172    // TODO(titzer): CHECK(binop->HasProperty(Operator::kCommutative));
173    Node* p = Parameter();
174    Node* k = Constant<T>(constant);
175    {
176      Node* n = CreateBinopNode(k, p);
177      MachineOperatorReducer reducer(&jsgraph);
178      Reduction reduction = reducer.Reduce(n);
179      CHECK(!reduction.Changed() || reduction.replacement() == n);
180      CHECK_EQ(p, n->InputAt(0));
181      CHECK_EQ(k, n->InputAt(1));
182    }
183    {
184      Node* n = CreateBinopNode(p, k);
185      MachineOperatorReducer reducer(&jsgraph);
186      Reduction reduction = reducer.Reduce(n);
187      CHECK(!reduction.Changed());
188      CHECK_EQ(p, n->InputAt(0));
189      CHECK_EQ(k, n->InputAt(1));
190    }
191  }
192
193  // Check that if the given constant appears on the left, the reducer will
194  // *NOT* swap it to be on the right.
195  template <typename T>
196  void CheckDontPutConstantOnRight(volatile T constant) {
197    CHECK(!binop->HasProperty(Operator::kCommutative));
198    Node* p = Parameter();
199    Node* k = Constant<T>(constant);
200    Node* n = CreateBinopNode(k, p);
201    MachineOperatorReducer reducer(&jsgraph);
202    Reduction reduction = reducer.Reduce(n);
203    CHECK(!reduction.Changed());
204    CHECK_EQ(k, n->InputAt(0));
205    CHECK_EQ(p, n->InputAt(1));
206  }
207
208  Node* Parameter(int32_t index = 0) {
209    return graph.NewNode(common.Parameter(index), graph.start());
210  }
211
212 private:
213  Node* CreateBinopNode(Node* left, Node* right) {
214    if (binop->ControlInputCount() > 0) {
215      return graph.NewNode(binop, left, right, graph.start());
216    } else {
217      return graph.NewNode(binop, left, right);
218    }
219  }
220};
221
222
223TEST(ReduceWord32And) {
224  ReducerTester R;
225  R.binop = R.machine.Word32And();
226
227  FOR_INT32_INPUTS(pl) {
228    FOR_INT32_INPUTS(pr) {
229      int32_t x = *pl, y = *pr;
230      R.CheckFoldBinop<int32_t>(x & y, x, y);
231    }
232  }
233
234  R.CheckPutConstantOnRight(33);
235  R.CheckPutConstantOnRight(44000);
236
237  Node* x = R.Parameter();
238  Node* zero = R.Constant<int32_t>(0);
239  Node* minus_1 = R.Constant<int32_t>(-1);
240
241  R.CheckBinop(zero, x, zero);  // x  & 0  => 0
242  R.CheckBinop(zero, zero, x);  // 0  & x  => 0
243  R.CheckBinop(x, x, minus_1);  // x  & -1 => 0
244  R.CheckBinop(x, minus_1, x);  // -1 & x  => 0
245  R.CheckBinop(x, x, x);        // x  & x  => x
246}
247
248
249TEST(ReduceWord32Or) {
250  ReducerTester R;
251  R.binop = R.machine.Word32Or();
252
253  FOR_INT32_INPUTS(pl) {
254    FOR_INT32_INPUTS(pr) {
255      int32_t x = *pl, y = *pr;
256      R.CheckFoldBinop<int32_t>(x | y, x, y);
257    }
258  }
259
260  R.CheckPutConstantOnRight(36);
261  R.CheckPutConstantOnRight(44001);
262
263  Node* x = R.Parameter();
264  Node* zero = R.Constant<int32_t>(0);
265  Node* minus_1 = R.Constant<int32_t>(-1);
266
267  R.CheckBinop(x, x, zero);           // x  & 0  => x
268  R.CheckBinop(x, zero, x);           // 0  & x  => x
269  R.CheckBinop(minus_1, x, minus_1);  // x  & -1 => -1
270  R.CheckBinop(minus_1, minus_1, x);  // -1 & x  => -1
271  R.CheckBinop(x, x, x);              // x  & x  => x
272}
273
274
275TEST(ReduceWord32Xor) {
276  ReducerTester R;
277  R.binop = R.machine.Word32Xor();
278
279  FOR_INT32_INPUTS(pl) {
280    FOR_INT32_INPUTS(pr) {
281      int32_t x = *pl, y = *pr;
282      R.CheckFoldBinop<int32_t>(x ^ y, x, y);
283    }
284  }
285
286  R.CheckPutConstantOnRight(39);
287  R.CheckPutConstantOnRight(4403);
288
289  Node* x = R.Parameter();
290  Node* zero = R.Constant<int32_t>(0);
291
292  R.CheckBinop(x, x, zero);            // x ^ 0  => x
293  R.CheckBinop(x, zero, x);            // 0 ^ x  => x
294  R.CheckFoldBinop<int32_t>(0, x, x);  // x ^ x  => 0
295}
296
297
298TEST(ReduceWord32Shl) {
299  ReducerTester R;
300  R.binop = R.machine.Word32Shl();
301
302  // TODO(titzer): out of range shifts
303  FOR_INT32_INPUTS(i) {
304    for (int y = 0; y < 32; y++) {
305      int32_t x = *i;
306      R.CheckFoldBinop<int32_t>(x << y, x, y);
307    }
308  }
309
310  R.CheckDontPutConstantOnRight(44);
311
312  Node* x = R.Parameter();
313  Node* zero = R.Constant<int32_t>(0);
314
315  R.CheckBinop(x, x, zero);  // x << 0  => x
316}
317
318
319TEST(ReduceWord32Shr) {
320  ReducerTester R;
321  R.binop = R.machine.Word32Shr();
322
323  // TODO(titzer): test out of range shifts
324  FOR_UINT32_INPUTS(i) {
325    for (uint32_t y = 0; y < 32; y++) {
326      uint32_t x = *i;
327      R.CheckFoldBinop<int32_t>(x >> y, x, y);
328    }
329  }
330
331  R.CheckDontPutConstantOnRight(44);
332
333  Node* x = R.Parameter();
334  Node* zero = R.Constant<int32_t>(0);
335
336  R.CheckBinop(x, x, zero);  // x >>> 0  => x
337}
338
339
340TEST(ReduceWord32Sar) {
341  ReducerTester R;
342  R.binop = R.machine.Word32Sar();
343
344  // TODO(titzer): test out of range shifts
345  FOR_INT32_INPUTS(i) {
346    for (int32_t y = 0; y < 32; y++) {
347      int32_t x = *i;
348      R.CheckFoldBinop<int32_t>(x >> y, x, y);
349    }
350  }
351
352  R.CheckDontPutConstantOnRight(44);
353
354  Node* x = R.Parameter();
355  Node* zero = R.Constant<int32_t>(0);
356
357  R.CheckBinop(x, x, zero);  // x >> 0  => x
358}
359
360
361static void CheckJsShift(ReducerTester* R) {
362  CHECK(R->machine.Word32ShiftIsSafe());
363
364  Node* x = R->Parameter(0);
365  Node* y = R->Parameter(1);
366  Node* thirty_one = R->Constant<int32_t>(0x1f);
367  Node* y_and_thirty_one =
368      R->graph.NewNode(R->machine.Word32And(), y, thirty_one);
369
370  // If the underlying machine shift instructions 'and' their right operand
371  // with 0x1f then:  x << (y & 0x1f) => x << y
372  R->CheckFoldBinop(x, y, x, y_and_thirty_one);
373}
374
375
376TEST(ReduceJsShifts) {
377  ReducerTester R(0, MachineOperatorBuilder::kWord32ShiftIsSafe);
378
379  R.binop = R.machine.Word32Shl();
380  CheckJsShift(&R);
381
382  R.binop = R.machine.Word32Shr();
383  CheckJsShift(&R);
384
385  R.binop = R.machine.Word32Sar();
386  CheckJsShift(&R);
387}
388
389
390TEST(Word32Equal) {
391  ReducerTester R;
392  R.binop = R.machine.Word32Equal();
393
394  FOR_INT32_INPUTS(pl) {
395    FOR_INT32_INPUTS(pr) {
396      int32_t x = *pl, y = *pr;
397      R.CheckFoldBinop<int32_t>(x == y ? 1 : 0, x, y);
398    }
399  }
400
401  R.CheckPutConstantOnRight(48);
402  R.CheckPutConstantOnRight(-48);
403
404  Node* x = R.Parameter(0);
405  Node* y = R.Parameter(1);
406  Node* zero = R.Constant<int32_t>(0);
407  Node* sub = R.graph.NewNode(R.machine.Int32Sub(), x, y);
408
409  R.CheckFoldBinop<int32_t>(1, x, x);  // x == x  => 1
410  R.CheckFoldBinop(x, y, sub, zero);   // x - y == 0  => x == y
411  R.CheckFoldBinop(x, y, zero, sub);   // 0 == x - y  => x == y
412}
413
414
415TEST(ReduceInt32Add) {
416  ReducerTester R;
417  R.binop = R.machine.Int32Add();
418
419  FOR_INT32_INPUTS(pl) {
420    FOR_INT32_INPUTS(pr) {
421      int32_t x = *pl, y = *pr;
422      R.CheckFoldBinop<int32_t>(x + y, x, y);  // TODO(titzer): signed overflow
423    }
424  }
425
426  R.CheckPutConstantOnRight(41);
427  R.CheckPutConstantOnRight(4407);
428
429  Node* x = R.Parameter();
430  Node* zero = R.Constant<int32_t>(0);
431
432  R.CheckBinop(x, x, zero);  // x + 0  => x
433  R.CheckBinop(x, zero, x);  // 0 + x  => x
434}
435
436
437TEST(ReduceInt32Sub) {
438  ReducerTester R;
439  R.binop = R.machine.Int32Sub();
440
441  FOR_INT32_INPUTS(pl) {
442    FOR_INT32_INPUTS(pr) {
443      int32_t x = *pl, y = *pr;
444      R.CheckFoldBinop<int32_t>(x - y, x, y);
445    }
446  }
447
448  R.CheckDontPutConstantOnRight(412);
449
450  Node* x = R.Parameter();
451  Node* zero = R.Constant<int32_t>(0);
452
453  R.CheckBinop(x, x, zero);  // x - 0  => x
454}
455
456
457TEST(ReduceInt32Mul) {
458  ReducerTester R;
459  R.binop = R.machine.Int32Mul();
460
461  FOR_INT32_INPUTS(pl) {
462    FOR_INT32_INPUTS(pr) {
463      int32_t x = *pl, y = *pr;
464      R.CheckFoldBinop<int32_t>(x * y, x, y);  // TODO(titzer): signed overflow
465    }
466  }
467
468  R.CheckPutConstantOnRight(4111);
469  R.CheckPutConstantOnRight(-4407);
470
471  Node* x = R.Parameter();
472  Node* zero = R.Constant<int32_t>(0);
473  Node* one = R.Constant<int32_t>(1);
474  Node* minus_one = R.Constant<int32_t>(-1);
475
476  R.CheckBinop(zero, x, zero);  // x * 0  => 0
477  R.CheckBinop(zero, zero, x);  // 0 * x  => 0
478  R.CheckBinop(x, x, one);      // x * 1  => x
479  R.CheckBinop(x, one, x);      // 1 * x  => x
480  R.CheckFoldBinop<int32_t>(0, R.machine.Int32Sub(), x, minus_one,
481                            x);  // -1 * x  => 0 - x
482  R.CheckFoldBinop<int32_t>(0, R.machine.Int32Sub(), x, x,
483                            minus_one);  // x * -1  => 0 - x
484
485  for (int32_t n = 1; n < 31; ++n) {
486    Node* multiplier = R.Constant<int32_t>(1 << n);
487    R.CheckFoldBinop<int32_t>(x, R.machine.Word32Shl(), n, x,
488                              multiplier);  // x * 2^n => x << n
489    R.CheckFoldBinop<int32_t>(x, R.machine.Word32Shl(), n, multiplier,
490                              x);  // 2^n * x => x << n
491  }
492}
493
494
495TEST(ReduceInt32Div) {
496  ReducerTester R;
497  R.binop = R.machine.Int32Div();
498
499  FOR_INT32_INPUTS(pl) {
500    FOR_INT32_INPUTS(pr) {
501      int32_t x = *pl, y = *pr;
502      if (y == 0) continue;              // TODO(titzer): test / 0
503      int32_t r = y == -1 ? -x : x / y;  // INT_MIN / -1 may explode in C
504      R.CheckFoldBinop<int32_t>(r, x, y);
505    }
506  }
507
508  R.CheckDontPutConstantOnRight(41111);
509  R.CheckDontPutConstantOnRight(-44071);
510
511  Node* x = R.Parameter();
512  Node* one = R.Constant<int32_t>(1);
513  Node* minus_one = R.Constant<int32_t>(-1);
514
515  R.CheckBinop(x, x, one);  // x / 1  => x
516  // TODO(titzer):                          // 0 / x  => 0 if x != 0
517  // TODO(titzer):                          // x / 2^n => x >> n and round
518  R.CheckFoldBinop<int32_t>(0, R.machine.Int32Sub(), x, x,
519                            minus_one);  // x / -1  => 0 - x
520}
521
522
523TEST(ReduceUint32Div) {
524  ReducerTester R;
525  R.binop = R.machine.Uint32Div();
526
527  FOR_UINT32_INPUTS(pl) {
528    FOR_UINT32_INPUTS(pr) {
529      uint32_t x = *pl, y = *pr;
530      if (y == 0) continue;  // TODO(titzer): test / 0
531      R.CheckFoldBinop<int32_t>(x / y, x, y);
532    }
533  }
534
535  R.CheckDontPutConstantOnRight(41311);
536  R.CheckDontPutConstantOnRight(-44371);
537
538  Node* x = R.Parameter();
539  Node* one = R.Constant<int32_t>(1);
540
541  R.CheckBinop(x, x, one);  // x / 1  => x
542  // TODO(titzer):                            // 0 / x  => 0 if x != 0
543
544  for (uint32_t n = 1; n < 32; ++n) {
545    Node* divisor = R.Constant<int32_t>(1u << n);
546    R.CheckFoldBinop<int32_t>(x, R.machine.Word32Shr(), n, x,
547                              divisor);  // x / 2^n => x >> n
548  }
549}
550
551
552TEST(ReduceInt32Mod) {
553  ReducerTester R;
554  R.binop = R.machine.Int32Mod();
555
556  FOR_INT32_INPUTS(pl) {
557    FOR_INT32_INPUTS(pr) {
558      int32_t x = *pl, y = *pr;
559      if (y == 0) continue;             // TODO(titzer): test % 0
560      int32_t r = y == -1 ? 0 : x % y;  // INT_MIN % -1 may explode in C
561      R.CheckFoldBinop<int32_t>(r, x, y);
562    }
563  }
564
565  R.CheckDontPutConstantOnRight(413);
566  R.CheckDontPutConstantOnRight(-4401);
567
568  Node* x = R.Parameter();
569  Node* one = R.Constant<int32_t>(1);
570
571  R.CheckFoldBinop<int32_t>(0, x, one);  // x % 1  => 0
572  // TODO(titzer):                       // x % 2^n => x & 2^n-1 and round
573}
574
575
576TEST(ReduceUint32Mod) {
577  ReducerTester R;
578  R.binop = R.machine.Uint32Mod();
579
580  FOR_INT32_INPUTS(pl) {
581    FOR_INT32_INPUTS(pr) {
582      uint32_t x = *pl, y = *pr;
583      if (y == 0) continue;  // TODO(titzer): test x % 0
584      R.CheckFoldBinop<int32_t>(x % y, x, y);
585    }
586  }
587
588  R.CheckDontPutConstantOnRight(417);
589  R.CheckDontPutConstantOnRight(-4371);
590
591  Node* x = R.Parameter();
592  Node* one = R.Constant<int32_t>(1);
593
594  R.CheckFoldBinop<int32_t>(0, x, one);  // x % 1  => 0
595
596  for (uint32_t n = 1; n < 32; ++n) {
597    Node* divisor = R.Constant<int32_t>(1u << n);
598    R.CheckFoldBinop<int32_t>(x, R.machine.Word32And(), (1u << n) - 1, x,
599                              divisor);  // x % 2^n => x & 2^n-1
600  }
601}
602
603
604TEST(ReduceInt32LessThan) {
605  ReducerTester R;
606  R.binop = R.machine.Int32LessThan();
607
608  FOR_INT32_INPUTS(pl) {
609    FOR_INT32_INPUTS(pr) {
610      int32_t x = *pl, y = *pr;
611      R.CheckFoldBinop<int32_t>(x < y ? 1 : 0, x, y);
612    }
613  }
614
615  R.CheckDontPutConstantOnRight(41399);
616  R.CheckDontPutConstantOnRight(-440197);
617
618  Node* x = R.Parameter(0);
619  Node* y = R.Parameter(1);
620  Node* zero = R.Constant<int32_t>(0);
621  Node* sub = R.graph.NewNode(R.machine.Int32Sub(), x, y);
622
623  R.CheckFoldBinop<int32_t>(0, x, x);  // x < x  => 0
624  R.CheckFoldBinop(x, y, sub, zero);   // x - y < 0 => x < y
625  R.CheckFoldBinop(y, x, zero, sub);   // 0 < x - y => y < x
626}
627
628
629TEST(ReduceInt32LessThanOrEqual) {
630  ReducerTester R;
631  R.binop = R.machine.Int32LessThanOrEqual();
632
633  FOR_INT32_INPUTS(pl) {
634    FOR_INT32_INPUTS(pr) {
635      int32_t x = *pl, y = *pr;
636      R.CheckFoldBinop<int32_t>(x <= y ? 1 : 0, x, y);
637    }
638  }
639
640  FOR_INT32_INPUTS(i) { R.CheckDontPutConstantOnRight<int32_t>(*i); }
641
642  Node* x = R.Parameter(0);
643  Node* y = R.Parameter(1);
644  Node* zero = R.Constant<int32_t>(0);
645  Node* sub = R.graph.NewNode(R.machine.Int32Sub(), x, y);
646
647  R.CheckFoldBinop<int32_t>(1, x, x);  // x <= x => 1
648  R.CheckFoldBinop(x, y, sub, zero);   // x - y <= 0 => x <= y
649  R.CheckFoldBinop(y, x, zero, sub);   // 0 <= x - y => y <= x
650}
651
652
653TEST(ReduceUint32LessThan) {
654  ReducerTester R;
655  R.binop = R.machine.Uint32LessThan();
656
657  FOR_UINT32_INPUTS(pl) {
658    FOR_UINT32_INPUTS(pr) {
659      uint32_t x = *pl, y = *pr;
660      R.CheckFoldBinop<int32_t>(x < y ? 1 : 0, x, y);
661    }
662  }
663
664  R.CheckDontPutConstantOnRight(41399);
665  R.CheckDontPutConstantOnRight(-440197);
666
667  Node* x = R.Parameter();
668  Node* max = R.maxuint32;
669  Node* zero = R.Constant<int32_t>(0);
670
671  R.CheckFoldBinop<int32_t>(0, max, x);   // M < x  => 0
672  R.CheckFoldBinop<int32_t>(0, x, zero);  // x < 0  => 0
673  R.CheckFoldBinop<int32_t>(0, x, x);     // x < x  => 0
674}
675
676
677TEST(ReduceUint32LessThanOrEqual) {
678  ReducerTester R;
679  R.binop = R.machine.Uint32LessThanOrEqual();
680
681  FOR_UINT32_INPUTS(pl) {
682    FOR_UINT32_INPUTS(pr) {
683      uint32_t x = *pl, y = *pr;
684      R.CheckFoldBinop<int32_t>(x <= y ? 1 : 0, x, y);
685    }
686  }
687
688  R.CheckDontPutConstantOnRight(41399);
689  R.CheckDontPutConstantOnRight(-440197);
690
691  Node* x = R.Parameter();
692  Node* max = R.maxuint32;
693  Node* zero = R.Constant<int32_t>(0);
694
695  R.CheckFoldBinop<int32_t>(1, x, max);   // x <= M  => 1
696  R.CheckFoldBinop<int32_t>(1, zero, x);  // 0 <= x  => 1
697  R.CheckFoldBinop<int32_t>(1, x, x);     // x <= x  => 1
698}
699
700
701TEST(ReduceLoadStore) {
702  ReducerTester R;
703
704  Node* base = R.Constant<int32_t>(11);
705  Node* index = R.Constant<int32_t>(4);
706  Node* load = R.graph.NewNode(R.machine.Load(MachineType::Int32()), base,
707                               index, R.graph.start(), R.graph.start());
708
709  {
710    MachineOperatorReducer reducer(&R.jsgraph);
711    Reduction reduction = reducer.Reduce(load);
712    CHECK(!reduction.Changed());  // loads should not be reduced.
713  }
714
715  {
716    Node* store =
717        R.graph.NewNode(R.machine.Store(StoreRepresentation(
718                            MachineRepresentation::kWord32, kNoWriteBarrier)),
719                        base, index, load, load, R.graph.start());
720    MachineOperatorReducer reducer(&R.jsgraph);
721    Reduction reduction = reducer.Reduce(store);
722    CHECK(!reduction.Changed());  // stores should not be reduced.
723  }
724}
725
726
727// TODO(titzer): test MachineOperatorReducer for Word64And
728// TODO(titzer): test MachineOperatorReducer for Word64Or
729// TODO(titzer): test MachineOperatorReducer for Word64Xor
730// TODO(titzer): test MachineOperatorReducer for Word64Shl
731// TODO(titzer): test MachineOperatorReducer for Word64Shr
732// TODO(titzer): test MachineOperatorReducer for Word64Sar
733// TODO(titzer): test MachineOperatorReducer for Word64Equal
734// TODO(titzer): test MachineOperatorReducer for Word64Not
735// TODO(titzer): test MachineOperatorReducer for Int64Add
736// TODO(titzer): test MachineOperatorReducer for Int64Sub
737// TODO(titzer): test MachineOperatorReducer for Int64Mul
738// TODO(titzer): test MachineOperatorReducer for Int64UMul
739// TODO(titzer): test MachineOperatorReducer for Int64Div
740// TODO(titzer): test MachineOperatorReducer for Uint64Div
741// TODO(titzer): test MachineOperatorReducer for Int64Mod
742// TODO(titzer): test MachineOperatorReducer for Uint64Mod
743// TODO(titzer): test MachineOperatorReducer for Int64Neg
744// TODO(titzer): test MachineOperatorReducer for ChangeInt32ToFloat64
745// TODO(titzer): test MachineOperatorReducer for ChangeFloat64ToInt32
746// TODO(titzer): test MachineOperatorReducer for Float64Compare
747// TODO(titzer): test MachineOperatorReducer for Float64Add
748// TODO(titzer): test MachineOperatorReducer for Float64Sub
749// TODO(titzer): test MachineOperatorReducer for Float64Mul
750// TODO(titzer): test MachineOperatorReducer for Float64Div
751// TODO(titzer): test MachineOperatorReducer for Float64Mod
752
753}  // namespace compiler
754}  // namespace internal
755}  // namespace v8
756