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