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