1 // Copyright 2013 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.
9 #include "graph-tester.h"
10 #include "src/compiler/node.h"
11 #include "src/compiler/operator.h"
13 using namespace v8::internal;
14 using namespace v8::internal::compiler;
16 #define NONE reinterpret_cast<Node*>(1)
18 static Operator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite,
19 "dummy", 0, 0, 0, 1, 0, 0);
21 #define CHECK_USES(node, ...) \
23 Node* __array[] = {__VA_ARGS__}; \
25 __array[0] != NONE ? static_cast<int>(arraysize(__array)) : 0; \
26 CheckUseChain(node, __array, __size); \
30 typedef std::multiset<Node*, std::less<Node*>> NodeMSet;
32 static void CheckUseChain(Node* node, Node** uses, int use_count) {
34 if (use_count == 1) CHECK(node->OwnedBy(uses[0]));
36 for (int i = 0; i < use_count; i++) {
37 CHECK(!node->OwnedBy(uses[i]));
41 // Check the self-reported use count.
42 CHECK_EQ(use_count, node->UseCount());
44 // Build the expectation set.
46 for (int i = 0; i < use_count; i++) {
47 expect_set.insert(uses[i]);
51 // Check that iterating over the uses gives the right counts.
53 for (auto use : node->uses()) {
56 CHECK(expect_set == use_set);
60 // Check that iterating over the use edges gives the right counts,
61 // input indices, from(), and to() pointers.
63 for (auto edge : node->use_edges()) {
64 CHECK_EQ(node, edge.to());
65 CHECK_EQ(node, edge.from()->InputAt(edge.index()));
66 use_set.insert(edge.from());
68 CHECK(expect_set == use_set);
72 // Check the use nodes actually have the node as inputs.
73 for (Node* use : node->uses()) {
75 for (Node* input : use->inputs()) {
76 if (input == node) count++;
78 CHECK_EQ(count, expect_set.count(use));
84 #define CHECK_INPUTS(node, ...) \
86 Node* __array[] = {__VA_ARGS__}; \
88 __array[0] != NONE ? static_cast<int>(arraysize(__array)) : 0; \
89 CheckInputs(node, __array, __size); \
93 static void CheckInputs(Node* node, Node** inputs, int input_count) {
94 CHECK_EQ(input_count, node->InputCount());
96 for (int i = 0; i < static_cast<int>(input_count); i++) {
97 CHECK_EQ(inputs[i], node->InputAt(i));
100 // Check input iterator.
102 for (Node* input : node->inputs()) {
103 CHECK_EQ(inputs[index], input);
107 // Check use lists of inputs.
108 for (int i = 0; i < static_cast<int>(input_count); i++) {
109 Node* input = inputs[i];
110 if (!input) continue; // skip null inputs
112 // Check regular use list.
113 for (Node* use : input->uses()) {
121 // Check use edge list.
122 for (auto edge : input->use_edges()) {
123 if (edge.from() == node && edge.to() == input && edge.index() == i) {
132 TEST(NodeUseIteratorReplaceUses) {
134 Node* n0 = graph.NewNode(&dummy_operator);
135 Node* n1 = graph.NewNode(&dummy_operator, n0);
136 Node* n2 = graph.NewNode(&dummy_operator, n0);
137 Node* n3 = graph.NewNode(&dummy_operator);
139 CHECK_USES(n0, n1, n2);
141 CHECK_INPUTS(n1, n0);
142 CHECK_INPUTS(n2, n0);
146 CHECK_USES(n0, NONE);
147 CHECK_USES(n1, NONE);
148 CHECK_USES(n2, NONE);
149 CHECK_USES(n3, n1, n2);
151 CHECK_INPUTS(n1, n3);
152 CHECK_INPUTS(n2, n3);
156 TEST(NodeUseIteratorReplaceUsesSelf) {
158 Node* n0 = graph.NewNode(&dummy_operator);
159 Node* n1 = graph.NewNode(&dummy_operator, n0);
162 CHECK_USES(n1, NONE);
164 n1->ReplaceInput(0, n1); // Create self-reference.
166 CHECK_USES(n0, NONE);
169 Node* n2 = graph.NewNode(&dummy_operator);
173 CHECK_USES(n0, NONE);
174 CHECK_USES(n1, NONE);
181 Node* n0 = graph.NewNode(&dummy_operator);
182 Node* n1 = graph.NewNode(&dummy_operator);
183 Node* n2 = graph.NewNode(&dummy_operator);
184 Node* n3 = graph.NewNode(&dummy_operator, n0, n1, n2);
185 Node* n4 = graph.NewNode(&dummy_operator);
190 CHECK_USES(n3, NONE);
191 CHECK_USES(n4, NONE);
193 CHECK_INPUTS(n3, n0, n1, n2);
195 n3->ReplaceInput(1, n4);
197 CHECK_USES(n1, NONE);
200 CHECK_INPUTS(n3, n0, n4, n2);
208 Node* n0 = graph.NewNode(&dummy_operator);
209 Node* n1 = graph.NewNode(&dummy_operator);
211 CHECK(!n0->OwnedBy(n1));
212 CHECK(!n1->OwnedBy(n0));
214 Node* n2 = graph.NewNode(&dummy_operator, n0);
215 CHECK(n0->OwnedBy(n2));
216 CHECK(!n2->OwnedBy(n0));
218 Node* n3 = graph.NewNode(&dummy_operator, n0);
219 CHECK(!n0->OwnedBy(n2));
220 CHECK(!n0->OwnedBy(n3));
221 CHECK(!n2->OwnedBy(n0));
222 CHECK(!n3->OwnedBy(n0));
226 Node* n0 = graph.NewNode(&dummy_operator);
227 Node* n1 = graph.NewNode(&dummy_operator, n0);
228 CHECK(n0->OwnedBy(n1));
229 CHECK(!n1->OwnedBy(n0));
230 Node* n2 = graph.NewNode(&dummy_operator, n0);
231 CHECK(!n0->OwnedBy(n1));
232 CHECK(!n0->OwnedBy(n2));
233 CHECK(!n1->OwnedBy(n0));
234 CHECK(!n1->OwnedBy(n2));
235 CHECK(!n2->OwnedBy(n0));
236 CHECK(!n2->OwnedBy(n1));
238 Node* n3 = graph.NewNode(&dummy_operator);
239 n2->ReplaceInput(0, n3);
241 CHECK(n0->OwnedBy(n1));
242 CHECK(!n1->OwnedBy(n0));
243 CHECK(!n1->OwnedBy(n0));
244 CHECK(!n1->OwnedBy(n2));
245 CHECK(!n2->OwnedBy(n0));
246 CHECK(!n2->OwnedBy(n1));
247 CHECK(n3->OwnedBy(n2));
248 CHECK(!n2->OwnedBy(n3));
256 Node* n0 = graph.NewNode(&dummy_operator);
257 Node* n1 = graph.NewNode(&dummy_operator, n0);
260 CHECK_USES(n1, NONE);
262 Node* n2 = graph.NewNode(&dummy_operator, n0);
264 CHECK_USES(n0, n1, n2);
265 CHECK_USES(n2, NONE);
267 Node* n3 = graph.NewNode(&dummy_operator, n0);
269 CHECK_USES(n0, n1, n2, n3);
270 CHECK_USES(n3, NONE);
277 Node* n0 = graph.NewNode(&dummy_operator);
278 Node* n1 = graph.NewNode(&dummy_operator, n0);
279 Node* n2 = graph.NewNode(&dummy_operator, n0);
280 Node* n3 = graph.NewNode(&dummy_operator, n0, n1, n2);
282 CHECK_INPUTS(n3, n0, n1, n2);
284 Node* n4 = graph.NewNode(&dummy_operator, n0, n1, n2);
285 n3->AppendInput(graph.zone(), n4);
287 CHECK_INPUTS(n3, n0, n1, n2, n4);
290 n3->AppendInput(graph.zone(), n4);
292 CHECK_INPUTS(n3, n0, n1, n2, n4, n4);
293 CHECK_USES(n4, n3, n3);
295 Node* n5 = graph.NewNode(&dummy_operator, n4);
297 CHECK_USES(n4, n3, n3, n5);
304 Node* n0 = graph.NewNode(&dummy_operator);
305 Node* n1 = graph.NewNode(&dummy_operator, n0);
306 Node* n2 = graph.NewNode(&dummy_operator, n0, n1);
308 CHECK_INPUTS(n0, NONE);
309 CHECK_INPUTS(n1, n0);
310 CHECK_INPUTS(n2, n0, n1);
311 CHECK_USES(n0, n1, n2);
314 CHECK_INPUTS(n1, NONE);
318 CHECK_INPUTS(n2, n1);
319 CHECK_USES(n0, NONE);
323 CHECK_INPUTS(n2, NONE);
324 CHECK_USES(n0, NONE);
325 CHECK_USES(n1, NONE);
326 CHECK_USES(n2, NONE);
330 TEST(AppendInputsAndIterator) {
333 Node* n0 = graph.NewNode(&dummy_operator);
334 Node* n1 = graph.NewNode(&dummy_operator, n0);
335 Node* n2 = graph.NewNode(&dummy_operator, n0, n1);
337 CHECK_INPUTS(n0, NONE);
338 CHECK_INPUTS(n1, n0);
339 CHECK_INPUTS(n2, n0, n1);
340 CHECK_USES(n0, n1, n2);
342 Node* n3 = graph.NewNode(&dummy_operator);
344 n2->AppendInput(graph.zone(), n3);
346 CHECK_INPUTS(n2, n0, n1, n3);
351 TEST(NullInputsSimple) {
354 Node* n0 = graph.NewNode(&dummy_operator);
355 Node* n1 = graph.NewNode(&dummy_operator, n0);
356 Node* n2 = graph.NewNode(&dummy_operator, n0, n1);
358 CHECK_INPUTS(n0, NONE);
359 CHECK_INPUTS(n1, n0);
360 CHECK_INPUTS(n2, n0, n1);
361 CHECK_USES(n0, n1, n2);
363 n2->ReplaceInput(0, nullptr);
365 CHECK_INPUTS(n2, NULL, n1);
369 n2->ReplaceInput(1, nullptr);
371 CHECK_INPUTS(n2, NULL, NULL);
373 CHECK_USES(n1, NONE);
377 TEST(NullInputsAppended) {
380 Node* n0 = graph.NewNode(&dummy_operator);
381 Node* n1 = graph.NewNode(&dummy_operator, n0);
382 Node* n2 = graph.NewNode(&dummy_operator, n0);
383 Node* n3 = graph.NewNode(&dummy_operator, n0);
384 n3->AppendInput(graph.zone(), n1);
385 n3->AppendInput(graph.zone(), n2);
387 CHECK_INPUTS(n3, n0, n1, n2);
388 CHECK_USES(n0, n1, n2, n3);
392 n3->ReplaceInput(1, NULL);
393 CHECK_USES(n1, NONE);
395 CHECK_INPUTS(n3, n0, NULL, n2);
399 TEST(ReplaceUsesFromAppendedInputs) {
402 Node* n0 = graph.NewNode(&dummy_operator);
403 Node* n1 = graph.NewNode(&dummy_operator, n0);
404 Node* n2 = graph.NewNode(&dummy_operator, n0);
405 Node* n3 = graph.NewNode(&dummy_operator);
407 CHECK_INPUTS(n2, n0);
409 n2->AppendInput(graph.zone(), n1);
410 CHECK_INPUTS(n2, n0, n1);
413 n2->AppendInput(graph.zone(), n0);
414 CHECK_INPUTS(n2, n0, n1, n0);
416 CHECK_USES(n0, n2, n1, n2);
420 CHECK_USES(n0, NONE);
421 CHECK_INPUTS(n2, n3, n1, n3);
422 CHECK_USES(n3, n2, n1, n2);
426 TEST(ReplaceInputMultipleUses) {
429 Node* n0 = graph.NewNode(&dummy_operator);
430 Node* n1 = graph.NewNode(&dummy_operator);
431 Node* n2 = graph.NewNode(&dummy_operator, n0);
432 n2->ReplaceInput(0, n1);
433 CHECK_EQ(0, n0->UseCount());
434 CHECK_EQ(1, n1->UseCount());
436 Node* n3 = graph.NewNode(&dummy_operator, n0);
437 n3->ReplaceInput(0, n1);
438 CHECK_EQ(0, n0->UseCount());
439 CHECK_EQ(2, n1->UseCount());
443 TEST(TrimInputCountInline) {
447 Node* n0 = graph.NewNode(&dummy_operator);
448 Node* n1 = graph.NewNode(&dummy_operator, n0);
449 n1->TrimInputCount(1);
450 CHECK_INPUTS(n1, n0);
455 Node* n0 = graph.NewNode(&dummy_operator);
456 Node* n1 = graph.NewNode(&dummy_operator, n0);
457 n1->TrimInputCount(0);
458 CHECK_INPUTS(n1, NONE);
459 CHECK_USES(n0, NONE);
463 Node* n0 = graph.NewNode(&dummy_operator);
464 Node* n1 = graph.NewNode(&dummy_operator);
465 Node* n2 = graph.NewNode(&dummy_operator, n0, n1);
466 n2->TrimInputCount(2);
467 CHECK_INPUTS(n2, n0, n1);
473 Node* n0 = graph.NewNode(&dummy_operator);
474 Node* n1 = graph.NewNode(&dummy_operator);
475 Node* n2 = graph.NewNode(&dummy_operator, n0, n1);
476 n2->TrimInputCount(1);
477 CHECK_INPUTS(n2, n0);
479 CHECK_USES(n1, NONE);
483 Node* n0 = graph.NewNode(&dummy_operator);
484 Node* n1 = graph.NewNode(&dummy_operator);
485 Node* n2 = graph.NewNode(&dummy_operator, n0, n1);
486 n2->TrimInputCount(0);
487 CHECK_INPUTS(n2, NONE);
488 CHECK_USES(n0, NONE);
489 CHECK_USES(n1, NONE);
493 Node* n0 = graph.NewNode(&dummy_operator);
494 Node* n2 = graph.NewNode(&dummy_operator, n0, n0);
495 n2->TrimInputCount(1);
496 CHECK_INPUTS(n2, n0);
501 Node* n0 = graph.NewNode(&dummy_operator);
502 Node* n2 = graph.NewNode(&dummy_operator, n0, n0);
503 n2->TrimInputCount(0);
504 CHECK_INPUTS(n2, NONE);
505 CHECK_USES(n0, NONE);
510 TEST(TrimInputCountOutOfLine1) {
514 Node* n0 = graph.NewNode(&dummy_operator);
515 Node* n1 = graph.NewNode(&dummy_operator);
516 n1->AppendInput(graph.zone(), n0);
517 CHECK_INPUTS(n1, n0);
520 n1->TrimInputCount(1);
521 CHECK_INPUTS(n1, n0);
526 Node* n0 = graph.NewNode(&dummy_operator);
527 Node* n1 = graph.NewNode(&dummy_operator);
528 n1->AppendInput(graph.zone(), n0);
529 CHECK_EQ(1, n1->InputCount());
530 n1->TrimInputCount(0);
531 CHECK_EQ(0, n1->InputCount());
532 CHECK_EQ(0, n0->UseCount());
536 Node* n0 = graph.NewNode(&dummy_operator);
537 Node* n1 = graph.NewNode(&dummy_operator);
538 Node* n2 = graph.NewNode(&dummy_operator);
539 n2->AppendInput(graph.zone(), n0);
540 n2->AppendInput(graph.zone(), n1);
541 CHECK_INPUTS(n2, n0, n1);
542 n2->TrimInputCount(2);
543 CHECK_INPUTS(n2, n0, n1);
546 CHECK_USES(n2, NONE);
550 Node* n0 = graph.NewNode(&dummy_operator);
551 Node* n1 = graph.NewNode(&dummy_operator);
552 Node* n2 = graph.NewNode(&dummy_operator);
553 n2->AppendInput(graph.zone(), n0);
554 n2->AppendInput(graph.zone(), n1);
555 CHECK_INPUTS(n2, n0, n1);
556 n2->TrimInputCount(1);
557 CHECK_INPUTS(n2, n0);
559 CHECK_USES(n1, NONE);
560 CHECK_USES(n2, NONE);
564 Node* n0 = graph.NewNode(&dummy_operator);
565 Node* n1 = graph.NewNode(&dummy_operator);
566 Node* n2 = graph.NewNode(&dummy_operator);
567 n2->AppendInput(graph.zone(), n0);
568 n2->AppendInput(graph.zone(), n1);
569 CHECK_INPUTS(n2, n0, n1);
570 n2->TrimInputCount(0);
571 CHECK_INPUTS(n2, NONE);
572 CHECK_USES(n0, NONE);
573 CHECK_USES(n1, NONE);
574 CHECK_USES(n2, NONE);
578 Node* n0 = graph.NewNode(&dummy_operator);
579 Node* n2 = graph.NewNode(&dummy_operator);
580 n2->AppendInput(graph.zone(), n0);
581 n2->AppendInput(graph.zone(), n0);
582 CHECK_INPUTS(n2, n0, n0);
583 CHECK_USES(n0, n2, n2);
584 n2->TrimInputCount(1);
585 CHECK_INPUTS(n2, n0);
590 Node* n0 = graph.NewNode(&dummy_operator);
591 Node* n2 = graph.NewNode(&dummy_operator);
592 n2->AppendInput(graph.zone(), n0);
593 n2->AppendInput(graph.zone(), n0);
594 CHECK_INPUTS(n2, n0, n0);
595 CHECK_USES(n0, n2, n2);
596 n2->TrimInputCount(0);
597 CHECK_INPUTS(n2, NONE);
598 CHECK_USES(n0, NONE);
603 TEST(TrimInputCountOutOfLine2) {
607 Node* n0 = graph.NewNode(&dummy_operator);
608 Node* n1 = graph.NewNode(&dummy_operator);
609 Node* n2 = graph.NewNode(&dummy_operator, n0);
610 n2->AppendInput(graph.zone(), n1);
611 CHECK_INPUTS(n2, n0, n1);
612 n2->TrimInputCount(2);
613 CHECK_INPUTS(n2, n0, n1);
616 CHECK_USES(n2, NONE);
620 Node* n0 = graph.NewNode(&dummy_operator);
621 Node* n1 = graph.NewNode(&dummy_operator);
622 Node* n2 = graph.NewNode(&dummy_operator, n0);
623 n2->AppendInput(graph.zone(), n1);
624 CHECK_INPUTS(n2, n0, n1);
625 n2->TrimInputCount(1);
626 CHECK_INPUTS(n2, n0);
628 CHECK_USES(n1, NONE);
629 CHECK_USES(n2, NONE);
633 Node* n0 = graph.NewNode(&dummy_operator);
634 Node* n1 = graph.NewNode(&dummy_operator);
635 Node* n2 = graph.NewNode(&dummy_operator, n0);
636 n2->AppendInput(graph.zone(), n1);
637 CHECK_INPUTS(n2, n0, n1);
638 n2->TrimInputCount(0);
639 CHECK_INPUTS(n2, NONE);
640 CHECK_USES(n0, NONE);
641 CHECK_USES(n1, NONE);
642 CHECK_USES(n2, NONE);
646 Node* n0 = graph.NewNode(&dummy_operator);
647 Node* n2 = graph.NewNode(&dummy_operator, n0);
648 n2->AppendInput(graph.zone(), n0);
649 CHECK_INPUTS(n2, n0, n0);
650 CHECK_USES(n0, n2, n2);
651 n2->TrimInputCount(1);
652 CHECK_INPUTS(n2, n0);
654 CHECK_USES(n2, NONE);
658 Node* n0 = graph.NewNode(&dummy_operator);
659 Node* n2 = graph.NewNode(&dummy_operator, n0);
660 n2->AppendInput(graph.zone(), n0);
661 CHECK_EQ(2, n2->InputCount());
662 CHECK_EQ(2, n0->UseCount());
663 n2->TrimInputCount(0);
664 CHECK_EQ(0, n2->InputCount());
665 CHECK_EQ(0, n0->UseCount());
666 CHECK_EQ(0, n2->UseCount());
671 TEST(NullAllInputs) {
674 for (int i = 0; i < 2; i++) {
675 Node* n0 = graph.NewNode(&dummy_operator);
676 Node* n1 = graph.NewNode(&dummy_operator, n0);
679 n2 = graph.NewNode(&dummy_operator, n0, n1);
680 CHECK_INPUTS(n2, n0, n1);
682 n2 = graph.NewNode(&dummy_operator, n0);
683 CHECK_INPUTS(n2, n0);
684 n2->AppendInput(graph.zone(), n1); // with out-of-line input.
685 CHECK_INPUTS(n2, n0, n1);
689 CHECK_INPUTS(n0, NONE);
691 CHECK_USES(n0, n1, n2);
693 CHECK_INPUTS(n1, NULL);
694 CHECK_INPUTS(n2, n0, n1);
698 CHECK_INPUTS(n1, NULL);
699 CHECK_INPUTS(n2, NULL, NULL);
700 CHECK_USES(n0, NONE);
704 Node* n0 = graph.NewNode(&dummy_operator);
705 Node* n1 = graph.NewNode(&dummy_operator, n0);
706 n1->ReplaceInput(0, n1); // self-reference.
708 CHECK_INPUTS(n0, NONE);
709 CHECK_INPUTS(n1, n1);
710 CHECK_USES(n0, NONE);
714 CHECK_INPUTS(n0, NONE);
715 CHECK_INPUTS(n1, NULL);
716 CHECK_USES(n0, NONE);
717 CHECK_USES(n1, NONE);
722 TEST(AppendAndTrim) {
726 graph.NewNode(&dummy_operator), graph.NewNode(&dummy_operator),
727 graph.NewNode(&dummy_operator), graph.NewNode(&dummy_operator),
728 graph.NewNode(&dummy_operator)};
730 int max = static_cast<int>(arraysize(nodes));
732 Node* last = graph.NewNode(&dummy_operator);
734 for (int i = 0; i < max; i++) {
735 last->AppendInput(graph.zone(), nodes[i]);
736 CheckInputs(last, nodes, i + 1);
738 for (int j = 0; j < max; j++) {
739 if (j <= i) CHECK_USES(nodes[j], last);
740 if (j > i) CHECK_USES(nodes[j], NONE);
743 CHECK_USES(last, NONE);
746 for (int i = max; i >= 0; i--) {
747 last->TrimInputCount(i);
748 CheckInputs(last, nodes, i);
750 for (int j = 0; j < i; j++) {
751 if (j < i) CHECK_USES(nodes[j], last);
752 if (j >= i) CHECK_USES(nodes[j], NONE);
755 CHECK_USES(last, NONE);