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