Jlm
Loading...
Searching...
No Matches
CommonNodeEliminationTests.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2017 Nico Reißmann <nico.reissmann@gmail.com>
3 * See COPYING for terms of redistribution.
4 */
5
6#include <gtest/gtest.h>
7
15#include <jlm/rvsdg/control.hpp>
16#include <jlm/rvsdg/gamma.hpp>
17#include <jlm/rvsdg/Phi.hpp>
20#include <jlm/rvsdg/theta.hpp>
21#include <jlm/rvsdg/view.hpp>
23
24namespace jlm::llvm
25{
26
28
29TEST(CommonNodeEliminationTests, test_simple)
30{
31 using namespace jlm::rvsdg;
32
33 // Arrange
34 auto vt = TestType::createValueType();
35
36 LlvmRvsdgModule rvsdgModule(util::FilePath(""), "", "");
37 auto & graph = rvsdgModule.Rvsdg();
38
39 auto x = &GraphImport::Create(graph, vt, "x");
40 auto y = &GraphImport::Create(graph, vt, "y");
41 auto z = &GraphImport::Create(graph, vt, "z");
42
43 auto n1 = TestOperation::createNode(&graph.GetRootRegion(), {}, { vt })->output(0);
44 auto n2 = TestOperation::createNode(&graph.GetRootRegion(), {}, { vt })->output(0);
45
46 auto u1 = TestOperation::createNode(&graph.GetRootRegion(), { z }, { vt })->output(0);
47
48 auto b1 = TestOperation::createNode(&graph.GetRootRegion(), { x, y }, { vt })->output(0);
49 auto b2 = TestOperation::createNode(&graph.GetRootRegion(), { x, y }, { vt })->output(0);
50 auto b3 = TestOperation::createNode(&graph.GetRootRegion(), { n1, z }, { vt })->output(0);
51 auto b4 = TestOperation::createNode(&graph.GetRootRegion(), { n2, z }, { vt })->output(0);
52
53 GraphExport::Create(*n1, "n1");
54 GraphExport::Create(*n2, "n2");
55 GraphExport::Create(*u1, "u1");
56 GraphExport::Create(*b1, "b1");
57 GraphExport::Create(*b2, "b2");
58 GraphExport::Create(*b3, "b3");
59 GraphExport::Create(*b4, "b4");
60
61 // jlm::rvsdg::view(graph.GetRootRegion(), stdout);
62
63 // Act
65 cne.Run(rvsdgModule, statisticsCollector);
66 // jlm::rvsdg::view(graph.GetRootRegion(), stdout);
67
68 // Assert
69 EXPECT_EQ(graph.GetRootRegion().result(0)->origin(), graph.GetRootRegion().result(1)->origin());
70 EXPECT_EQ(graph.GetRootRegion().result(3)->origin(), graph.GetRootRegion().result(4)->origin());
71 EXPECT_EQ(graph.GetRootRegion().result(5)->origin(), graph.GetRootRegion().result(6)->origin());
72}
73
74TEST(CommonNodeEliminationTests, test_gamma)
75{
76 using namespace jlm::rvsdg;
77
78 // Arrange
79 auto vt = TestType::createValueType();
80 auto ct = ControlType::Create(2);
81
82 LlvmRvsdgModule rvsdgModule(util::FilePath(""), "", "");
83 auto & graph = rvsdgModule.Rvsdg();
84
85 auto c = &GraphImport::Create(graph, ct, "c");
86 auto ix = &GraphImport::Create(graph, vt, "x");
87 auto iy = &GraphImport::Create(graph, vt, "y");
88 auto iz = &GraphImport::Create(graph, vt, "z");
89
90 auto u1 = TestOperation::createNode(&graph.GetRootRegion(), { ix }, { vt })->output(0);
91 auto u2 = TestOperation::createNode(&graph.GetRootRegion(), { ix }, { vt })->output(0);
92
93 auto gamma = GammaNode::create(c, 2);
94
95 auto ev1 = gamma->AddEntryVar(u1);
96 auto ev2 = gamma->AddEntryVar(u2);
97 auto ev3 = gamma->AddEntryVar(iy);
98 auto ev4 = gamma->AddEntryVar(iz);
99 auto ev5 = gamma->AddEntryVar(iz);
100
101 auto n1 = TestOperation::createNode(gamma->subregion(0), {}, { vt })->output(0);
102 auto n2 = TestOperation::createNode(gamma->subregion(0), {}, { vt })->output(0);
103 auto n3 = TestOperation::createNode(gamma->subregion(0), {}, { vt })->output(0);
104
105 gamma->AddExitVar({ ev1.branchArgument[0], ev1.branchArgument[1] });
106 gamma->AddExitVar({ ev2.branchArgument[0], ev2.branchArgument[1] });
107 gamma->AddExitVar({ ev3.branchArgument[0], ev3.branchArgument[1] });
108 gamma->AddExitVar({ n1, ev3.branchArgument[1] });
109 gamma->AddExitVar({ n2, ev3.branchArgument[1] });
110 gamma->AddExitVar({ n3, ev3.branchArgument[1] });
111 gamma->AddExitVar({ ev5.branchArgument[0], ev4.branchArgument[1] });
112
113 auto & ex1 = GraphExport::Create(*gamma->output(0), "x1");
114 auto & ex2 = GraphExport::Create(*gamma->output(1), "x2");
115 auto & ex3 = GraphExport::Create(*gamma->output(2), "x3");
116
117 // jlm::rvsdg::view(graph.GetRootRegion(), stdout);
118
119 // Act
121 cne.Run(rvsdgModule, statisticsCollector);
122 // jlm::rvsdg::view(graph.GetRootRegion(), stdout);
123
124 // Assert
125 // We expect that the gamma node has been pruned
126 EXPECT_FALSE(Region::containsNodeType<GammaNode>(graph.GetRootRegion(), false));
127
128 EXPECT_TRUE(graph.GetRootRegion().numNodes() == 1);
129 auto & node = *graph.GetRootRegion().Nodes().begin();
130
131 EXPECT_EQ(ex1.origin(), node.output(0));
132 EXPECT_EQ(ex2.origin(), node.output(0));
133 EXPECT_EQ(ex3.origin(), iy);
134}
135
136TEST(CommonNodeEliminationTests, test_gamma_congruent_exit_vars)
137{
138 using namespace jlm::rvsdg;
139
163 // Arrange
164 auto vt = TestType::createValueType();
165 auto ct = ControlType::Create(2);
166
167 LlvmRvsdgModule rvsdgModule(util::FilePath(""), "", "");
168 auto & graph = rvsdgModule.Rvsdg();
169
170 auto importPredicate = &GraphImport::Create(graph, ct, "c");
171 auto importA = &GraphImport::Create(graph, vt, "a");
172 auto importB = &GraphImport::Create(graph, vt, "b");
173
174 auto gamma = GammaNode::create(importPredicate, 2);
175
176 auto entryVarA = gamma->AddEntryVar(importA);
177 auto entryVarB = gamma->AddEntryVar(importB);
178
179 // Create invariant exit variables that simply copy the inputs
180 auto exitVarA = gamma->AddExitVar({ entryVarA.branchArgument[0], entryVarA.branchArgument[1] });
181 auto exitVarB = gamma->AddExitVar({ entryVarB.branchArgument[0], entryVarB.branchArgument[1] });
182
183 // Create exit variables that mix between different inputs
184 auto exitVarX = gamma->AddExitVar({ entryVarA.branchArgument[0], entryVarB.branchArgument[1] });
185 auto exitVarY = gamma->AddExitVar({ entryVarA.branchArgument[0], entryVarB.branchArgument[1] });
186 auto exitVarZ = gamma->AddExitVar({ entryVarB.branchArgument[0], entryVarA.branchArgument[1] });
187
188 auto & exportA = GraphExport::Create(*exitVarA.output, "a2");
189 auto & exportB = GraphExport::Create(*exitVarB.output, "b2");
190 auto & exportX = GraphExport::Create(*exitVarX.output, "x");
191 auto & exportY = GraphExport::Create(*exitVarY.output, "y");
192 auto & exportZ = GraphExport::Create(*exitVarZ.output, "z");
193
194 // Act
196 cne.Run(rvsdgModule, statisticsCollector);
197
198 // Assert
199
200 // The invariant gamma outputs have been routed around the gamma
201 EXPECT_EQ(exportA.origin(), importA);
202 EXPECT_EQ(exportB.origin(), importB);
203
204 // "x" and "y" are identical, so they should have a single origin (exit var X)
205 EXPECT_EQ(exportX.origin(), exitVarX.output);
206 EXPECT_EQ(exportY.origin(), exitVarX.output);
207 EXPECT_EQ(exitVarY.output->nusers(), 0u);
208
209 // "z" should remain untouched
210 EXPECT_EQ(exportZ.origin(), exitVarZ.output);
211}
212
213TEST(CommonNodeEliminationTests, test_theta)
214{
215 using namespace jlm::rvsdg;
216
217 // Arrange
218 auto vt = TestType::createValueType();
219 auto ct = ControlType::Create(2);
220
221 LlvmRvsdgModule rvsdgModule(util::FilePath(""), "", "");
222 auto & graph = rvsdgModule.Rvsdg();
223
224 auto c = &GraphImport::Create(graph, ct, "c");
225 auto x = &GraphImport::Create(graph, vt, "x");
226
227 auto theta = ThetaNode::create(&graph.GetRootRegion());
228 auto region = theta->subregion();
229
230 auto lv1 = theta->AddLoopVar(c);
231 auto lv2 = theta->AddLoopVar(x);
232 auto lv3 = theta->AddLoopVar(x);
233 auto lv4 = theta->AddLoopVar(x);
234
235 auto u1 = TestOperation::createNode(region, { lv2.pre }, { vt })->output(0);
236 auto u2 = TestOperation::createNode(region, { lv3.pre }, { vt })->output(0);
237 auto b1 = TestOperation::createNode(region, { lv3.pre, lv4.pre }, { vt })->output(0);
238
239 lv2.post->divert_to(u1);
240 lv3.post->divert_to(u2);
241 lv4.post->divert_to(b1);
242
243 theta->set_predicate(lv1.pre);
244
245 auto & elv2 = GraphExport::Create(*lv2.output, "lv2");
246 auto & elv3 = GraphExport::Create(*lv3.output, "lv3");
247 auto & elv4 = GraphExport::Create(*lv4.output, "lv4");
248
249 // jlm::rvsdg::view(graph.GetRootRegion(), stdout);
250
251 // Act
253 cne.Run(rvsdgModule, statisticsCollector);
254 // jlm::rvsdg::view(graph.GetRootRegion(), stdout);
255
256 // Assert
257 EXPECT_EQ(lv2.post->origin(), lv3.post->origin());
258 EXPECT_EQ(lv4.post->origin(), lv4.post->origin());
259 EXPECT_EQ(elv2.origin(), elv3.origin());
260 EXPECT_EQ(elv4.origin(), lv4.output);
261}
262
263TEST(CommonNodeEliminationTests, test_theta2)
264{
265 using namespace jlm::rvsdg;
266
267 auto vt = TestType::createValueType();
268 auto ct = ControlType::Create(2);
269
270 LlvmRvsdgModule rvsdgModule(util::FilePath(""), "", "");
271 auto & graph = rvsdgModule.Rvsdg();
272
273 auto c = &GraphImport::Create(graph, ct, "c");
274 auto x = &GraphImport::Create(graph, vt, "x");
275
276 auto theta = ThetaNode::create(&graph.GetRootRegion());
277 auto region = theta->subregion();
278
279 auto lv1 = theta->AddLoopVar(c);
280 auto lv2 = theta->AddLoopVar(x);
281 auto lv3 = theta->AddLoopVar(x);
282
283 auto u1 = TestOperation::createNode(region, { lv2.pre }, { vt })->output(0);
284 auto u2 = TestOperation::createNode(region, { lv3.pre }, { vt })->output(0);
285 auto b1 = TestOperation::createNode(region, { u2, u2 }, { vt })->output(0);
286
287 lv2.post->divert_to(u1);
288 lv3.post->divert_to(b1);
289
290 theta->set_predicate(lv1.pre);
291
292 GraphExport::Create(*lv2.output, "lv2");
293 GraphExport::Create(*lv3.output, "lv3");
294
295 // jlm::rvsdg::view(graph, stdout);
296
297 // Act
299 cne.Run(rvsdgModule, statisticsCollector);
300 // jlm::rvsdg::view(graph, stdout);
301
302 // Assert
303 EXPECT_EQ(lv2.post->origin(), u1);
304 EXPECT_NE(lv2.pre->nusers(), 0u);
305 EXPECT_NE(lv3.pre->nusers(), 0u);
306}
307
308TEST(CommonNodeEliminationTests, test_theta3)
309{
310 using namespace jlm::rvsdg;
311
312 auto vt = TestType::createValueType();
313 auto ct = ControlType::Create(2);
314
315 LlvmRvsdgModule rvsdgModule(util::FilePath(""), "", "");
316 auto & graph = rvsdgModule.Rvsdg();
317
318 auto c = &GraphImport::Create(graph, ct, "c");
319 auto x = &GraphImport::Create(graph, vt, "x");
320
321 auto theta1 = ThetaNode::create(&graph.GetRootRegion());
322 auto r1 = theta1->subregion();
323
324 auto lv1 = theta1->AddLoopVar(c);
325 auto lv2 = theta1->AddLoopVar(x);
326 auto lv3 = theta1->AddLoopVar(x);
327 auto lv4 = theta1->AddLoopVar(x);
328
329 auto theta2 = ThetaNode::create(r1);
330 auto p1 = theta2->AddLoopVar(lv1.pre);
331 auto p2 = theta2->AddLoopVar(lv2.pre);
332 auto p3 = theta2->AddLoopVar(lv3.pre);
333 auto p4 = theta2->AddLoopVar(lv4.pre);
334 theta2->set_predicate(p1.pre);
335
336 auto u1 = TestOperation::createNode(r1, { p2.output }, { vt });
337 auto b1 = TestOperation::createNode(r1, { p3.output, p3.output }, { vt });
338 TestOperation::createNode(r1, { p4.output }, { vt });
339
340 lv2.post->divert_to(u1->output(0));
341 lv3.post->divert_to(b1->output(0));
342 lv4.post->divert_to(u1->output(0));
343
344 theta1->set_predicate(lv1.pre);
345
346 auto & elv2 = GraphExport::Create(*lv2.output, "lv2");
347 auto & elv3 = GraphExport::Create(*lv3.output, "lv3");
348 auto & elv4 = GraphExport::Create(*lv4.output, "lv4");
349
350 // jlm::rvsdg::view(graph, stdout);
351
352 // Act
354 cne.Run(rvsdgModule, statisticsCollector);
355 // jlm::rvsdg::view(graph, stdout);
356
357 // Assert
358 EXPECT_EQ(elv2.origin(), lv2.output);
359 EXPECT_EQ(elv3.origin(), lv3.output);
360 EXPECT_EQ(elv4.origin(), lv2.output);
361
362 EXPECT_EQ(lv1.post->origin(), lv1.pre);
363 EXPECT_EQ(lv2.post->origin(), u1->output(0));
364 EXPECT_EQ(lv3.post->origin(), b1->output(0));
365 EXPECT_EQ(lv4.post->origin(), u1->output(0));
366
367 // theta2 should have been removed
368 EXPECT_FALSE(Region::containsNodeType<rvsdg::ThetaNode>(*theta1->subregion(), false));
369
370 EXPECT_EQ(u1->input(0)->origin(), lv2.pre);
371 EXPECT_EQ(b1->input(0)->origin(), lv3.pre);
372 EXPECT_EQ(b1->input(1)->origin(), lv3.pre);
373 EXPECT_EQ(lv4.pre->nusers(), 0u);
374
375 EXPECT_EQ(lv1.input->origin(), c);
376 EXPECT_EQ(lv2.input->origin(), x);
377 EXPECT_EQ(lv3.input->origin(), x);
378 EXPECT_EQ(lv4.input->origin(), x);
379}
380
381TEST(CommonNodeEliminationTests, test_theta4)
382{
383 using namespace jlm::rvsdg;
384
385 // Arrange
386 auto vt = TestType::createValueType();
387 auto ct = ControlType::Create(2);
388
389 LlvmRvsdgModule rvsdgModule(util::FilePath(""), "", "");
390 auto & graph = rvsdgModule.Rvsdg();
391
392 auto c = &GraphImport::Create(graph, ct, "c");
393 auto x = &GraphImport::Create(graph, vt, "x");
394 auto y = &GraphImport::Create(graph, vt, "y");
395
396 auto theta = ThetaNode::create(&graph.GetRootRegion());
397 auto region = theta->subregion();
398
399 auto lv1 = theta->AddLoopVar(c);
400 auto lv2 = theta->AddLoopVar(x);
401 auto lv3 = theta->AddLoopVar(x);
402 auto lv4 = theta->AddLoopVar(y);
403 auto lv5 = theta->AddLoopVar(y);
404 auto lv6 = theta->AddLoopVar(x);
405 auto lv7 = theta->AddLoopVar(x);
406
407 auto u1 = TestOperation::createNode(region, { lv2.pre }, { vt });
408 auto b1 = TestOperation::createNode(region, { lv3.pre, lv3.pre }, { vt });
409
410 lv2.post->divert_to(lv4.pre);
411 lv3.post->divert_to(lv5.pre);
412 lv4.post->divert_to(u1->output(0));
413 lv5.post->divert_to(b1->output(0));
414
415 theta->set_predicate(lv1.pre);
416
417 auto & ex1 = GraphExport::Create(*theta->output(1), "lv2");
418 auto & ex2 = GraphExport::Create(*theta->output(2), "lv3");
419 GraphExport::Create(*theta->output(3), "lv4");
420 GraphExport::Create(*theta->output(4), "lv5");
421
422 // jlm::rvsdg::view(graph, stdout);
423
424 // Act
426 cne.Run(rvsdgModule, statisticsCollector);
427 // jlm::rvsdg::view(graph, stdout);
428
429 // Assert
430 EXPECT_NE(ex1.origin(), ex2.origin());
431 EXPECT_NE(lv2.pre->nusers(), 0u);
432 EXPECT_NE(lv3.pre->nusers(), 0u);
433 EXPECT_EQ(lv6.post->origin(), lv7.post->origin());
434}
435
436TEST(CommonNodeEliminationTests, test_theta5)
437{
438 using namespace jlm::rvsdg;
439
440 // Arrange
441 auto vt = TestType::createValueType();
442 auto ct = ControlType::Create(2);
443
444 LlvmRvsdgModule rvsdgModule(util::FilePath(""), "", "");
445 auto & graph = rvsdgModule.Rvsdg();
446
447 auto c = &GraphImport::Create(graph, ct, "c");
448 auto x = &GraphImport::Create(graph, vt, "x");
449 auto y = &GraphImport::Create(graph, vt, "y");
450
451 auto theta = ThetaNode::create(&graph.GetRootRegion());
452 auto lv0 = theta->AddLoopVar(c);
453 auto lv1 = theta->AddLoopVar(x);
454 auto lv2 = theta->AddLoopVar(x);
455 auto lv3 = theta->AddLoopVar(y);
456 auto lv4 = theta->AddLoopVar(y);
457
458 lv1.post->divert_to(lv3.pre);
459 lv2.post->divert_to(lv4.pre);
460
461 theta->set_predicate(lv0.pre);
462
463 auto & ex1 = GraphExport::Create(*theta->output(1), "lv1");
464 auto & ex2 = GraphExport::Create(*theta->output(2), "lv2");
465 auto & ex3 = GraphExport::Create(*theta->output(3), "lv3");
466 auto & ex4 = GraphExport::Create(*theta->output(4), "lv4");
467
468 // jlm::rvsdg::view(graph, stdout);
469
470 // Act
472 cne.Run(rvsdgModule, statisticsCollector);
473 // jlm::rvsdg::view(graph, stdout);
474
475 // Arrange
476 // We expect the theta node to be pruned
477 EXPECT_FALSE(Region::containsNodeType<rvsdg::ThetaNode>(graph.GetRootRegion(), true));
478
479 EXPECT_EQ(ex1.origin(), y);
480 EXPECT_EQ(ex1.origin(), ex2.origin());
481 EXPECT_EQ(ex2.origin(), ex3.origin());
482 EXPECT_EQ(ex3.origin(), ex4.origin());
483}
484
485TEST(CommonNodeEliminationTests, MultipleThetas)
486{
487 using namespace jlm::rvsdg;
488
489 // Arrange
490 const auto valueType = TestType::createValueType();
491
492 LlvmRvsdgModule rvsdgModule(util::FilePath(""), "", "");
493 auto & rvsdg = rvsdgModule.Rvsdg();
494
495 auto & i0 = GraphImport::Create(rvsdg, valueType, "i0");
496
497 // Loop 1
498 auto thetaNode1 = ThetaNode::create(&rvsdg.GetRootRegion());
499 auto loopVariable1 = thetaNode1->AddLoopVar(&i0);
500 auto node1 =
501 TestOperation::createNode(thetaNode1->subregion(), { loopVariable1.pre }, { valueType });
502 loopVariable1.post->divert_to(node1->output(0));
503
504 // Loop 2
505 auto thetaNode2 = ThetaNode::create(&rvsdg.GetRootRegion());
506 auto predicate = &ControlConstantOperation::create(*thetaNode2->subregion(), 2, 1);
507 thetaNode2->set_predicate(predicate);
508 auto loopVariable2 = thetaNode2->AddLoopVar(&i0);
509 auto node2 =
510 TestOperation::createNode(thetaNode1->subregion(), { loopVariable2.pre }, { valueType });
511 loopVariable2.post->divert_to(node2->output(0));
512
513 // Loop 3
514 auto thetaNode3 = ThetaNode::create(&rvsdg.GetRootRegion());
515 auto loopVariable3 = thetaNode3->AddLoopVar(loopVariable1.output);
516 auto loopVariable4 = thetaNode3->AddLoopVar(loopVariable2.output);
517
518 auto & x1 = GraphExport::Create(*loopVariable3.output, "x1");
519 auto & x2 = GraphExport::Create(*loopVariable4.output, "x2");
520
521 view(rvsdg, stdout);
522
523 // Act
524 CommonNodeElimination commonNodeElimination;
525 commonNodeElimination.Run(rvsdgModule, statisticsCollector);
526
527 view(rvsdg, stdout);
528
529 // Assert
530 // The origins from x1 and x2 are ultimately from two different loops with different iteration
531 // counts. They are NOT congruent.
532 EXPECT_NE(x1.origin(), x2.origin());
533}
534
535TEST(CommonNodeEliminationTests, MultipleThetasPassthrough)
536{
537 using namespace jlm::rvsdg;
538
539 // Arrange
540 const auto valueType = TestType::createValueType();
541
542 jlm::llvm::LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
543 auto & rvsdg = rvsdgModule.Rvsdg();
544
545 auto & i0 = GraphImport::Create(rvsdg, valueType, "i0");
546
547 // Loop 1
548 auto thetaNode1 = ThetaNode::create(&rvsdg.GetRootRegion());
549 auto loopVariable1 = thetaNode1->AddLoopVar(&i0);
550
551 // Loop 2
552 auto thetaNode2 = ThetaNode::create(&rvsdg.GetRootRegion());
553 auto predicate = &ControlConstantOperation::create(*thetaNode2->subregion(), 2, 1);
554 thetaNode2->set_predicate(predicate);
555 auto loopVariable2 = thetaNode2->AddLoopVar(&i0);
556
557 // Loop 3
558 auto thetaNode3 = ThetaNode::create(&rvsdg.GetRootRegion());
559 auto loopVariable3 = thetaNode3->AddLoopVar(loopVariable1.output);
560 auto loopVariable4 = thetaNode3->AddLoopVar(loopVariable2.output);
561
562 auto & x1 = GraphExport::Create(*loopVariable3.output, "x1");
563 auto & x2 = GraphExport::Create(*loopVariable4.output, "x2");
564
565 view(rvsdg, stdout);
566
567 // Act
568 CommonNodeElimination commonNodeElimination;
569 commonNodeElimination.Run(rvsdgModule, statisticsCollector);
570
571 view(rvsdg, stdout);
572
573 // Assert
574 // The origins from x1 and x2 are ultimately from two different loops with different iteration
575 // counts, BUT the values in these loops are only passthrough values. Thus, we would expect them
576 // to be congruent.
577 EXPECT_EQ(x1.origin(), x2.origin());
578}
579
580TEST(CommonNodeEliminationTests, test_lambda)
581{
582 using namespace jlm::rvsdg;
583
584 // Arrange
585 auto vt = TestType::createValueType();
586 auto ft = FunctionType::Create({ vt, vt }, { vt });
587
588 LlvmRvsdgModule rvsdgModule(util::FilePath(""), "", "");
589 auto & graph = rvsdgModule.Rvsdg();
590
591 auto x = &GraphImport::Create(graph, vt, "x");
592
593 auto lambda = LambdaNode::Create(
594 graph.GetRootRegion(),
596
597 auto d1 = lambda->AddContextVar(*x).inner;
598 auto d2 = lambda->AddContextVar(*x).inner;
599
600 auto b1 = TestOperation::createNode(lambda->subregion(), { d1, d2 }, { vt })->output(0);
601
602 auto output = lambda->finalize({ b1 });
603
604 GraphExport::Create(*output, "f");
605
606 // jlm::rvsdg::view(graph.GetRootRegion(), stdout);
607
608 // Act
610 cne.Run(rvsdgModule, statisticsCollector);
611 // jlm::rvsdg::view(graph.GetRootRegion(), stdout);
612
613 // Assert
615 EXPECT_EQ(bn1->input(0)->origin(), bn1->input(1)->origin());
616}
617
618TEST(CommonNodeEliminationTests, test_phi)
619{
620 using namespace jlm::rvsdg;
621
622 // Arrange
623 auto vt = TestType::createValueType();
624 auto ft = FunctionType::Create({ vt, vt }, { vt });
625
626 LlvmRvsdgModule rvsdgModule(util::FilePath(""), "", "");
627 auto & graph = rvsdgModule.Rvsdg();
628
629 auto & x = GraphImport::Create(graph, vt, "x");
630
631 PhiBuilder pb;
632 pb.begin(&graph.GetRootRegion());
633 auto region = pb.subregion();
634
635 auto d1 = pb.AddContextVar(x);
636 auto d2 = pb.AddContextVar(x);
637
638 auto r1 = pb.AddFixVar(ft);
639 auto r2 = pb.AddFixVar(ft);
640
641 auto lambda1 =
642 LambdaNode::Create(*region, LlvmLambdaOperation::Create(ft, "f", Linkage::externalLinkage));
643 auto cv1 = lambda1->AddContextVar(*d1.inner).inner;
644 auto f1 = lambda1->finalize({ cv1 });
645
646 auto lambda2 =
647 LambdaNode::Create(*region, LlvmLambdaOperation::Create(ft, "f", Linkage::externalLinkage));
648 auto cv2 = lambda2->AddContextVar(*d2.inner).inner;
649 auto f2 = lambda2->finalize({ cv2 });
650
651 r1.result->divert_to(f1);
652 r2.result->divert_to(f2);
653
654 auto phi = pb.end();
655
656 GraphExport::Create(*phi->output(0), "f1");
657 GraphExport::Create(*phi->output(1), "f2");
658
659 // jlm::rvsdg::view(graph.GetRootRegion(), stdout);
660
661 // Act
663 cne.Run(rvsdgModule, statisticsCollector);
664 // jlm::rvsdg::view(graph.GetRootRegion(), stdout);
665
666 // Assert
667 EXPECT_EQ(
670}
671
672TEST(CommonNodeEliminationTests, EmptyTheta)
673{
674 using namespace jlm::rvsdg;
675
676 // Arrange
677 auto valueType = TestType::createValueType();
678 auto controlType = ControlType::Create(2);
679
680 LlvmRvsdgModule rvsdgModule(util::FilePath(""), "", "");
681 auto & rvsdg = rvsdgModule.Rvsdg();
682
683 auto & i0 = GraphImport::Create(rvsdg, controlType, "i0");
684
685 auto thetaNode = ThetaNode::create(&rvsdg.GetRootRegion());
686 auto lv1 = thetaNode->AddLoopVar(&i0);
687
688 auto node1 = TestOperation::createNode(thetaNode->subregion(), {}, { valueType });
689 auto node2 =
690 TestOperation::createNode(thetaNode->subregion(), { node1->output(0) }, { valueType });
691 auto node3 =
692 TestOperation::createNode(thetaNode->subregion(), { node1->output(0) }, { valueType });
693 auto node4 = TestOperation::createNode(
694 thetaNode->subregion(),
695 { node2->output(0), node3->output(0) },
696 { controlType });
697
698 thetaNode->set_predicate(node4->output(0));
699 lv1.post->divert_to(node4->output(0));
700
701 GraphExport::Create(*lv1.output, "e0");
702
703 view(rvsdg, stdout);
704
705 // Act
706 CommonNodeElimination commonNodeElimination;
707 commonNodeElimination.Run(rvsdgModule, statisticsCollector);
708
709 view(rvsdg, stdout);
710
711 // Assert
712 // We expect that node2 and node3 are unified in the theta subregion
713 EXPECT_EQ(thetaNode->subregion()->numNodes(), 3u);
714}
715
716TEST(CommonNodeEliminationTests, GammaInTheta)
717{
742 using namespace jlm::rvsdg;
743
744 // Arrange
745 const auto valueType = TestType::createValueType();
746
747 LlvmRvsdgModule rvsdgModule(util::FilePath(""), "", "");
748 auto & rvsdg = rvsdgModule.Rvsdg();
749
750 auto & constant10 = BitConstantOperation::create(rvsdg.GetRootRegion(), { 32, 10 });
751
752 auto thetaNode = ThetaNode::create(&rvsdg.GetRootRegion());
753 auto loopVar1 = thetaNode->AddLoopVar(&constant10);
754 auto loopVar2 = thetaNode->AddLoopVar(&constant10);
755 auto & thetaRegion = *thetaNode->subregion();
756
757 auto & control0 = ControlConstantOperation::create(thetaRegion, 2, 0);
758 auto gammaNode = GammaNode::create(&control0, 2);
759 auto entryVar1 = gammaNode->AddEntryVar(loopVar1.pre);
760 auto entryVar2 = gammaNode->AddEntryVar(loopVar2.pre);
761 auto gammaOutput =
762 gammaNode->AddExitVar({ entryVar1.branchArgument[0], entryVar2.branchArgument[1] }).output;
763
764 auto user1 = TestOperation::createNode(&thetaRegion, { gammaOutput }, { BitType::Create(32) });
765
766 auto & constant7 = BitConstantOperation::create(thetaRegion, { 32, 7 });
767 loopVar1.post->divert_to(user1->output(0));
768 loopVar2.post->divert_to(&constant7);
769
770 GraphExport::Create(*loopVar1.output, "e0");
771
772 // Act
773 CommonNodeElimination commonNodeElimination;
774 commonNodeElimination.Run(rvsdgModule, statisticsCollector);
775
776 // Assert
777 const auto & user1Origin = *user1->input(0)->origin();
778 EXPECT_EQ(TryGetOwnerNode<GammaNode>(user1Origin), gammaNode);
779}
780
781TEST(CommonNodeEliminationTests, InvariantThetaInTheta)
782{
832 // Arrange
833 using namespace jlm::rvsdg;
834
835 LlvmRvsdgModule rvsdgModule(util::FilePath(""), "", "");
836 auto & graph = rvsdgModule.Rvsdg();
837
838 auto controlType = ControlType::Create(2);
839
840 auto & zero = *IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 0).output(0);
841
842 auto & theta0 = *ThetaNode::create(&graph.GetRootRegion());
843 auto loopVarX0 = theta0.AddLoopVar(&zero);
844 auto loopVarY0 = theta0.AddLoopVar(&zero);
845
846 // Create the inner theta
847 auto & five = *IntegerConstantOperation::Create(*theta0.subregion(), 32, 5).output(0);
848 auto & theta1 = *ThetaNode::create(theta0.subregion());
849 theta1.AddLoopVar(&five);
850 auto loopVarY1 = theta1.AddLoopVar(loopVarY0.pre);
851 auto & predicate1 = ControlConstantOperation::create(*theta1.subregion(), 2, 0);
852 theta1.set_predicate(&predicate1);
853
854 auto & one = *IntegerConstantOperation::Create(*theta0.subregion(), 32, 1).output(0);
855 auto & plus1Node = IntegerAddOperation::createNode(32, *loopVarX0.pre, one);
856 auto & xPlus1 = *plus1Node.output(0);
857
858 auto & two = *IntegerConstantOperation::Create(*theta0.subregion(), 32, 2).output(0);
859 auto & plus2Node = IntegerAddOperation::createNode(32, *loopVarY1.output, two);
860 auto & yPlus2 = *plus2Node.output(0);
861
862 auto & ten = *IntegerConstantOperation::Create(*theta0.subregion(), 32, 10).output(0);
863 auto & slt = *IntegerSltOperation::createNode(32, xPlus1, ten).output(0);
864 auto & predicate0 = *MatchOperation::CreateNode(slt, { { 1, 1 } }, 0, 2).output(0);
865
866 theta0.set_predicate(&predicate0);
867 loopVarX0.post->divert_to(&xPlus1);
868 loopVarY0.post->divert_to(&yPlus2);
869
870 GraphExport::Create(*loopVarX0.output, "x");
871 GraphExport::Create(*loopVarY0.output, "y");
872
873 // Act
875 cne.Run(rvsdgModule, statisticsCollector);
876
877 // Assert
878
879 // The inner theta should have been pruned.
880 EXPECT_FALSE(Region::containsNodeType<rvsdg::ThetaNode>(*theta0.subregion(), false));
881
882 // The add operations should take the corresponding loop variables as input
883 EXPECT_EQ(plus1Node.input(0)->origin(), loopVarX0.pre);
884 EXPECT_EQ(plus2Node.input(0)->origin(), loopVarY0.pre);
885}
886
887TEST(CommonNodeEliminationTests, InvariantLoopOutputs)
888{
919 // Arrange
920 using namespace jlm::rvsdg;
921
922 LlvmRvsdgModule rvsdgModule(util::FilePath(""), "", "");
923 auto & graph = rvsdgModule.Rvsdg();
924
925 const auto bit32 = BitType::Create(32);
926
927 auto & zero = *IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 0).output(0);
928 auto & undefValue = *UndefValueOperation::Create(graph.GetRootRegion(), bit32);
929
930 auto theta = ThetaNode::create(&graph.GetRootRegion());
931 auto region = theta->subregion();
932
933 auto lvX = theta->AddLoopVar(&undefValue);
934 auto lvY = theta->AddLoopVar(&zero);
935 auto lvZ = theta->AddLoopVar(&undefValue);
936
937 auto & controlGamma = ControlConstantOperation::create(*region, 2, 0);
938 auto gamma = GammaNode::create(&controlGamma, 2);
939
940 auto entryY = gamma->AddEntryVar(lvY.pre);
941 auto & exitY = *gamma->AddExitVar({ entryY.branchArgument[0], entryY.branchArgument[1] }).output;
942
943 lvX.post->divert_to(&exitY);
944 lvY.post->divert_to(&exitY);
945 lvZ.post->divert_to(lvY.pre);
946
947 auto & exportX = GraphExport::Create(*lvX.output, "x");
948 auto & exportY = GraphExport::Create(*lvY.output, "y");
949 auto & exportZ = GraphExport::Create(*lvZ.output, "z");
950
951 // Act
953 cne.Run(rvsdgModule, statisticsCollector);
954
955 // Assert
956 EXPECT_EQ(exportX.origin(), &zero);
957 EXPECT_EQ(exportY.origin(), &zero);
958 EXPECT_EQ(exportZ.origin(), &zero);
959}
960
961}
static const auto vt
Definition PullTests.cpp:16
Common Node Elimination Discovers simple nodes, region arguments and structural node outputs that are...
void Run(rvsdg::RvsdgModule &module, util::StatisticsCollector &statisticsCollector) override
Perform RVSDG transformation.
static rvsdg::Node & createNode(const size_t numBits, rvsdg::Output &operand1, rvsdg::Output &operand2)
static rvsdg::Node & Create(rvsdg::Region &region, IntegerValueRepresentation representation)
static rvsdg::Node & createNode(const size_t numBits, rvsdg::Output &operand1, rvsdg::Output &operand2)
static std::unique_ptr< LlvmLambdaOperation > Create(std::shared_ptr< const jlm::rvsdg::FunctionType > type, std::string name, const jlm::llvm::Linkage &linkage, jlm::llvm::CallingConvention callingConvention, jlm::llvm::AttributeSet attributes)
Definition lambda.hpp:84
static jlm::rvsdg::Output * Create(rvsdg::Region &region, std::shared_ptr< const jlm::rvsdg::Type > type)
NodeOutput * output(size_t index) const noexcept
Definition node.hpp:650
PhiNode * end()
Definition Phi.cpp:270
PhiNode::ContextVar AddContextVar(jlm::rvsdg::Output &origin)
Definition Phi.cpp:251
PhiNode::FixVar AddFixVar(std::shared_ptr< const jlm::rvsdg::Type > type)
Definition Phi.cpp:257
void begin(rvsdg::Region *parent)
Definition Phi.hpp:355
rvsdg::Region * subregion() const noexcept
Definition Phi.hpp:349
Graph & Rvsdg() noexcept
Global memory state passed between functions.
static util::StatisticsCollector statisticsCollector
TEST(ControlOperationsTests, foldConstants)
NodeType * TryGetOwnerNode(const rvsdg::Input &input) noexcept
Checks if this is an input to a node of specified type.
Definition node.hpp:872