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