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