Home | History | Annotate | Download | only in compiler
      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 
     14 namespace v8 {
     15 namespace internal {
     16 namespace compiler {
     17 
     18 template <typename T>
     19 const Operator* NewConstantOperator(CommonOperatorBuilder* common,
     20                                     volatile T value);
     21 
     22 template <>
     23 const Operator* NewConstantOperator<int32_t>(CommonOperatorBuilder* common,
     24                                              volatile int32_t value) {
     25   return common->Int32Constant(value);
     26 }
     27 
     28 template <>
     29 const Operator* NewConstantOperator<double>(CommonOperatorBuilder* common,
     30                                             volatile double value) {
     31   return common->Float64Constant(value);
     32 }
     33 
     34 
     35 template <typename T>
     36 T ValueOfOperator(const Operator* op);
     37 
     38 template <>
     39 int32_t ValueOfOperator<int32_t>(const Operator* op) {
     40   CHECK_EQ(IrOpcode::kInt32Constant, op->opcode());
     41   return OpParameter<int32_t>(op);
     42 }
     43 
     44 template <>
     45 double ValueOfOperator<double>(const Operator* op) {
     46   CHECK_EQ(IrOpcode::kFloat64Constant, op->opcode());
     47   return OpParameter<double>(op);
     48 }
     49 
     50 
     51 class 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 
    223 TEST(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 
    249 TEST(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 
    275 TEST(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 
    298 TEST(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 
    319 TEST(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 
    340 TEST(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 
    361 static 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 
    376 TEST(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 
    390 TEST(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 
    415 TEST(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 
    437 TEST(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 
    457 TEST(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 
    495 TEST(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 
    523 TEST(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 
    552 TEST(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 
    576 TEST(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 
    604 TEST(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 
    629 TEST(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 
    653 TEST(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 
    677 TEST(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 
    701 TEST(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