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