LCOV - code coverage report
Current view: top level - test/cctest/compiler - test-machine-operator-reducer.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 509 513 99.2 %
Date: 2019-01-20 Functions: 56 60 93.3 %

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

Generated by: LCOV version 1.10