blob: 648e1b923aa50c8da42b5ceb34843359df8ae8d4 [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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 "test/cctest/cctest.h"
6
7#include "src/base/utils/random-number-generator.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008#include "src/codegen.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009#include "src/compiler/graph-inl.h"
10#include "src/compiler/js-graph.h"
11#include "src/compiler/machine-operator-reducer.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012#include "src/compiler/operator-properties.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013#include "src/compiler/typer.h"
14#include "test/cctest/compiler/value-helper.h"
15
16using namespace v8::internal;
17using namespace v8::internal::compiler;
18
19template <typename T>
20const Operator* NewConstantOperator(CommonOperatorBuilder* common,
21 volatile T value);
22
23template <>
24const Operator* NewConstantOperator<int32_t>(CommonOperatorBuilder* common,
25 volatile int32_t value) {
26 return common->Int32Constant(value);
27}
28
29template <>
30const Operator* NewConstantOperator<double>(CommonOperatorBuilder* common,
31 volatile double value) {
32 return common->Float64Constant(value);
33}
34
35
36template <typename T>
37T ValueOfOperator(const Operator* op);
38
39template <>
40int32_t ValueOfOperator<int32_t>(const Operator* op) {
41 CHECK_EQ(IrOpcode::kInt32Constant, op->opcode());
42 return OpParameter<int32_t>(op);
43}
44
45template <>
46double ValueOfOperator<double>(const Operator* op) {
47 CHECK_EQ(IrOpcode::kFloat64Constant, op->opcode());
48 return OpParameter<double>(op);
49}
50
51
52class ReducerTester : public HandleAndZoneScope {
53 public:
Emily Bernierd0a1eb72015-03-24 16:35:39 -040054 explicit ReducerTester(
55 int num_parameters = 0,
56 MachineOperatorBuilder::Flags flags = MachineOperatorBuilder::kNoFlags)
Ben Murdochb8a8cc12014-11-26 15:28:44 +000057 : isolate(main_isolate()),
58 binop(NULL),
59 unop(NULL),
Emily Bernierd0a1eb72015-03-24 16:35:39 -040060 machine(main_zone(), kMachPtr, flags),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000061 common(main_zone()),
62 graph(main_zone()),
63 javascript(main_zone()),
Emily Bernierd0a1eb72015-03-24 16:35:39 -040064 typer(&graph, MaybeHandle<Context>()),
65 jsgraph(&graph, &common, &javascript, &machine),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000066 maxuint32(Constant<int32_t>(kMaxUInt32)) {
67 Node* s = graph.NewNode(common.Start(num_parameters));
68 graph.SetStart(s);
69 }
70
71 Isolate* isolate;
72 const Operator* binop;
73 const Operator* unop;
74 MachineOperatorBuilder machine;
75 CommonOperatorBuilder common;
76 Graph graph;
77 JSOperatorBuilder javascript;
78 Typer typer;
79 JSGraph jsgraph;
80 Node* maxuint32;
81
82 template <typename T>
83 Node* Constant(volatile T value) {
84 return graph.NewNode(NewConstantOperator<T>(&common, value));
85 }
86
87 template <typename T>
88 const T ValueOf(const Operator* op) {
89 return ValueOfOperator<T>(op);
90 }
91
92 // Check that the reduction of this binop applied to constants {a} and {b}
93 // yields the {expect} value.
94 template <typename T>
95 void CheckFoldBinop(volatile T expect, volatile T a, volatile T b) {
96 CheckFoldBinop<T>(expect, Constant<T>(a), Constant<T>(b));
97 }
98
99 // Check that the reduction of this binop applied to {a} and {b} yields
100 // the {expect} value.
101 template <typename T>
102 void CheckFoldBinop(volatile T expect, Node* a, Node* b) {
103 CHECK_NE(NULL, binop);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400104 Node* n = CreateBinopNode(a, b);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000105 MachineOperatorReducer reducer(&jsgraph);
106 Reduction reduction = reducer.Reduce(n);
107 CHECK(reduction.Changed());
108 CHECK_NE(n, reduction.replacement());
109 CHECK_EQ(expect, ValueOf<T>(reduction.replacement()->op()));
110 }
111
112 // Check that the reduction of this binop applied to {a} and {b} yields
113 // the {expect} node.
114 void CheckBinop(Node* expect, Node* a, Node* b) {
115 CHECK_NE(NULL, binop);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400116 Node* n = CreateBinopNode(a, b);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000117 MachineOperatorReducer reducer(&jsgraph);
118 Reduction reduction = reducer.Reduce(n);
119 CHECK(reduction.Changed());
120 CHECK_EQ(expect, reduction.replacement());
121 }
122
123 // Check that the reduction of this binop applied to {left} and {right} yields
124 // this binop applied to {left_expect} and {right_expect}.
125 void CheckFoldBinop(Node* left_expect, Node* right_expect, Node* left,
126 Node* right) {
127 CHECK_NE(NULL, binop);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400128 Node* n = CreateBinopNode(left, right);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000129 MachineOperatorReducer reducer(&jsgraph);
130 Reduction reduction = reducer.Reduce(n);
131 CHECK(reduction.Changed());
132 CHECK_EQ(binop, reduction.replacement()->op());
133 CHECK_EQ(left_expect, reduction.replacement()->InputAt(0));
134 CHECK_EQ(right_expect, reduction.replacement()->InputAt(1));
135 }
136
137 // Check that the reduction of this binop applied to {left} and {right} yields
138 // the {op_expect} applied to {left_expect} and {right_expect}.
139 template <typename T>
140 void CheckFoldBinop(volatile T left_expect, const Operator* op_expect,
141 Node* right_expect, Node* left, Node* right) {
142 CHECK_NE(NULL, binop);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400143 Node* n = CreateBinopNode(left, right);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000144 MachineOperatorReducer reducer(&jsgraph);
145 Reduction r = reducer.Reduce(n);
146 CHECK(r.Changed());
147 CHECK_EQ(op_expect->opcode(), r.replacement()->op()->opcode());
148 CHECK_EQ(left_expect, ValueOf<T>(r.replacement()->InputAt(0)->op()));
149 CHECK_EQ(right_expect, r.replacement()->InputAt(1));
150 }
151
152 // Check that the reduction of this binop applied to {left} and {right} yields
153 // the {op_expect} applied to {left_expect} and {right_expect}.
154 template <typename T>
155 void CheckFoldBinop(Node* left_expect, const Operator* op_expect,
156 volatile T right_expect, Node* left, Node* right) {
157 CHECK_NE(NULL, binop);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400158 Node* n = CreateBinopNode(left, right);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000159 MachineOperatorReducer reducer(&jsgraph);
160 Reduction r = reducer.Reduce(n);
161 CHECK(r.Changed());
162 CHECK_EQ(op_expect->opcode(), r.replacement()->op()->opcode());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400163 CHECK_EQ(OperatorProperties::GetTotalInputCount(op_expect),
164 r.replacement()->InputCount());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000165 CHECK_EQ(left_expect, r.replacement()->InputAt(0));
166 CHECK_EQ(right_expect, ValueOf<T>(r.replacement()->InputAt(1)->op()));
167 }
168
169 // Check that if the given constant appears on the left, the reducer will
170 // swap it to be on the right.
171 template <typename T>
172 void CheckPutConstantOnRight(volatile T constant) {
173 // TODO(titzer): CHECK(binop->HasProperty(Operator::kCommutative));
174 Node* p = Parameter();
175 Node* k = Constant<T>(constant);
176 {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400177 Node* n = CreateBinopNode(k, p);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000178 MachineOperatorReducer reducer(&jsgraph);
179 Reduction reduction = reducer.Reduce(n);
180 CHECK(!reduction.Changed() || reduction.replacement() == n);
181 CHECK_EQ(p, n->InputAt(0));
182 CHECK_EQ(k, n->InputAt(1));
183 }
184 {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400185 Node* n = CreateBinopNode(p, k);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000186 MachineOperatorReducer reducer(&jsgraph);
187 Reduction reduction = reducer.Reduce(n);
188 CHECK(!reduction.Changed());
189 CHECK_EQ(p, n->InputAt(0));
190 CHECK_EQ(k, n->InputAt(1));
191 }
192 }
193
194 // Check that if the given constant appears on the left, the reducer will
195 // *NOT* swap it to be on the right.
196 template <typename T>
197 void CheckDontPutConstantOnRight(volatile T constant) {
198 CHECK(!binop->HasProperty(Operator::kCommutative));
199 Node* p = Parameter();
200 Node* k = Constant<T>(constant);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400201 Node* n = CreateBinopNode(k, p);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000202 MachineOperatorReducer reducer(&jsgraph);
203 Reduction reduction = reducer.Reduce(n);
204 CHECK(!reduction.Changed());
205 CHECK_EQ(k, n->InputAt(0));
206 CHECK_EQ(p, n->InputAt(1));
207 }
208
209 Node* Parameter(int32_t index = 0) {
210 return graph.NewNode(common.Parameter(index), graph.start());
211 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400212
213 private:
214 Node* CreateBinopNode(Node* left, Node* right) {
215 if (binop->ControlInputCount() > 0) {
216 return graph.NewNode(binop, left, right, graph.start());
217 } else {
218 return graph.NewNode(binop, left, right);
219 }
220 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000221};
222
223
224TEST(ReduceWord32And) {
225 ReducerTester R;
226 R.binop = R.machine.Word32And();
227
228 FOR_INT32_INPUTS(pl) {
229 FOR_INT32_INPUTS(pr) {
230 int32_t x = *pl, y = *pr;
231 R.CheckFoldBinop<int32_t>(x & y, x, y);
232 }
233 }
234
235 R.CheckPutConstantOnRight(33);
236 R.CheckPutConstantOnRight(44000);
237
238 Node* x = R.Parameter();
239 Node* zero = R.Constant<int32_t>(0);
240 Node* minus_1 = R.Constant<int32_t>(-1);
241
242 R.CheckBinop(zero, x, zero); // x & 0 => 0
243 R.CheckBinop(zero, zero, x); // 0 & x => 0
244 R.CheckBinop(x, x, minus_1); // x & -1 => 0
245 R.CheckBinop(x, minus_1, x); // -1 & x => 0
246 R.CheckBinop(x, x, x); // x & x => x
247}
248
249
250TEST(ReduceWord32Or) {
251 ReducerTester R;
252 R.binop = R.machine.Word32Or();
253
254 FOR_INT32_INPUTS(pl) {
255 FOR_INT32_INPUTS(pr) {
256 int32_t x = *pl, y = *pr;
257 R.CheckFoldBinop<int32_t>(x | y, x, y);
258 }
259 }
260
261 R.CheckPutConstantOnRight(36);
262 R.CheckPutConstantOnRight(44001);
263
264 Node* x = R.Parameter();
265 Node* zero = R.Constant<int32_t>(0);
266 Node* minus_1 = R.Constant<int32_t>(-1);
267
268 R.CheckBinop(x, x, zero); // x & 0 => x
269 R.CheckBinop(x, zero, x); // 0 & x => x
270 R.CheckBinop(minus_1, x, minus_1); // x & -1 => -1
271 R.CheckBinop(minus_1, minus_1, x); // -1 & x => -1
272 R.CheckBinop(x, x, x); // x & x => x
273}
274
275
276TEST(ReduceWord32Xor) {
277 ReducerTester R;
278 R.binop = R.machine.Word32Xor();
279
280 FOR_INT32_INPUTS(pl) {
281 FOR_INT32_INPUTS(pr) {
282 int32_t x = *pl, y = *pr;
283 R.CheckFoldBinop<int32_t>(x ^ y, x, y);
284 }
285 }
286
287 R.CheckPutConstantOnRight(39);
288 R.CheckPutConstantOnRight(4403);
289
290 Node* x = R.Parameter();
291 Node* zero = R.Constant<int32_t>(0);
292
293 R.CheckBinop(x, x, zero); // x ^ 0 => x
294 R.CheckBinop(x, zero, x); // 0 ^ x => x
295 R.CheckFoldBinop<int32_t>(0, x, x); // x ^ x => 0
296}
297
298
299TEST(ReduceWord32Shl) {
300 ReducerTester R;
301 R.binop = R.machine.Word32Shl();
302
303 // TODO(titzer): out of range shifts
304 FOR_INT32_INPUTS(i) {
305 for (int y = 0; y < 32; y++) {
306 int32_t x = *i;
307 R.CheckFoldBinop<int32_t>(x << y, x, y);
308 }
309 }
310
311 R.CheckDontPutConstantOnRight(44);
312
313 Node* x = R.Parameter();
314 Node* zero = R.Constant<int32_t>(0);
315
316 R.CheckBinop(x, x, zero); // x << 0 => x
317}
318
319
320TEST(ReduceWord32Shr) {
321 ReducerTester R;
322 R.binop = R.machine.Word32Shr();
323
324 // TODO(titzer): test out of range shifts
325 FOR_UINT32_INPUTS(i) {
326 for (uint32_t y = 0; y < 32; y++) {
327 uint32_t x = *i;
328 R.CheckFoldBinop<int32_t>(x >> y, x, y);
329 }
330 }
331
332 R.CheckDontPutConstantOnRight(44);
333
334 Node* x = R.Parameter();
335 Node* zero = R.Constant<int32_t>(0);
336
337 R.CheckBinop(x, x, zero); // x >>> 0 => x
338}
339
340
341TEST(ReduceWord32Sar) {
342 ReducerTester R;
343 R.binop = R.machine.Word32Sar();
344
345 // TODO(titzer): test out of range shifts
346 FOR_INT32_INPUTS(i) {
347 for (int32_t y = 0; y < 32; y++) {
348 int32_t x = *i;
349 R.CheckFoldBinop<int32_t>(x >> y, x, y);
350 }
351 }
352
353 R.CheckDontPutConstantOnRight(44);
354
355 Node* x = R.Parameter();
356 Node* zero = R.Constant<int32_t>(0);
357
358 R.CheckBinop(x, x, zero); // x >> 0 => x
359}
360
361
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400362static void CheckJsShift(ReducerTester* R) {
363 DCHECK(R->machine.Word32ShiftIsSafe());
364
365 Node* x = R->Parameter(0);
366 Node* y = R->Parameter(1);
367 Node* thirty_one = R->Constant<int32_t>(0x1f);
368 Node* y_and_thirty_one =
369 R->graph.NewNode(R->machine.Word32And(), y, thirty_one);
370
371 // If the underlying machine shift instructions 'and' their right operand
372 // with 0x1f then: x << (y & 0x1f) => x << y
373 R->CheckFoldBinop(x, y, x, y_and_thirty_one);
374}
375
376
377TEST(ReduceJsShifts) {
378 ReducerTester R(0, MachineOperatorBuilder::kWord32ShiftIsSafe);
379
380 R.binop = R.machine.Word32Shl();
381 CheckJsShift(&R);
382
383 R.binop = R.machine.Word32Shr();
384 CheckJsShift(&R);
385
386 R.binop = R.machine.Word32Sar();
387 CheckJsShift(&R);
388}
389
390
391TEST(Word32Equal) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000392 ReducerTester R;
393 R.binop = R.machine.Word32Equal();
394
395 FOR_INT32_INPUTS(pl) {
396 FOR_INT32_INPUTS(pr) {
397 int32_t x = *pl, y = *pr;
398 R.CheckFoldBinop<int32_t>(x == y ? 1 : 0, x, y);
399 }
400 }
401
402 R.CheckPutConstantOnRight(48);
403 R.CheckPutConstantOnRight(-48);
404
405 Node* x = R.Parameter(0);
406 Node* y = R.Parameter(1);
407 Node* zero = R.Constant<int32_t>(0);
408 Node* sub = R.graph.NewNode(R.machine.Int32Sub(), x, y);
409
410 R.CheckFoldBinop<int32_t>(1, x, x); // x == x => 1
411 R.CheckFoldBinop(x, y, sub, zero); // x - y == 0 => x == y
412 R.CheckFoldBinop(x, y, zero, sub); // 0 == x - y => x == y
413}
414
415
416TEST(ReduceInt32Add) {
417 ReducerTester R;
418 R.binop = R.machine.Int32Add();
419
420 FOR_INT32_INPUTS(pl) {
421 FOR_INT32_INPUTS(pr) {
422 int32_t x = *pl, y = *pr;
423 R.CheckFoldBinop<int32_t>(x + y, x, y); // TODO(titzer): signed overflow
424 }
425 }
426
427 R.CheckPutConstantOnRight(41);
428 R.CheckPutConstantOnRight(4407);
429
430 Node* x = R.Parameter();
431 Node* zero = R.Constant<int32_t>(0);
432
433 R.CheckBinop(x, x, zero); // x + 0 => x
434 R.CheckBinop(x, zero, x); // 0 + x => x
435}
436
437
438TEST(ReduceInt32Sub) {
439 ReducerTester R;
440 R.binop = R.machine.Int32Sub();
441
442 FOR_INT32_INPUTS(pl) {
443 FOR_INT32_INPUTS(pr) {
444 int32_t x = *pl, y = *pr;
445 R.CheckFoldBinop<int32_t>(x - y, x, y);
446 }
447 }
448
449 R.CheckDontPutConstantOnRight(412);
450
451 Node* x = R.Parameter();
452 Node* zero = R.Constant<int32_t>(0);
453
454 R.CheckBinop(x, x, zero); // x - 0 => x
455}
456
457
458TEST(ReduceInt32Mul) {
459 ReducerTester R;
460 R.binop = R.machine.Int32Mul();
461
462 FOR_INT32_INPUTS(pl) {
463 FOR_INT32_INPUTS(pr) {
464 int32_t x = *pl, y = *pr;
465 R.CheckFoldBinop<int32_t>(x * y, x, y); // TODO(titzer): signed overflow
466 }
467 }
468
469 R.CheckPutConstantOnRight(4111);
470 R.CheckPutConstantOnRight(-4407);
471
472 Node* x = R.Parameter();
473 Node* zero = R.Constant<int32_t>(0);
474 Node* one = R.Constant<int32_t>(1);
475 Node* minus_one = R.Constant<int32_t>(-1);
476
477 R.CheckBinop(zero, x, zero); // x * 0 => 0
478 R.CheckBinop(zero, zero, x); // 0 * x => 0
479 R.CheckBinop(x, x, one); // x * 1 => x
480 R.CheckBinop(x, one, x); // 1 * x => x
481 R.CheckFoldBinop<int32_t>(0, R.machine.Int32Sub(), x, minus_one,
482 x); // -1 * x => 0 - x
483 R.CheckFoldBinop<int32_t>(0, R.machine.Int32Sub(), x, x,
484 minus_one); // x * -1 => 0 - x
485
486 for (int32_t n = 1; n < 31; ++n) {
487 Node* multiplier = R.Constant<int32_t>(1 << n);
488 R.CheckFoldBinop<int32_t>(x, R.machine.Word32Shl(), n, x,
489 multiplier); // x * 2^n => x << n
490 R.CheckFoldBinop<int32_t>(x, R.machine.Word32Shl(), n, multiplier,
491 x); // 2^n * x => x << n
492 }
493}
494
495
496TEST(ReduceInt32Div) {
497 ReducerTester R;
498 R.binop = R.machine.Int32Div();
499
500 FOR_INT32_INPUTS(pl) {
501 FOR_INT32_INPUTS(pr) {
502 int32_t x = *pl, y = *pr;
503 if (y == 0) continue; // TODO(titzer): test / 0
504 int32_t r = y == -1 ? -x : x / y; // INT_MIN / -1 may explode in C
505 R.CheckFoldBinop<int32_t>(r, x, y);
506 }
507 }
508
509 R.CheckDontPutConstantOnRight(41111);
510 R.CheckDontPutConstantOnRight(-44071);
511
512 Node* x = R.Parameter();
513 Node* one = R.Constant<int32_t>(1);
514 Node* minus_one = R.Constant<int32_t>(-1);
515
516 R.CheckBinop(x, x, one); // x / 1 => x
517 // TODO(titzer): // 0 / x => 0 if x != 0
518 // TODO(titzer): // x / 2^n => x >> n and round
519 R.CheckFoldBinop<int32_t>(0, R.machine.Int32Sub(), x, x,
520 minus_one); // x / -1 => 0 - x
521}
522
523
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400524TEST(ReduceUint32Div) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000525 ReducerTester R;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400526 R.binop = R.machine.Uint32Div();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000527
528 FOR_UINT32_INPUTS(pl) {
529 FOR_UINT32_INPUTS(pr) {
530 uint32_t x = *pl, y = *pr;
531 if (y == 0) continue; // TODO(titzer): test / 0
532 R.CheckFoldBinop<int32_t>(x / y, x, y);
533 }
534 }
535
536 R.CheckDontPutConstantOnRight(41311);
537 R.CheckDontPutConstantOnRight(-44371);
538
539 Node* x = R.Parameter();
540 Node* one = R.Constant<int32_t>(1);
541
542 R.CheckBinop(x, x, one); // x / 1 => x
543 // TODO(titzer): // 0 / x => 0 if x != 0
544
545 for (uint32_t n = 1; n < 32; ++n) {
546 Node* divisor = R.Constant<int32_t>(1u << n);
547 R.CheckFoldBinop<int32_t>(x, R.machine.Word32Shr(), n, x,
548 divisor); // x / 2^n => x >> n
549 }
550}
551
552
553TEST(ReduceInt32Mod) {
554 ReducerTester R;
555 R.binop = R.machine.Int32Mod();
556
557 FOR_INT32_INPUTS(pl) {
558 FOR_INT32_INPUTS(pr) {
559 int32_t x = *pl, y = *pr;
560 if (y == 0) continue; // TODO(titzer): test % 0
561 int32_t r = y == -1 ? 0 : x % y; // INT_MIN % -1 may explode in C
562 R.CheckFoldBinop<int32_t>(r, x, y);
563 }
564 }
565
566 R.CheckDontPutConstantOnRight(413);
567 R.CheckDontPutConstantOnRight(-4401);
568
569 Node* x = R.Parameter();
570 Node* one = R.Constant<int32_t>(1);
571
572 R.CheckFoldBinop<int32_t>(0, x, one); // x % 1 => 0
573 // TODO(titzer): // x % 2^n => x & 2^n-1 and round
574}
575
576
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400577TEST(ReduceUint32Mod) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000578 ReducerTester R;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400579 R.binop = R.machine.Uint32Mod();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000580
581 FOR_INT32_INPUTS(pl) {
582 FOR_INT32_INPUTS(pr) {
583 uint32_t x = *pl, y = *pr;
584 if (y == 0) continue; // TODO(titzer): test x % 0
585 R.CheckFoldBinop<int32_t>(x % y, x, y);
586 }
587 }
588
589 R.CheckDontPutConstantOnRight(417);
590 R.CheckDontPutConstantOnRight(-4371);
591
592 Node* x = R.Parameter();
593 Node* one = R.Constant<int32_t>(1);
594
595 R.CheckFoldBinop<int32_t>(0, x, one); // x % 1 => 0
596
597 for (uint32_t n = 1; n < 32; ++n) {
598 Node* divisor = R.Constant<int32_t>(1u << n);
599 R.CheckFoldBinop<int32_t>(x, R.machine.Word32And(), (1u << n) - 1, x,
600 divisor); // x % 2^n => x & 2^n-1
601 }
602}
603
604
605TEST(ReduceInt32LessThan) {
606 ReducerTester R;
607 R.binop = R.machine.Int32LessThan();
608
609 FOR_INT32_INPUTS(pl) {
610 FOR_INT32_INPUTS(pr) {
611 int32_t x = *pl, y = *pr;
612 R.CheckFoldBinop<int32_t>(x < y ? 1 : 0, x, y);
613 }
614 }
615
616 R.CheckDontPutConstantOnRight(41399);
617 R.CheckDontPutConstantOnRight(-440197);
618
619 Node* x = R.Parameter(0);
620 Node* y = R.Parameter(1);
621 Node* zero = R.Constant<int32_t>(0);
622 Node* sub = R.graph.NewNode(R.machine.Int32Sub(), x, y);
623
624 R.CheckFoldBinop<int32_t>(0, x, x); // x < x => 0
625 R.CheckFoldBinop(x, y, sub, zero); // x - y < 0 => x < y
626 R.CheckFoldBinop(y, x, zero, sub); // 0 < x - y => y < x
627}
628
629
630TEST(ReduceInt32LessThanOrEqual) {
631 ReducerTester R;
632 R.binop = R.machine.Int32LessThanOrEqual();
633
634 FOR_INT32_INPUTS(pl) {
635 FOR_INT32_INPUTS(pr) {
636 int32_t x = *pl, y = *pr;
637 R.CheckFoldBinop<int32_t>(x <= y ? 1 : 0, x, y);
638 }
639 }
640
641 FOR_INT32_INPUTS(i) { R.CheckDontPutConstantOnRight<int32_t>(*i); }
642
643 Node* x = R.Parameter(0);
644 Node* y = R.Parameter(1);
645 Node* zero = R.Constant<int32_t>(0);
646 Node* sub = R.graph.NewNode(R.machine.Int32Sub(), x, y);
647
648 R.CheckFoldBinop<int32_t>(1, x, x); // x <= x => 1
649 R.CheckFoldBinop(x, y, sub, zero); // x - y <= 0 => x <= y
650 R.CheckFoldBinop(y, x, zero, sub); // 0 <= x - y => y <= x
651}
652
653
654TEST(ReduceUint32LessThan) {
655 ReducerTester R;
656 R.binop = R.machine.Uint32LessThan();
657
658 FOR_UINT32_INPUTS(pl) {
659 FOR_UINT32_INPUTS(pr) {
660 uint32_t x = *pl, y = *pr;
661 R.CheckFoldBinop<int32_t>(x < y ? 1 : 0, x, y);
662 }
663 }
664
665 R.CheckDontPutConstantOnRight(41399);
666 R.CheckDontPutConstantOnRight(-440197);
667
668 Node* x = R.Parameter();
669 Node* max = R.maxuint32;
670 Node* zero = R.Constant<int32_t>(0);
671
672 R.CheckFoldBinop<int32_t>(0, max, x); // M < x => 0
673 R.CheckFoldBinop<int32_t>(0, x, zero); // x < 0 => 0
674 R.CheckFoldBinop<int32_t>(0, x, x); // x < x => 0
675}
676
677
678TEST(ReduceUint32LessThanOrEqual) {
679 ReducerTester R;
680 R.binop = R.machine.Uint32LessThanOrEqual();
681
682 FOR_UINT32_INPUTS(pl) {
683 FOR_UINT32_INPUTS(pr) {
684 uint32_t x = *pl, y = *pr;
685 R.CheckFoldBinop<int32_t>(x <= y ? 1 : 0, x, y);
686 }
687 }
688
689 R.CheckDontPutConstantOnRight(41399);
690 R.CheckDontPutConstantOnRight(-440197);
691
692 Node* x = R.Parameter();
693 Node* max = R.maxuint32;
694 Node* zero = R.Constant<int32_t>(0);
695
696 R.CheckFoldBinop<int32_t>(1, x, max); // x <= M => 1
697 R.CheckFoldBinop<int32_t>(1, zero, x); // 0 <= x => 1
698 R.CheckFoldBinop<int32_t>(1, x, x); // x <= x => 1
699}
700
701
702TEST(ReduceLoadStore) {
703 ReducerTester R;
704
705 Node* base = R.Constant<int32_t>(11);
706 Node* index = R.Constant<int32_t>(4);
707 Node* load = R.graph.NewNode(R.machine.Load(kMachInt32), base, index);
708
709 {
710 MachineOperatorReducer reducer(&R.jsgraph);
711 Reduction reduction = reducer.Reduce(load);
712 CHECK(!reduction.Changed()); // loads should not be reduced.
713 }
714
715 {
716 Node* store = R.graph.NewNode(
717 R.machine.Store(StoreRepresentation(kMachInt32, kNoWriteBarrier)), base,
718 index, load);
719 MachineOperatorReducer reducer(&R.jsgraph);
720 Reduction reduction = reducer.Reduce(store);
721 CHECK(!reduction.Changed()); // stores should not be reduced.
722 }
723}
724
725
726static void CheckNans(ReducerTester* R) {
727 Node* x = R->Parameter();
728 std::vector<double> nans = ValueHelper::nan_vector();
729 for (std::vector<double>::const_iterator pl = nans.begin(); pl != nans.end();
730 ++pl) {
731 for (std::vector<double>::const_iterator pr = nans.begin();
732 pr != nans.end(); ++pr) {
733 Node* nan1 = R->Constant<double>(*pl);
734 Node* nan2 = R->Constant<double>(*pr);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400735 R->CheckBinop(nan1, x, nan1); // x op NaN => NaN
736 R->CheckBinop(nan1, nan1, x); // NaN op x => NaN
737 R->CheckBinop(nan1, nan2, nan1); // NaN op NaN => NaN
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000738 }
739 }
740}
741
742
743TEST(ReduceFloat64Add) {
744 ReducerTester R;
745 R.binop = R.machine.Float64Add();
746
747 FOR_FLOAT64_INPUTS(pl) {
748 FOR_FLOAT64_INPUTS(pr) {
749 double x = *pl, y = *pr;
750 R.CheckFoldBinop<double>(x + y, x, y);
751 }
752 }
753
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400754 FOR_FLOAT64_INPUTS(i) {
755 Double tmp(*i);
756 if (!tmp.IsSpecial() || tmp.IsInfinite()) {
757 // Don't check NaNs as they are reduced more.
758 R.CheckPutConstantOnRight(*i);
759 }
760 }
761
762 CheckNans(&R);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000763}
764
765
766TEST(ReduceFloat64Sub) {
767 ReducerTester R;
768 R.binop = R.machine.Float64Sub();
769
770 FOR_FLOAT64_INPUTS(pl) {
771 FOR_FLOAT64_INPUTS(pr) {
772 double x = *pl, y = *pr;
773 R.CheckFoldBinop<double>(x - y, x, y);
774 }
775 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400776
777 Node* zero = R.Constant<double>(0.0);
778 Node* x = R.Parameter();
779
780 R.CheckBinop(x, x, zero); // x - 0.0 => x
781
782 CheckNans(&R);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000783}
784
785
786TEST(ReduceFloat64Mul) {
787 ReducerTester R;
788 R.binop = R.machine.Float64Mul();
789
790 FOR_FLOAT64_INPUTS(pl) {
791 FOR_FLOAT64_INPUTS(pr) {
792 double x = *pl, y = *pr;
793 R.CheckFoldBinop<double>(x * y, x, y);
794 }
795 }
796
797 double inf = V8_INFINITY;
798 R.CheckPutConstantOnRight(-inf);
799 R.CheckPutConstantOnRight(-0.1);
800 R.CheckPutConstantOnRight(0.1);
801 R.CheckPutConstantOnRight(inf);
802
803 Node* x = R.Parameter();
804 Node* one = R.Constant<double>(1.0);
805
806 R.CheckBinop(x, x, one); // x * 1.0 => x
807 R.CheckBinop(x, one, x); // 1.0 * x => x
808
809 CheckNans(&R);
810}
811
812
813TEST(ReduceFloat64Div) {
814 ReducerTester R;
815 R.binop = R.machine.Float64Div();
816
817 FOR_FLOAT64_INPUTS(pl) {
818 FOR_FLOAT64_INPUTS(pr) {
819 double x = *pl, y = *pr;
820 R.CheckFoldBinop<double>(x / y, x, y);
821 }
822 }
823
824 Node* x = R.Parameter();
825 Node* one = R.Constant<double>(1.0);
826
827 R.CheckBinop(x, x, one); // x / 1.0 => x
828
829 CheckNans(&R);
830}
831
832
833TEST(ReduceFloat64Mod) {
834 ReducerTester R;
835 R.binop = R.machine.Float64Mod();
836
837 FOR_FLOAT64_INPUTS(pl) {
838 FOR_FLOAT64_INPUTS(pr) {
839 double x = *pl, y = *pr;
840 R.CheckFoldBinop<double>(modulo(x, y), x, y);
841 }
842 }
843
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400844 Node* x = R.Parameter();
845 Node* zero = R.Constant<double>(0.0);
846
847 R.CheckFoldBinop<double>(v8::base::OS::nan_value(), x, zero);
848
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000849 CheckNans(&R);
850}
851
852
853// TODO(titzer): test MachineOperatorReducer for Word64And
854// TODO(titzer): test MachineOperatorReducer for Word64Or
855// TODO(titzer): test MachineOperatorReducer for Word64Xor
856// TODO(titzer): test MachineOperatorReducer for Word64Shl
857// TODO(titzer): test MachineOperatorReducer for Word64Shr
858// TODO(titzer): test MachineOperatorReducer for Word64Sar
859// TODO(titzer): test MachineOperatorReducer for Word64Equal
860// TODO(titzer): test MachineOperatorReducer for Word64Not
861// TODO(titzer): test MachineOperatorReducer for Int64Add
862// TODO(titzer): test MachineOperatorReducer for Int64Sub
863// TODO(titzer): test MachineOperatorReducer for Int64Mul
864// TODO(titzer): test MachineOperatorReducer for Int64UMul
865// TODO(titzer): test MachineOperatorReducer for Int64Div
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400866// TODO(titzer): test MachineOperatorReducer for Uint64Div
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000867// TODO(titzer): test MachineOperatorReducer for Int64Mod
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400868// TODO(titzer): test MachineOperatorReducer for Uint64Mod
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000869// TODO(titzer): test MachineOperatorReducer for Int64Neg
870// TODO(titzer): test MachineOperatorReducer for ChangeInt32ToFloat64
871// TODO(titzer): test MachineOperatorReducer for ChangeFloat64ToInt32
872// TODO(titzer): test MachineOperatorReducer for Float64Compare