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:
JSTypedLoweringTester(int num_parameters=0)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 
Parameter(Type * t,int32_t index=0)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 
UndefinedConstant()51   Node* UndefinedConstant() {
52     Unique<Object> unique =
53         Unique<Object>::CreateImmovable(isolate->factory()->undefined_value());
54     return graph.NewNode(common.HeapConstant(unique));
55   }
56 
HeapConstant(Handle<Object> constant)57   Node* HeapConstant(Handle<Object> constant) {
58     Unique<Object> unique = Unique<Object>::CreateUninitialized(constant);
59     return graph.NewNode(common.HeapConstant(unique));
60   }
61 
EmptyFrameState(Node * context)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 
reduce(Node * node)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 
start()82   Node* start() { return graph.start(); }
83 
context()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 
control()91   Node* control() { return start(); }
92 
CheckPureBinop(IrOpcode::Value expected,Node * node)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 
CheckPureBinop(const Operator * expected,Node * node)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 
ReduceUnop(const Operator * op,Type * input_type)103   Node* ReduceUnop(const Operator* op, Type* input_type) {
104     return reduce(Unop(op, Parameter(input_type)));
105   }
106 
ReduceBinop(const Operator * op,Type * left_type,Type * right_type)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 
Binop(const Operator * op,Node * left,Node * right)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 
Unop(const Operator * op,Node * input)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 
UseForEffect(Node * node)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 
CheckEffectInput(Node * effect,Node * use)127   void CheckEffectInput(Node* effect, Node* use) {
128     CHECK_EQ(effect, NodeProperties::GetEffectInput(use));
129   }
130 
CheckInt32Constant(int32_t expected,Node * result)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 
CheckNumberConstant(double expected,Node * result)136   void CheckNumberConstant(double expected, Node* result) {
137     CHECK_EQ(IrOpcode::kNumberConstant, result->opcode());
138     CHECK_EQ(expected, OpParameter<double>(result));
139   }
140 
CheckNaN(Node * result)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 
CheckTrue(Node * result)147   void CheckTrue(Node* result) {
148     CheckHandle(isolate->factory()->true_value(), result);
149   }
150 
CheckFalse(Node * result)151   void CheckFalse(Node* result) {
152     CheckHandle(isolate->factory()->false_value(), result);
153   }
154 
CheckHandle(Handle<Object> expected,Node * result)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 
162 static Type* kStringTypes[] = {Type::InternalizedString(), Type::OtherString(),
163                                Type::String()};
164 
165 
166 static 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 
172 static 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 
180 static Type* kJSTypes[] = {Type::Undefined(), Type::Null(),   Type::Boolean(),
181                            Type::Number(),    Type::String(), Type::Object()};
182 
183 
I32Type(bool is_signed)184 static Type* I32Type(bool is_signed) {
185   return is_signed ? Type::Signed32() : Type::Unsigned32();
186 }
187 
188 
NumberToI32(bool is_signed)189 static 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
196 TEST(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 
TEST(AddNumber1)217 TEST(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 
TEST(NumberBinops)232 TEST(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 
CheckToI32(Node * old_input,Node * new_input,bool is_signed)261 static 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.
278 class JSBitwiseShiftTypedLoweringTester : public JSTypedLoweringTester {
279  public:
280   static const int kNumberOps = 6;
281   const Operator* ops[kNumberOps];
282   bool signedness[kNumberOps];
283 
JSBitwiseShiftTypedLoweringTester()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:
set(int idx,const Operator * op,bool s)295   void set(int idx, const Operator* op, bool s) {
296     ops[idx] = op;
297     signedness[idx] = s;
298   }
299 };
300 
301 
TEST(Int32BitwiseShifts)302 TEST(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.
338 class JSBitwiseTypedLoweringTester : public JSTypedLoweringTester {
339  public:
340   static const int kNumberOps = 6;
341   const Operator* ops[kNumberOps];
342   bool signedness[kNumberOps];
343 
JSBitwiseTypedLoweringTester()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:
set(int idx,const Operator * op,bool s)355   void set(int idx, const Operator* op, bool s) {
356     ops[idx] = op;
357     signedness[idx] = s;
358   }
359 };
360 
361 
TEST(Int32BitwiseBinops)362 TEST(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 
TEST(JSToNumber1)392 TEST(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 
TEST(JSToNumber_replacement)413 TEST(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 
TEST(JSToNumberOfConstant)441 TEST(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 
TEST(JSToNumberOfNumberOrOtherPrimitive)469 TEST(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 
TEST(JSToBoolean)482 TEST(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 
TEST(JSToBoolean_replacement)532 TEST(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 
TEST(JSToString1)564 TEST(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 
TEST(JSToString_replacement)608 TEST(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 
TEST(StringComparison)636 TEST(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 
CheckIsConvertedToNumber(Node * val,Node * converted)670 static 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 
TEST(NumberComparison)684 TEST(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 
TEST(MixedComparison1)725 TEST(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 
TEST(ObjectComparison)756 TEST(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 
TEST(UnaryNot)786 TEST(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 
TEST(RemoveToNumberEffects)807 TEST(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.
866 class BinopEffectsTester {
867  public:
BinopEffectsTester(const Operator * op,Type * t0,Type * t1)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 
CheckEffectsRemoved()887   void CheckEffectsRemoved() { R.CheckEffectInput(R.start(), effect_use); }
888 
CheckEffectOrdering(Node * n0)889   void CheckEffectOrdering(Node* n0) {
890     R.CheckEffectInput(R.start(), n0);
891     R.CheckEffectInput(n0, effect_use);
892   }
893 
CheckEffectOrdering(Node * n0,Node * n1)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 
CheckConvertedInput(IrOpcode::Value opcode,int which,bool effects)900   Node* CheckConvertedInput(IrOpcode::Value opcode, int which, bool effects) {
901     return CheckConverted(opcode, result->InputAt(which), effects);
902   }
903 
CheckConverted(IrOpcode::Value opcode,Node * node,bool effects)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 
CheckNoOp(int which)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.
CheckEqualityReduction(JSTypedLoweringTester * R,bool strict,Node * l,Node * r,IrOpcode::Value expected)922 void 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 
TEST(EqualityForNumbers)948 TEST(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 
TEST(StrictEqualityForRefEqualTypes)969 TEST(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 
TEST(StringEquality)984 TEST(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 
TEST(RemovePureNumberBinopEffects)994 TEST(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 
TEST(OrderNumberBinopEffects1)1022 TEST(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 
TEST(OrderNumberBinopEffects2)1048 TEST(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 
TEST(OrderCompareEffects)1087 TEST(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 
TEST(Int32BinopEffects)1138 TEST(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 
TEST(UnaryNotEffects)1221 TEST(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 
TEST(Int32AddNarrowing)1248 TEST(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 
TEST(Int32AddNarrowingNotOwned)1306 TEST(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 
TEST(Int32Comparisons)1331 TEST(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