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/compilation-dependencies.h"
      6 #include "src/compiler/js-graph.h"
      7 #include "src/compiler/js-typed-lowering.h"
      8 #include "src/compiler/machine-operator.h"
      9 #include "src/compiler/node-properties.h"
     10 #include "src/compiler/opcodes.h"
     11 #include "src/compiler/operator-properties.h"
     12 #include "src/compiler/simplified-operator.h"
     13 #include "src/compiler/typer.h"
     14 #include "test/cctest/cctest.h"
     15 
     16 namespace v8 {
     17 namespace internal {
     18 namespace compiler {
     19 
     20 #ifndef TEST_WITH_STRONG
     21 #define TEST_WITH_STRONG(Name)                                                 \
     22   static void Test##Name();                                                    \
     23   static void TestWithStrong##Name(LanguageMode language_mode);                \
     24   CcTest register_test_##Name(Test##Name, __FILE__, #Name, NULL, true, true);  \
     25   static void Test##Name() {                                                   \
     26     TestWithStrong##Name(LanguageMode::SLOPPY);                                \
     27     TestWithStrong##Name(LanguageMode::STRONG);                                \
     28   }                                                                            \
     29   static void TestWithStrong##Name(LanguageMode language_mode)
     30 #endif
     31 
     32 
     33 class JSTypedLoweringTester : public HandleAndZoneScope {
     34  public:
     35   explicit JSTypedLoweringTester(int num_parameters = 0)
     36       : isolate(main_isolate()),
     37         binop(NULL),
     38         unop(NULL),
     39         javascript(main_zone()),
     40         machine(main_zone()),
     41         simplified(main_zone()),
     42         common(main_zone()),
     43         deps(main_isolate(), main_zone()),
     44         graph(main_zone()),
     45         typer(main_isolate(), &graph),
     46         context_node(NULL) {
     47     graph.SetStart(graph.NewNode(common.Start(num_parameters)));
     48     graph.SetEnd(graph.NewNode(common.End(1), graph.start()));
     49     typer.Run();
     50   }
     51 
     52   Isolate* isolate;
     53   const Operator* binop;
     54   const Operator* unop;
     55   JSOperatorBuilder javascript;
     56   MachineOperatorBuilder machine;
     57   SimplifiedOperatorBuilder simplified;
     58   CommonOperatorBuilder common;
     59   CompilationDependencies deps;
     60   Graph graph;
     61   Typer typer;
     62   Node* context_node;
     63   BinaryOperationHints const hints = BinaryOperationHints::Any();
     64 
     65   Node* Parameter(Type* t, int32_t index = 0) {
     66     Node* n = graph.NewNode(common.Parameter(index), graph.start());
     67     NodeProperties::SetType(n, t);
     68     return n;
     69   }
     70 
     71   Node* UndefinedConstant() {
     72     Handle<HeapObject> value = isolate->factory()->undefined_value();
     73     return graph.NewNode(common.HeapConstant(value));
     74   }
     75 
     76   Node* HeapConstant(Handle<HeapObject> constant) {
     77     return graph.NewNode(common.HeapConstant(constant));
     78   }
     79 
     80   Node* EmptyFrameState(Node* context) {
     81     Node* parameters = graph.NewNode(common.StateValues(0));
     82     Node* locals = graph.NewNode(common.StateValues(0));
     83     Node* stack = graph.NewNode(common.StateValues(0));
     84 
     85     Node* state_node = graph.NewNode(
     86         common.FrameState(BailoutId::None(), OutputFrameStateCombine::Ignore(),
     87                           nullptr),
     88         parameters, locals, stack, context, UndefinedConstant(), graph.start());
     89 
     90     return state_node;
     91   }
     92 
     93   Node* reduce(Node* node) {
     94     JSGraph jsgraph(main_isolate(), &graph, &common, &javascript, &simplified,
     95                     &machine);
     96     // TODO(titzer): mock the GraphReducer here for better unit testing.
     97     GraphReducer graph_reducer(main_zone(), &graph);
     98     JSTypedLowering reducer(&graph_reducer, &deps,
     99                             JSTypedLowering::kDeoptimizationEnabled, &jsgraph,
    100                             main_zone());
    101     Reduction reduction = reducer.Reduce(node);
    102     if (reduction.Changed()) return reduction.replacement();
    103     return node;
    104   }
    105 
    106   Node* start() { return graph.start(); }
    107 
    108   Node* context() {
    109     if (context_node == NULL) {
    110       context_node = graph.NewNode(common.Parameter(-1), graph.start());
    111     }
    112     return context_node;
    113   }
    114 
    115   Node* control() { return start(); }
    116 
    117   void CheckBinop(IrOpcode::Value expected, Node* node) {
    118     CHECK_EQ(expected, node->opcode());
    119   }
    120 
    121   void CheckBinop(const Operator* expected, Node* node) {
    122     CHECK_EQ(expected->opcode(), node->op()->opcode());
    123   }
    124 
    125   Node* ReduceUnop(const Operator* op, Type* input_type) {
    126     return reduce(Unop(op, Parameter(input_type)));
    127   }
    128 
    129   Node* ReduceBinop(const Operator* op, Type* left_type, Type* right_type) {
    130     return reduce(Binop(op, Parameter(left_type, 0), Parameter(right_type, 1)));
    131   }
    132 
    133   Node* Binop(const Operator* op, Node* left, Node* right) {
    134     // JS binops also require context, effect, and control
    135     std::vector<Node*> inputs;
    136     inputs.push_back(left);
    137     inputs.push_back(right);
    138     if (OperatorProperties::HasContextInput(op)) {
    139       inputs.push_back(context());
    140     }
    141     for (int i = 0; i < OperatorProperties::GetFrameStateInputCount(op); i++) {
    142       inputs.push_back(EmptyFrameState(context()));
    143     }
    144     if (op->EffectInputCount() > 0) {
    145       inputs.push_back(start());
    146     }
    147     if (op->ControlInputCount() > 0) {
    148       inputs.push_back(control());
    149     }
    150     return graph.NewNode(op, static_cast<int>(inputs.size()),
    151                          &(inputs.front()));
    152   }
    153 
    154   Node* Unop(const Operator* op, Node* input) {
    155     // JS unops also require context, effect, and control
    156     if (OperatorProperties::GetFrameStateInputCount(op) > 0) {
    157       CHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(op));
    158       return graph.NewNode(op, input, context(), EmptyFrameState(context()),
    159                            start(), control());
    160     } else {
    161       return graph.NewNode(op, input, context(), start(), control());
    162     }
    163   }
    164 
    165   Node* UseForEffect(Node* node) {
    166     // TODO(titzer): use EffectPhi after fixing EffectCount
    167     if (OperatorProperties::GetFrameStateInputCount(javascript.ToNumber()) >
    168         0) {
    169       CHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(
    170                       javascript.ToNumber()));
    171       return graph.NewNode(javascript.ToNumber(), node, context(),
    172                            EmptyFrameState(context()), node, control());
    173     } else {
    174       return graph.NewNode(javascript.ToNumber(), node, context(), node,
    175                            control());
    176     }
    177   }
    178 
    179   void CheckEffectInput(Node* effect, Node* use) {
    180     CHECK_EQ(effect, NodeProperties::GetEffectInput(use));
    181   }
    182 
    183   void CheckInt32Constant(int32_t expected, Node* result) {
    184     CHECK_EQ(IrOpcode::kInt32Constant, result->opcode());
    185     CHECK_EQ(expected, OpParameter<int32_t>(result));
    186   }
    187 
    188   void CheckNumberConstant(double expected, Node* result) {
    189     CHECK_EQ(IrOpcode::kNumberConstant, result->opcode());
    190     CHECK_EQ(expected, OpParameter<double>(result));
    191   }
    192 
    193   void CheckNaN(Node* result) {
    194     CHECK_EQ(IrOpcode::kNumberConstant, result->opcode());
    195     double value = OpParameter<double>(result);
    196     CHECK(std::isnan(value));
    197   }
    198 
    199   void CheckTrue(Node* result) {
    200     CheckHandle(isolate->factory()->true_value(), result);
    201   }
    202 
    203   void CheckFalse(Node* result) {
    204     CheckHandle(isolate->factory()->false_value(), result);
    205   }
    206 
    207   void CheckHandle(Handle<HeapObject> expected, Node* result) {
    208     CHECK_EQ(IrOpcode::kHeapConstant, result->opcode());
    209     Handle<HeapObject> value = OpParameter<Handle<HeapObject>>(result);
    210     CHECK_EQ(*expected, *value);
    211   }
    212 };
    213 
    214 static Type* kStringTypes[] = {Type::InternalizedString(), Type::OtherString(),
    215                                Type::String()};
    216 
    217 
    218 static Type* kInt32Types[] = {Type::UnsignedSmall(), Type::Negative32(),
    219                               Type::Unsigned31(),    Type::SignedSmall(),
    220                               Type::Signed32(),      Type::Unsigned32(),
    221                               Type::Integral32()};
    222 
    223 
    224 static Type* kNumberTypes[] = {
    225     Type::UnsignedSmall(), Type::Negative32(),  Type::Unsigned31(),
    226     Type::SignedSmall(),   Type::Signed32(),    Type::Unsigned32(),
    227     Type::Integral32(),    Type::MinusZero(),   Type::NaN(),
    228     Type::OrderedNumber(), Type::PlainNumber(), Type::Number()};
    229 
    230 
    231 static Type* I32Type(bool is_signed) {
    232   return is_signed ? Type::Signed32() : Type::Unsigned32();
    233 }
    234 
    235 
    236 static IrOpcode::Value NumberToI32(bool is_signed) {
    237   return is_signed ? IrOpcode::kNumberToInt32 : IrOpcode::kNumberToUint32;
    238 }
    239 
    240 
    241 // TODO(turbofan): Lowering of StringAdd is disabled for now.
    242 #if 0
    243 TEST_WITH_STRONG(StringBinops) {
    244   JSTypedLoweringTester R;
    245 
    246   for (size_t i = 0; i < arraysize(kStringTypes); ++i) {
    247     Node* p0 = R.Parameter(kStringTypes[i], 0);
    248 
    249     for (size_t j = 0; j < arraysize(kStringTypes); ++j) {
    250       Node* p1 = R.Parameter(kStringTypes[j], 1);
    251 
    252       Node* add = R.Binop(R.javascript.Add(language_mode), p0, p1);
    253       Node* r = R.reduce(add);
    254 
    255       R.CheckBinop(IrOpcode::kStringAdd, r);
    256       CHECK_EQ(p0, r->InputAt(0));
    257       CHECK_EQ(p1, r->InputAt(1));
    258     }
    259   }
    260 }
    261 #endif
    262 
    263 
    264 TEST_WITH_STRONG(AddNumber1) {
    265   JSTypedLoweringTester R;
    266   for (size_t i = 0; i < arraysize(kNumberTypes); ++i) {
    267     Node* p0 = R.Parameter(kNumberTypes[i], 0);
    268     Node* p1 = R.Parameter(kNumberTypes[i], 1);
    269     Node* add = R.Binop(
    270         R.javascript.Add(language_mode, BinaryOperationHints::Any()), p0, p1);
    271     Node* r = R.reduce(add);
    272 
    273     R.CheckBinop(IrOpcode::kNumberAdd, r);
    274     CHECK_EQ(p0, r->InputAt(0));
    275     CHECK_EQ(p1, r->InputAt(1));
    276   }
    277 }
    278 
    279 
    280 TEST_WITH_STRONG(NumberBinops) {
    281   JSTypedLoweringTester R;
    282   const Operator* ops[] = {
    283       R.javascript.Add(language_mode, R.hints),
    284       R.simplified.NumberAdd(),
    285       R.javascript.Subtract(language_mode, R.hints),
    286       R.simplified.NumberSubtract(),
    287       R.javascript.Multiply(language_mode, R.hints),
    288       R.simplified.NumberMultiply(),
    289       R.javascript.Divide(language_mode, R.hints),
    290       R.simplified.NumberDivide(),
    291       R.javascript.Modulus(language_mode, R.hints),
    292       R.simplified.NumberModulus(),
    293   };
    294 
    295   for (size_t i = 0; i < arraysize(kNumberTypes); ++i) {
    296     Node* p0 = R.Parameter(kNumberTypes[i], 0);
    297 
    298     for (size_t j = 0; j < arraysize(kNumberTypes); ++j) {
    299       Node* p1 = R.Parameter(kNumberTypes[j], 1);
    300 
    301       for (size_t k = 0; k < arraysize(ops); k += 2) {
    302         Node* add = R.Binop(ops[k], p0, p1);
    303         Node* r = R.reduce(add);
    304 
    305         R.CheckBinop(ops[k + 1], r);
    306         CHECK_EQ(p0, r->InputAt(0));
    307         CHECK_EQ(p1, r->InputAt(1));
    308       }
    309     }
    310   }
    311 }
    312 
    313 
    314 static void CheckToI32(Node* old_input, Node* new_input, bool is_signed) {
    315   Type* old_type = NodeProperties::GetType(old_input);
    316   Type* new_type = NodeProperties::GetType(new_input);
    317   Type* expected_type = I32Type(is_signed);
    318   CHECK(new_type->Is(expected_type));
    319   if (old_type->Is(expected_type)) {
    320     CHECK_EQ(old_input, new_input);
    321   } else if (new_input->opcode() == IrOpcode::kNumberConstant) {
    322     double v = OpParameter<double>(new_input);
    323     double e = static_cast<double>(is_signed ? FastD2I(v) : FastD2UI(v));
    324     CHECK_EQ(e, v);
    325   }
    326 }
    327 
    328 
    329 // A helper class for testing lowering of bitwise shift operators.
    330 class JSBitwiseShiftTypedLoweringTester : public JSTypedLoweringTester {
    331  public:
    332   explicit JSBitwiseShiftTypedLoweringTester(LanguageMode language_mode)
    333       : JSTypedLoweringTester(), language_mode_(language_mode) {
    334     int i = 0;
    335     set(i++, javascript.ShiftLeft(language_mode_, hints), true);
    336     set(i++, simplified.NumberShiftLeft(), false);
    337     set(i++, javascript.ShiftRight(language_mode_, hints), true);
    338     set(i++, simplified.NumberShiftRight(), false);
    339     set(i++, javascript.ShiftRightLogical(language_mode_, hints), false);
    340     set(i++, simplified.NumberShiftRightLogical(), false);
    341   }
    342   static const int kNumberOps = 6;
    343   const Operator* ops[kNumberOps];
    344   bool signedness[kNumberOps];
    345 
    346  private:
    347   LanguageMode language_mode_;
    348   void set(int idx, const Operator* op, bool s) {
    349     ops[idx] = op;
    350     signedness[idx] = s;
    351   }
    352 };
    353 
    354 
    355 TEST(Int32BitwiseShifts) {
    356   JSBitwiseShiftTypedLoweringTester R(LanguageMode::SLOPPY);
    357 
    358   Type* types[] = {
    359       Type::SignedSmall(), Type::UnsignedSmall(), Type::Negative32(),
    360       Type::Unsigned31(),  Type::Unsigned32(),    Type::Signed32(),
    361       Type::MinusZero(),   Type::NaN(),           Type::Undefined(),
    362       Type::Null(),        Type::Boolean(),       Type::Number(),
    363       Type::PlainNumber(), Type::String()};
    364 
    365   for (size_t i = 0; i < arraysize(types); ++i) {
    366     Node* p0 = R.Parameter(types[i], 0);
    367 
    368     for (size_t j = 0; j < arraysize(types); ++j) {
    369       Node* p1 = R.Parameter(types[j], 1);
    370 
    371       for (int k = 0; k < R.kNumberOps; k += 2) {
    372         Node* add = R.Binop(R.ops[k], p0, p1);
    373         Node* r = R.reduce(add);
    374 
    375         R.CheckBinop(R.ops[k + 1], r);
    376         Node* r0 = r->InputAt(0);
    377         Node* r1 = r->InputAt(1);
    378 
    379         CheckToI32(p0, r0, R.signedness[k]);
    380         CheckToI32(p1, r1, false);
    381       }
    382     }
    383   }
    384 }
    385 
    386 
    387 // A helper class for testing lowering of bitwise operators.
    388 class JSBitwiseTypedLoweringTester : public JSTypedLoweringTester {
    389  public:
    390   explicit JSBitwiseTypedLoweringTester(LanguageMode language_mode)
    391       : JSTypedLoweringTester(), language_mode_(language_mode) {
    392     int i = 0;
    393     set(i++, javascript.BitwiseOr(language_mode_, hints), true);
    394     set(i++, simplified.NumberBitwiseOr(), true);
    395     set(i++, javascript.BitwiseXor(language_mode_, hints), true);
    396     set(i++, simplified.NumberBitwiseXor(), true);
    397     set(i++, javascript.BitwiseAnd(language_mode_, hints), true);
    398     set(i++, simplified.NumberBitwiseAnd(), true);
    399   }
    400   static const int kNumberOps = 6;
    401   const Operator* ops[kNumberOps];
    402   bool signedness[kNumberOps];
    403 
    404  private:
    405   LanguageMode language_mode_;
    406   void set(int idx, const Operator* op, bool s) {
    407     ops[idx] = op;
    408     signedness[idx] = s;
    409   }
    410 };
    411 
    412 
    413 TEST(Int32BitwiseBinops) {
    414   JSBitwiseTypedLoweringTester R(LanguageMode::SLOPPY);
    415 
    416   Type* types[] = {
    417       Type::SignedSmall(),   Type::UnsignedSmall(), Type::Unsigned32(),
    418       Type::Signed32(),      Type::MinusZero(),     Type::NaN(),
    419       Type::OrderedNumber(), Type::PlainNumber(),   Type::Undefined(),
    420       Type::Null(),          Type::Boolean(),       Type::Number(),
    421       Type::String()};
    422 
    423   for (size_t i = 0; i < arraysize(types); ++i) {
    424     Node* p0 = R.Parameter(types[i], 0);
    425 
    426     for (size_t j = 0; j < arraysize(types); ++j) {
    427       Node* p1 = R.Parameter(types[j], 1);
    428 
    429       for (int k = 0; k < R.kNumberOps; k += 2) {
    430         Node* add = R.Binop(R.ops[k], p0, p1);
    431         Node* r = R.reduce(add);
    432 
    433         R.CheckBinop(R.ops[k + 1], r);
    434 
    435         CheckToI32(p0, r->InputAt(0), R.signedness[k]);
    436         CheckToI32(p1, r->InputAt(1), R.signedness[k + 1]);
    437       }
    438     }
    439   }
    440 }
    441 
    442 
    443 TEST(JSToNumber1) {
    444   JSTypedLoweringTester R;
    445   const Operator* ton = R.javascript.ToNumber();
    446 
    447   for (size_t i = 0; i < arraysize(kNumberTypes); i++) {  // ToNumber(number)
    448     Node* r = R.ReduceUnop(ton, kNumberTypes[i]);
    449     CHECK_EQ(IrOpcode::kParameter, r->opcode());
    450   }
    451 
    452   {  // ToNumber(undefined)
    453     Node* r = R.ReduceUnop(ton, Type::Undefined());
    454     R.CheckNaN(r);
    455   }
    456 
    457   {  // ToNumber(null)
    458     Node* r = R.ReduceUnop(ton, Type::Null());
    459     R.CheckNumberConstant(0.0, r);
    460   }
    461 }
    462 
    463 
    464 TEST(JSToNumber_replacement) {
    465   JSTypedLoweringTester R;
    466 
    467   Type* types[] = {Type::Null(), Type::Undefined(), Type::Number()};
    468 
    469   for (size_t i = 0; i < arraysize(types); i++) {
    470     Node* n = R.Parameter(types[i]);
    471     Node* c =
    472         R.graph.NewNode(R.javascript.ToNumber(), n, R.context(),
    473                         R.EmptyFrameState(R.context()), R.start(), R.start());
    474     Node* effect_use = R.UseForEffect(c);
    475     Node* add = R.graph.NewNode(R.simplified.ReferenceEqual(Type::Any()), n, c);
    476 
    477     R.CheckEffectInput(c, effect_use);
    478     Node* r = R.reduce(c);
    479 
    480     if (types[i]->Is(Type::Number())) {
    481       CHECK_EQ(n, r);
    482     } else {
    483       CHECK_EQ(IrOpcode::kNumberConstant, r->opcode());
    484     }
    485 
    486     CHECK_EQ(n, add->InputAt(0));
    487     CHECK_EQ(r, add->InputAt(1));
    488     R.CheckEffectInput(R.start(), effect_use);
    489   }
    490 }
    491 
    492 
    493 TEST(JSToNumberOfConstant) {
    494   JSTypedLoweringTester R;
    495 
    496   const Operator* ops[] = {
    497       R.common.NumberConstant(0), R.common.NumberConstant(-1),
    498       R.common.NumberConstant(0.1), R.common.Int32Constant(1177),
    499       R.common.Float64Constant(0.99)};
    500 
    501   for (size_t i = 0; i < arraysize(ops); i++) {
    502     Node* n = R.graph.NewNode(ops[i]);
    503     Node* convert = R.Unop(R.javascript.ToNumber(), n);
    504     Node* r = R.reduce(convert);
    505     // Note that either outcome below is correct. It only depends on whether
    506     // the types of constants are eagerly computed or only computed by the
    507     // typing pass.
    508     if (NodeProperties::GetType(n)->Is(Type::Number())) {
    509       // If number constants are eagerly typed, then reduction should
    510       // remove the ToNumber.
    511       CHECK_EQ(n, r);
    512     } else {
    513       // Otherwise, type-based lowering should only look at the type, and
    514       // *not* try to constant fold.
    515       CHECK_EQ(convert, r);
    516     }
    517   }
    518 }
    519 
    520 
    521 TEST(JSToNumberOfNumberOrOtherPrimitive) {
    522   JSTypedLoweringTester R;
    523   Type* others[] = {Type::Undefined(), Type::Null(), Type::Boolean(),
    524                     Type::String()};
    525 
    526   for (size_t i = 0; i < arraysize(others); i++) {
    527     Type* t = Type::Union(Type::Number(), others[i], R.main_zone());
    528     Node* r = R.ReduceUnop(R.javascript.ToNumber(), t);
    529     CHECK_EQ(IrOpcode::kJSToNumber, r->opcode());
    530   }
    531 }
    532 
    533 
    534 TEST(JSToString1) {
    535   JSTypedLoweringTester R;
    536 
    537   for (size_t i = 0; i < arraysize(kStringTypes); i++) {
    538     Node* r = R.ReduceUnop(R.javascript.ToString(), kStringTypes[i]);
    539     CHECK_EQ(IrOpcode::kParameter, r->opcode());
    540   }
    541 
    542   const Operator* op = R.javascript.ToString();
    543 
    544   {  // ToString(undefined) => "undefined"
    545     Node* r = R.ReduceUnop(op, Type::Undefined());
    546     R.CheckHandle(R.isolate->factory()->undefined_string(), r);
    547   }
    548 
    549   {  // ToString(null) => "null"
    550     Node* r = R.ReduceUnop(op, Type::Null());
    551     R.CheckHandle(R.isolate->factory()->null_string(), r);
    552   }
    553 
    554   {  // ToString(boolean)
    555     Node* r = R.ReduceUnop(op, Type::Boolean());
    556     CHECK_EQ(IrOpcode::kSelect, r->opcode());
    557   }
    558 
    559   {  // ToString(number)
    560     Node* r = R.ReduceUnop(op, Type::Number());
    561     // TODO(titzer): could remove effects
    562     CHECK_EQ(IrOpcode::kJSToString, r->opcode());
    563   }
    564 
    565   {  // ToString(string)
    566     Node* r = R.ReduceUnop(op, Type::String());
    567     CHECK_EQ(IrOpcode::kParameter, r->opcode());  // No-op
    568   }
    569 
    570   {  // ToString(object)
    571     Node* r = R.ReduceUnop(op, Type::Object());
    572     CHECK_EQ(IrOpcode::kJSToString, r->opcode());  // No reduction.
    573   }
    574 }
    575 
    576 
    577 TEST(JSToString_replacement) {
    578   JSTypedLoweringTester R;
    579 
    580   Type* types[] = {Type::Null(), Type::Undefined(), Type::String()};
    581 
    582   for (size_t i = 0; i < arraysize(types); i++) {
    583     Node* n = R.Parameter(types[i]);
    584     Node* c =
    585         R.graph.NewNode(R.javascript.ToString(), n, R.context(),
    586                         R.EmptyFrameState(R.context()), R.start(), R.start());
    587     Node* effect_use = R.UseForEffect(c);
    588     Node* add = R.graph.NewNode(R.simplified.ReferenceEqual(Type::Any()), n, c);
    589 
    590     R.CheckEffectInput(c, effect_use);
    591     Node* r = R.reduce(c);
    592 
    593     if (types[i]->Is(Type::String())) {
    594       CHECK_EQ(n, r);
    595     } else {
    596       CHECK_EQ(IrOpcode::kHeapConstant, r->opcode());
    597     }
    598 
    599     CHECK_EQ(n, add->InputAt(0));
    600     CHECK_EQ(r, add->InputAt(1));
    601     R.CheckEffectInput(R.start(), effect_use);
    602   }
    603 }
    604 
    605 
    606 TEST_WITH_STRONG(StringComparison) {
    607   JSTypedLoweringTester R;
    608 
    609   const Operator* ops[] = {
    610       R.javascript.LessThan(language_mode), R.simplified.StringLessThan(),
    611       R.javascript.LessThanOrEqual(language_mode),
    612       R.simplified.StringLessThanOrEqual(),
    613       R.javascript.GreaterThan(language_mode), R.simplified.StringLessThan(),
    614       R.javascript.GreaterThanOrEqual(language_mode),
    615       R.simplified.StringLessThanOrEqual()};
    616 
    617   for (size_t i = 0; i < arraysize(kStringTypes); i++) {
    618     Node* p0 = R.Parameter(kStringTypes[i], 0);
    619     for (size_t j = 0; j < arraysize(kStringTypes); j++) {
    620       Node* p1 = R.Parameter(kStringTypes[j], 1);
    621 
    622       for (size_t k = 0; k < arraysize(ops); k += 2) {
    623         Node* cmp = R.Binop(ops[k], p0, p1);
    624         Node* r = R.reduce(cmp);
    625 
    626         R.CheckBinop(ops[k + 1], r);
    627         if (k >= 4) {
    628           // GreaterThan and GreaterThanOrEqual commute the inputs
    629           // and use the LessThan and LessThanOrEqual operators.
    630           CHECK_EQ(p1, r->InputAt(0));
    631           CHECK_EQ(p0, r->InputAt(1));
    632         } else {
    633           CHECK_EQ(p0, r->InputAt(0));
    634           CHECK_EQ(p1, r->InputAt(1));
    635         }
    636       }
    637     }
    638   }
    639 }
    640 
    641 
    642 static void CheckIsConvertedToNumber(Node* val, Node* converted) {
    643   if (NodeProperties::GetType(val)->Is(Type::Number())) {
    644     CHECK_EQ(val, converted);
    645   } else if (NodeProperties::GetType(val)->Is(Type::Boolean())) {
    646     CHECK_EQ(IrOpcode::kBooleanToNumber, converted->opcode());
    647     CHECK_EQ(val, converted->InputAt(0));
    648   } else {
    649     if (converted->opcode() == IrOpcode::kNumberConstant) return;
    650     CHECK_EQ(IrOpcode::kJSToNumber, converted->opcode());
    651     CHECK_EQ(val, converted->InputAt(0));
    652   }
    653 }
    654 
    655 
    656 TEST_WITH_STRONG(NumberComparison) {
    657   JSTypedLoweringTester R;
    658 
    659   const Operator* ops[] = {
    660       R.javascript.LessThan(language_mode), R.simplified.NumberLessThan(),
    661       R.javascript.LessThanOrEqual(language_mode),
    662       R.simplified.NumberLessThanOrEqual(),
    663       R.javascript.GreaterThan(language_mode), R.simplified.NumberLessThan(),
    664       R.javascript.GreaterThanOrEqual(language_mode),
    665       R.simplified.NumberLessThanOrEqual()};
    666 
    667   Node* const p0 = R.Parameter(Type::Number(), 0);
    668   Node* const p1 = R.Parameter(Type::Number(), 1);
    669 
    670   for (size_t k = 0; k < arraysize(ops); k += 2) {
    671     Node* cmp = R.Binop(ops[k], p0, p1);
    672     Node* r = R.reduce(cmp);
    673 
    674     R.CheckBinop(ops[k + 1], r);
    675     if (k >= 4) {
    676       // GreaterThan and GreaterThanOrEqual commute the inputs
    677       // and use the LessThan and LessThanOrEqual operators.
    678       CheckIsConvertedToNumber(p1, r->InputAt(0));
    679       CheckIsConvertedToNumber(p0, r->InputAt(1));
    680     } else {
    681       CheckIsConvertedToNumber(p0, r->InputAt(0));
    682       CheckIsConvertedToNumber(p1, r->InputAt(1));
    683     }
    684   }
    685 }
    686 
    687 
    688 TEST_WITH_STRONG(MixedComparison1) {
    689   JSTypedLoweringTester R;
    690 
    691   Type* types[] = {Type::Number(), Type::String(),
    692                    Type::Union(Type::Number(), Type::String(), R.main_zone())};
    693 
    694   for (size_t i = 0; i < arraysize(types); i++) {
    695     Node* p0 = R.Parameter(types[i], 0);
    696 
    697     for (size_t j = 0; j < arraysize(types); j++) {
    698       Node* p1 = R.Parameter(types[j], 1);
    699       {
    700         const Operator* less_than = R.javascript.LessThan(language_mode);
    701         Node* cmp = R.Binop(less_than, p0, p1);
    702         Node* r = R.reduce(cmp);
    703         if (types[i]->Is(Type::String()) && types[j]->Is(Type::String())) {
    704           R.CheckBinop(R.simplified.StringLessThan(), r);
    705         } else if ((types[i]->Is(Type::Number()) &&
    706                     types[j]->Is(Type::Number())) ||
    707                    (!is_strong(language_mode) &&
    708                     (!types[i]->Maybe(Type::String()) ||
    709                      !types[j]->Maybe(Type::String())))) {
    710           R.CheckBinop(R.simplified.NumberLessThan(), r);
    711         } else {
    712           // No reduction of mixed types.
    713           CHECK_EQ(r->op(), less_than);
    714         }
    715       }
    716     }
    717   }
    718 }
    719 
    720 
    721 TEST_WITH_STRONG(RemoveToNumberEffects) {
    722   JSTypedLoweringTester R;
    723 
    724   Node* effect_use = NULL;
    725   for (int i = 0; i < 10; i++) {
    726     Node* p0 = R.Parameter(Type::Number());
    727     Node* ton = R.Unop(R.javascript.ToNumber(), p0);
    728     Node* frame_state = R.EmptyFrameState(R.context());
    729     effect_use = NULL;
    730 
    731     switch (i) {
    732       case 0:
    733         CHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(
    734                         R.javascript.ToNumber()));
    735         effect_use = R.graph.NewNode(R.javascript.ToNumber(), p0, R.context(),
    736                                      frame_state, ton, R.start());
    737         break;
    738       case 1:
    739         CHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(
    740                         R.javascript.ToNumber()));
    741         effect_use = R.graph.NewNode(R.javascript.ToNumber(), ton, R.context(),
    742                                      frame_state, ton, R.start());
    743         break;
    744       case 2:
    745         effect_use = R.graph.NewNode(R.common.EffectPhi(1), ton, R.start());
    746       case 3:
    747         effect_use = R.graph.NewNode(R.javascript.Add(language_mode, R.hints),
    748                                      ton, ton, R.context(), frame_state,
    749                                      frame_state, ton, R.start());
    750         break;
    751       case 4:
    752         effect_use = R.graph.NewNode(R.javascript.Add(language_mode, R.hints),
    753                                      p0, p0, R.context(), frame_state,
    754                                      frame_state, ton, R.start());
    755         break;
    756       case 5:
    757         effect_use = R.graph.NewNode(R.common.Return(), p0, ton, R.start());
    758         break;
    759       case 6:
    760         effect_use = R.graph.NewNode(R.common.Return(), ton, ton, R.start());
    761     }
    762 
    763     R.CheckEffectInput(R.start(), ton);
    764     if (effect_use != NULL) R.CheckEffectInput(ton, effect_use);
    765 
    766     Node* r = R.reduce(ton);
    767     CHECK_EQ(p0, r);
    768     CHECK_NE(R.start(), r);
    769 
    770     if (effect_use != NULL) {
    771       R.CheckEffectInput(R.start(), effect_use);
    772       // Check that value uses of ToNumber() do not go to start().
    773       for (int i = 0; i < effect_use->op()->ValueInputCount(); i++) {
    774         CHECK_NE(R.start(), effect_use->InputAt(i));
    775       }
    776     }
    777   }
    778 
    779   CHECK(!effect_use);  // should have done all cases above.
    780 }
    781 
    782 
    783 // Helper class for testing the reduction of a single binop.
    784 class BinopEffectsTester {
    785  public:
    786   explicit BinopEffectsTester(const Operator* op, Type* t0, Type* t1)
    787       : R(),
    788         p0(R.Parameter(t0, 0)),
    789         p1(R.Parameter(t1, 1)),
    790         binop(R.Binop(op, p0, p1)),
    791         effect_use(R.graph.NewNode(R.common.EffectPhi(1), binop, R.start())) {
    792     // Effects should be ordered start -> binop -> effect_use
    793     R.CheckEffectInput(R.start(), binop);
    794     R.CheckEffectInput(binop, effect_use);
    795     result = R.reduce(binop);
    796   }
    797 
    798   JSTypedLoweringTester R;
    799   Node* p0;
    800   Node* p1;
    801   Node* binop;
    802   Node* effect_use;
    803   Node* result;
    804 
    805   void CheckEffectsRemoved() { R.CheckEffectInput(R.start(), effect_use); }
    806 
    807   void CheckEffectOrdering(Node* n0) {
    808     R.CheckEffectInput(R.start(), n0);
    809     R.CheckEffectInput(n0, effect_use);
    810   }
    811 
    812   void CheckEffectOrdering(Node* n0, Node* n1) {
    813     R.CheckEffectInput(R.start(), n0);
    814     R.CheckEffectInput(n0, n1);
    815     R.CheckEffectInput(n1, effect_use);
    816   }
    817 
    818   Node* CheckConvertedInput(IrOpcode::Value opcode, int which, bool effects) {
    819     return CheckConverted(opcode, result->InputAt(which), effects);
    820   }
    821 
    822   Node* CheckConverted(IrOpcode::Value opcode, Node* node, bool effects) {
    823     CHECK_EQ(opcode, node->opcode());
    824     if (effects) {
    825       CHECK_LT(0, node->op()->EffectInputCount());
    826     } else {
    827       CHECK_EQ(0, node->op()->EffectInputCount());
    828     }
    829     return node;
    830   }
    831 
    832   Node* CheckNoOp(int which) {
    833     CHECK_EQ(which == 0 ? p0 : p1, result->InputAt(which));
    834     return result->InputAt(which);
    835   }
    836 };
    837 
    838 
    839 // Helper function for strict and non-strict equality reductions.
    840 void CheckEqualityReduction(JSTypedLoweringTester* R, bool strict, Node* l,
    841                             Node* r, IrOpcode::Value expected) {
    842   for (int j = 0; j < 2; j++) {
    843     Node* p0 = j == 0 ? l : r;
    844     Node* p1 = j == 1 ? l : r;
    845 
    846     {
    847       const Operator* op =
    848           strict ? R->javascript.StrictEqual() : R->javascript.Equal();
    849       Node* eq = R->Binop(op, p0, p1);
    850       Node* r = R->reduce(eq);
    851       R->CheckBinop(expected, r);
    852     }
    853 
    854     {
    855       const Operator* op =
    856           strict ? R->javascript.StrictNotEqual() : R->javascript.NotEqual();
    857       Node* ne = R->Binop(op, p0, p1);
    858       Node* n = R->reduce(ne);
    859       CHECK_EQ(IrOpcode::kBooleanNot, n->opcode());
    860       Node* r = n->InputAt(0);
    861       R->CheckBinop(expected, r);
    862     }
    863   }
    864 }
    865 
    866 
    867 TEST(EqualityForNumbers) {
    868   JSTypedLoweringTester R;
    869 
    870   Type* simple_number_types[] = {Type::UnsignedSmall(), Type::SignedSmall(),
    871                                  Type::Signed32(), Type::Unsigned32(),
    872                                  Type::Number()};
    873 
    874 
    875   for (size_t i = 0; i < arraysize(simple_number_types); ++i) {
    876     Node* p0 = R.Parameter(simple_number_types[i], 0);
    877 
    878     for (size_t j = 0; j < arraysize(simple_number_types); ++j) {
    879       Node* p1 = R.Parameter(simple_number_types[j], 1);
    880 
    881       CheckEqualityReduction(&R, true, p0, p1, IrOpcode::kNumberEqual);
    882       CheckEqualityReduction(&R, false, p0, p1, IrOpcode::kNumberEqual);
    883     }
    884   }
    885 }
    886 
    887 
    888 TEST(StrictEqualityForRefEqualTypes) {
    889   JSTypedLoweringTester R;
    890 
    891   Type* types[] = {Type::Undefined(), Type::Null(), Type::Boolean(),
    892                    Type::Object(), Type::Receiver()};
    893 
    894   Node* p0 = R.Parameter(Type::Any());
    895   for (size_t i = 0; i < arraysize(types); i++) {
    896     Node* p1 = R.Parameter(types[i]);
    897     CheckEqualityReduction(&R, true, p0, p1, IrOpcode::kReferenceEqual);
    898   }
    899   // TODO(titzer): Equal(RefEqualTypes)
    900 }
    901 
    902 
    903 TEST(StringEquality) {
    904   JSTypedLoweringTester R;
    905   Node* p0 = R.Parameter(Type::String());
    906   Node* p1 = R.Parameter(Type::String());
    907 
    908   CheckEqualityReduction(&R, true, p0, p1, IrOpcode::kStringEqual);
    909   CheckEqualityReduction(&R, false, p0, p1, IrOpcode::kStringEqual);
    910 }
    911 
    912 
    913 TEST_WITH_STRONG(RemovePureNumberBinopEffects) {
    914   JSTypedLoweringTester R;
    915 
    916   const Operator* ops[] = {
    917       R.javascript.Equal(),
    918       R.simplified.NumberEqual(),
    919       R.javascript.Add(language_mode, R.hints),
    920       R.simplified.NumberAdd(),
    921       R.javascript.Subtract(language_mode, R.hints),
    922       R.simplified.NumberSubtract(),
    923       R.javascript.Multiply(language_mode, R.hints),
    924       R.simplified.NumberMultiply(),
    925       R.javascript.Divide(language_mode, R.hints),
    926       R.simplified.NumberDivide(),
    927       R.javascript.Modulus(language_mode, R.hints),
    928       R.simplified.NumberModulus(),
    929       R.javascript.LessThan(language_mode),
    930       R.simplified.NumberLessThan(),
    931       R.javascript.LessThanOrEqual(language_mode),
    932       R.simplified.NumberLessThanOrEqual(),
    933   };
    934 
    935   for (size_t j = 0; j < arraysize(ops); j += 2) {
    936     BinopEffectsTester B(ops[j], Type::Number(), Type::Number());
    937     CHECK_EQ(ops[j + 1]->opcode(), B.result->op()->opcode());
    938 
    939     B.R.CheckBinop(B.result->opcode(), B.result);
    940 
    941     B.CheckNoOp(0);
    942     B.CheckNoOp(1);
    943 
    944     B.CheckEffectsRemoved();
    945   }
    946 }
    947 
    948 
    949 TEST(OrderNumberBinopEffects1) {
    950   JSTypedLoweringTester R;
    951 
    952   const Operator* ops[] = {
    953       R.javascript.Subtract(LanguageMode::SLOPPY, R.hints),
    954       R.simplified.NumberSubtract(),
    955       R.javascript.Multiply(LanguageMode::SLOPPY, R.hints),
    956       R.simplified.NumberMultiply(),
    957       R.javascript.Divide(LanguageMode::SLOPPY, R.hints),
    958       R.simplified.NumberDivide(),
    959   };
    960 
    961   for (size_t j = 0; j < arraysize(ops); j += 2) {
    962     BinopEffectsTester B(ops[j], Type::Symbol(), Type::Symbol());
    963     CHECK_EQ(ops[j + 1]->opcode(), B.result->op()->opcode());
    964 
    965     Node* i0 = B.CheckConvertedInput(IrOpcode::kJSToNumber, 0, true);
    966     Node* i1 = B.CheckConvertedInput(IrOpcode::kJSToNumber, 1, true);
    967 
    968     CHECK_EQ(B.p0, i0->InputAt(0));
    969     CHECK_EQ(B.p1, i1->InputAt(0));
    970 
    971     // Effects should be ordered start -> i0 -> i1 -> effect_use
    972     B.CheckEffectOrdering(i0, i1);
    973   }
    974 }
    975 
    976 
    977 TEST(OrderNumberBinopEffects2) {
    978   JSTypedLoweringTester R;
    979 
    980   const Operator* ops[] = {
    981       R.javascript.Add(LanguageMode::SLOPPY, R.hints),
    982       R.simplified.NumberAdd(),
    983       R.javascript.Subtract(LanguageMode::SLOPPY, R.hints),
    984       R.simplified.NumberSubtract(),
    985       R.javascript.Multiply(LanguageMode::SLOPPY, R.hints),
    986       R.simplified.NumberMultiply(),
    987       R.javascript.Divide(LanguageMode::SLOPPY, R.hints),
    988       R.simplified.NumberDivide(),
    989   };
    990 
    991   for (size_t j = 0; j < arraysize(ops); j += 2) {
    992     BinopEffectsTester B(ops[j], Type::Number(), Type::Symbol());
    993 
    994     Node* i0 = B.CheckNoOp(0);
    995     Node* i1 = B.CheckConvertedInput(IrOpcode::kJSToNumber, 1, true);
    996 
    997     CHECK_EQ(B.p0, i0);
    998     CHECK_EQ(B.p1, i1->InputAt(0));
    999 
   1000     // Effects should be ordered start -> i1 -> effect_use
   1001     B.CheckEffectOrdering(i1);
   1002   }
   1003 
   1004   for (size_t j = 0; j < arraysize(ops); j += 2) {
   1005     BinopEffectsTester B(ops[j], Type::Symbol(), Type::Number());
   1006 
   1007     Node* i0 = B.CheckConvertedInput(IrOpcode::kJSToNumber, 0, true);
   1008     Node* i1 = B.CheckNoOp(1);
   1009 
   1010     CHECK_EQ(B.p0, i0->InputAt(0));
   1011     CHECK_EQ(B.p1, i1);
   1012 
   1013     // Effects should be ordered start -> i0 -> effect_use
   1014     B.CheckEffectOrdering(i0);
   1015   }
   1016 }
   1017 
   1018 
   1019 TEST(OrderCompareEffects) {
   1020   JSTypedLoweringTester R;
   1021 
   1022   const Operator* ops[] = {
   1023       R.javascript.GreaterThan(LanguageMode::SLOPPY),
   1024       R.simplified.NumberLessThan(),
   1025       R.javascript.GreaterThanOrEqual(LanguageMode::SLOPPY),
   1026       R.simplified.NumberLessThanOrEqual(),
   1027   };
   1028 
   1029   for (size_t j = 0; j < arraysize(ops); j += 2) {
   1030     BinopEffectsTester B(ops[j], Type::Symbol(), Type::String());
   1031     CHECK_EQ(ops[j + 1]->opcode(), B.result->op()->opcode());
   1032 
   1033     Node* i0 = B.CheckConvertedInput(IrOpcode::kJSToNumber, 0, true);
   1034     Node* i1 = B.CheckConvertedInput(IrOpcode::kJSToNumber, 1, true);
   1035 
   1036     // Inputs should be commuted.
   1037     CHECK_EQ(B.p1, i0->InputAt(0));
   1038     CHECK_EQ(B.p0, i1->InputAt(0));
   1039 
   1040     // But effects should be ordered start -> i1 -> effect_use
   1041     B.CheckEffectOrdering(i1);
   1042   }
   1043 
   1044   for (size_t j = 0; j < arraysize(ops); j += 2) {
   1045     BinopEffectsTester B(ops[j], Type::Number(), Type::Symbol());
   1046 
   1047     Node* i0 = B.CheckConvertedInput(IrOpcode::kJSToNumber, 0, true);
   1048     Node* i1 = B.result->InputAt(1);
   1049 
   1050     CHECK_EQ(B.p1, i0->InputAt(0));  // Should be commuted.
   1051     CHECK_EQ(B.p0, i1);
   1052 
   1053     // Effects should be ordered start -> i1 -> effect_use
   1054     B.CheckEffectOrdering(i0);
   1055   }
   1056 
   1057   for (size_t j = 0; j < arraysize(ops); j += 2) {
   1058     BinopEffectsTester B(ops[j], Type::Symbol(), Type::Number());
   1059 
   1060     Node* i0 = B.result->InputAt(0);
   1061     Node* i1 = B.CheckConvertedInput(IrOpcode::kJSToNumber, 1, true);
   1062 
   1063     CHECK_EQ(B.p1, i0);  // Should be commuted.
   1064     CHECK_EQ(B.p0, i1->InputAt(0));
   1065 
   1066     // Effects should be ordered start -> i0 -> effect_use
   1067     B.CheckEffectOrdering(i1);
   1068   }
   1069 }
   1070 
   1071 
   1072 TEST(Int32BinopEffects) {
   1073   JSBitwiseTypedLoweringTester R(LanguageMode::SLOPPY);
   1074   for (int j = 0; j < R.kNumberOps; j += 2) {
   1075     bool signed_left = R.signedness[j], signed_right = R.signedness[j + 1];
   1076     BinopEffectsTester B(R.ops[j], I32Type(signed_left), I32Type(signed_right));
   1077     CHECK_EQ(R.ops[j + 1]->opcode(), B.result->op()->opcode());
   1078 
   1079     B.R.CheckBinop(B.result->opcode(), B.result);
   1080 
   1081     B.CheckNoOp(0);
   1082     B.CheckNoOp(1);
   1083 
   1084     B.CheckEffectsRemoved();
   1085   }
   1086 
   1087   for (int j = 0; j < R.kNumberOps; j += 2) {
   1088     bool signed_left = R.signedness[j], signed_right = R.signedness[j + 1];
   1089     BinopEffectsTester B(R.ops[j], Type::Number(), Type::Number());
   1090     CHECK_EQ(R.ops[j + 1]->opcode(), B.result->op()->opcode());
   1091 
   1092     B.R.CheckBinop(B.result->opcode(), B.result);
   1093 
   1094     B.CheckConvertedInput(NumberToI32(signed_left), 0, false);
   1095     B.CheckConvertedInput(NumberToI32(signed_right), 1, false);
   1096 
   1097     B.CheckEffectsRemoved();
   1098   }
   1099 
   1100   for (int j = 0; j < R.kNumberOps; j += 2) {
   1101     bool signed_left = R.signedness[j], signed_right = R.signedness[j + 1];
   1102     BinopEffectsTester B(R.ops[j], Type::Number(), Type::Primitive());
   1103 
   1104     B.R.CheckBinop(B.result->opcode(), B.result);
   1105 
   1106     Node* i0 = B.CheckConvertedInput(NumberToI32(signed_left), 0, false);
   1107     Node* i1 = B.CheckConvertedInput(NumberToI32(signed_right), 1, false);
   1108 
   1109     CHECK_EQ(B.p0, i0->InputAt(0));
   1110     Node* ii1 = B.CheckConverted(IrOpcode::kJSToNumber, i1->InputAt(0), true);
   1111 
   1112     CHECK_EQ(B.p1, ii1->InputAt(0));
   1113 
   1114     B.CheckEffectOrdering(ii1);
   1115   }
   1116 
   1117   for (int j = 0; j < R.kNumberOps; j += 2) {
   1118     bool signed_left = R.signedness[j], signed_right = R.signedness[j + 1];
   1119     BinopEffectsTester B(R.ops[j], Type::Primitive(), Type::Number());
   1120 
   1121     B.R.CheckBinop(B.result->opcode(), B.result);
   1122 
   1123     Node* i0 = B.CheckConvertedInput(NumberToI32(signed_left), 0, false);
   1124     Node* i1 = B.CheckConvertedInput(NumberToI32(signed_right), 1, false);
   1125 
   1126     Node* ii0 = B.CheckConverted(IrOpcode::kJSToNumber, i0->InputAt(0), true);
   1127     CHECK_EQ(B.p1, i1->InputAt(0));
   1128 
   1129     CHECK_EQ(B.p0, ii0->InputAt(0));
   1130 
   1131     B.CheckEffectOrdering(ii0);
   1132   }
   1133 
   1134   for (int j = 0; j < R.kNumberOps; j += 2) {
   1135     bool signed_left = R.signedness[j], signed_right = R.signedness[j + 1];
   1136     BinopEffectsTester B(R.ops[j], Type::Primitive(), Type::Primitive());
   1137 
   1138     B.R.CheckBinop(B.result->opcode(), B.result);
   1139 
   1140     Node* i0 = B.CheckConvertedInput(NumberToI32(signed_left), 0, false);
   1141     Node* i1 = B.CheckConvertedInput(NumberToI32(signed_right), 1, false);
   1142 
   1143     Node* ii0 = B.CheckConverted(IrOpcode::kJSToNumber, i0->InputAt(0), true);
   1144     Node* ii1 = B.CheckConverted(IrOpcode::kJSToNumber, i1->InputAt(0), true);
   1145 
   1146     CHECK_EQ(B.p0, ii0->InputAt(0));
   1147     CHECK_EQ(B.p1, ii1->InputAt(0));
   1148 
   1149     B.CheckEffectOrdering(ii0, ii1);
   1150   }
   1151 }
   1152 
   1153 
   1154 TEST_WITH_STRONG(Int32AddNarrowing) {
   1155   {
   1156     JSBitwiseTypedLoweringTester R(language_mode);
   1157 
   1158     for (int o = 0; o < R.kNumberOps; o += 2) {
   1159       for (size_t i = 0; i < arraysize(kInt32Types); i++) {
   1160         Node* n0 = R.Parameter(kInt32Types[i]);
   1161         for (size_t j = 0; j < arraysize(kInt32Types); j++) {
   1162           Node* n1 = R.Parameter(kInt32Types[j]);
   1163           Node* one = R.graph.NewNode(R.common.NumberConstant(1));
   1164 
   1165           for (int l = 0; l < 2; l++) {
   1166             Node* add_node = R.Binop(R.simplified.NumberAdd(), n0, n1);
   1167             Node* or_node =
   1168                 R.Binop(R.ops[o], l ? add_node : one, l ? one : add_node);
   1169             Node* r = R.reduce(or_node);
   1170 
   1171             CHECK_EQ(R.ops[o + 1]->opcode(), r->op()->opcode());
   1172             CHECK_EQ(IrOpcode::kNumberAdd, add_node->opcode());
   1173           }
   1174         }
   1175       }
   1176     }
   1177   }
   1178   {
   1179     JSBitwiseShiftTypedLoweringTester R(language_mode);
   1180 
   1181     for (int o = 0; o < R.kNumberOps; o += 2) {
   1182       for (size_t i = 0; i < arraysize(kInt32Types); i++) {
   1183         Node* n0 = R.Parameter(kInt32Types[i]);
   1184         for (size_t j = 0; j < arraysize(kInt32Types); j++) {
   1185           Node* n1 = R.Parameter(kInt32Types[j]);
   1186           Node* one = R.graph.NewNode(R.common.NumberConstant(1));
   1187 
   1188           for (int l = 0; l < 2; l++) {
   1189             Node* add_node = R.Binop(R.simplified.NumberAdd(), n0, n1);
   1190             Node* or_node =
   1191                 R.Binop(R.ops[o], l ? add_node : one, l ? one : add_node);
   1192             Node* r = R.reduce(or_node);
   1193 
   1194             CHECK_EQ(R.ops[o + 1]->opcode(), r->op()->opcode());
   1195             CHECK_EQ(IrOpcode::kNumberAdd, add_node->opcode());
   1196           }
   1197         }
   1198       }
   1199     }
   1200   }
   1201   {
   1202     JSBitwiseTypedLoweringTester R(language_mode);
   1203 
   1204     for (int o = 0; o < R.kNumberOps; o += 2) {
   1205       Node* n0 = R.Parameter(I32Type(R.signedness[o]));
   1206       Node* n1 = R.Parameter(I32Type(R.signedness[o + 1]));
   1207       Node* one = R.graph.NewNode(R.common.NumberConstant(1));
   1208 
   1209       Node* add_node = R.Binop(R.simplified.NumberAdd(), n0, n1);
   1210       Node* or_node = R.Binop(R.ops[o], add_node, one);
   1211       Node* other_use = R.Binop(R.simplified.NumberAdd(), add_node, one);
   1212       Node* r = R.reduce(or_node);
   1213       CHECK_EQ(R.ops[o + 1]->opcode(), r->op()->opcode());
   1214       CHECK_EQ(IrOpcode::kNumberAdd, add_node->opcode());
   1215       // Conversion to int32 should be done.
   1216       CheckToI32(add_node, r->InputAt(0), R.signedness[o]);
   1217       CheckToI32(one, r->InputAt(1), R.signedness[o + 1]);
   1218       // The other use should also not be touched.
   1219       CHECK_EQ(add_node, other_use->InputAt(0));
   1220       CHECK_EQ(one, other_use->InputAt(1));
   1221     }
   1222   }
   1223 }
   1224 
   1225 
   1226 TEST_WITH_STRONG(Int32Comparisons) {
   1227   JSTypedLoweringTester R;
   1228 
   1229   struct Entry {
   1230     const Operator* js_op;
   1231     const Operator* uint_op;
   1232     const Operator* int_op;
   1233     const Operator* num_op;
   1234     bool commute;
   1235   };
   1236 
   1237   Entry ops[] = {
   1238       {R.javascript.LessThan(language_mode), R.machine.Uint32LessThan(),
   1239        R.machine.Int32LessThan(), R.simplified.NumberLessThan(), false},
   1240       {R.javascript.LessThanOrEqual(language_mode),
   1241        R.machine.Uint32LessThanOrEqual(), R.machine.Int32LessThanOrEqual(),
   1242        R.simplified.NumberLessThanOrEqual(), false},
   1243       {R.javascript.GreaterThan(language_mode), R.machine.Uint32LessThan(),
   1244        R.machine.Int32LessThan(), R.simplified.NumberLessThan(), true},
   1245       {R.javascript.GreaterThanOrEqual(language_mode),
   1246        R.machine.Uint32LessThanOrEqual(), R.machine.Int32LessThanOrEqual(),
   1247        R.simplified.NumberLessThanOrEqual(), true}
   1248   };
   1249 
   1250   for (size_t o = 0; o < arraysize(ops); o++) {
   1251     for (size_t i = 0; i < arraysize(kNumberTypes); i++) {
   1252       Type* t0 = kNumberTypes[i];
   1253       Node* p0 = R.Parameter(t0, 0);
   1254 
   1255       for (size_t j = 0; j < arraysize(kNumberTypes); j++) {
   1256         Type* t1 = kNumberTypes[j];
   1257         Node* p1 = R.Parameter(t1, 1);
   1258 
   1259         Node* cmp = R.Binop(ops[o].js_op, p0, p1);
   1260         Node* r = R.reduce(cmp);
   1261 
   1262         const Operator* expected;
   1263         if (t0->Is(Type::Unsigned32()) && t1->Is(Type::Unsigned32())) {
   1264           expected = ops[o].uint_op;
   1265         } else if (t0->Is(Type::Signed32()) && t1->Is(Type::Signed32())) {
   1266           expected = ops[o].int_op;
   1267         } else {
   1268           expected = ops[o].num_op;
   1269         }
   1270         R.CheckBinop(expected, r);
   1271         if (ops[o].commute) {
   1272           CHECK_EQ(p1, r->InputAt(0));
   1273           CHECK_EQ(p0, r->InputAt(1));
   1274         } else {
   1275           CHECK_EQ(p0, r->InputAt(0));
   1276           CHECK_EQ(p1, r->InputAt(1));
   1277         }
   1278       }
   1279     }
   1280   }
   1281 }
   1282 
   1283 }  // namespace compiler
   1284 }  // namespace internal
   1285 }  // namespace v8
   1286