Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(16)

Side by Side Diff: test/cctest/compiler/test-js-typed-lowering.cc

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

Powered by Google App Engine
This is Rietveld 408576698