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

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

Powered by Google App Engine
This is Rietveld 408576698