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
25
26TEST(CommonNodeEliminationTests, test_simple)
27{
28 using namespace jlm::llvm;
29 using namespace jlm::rvsdg;
30
32
34 auto & graph = rm.Rvsdg();
35
36 auto x = &jlm::rvsdg::GraphImport::Create(graph, vt, "x");
37 auto y = &jlm::rvsdg::GraphImport::Create(graph, vt, "y");
38 auto z = &jlm::rvsdg::GraphImport::Create(graph, vt, "z");
39
40 auto n1 = TestOperation::createNode(&graph.GetRootRegion(), {}, { vt })->output(0);
41 auto n2 = TestOperation::createNode(&graph.GetRootRegion(), {}, { vt })->output(0);
42
43 auto u1 = TestOperation::createNode(&graph.GetRootRegion(), { z }, { vt })->output(0);
44
45 auto b1 = TestOperation::createNode(&graph.GetRootRegion(), { x, y }, { vt })->output(0);
46 auto b2 = TestOperation::createNode(&graph.GetRootRegion(), { x, y }, { vt })->output(0);
47 auto b3 = TestOperation::createNode(&graph.GetRootRegion(), { n1, z }, { vt })->output(0);
48 auto b4 = TestOperation::createNode(&graph.GetRootRegion(), { n2, z }, { vt })->output(0);
49
57
58 // jlm::rvsdg::view(graph.GetRootRegion(), stdout);
60 cne.Run(rm, statisticsCollector);
61 // jlm::rvsdg::view(graph.GetRootRegion(), stdout);
62
63 EXPECT_EQ(graph.GetRootRegion().result(0)->origin(), graph.GetRootRegion().result(1)->origin());
64 EXPECT_EQ(graph.GetRootRegion().result(3)->origin(), graph.GetRootRegion().result(4)->origin());
65 EXPECT_EQ(graph.GetRootRegion().result(5)->origin(), graph.GetRootRegion().result(6)->origin());
66}
67
68TEST(CommonNodeEliminationTests, test_gamma)
69{
70 using namespace jlm::llvm;
71 using namespace jlm::rvsdg;
72
75
77 auto & graph = rm.Rvsdg();
78
79 auto c = &jlm::rvsdg::GraphImport::Create(graph, ct, "c");
80 auto x = &jlm::rvsdg::GraphImport::Create(graph, vt, "x");
81 auto y = &jlm::rvsdg::GraphImport::Create(graph, vt, "y");
82 auto z = &jlm::rvsdg::GraphImport::Create(graph, vt, "z");
83
84 auto u1 = TestOperation::createNode(&graph.GetRootRegion(), { x }, { vt })->output(0);
85 auto u2 = TestOperation::createNode(&graph.GetRootRegion(), { x }, { vt })->output(0);
86
87 auto gamma = jlm::rvsdg::GammaNode::create(c, 2);
88
89 auto ev1 = gamma->AddEntryVar(u1);
90 auto ev2 = gamma->AddEntryVar(u2);
91 auto ev3 = gamma->AddEntryVar(y);
92 auto ev4 = gamma->AddEntryVar(z);
93 auto ev5 = gamma->AddEntryVar(z);
94
95 auto n1 = TestOperation::createNode(gamma->subregion(0), {}, { vt })->output(0);
96 auto n2 = TestOperation::createNode(gamma->subregion(0), {}, { vt })->output(0);
97 auto n3 = TestOperation::createNode(gamma->subregion(0), {}, { vt })->output(0);
98
99 gamma->AddExitVar({ ev1.branchArgument[0], ev1.branchArgument[1] });
100 gamma->AddExitVar({ ev2.branchArgument[0], ev2.branchArgument[1] });
101 gamma->AddExitVar({ ev3.branchArgument[0], ev3.branchArgument[1] });
102 gamma->AddExitVar({ n1, ev3.branchArgument[1] });
103 gamma->AddExitVar({ n2, ev3.branchArgument[1] });
104 gamma->AddExitVar({ n3, ev3.branchArgument[1] });
105 gamma->AddExitVar({ ev5.branchArgument[0], ev4.branchArgument[1] });
106
107 jlm::rvsdg::GraphExport::Create(*gamma->output(0), "x1");
108 jlm::rvsdg::GraphExport::Create(*gamma->output(1), "x2");
109 jlm::rvsdg::GraphExport::Create(*gamma->output(2), "y");
110
111 // jlm::rvsdg::view(graph.GetRootRegion(), stdout);
113 cne.Run(rm, statisticsCollector);
114 // jlm::rvsdg::view(graph.GetRootRegion(), stdout);
115
116 auto subregion0 = gamma->subregion(0);
117 auto subregion1 = gamma->subregion(1);
118 EXPECT_EQ(gamma->input(1)->origin(), gamma->input(2)->origin());
119 EXPECT_EQ(subregion0->result(0)->origin(), subregion0->result(1)->origin());
120 EXPECT_EQ(subregion0->result(3)->origin(), subregion0->result(4)->origin());
121 EXPECT_EQ(subregion0->result(3)->origin(), subregion0->result(5)->origin());
122 EXPECT_EQ(subregion1->result(0)->origin(), subregion1->result(1)->origin());
123 EXPECT_EQ(graph.GetRootRegion().result(0)->origin(), graph.GetRootRegion().result(1)->origin());
124
125 auto argument0 =
126 dynamic_cast<const jlm::rvsdg::RegionArgument *>(subregion0->result(6)->origin());
127 auto argument1 =
128 dynamic_cast<const jlm::rvsdg::RegionArgument *>(subregion1->result(6)->origin());
129 EXPECT_EQ(argument0->input(), argument1->input());
130}
131
132TEST(CommonNodeEliminationTests, test_gamma_congruent_exit_vars)
133{
134 using namespace jlm::llvm;
135 using namespace jlm::rvsdg;
136
160 // Arrange
163
165 auto & graph = rm.Rvsdg();
166
167 auto importPredicate = &jlm::rvsdg::GraphImport::Create(graph, ct, "c");
168 auto importA = &jlm::rvsdg::GraphImport::Create(graph, vt, "a");
169 auto importB = &jlm::rvsdg::GraphImport::Create(graph, vt, "b");
170
171 auto gamma = jlm::rvsdg::GammaNode::create(importPredicate, 2);
172
173 auto entryVarA = gamma->AddEntryVar(importA);
174 auto entryVarB = gamma->AddEntryVar(importB);
175
176 // Create invariant exit variables that simply copy the inputs
177 auto exitVarA = gamma->AddExitVar({ entryVarA.branchArgument[0], entryVarA.branchArgument[1] });
178 auto exitVarB = gamma->AddExitVar({ entryVarB.branchArgument[0], entryVarB.branchArgument[1] });
179
180 // Create exit variables that mix between different inputs
181 auto exitVarX = gamma->AddExitVar({ entryVarA.branchArgument[0], entryVarB.branchArgument[1] });
182 auto exitVarY = gamma->AddExitVar({ entryVarA.branchArgument[0], entryVarB.branchArgument[1] });
183 auto exitVarZ = gamma->AddExitVar({ entryVarB.branchArgument[0], entryVarA.branchArgument[1] });
184
185 auto & exportA = jlm::rvsdg::GraphExport::Create(*exitVarA.output, "a2");
186 auto & exportB = jlm::rvsdg::GraphExport::Create(*exitVarB.output, "b2");
187 auto & exportX = jlm::rvsdg::GraphExport::Create(*exitVarX.output, "x");
188 auto & exportY = jlm::rvsdg::GraphExport::Create(*exitVarY.output, "y");
189 auto & exportZ = jlm::rvsdg::GraphExport::Create(*exitVarZ.output, "z");
190
191 // Act
193 cne.Run(rm, statisticsCollector);
194
195 // Assert
196
197 // The invariant gamma outputs have been routed around the gamma
198 EXPECT_EQ(exportA.origin(), importA);
199 EXPECT_EQ(exportB.origin(), importB);
200
201 // "x" and "y" are identical, so they should have a single origin (exit var X)
202 EXPECT_EQ(exportX.origin(), exitVarX.output);
203 EXPECT_EQ(exportY.origin(), exitVarX.output);
204 EXPECT_EQ(exitVarY.output->nusers(), 0u);
205
206 // "z" should remain untouced
207 EXPECT_EQ(exportZ.origin(), exitVarZ.output);
208}
209
210TEST(CommonNodeEliminationTests, test_theta)
211{
212 using namespace jlm::llvm;
213 using namespace jlm::rvsdg;
214
217
219 auto & graph = rm.Rvsdg();
220
221 auto c = &jlm::rvsdg::GraphImport::Create(graph, ct, "c");
222 auto x = &jlm::rvsdg::GraphImport::Create(graph, vt, "x");
223
224 auto theta = jlm::rvsdg::ThetaNode::create(&graph.GetRootRegion());
225 auto region = theta->subregion();
226
227 auto lv1 = theta->AddLoopVar(c);
228 auto lv2 = theta->AddLoopVar(x);
229 auto lv3 = theta->AddLoopVar(x);
230 auto lv4 = theta->AddLoopVar(x);
231
232 auto u1 = TestOperation::createNode(region, { lv2.pre }, { vt })->output(0);
233 auto u2 = TestOperation::createNode(region, { lv3.pre }, { vt })->output(0);
234 auto b1 = TestOperation::createNode(region, { lv3.pre, lv4.pre }, { vt })->output(0);
235
236 lv2.post->divert_to(u1);
237 lv3.post->divert_to(u2);
238 lv4.post->divert_to(b1);
239
240 theta->set_predicate(lv1.pre);
241
242 jlm::rvsdg::GraphExport::Create(*lv2.output, "lv2");
243 jlm::rvsdg::GraphExport::Create(*lv3.output, "lv3");
244 jlm::rvsdg::GraphExport::Create(*lv4.output, "lv4");
245
246 // jlm::rvsdg::view(graph.GetRootRegion(), stdout);
248 cne.Run(rm, statisticsCollector);
249 // jlm::rvsdg::view(graph.GetRootRegion(), stdout);
250
254 EXPECT_EQ(un1->input(0)->origin(), un2->input(0)->origin());
255 EXPECT_EQ(bn1->input(0)->origin(), un1->input(0)->origin());
256 EXPECT_EQ(bn1->input(1)->origin(), region->argument(3));
257 EXPECT_EQ(region->result(2)->origin(), region->result(3)->origin());
258 EXPECT_EQ(graph.GetRootRegion().result(0)->origin(), graph.GetRootRegion().result(1)->origin());
259}
260
261TEST(CommonNodeEliminationTests, test_theta2)
262{
263 using namespace jlm::llvm;
264 using namespace jlm::rvsdg;
265
268
270 auto & graph = rm.Rvsdg();
271
272 auto c = &jlm::rvsdg::GraphImport::Create(graph, ct, "c");
273 auto x = &jlm::rvsdg::GraphImport::Create(graph, vt, "x");
274
275 auto theta = jlm::rvsdg::ThetaNode::create(&graph.GetRootRegion());
276 auto region = theta->subregion();
277
278 auto lv1 = theta->AddLoopVar(c);
279 auto lv2 = theta->AddLoopVar(x);
280 auto lv3 = theta->AddLoopVar(x);
281
282 auto u1 = TestOperation::createNode(region, { lv2.pre }, { vt })->output(0);
283 auto u2 = TestOperation::createNode(region, { lv3.pre }, { vt })->output(0);
284 auto b1 = TestOperation::createNode(region, { u2, u2 }, { vt })->output(0);
285
286 lv2.post->divert_to(u1);
287 lv3.post->divert_to(b1);
288
289 theta->set_predicate(lv1.pre);
290
291 jlm::rvsdg::GraphExport::Create(*lv2.output, "lv2");
292 jlm::rvsdg::GraphExport::Create(*lv3.output, "lv3");
293
294 // jlm::rvsdg::view(graph, stdout);
296 cne.Run(rm, statisticsCollector);
297 // jlm::rvsdg::view(graph, stdout);
298
299 EXPECT_EQ(lv2.post->origin(), u1);
300 EXPECT_NE(lv2.pre->nusers(), 0u);
301 EXPECT_NE(lv3.pre->nusers(), 0u);
302}
303
304TEST(CommonNodeEliminationTests, test_theta3)
305{
306 using namespace jlm::llvm;
307 using namespace jlm::rvsdg;
308
311
313 auto & graph = rm.Rvsdg();
314
315 auto c = &jlm::rvsdg::GraphImport::Create(graph, ct, "c");
316 auto x = &jlm::rvsdg::GraphImport::Create(graph, vt, "x");
317
318 auto theta1 = jlm::rvsdg::ThetaNode::create(&graph.GetRootRegion());
319 auto r1 = theta1->subregion();
320
321 auto lv1 = theta1->AddLoopVar(c);
322 auto lv2 = theta1->AddLoopVar(x);
323 auto lv3 = theta1->AddLoopVar(x);
324 auto lv4 = theta1->AddLoopVar(x);
325
326 auto theta2 = jlm::rvsdg::ThetaNode::create(r1);
327 auto r2 = theta2->subregion();
328 auto p = theta2->AddLoopVar(lv1.pre);
329 auto p2 = theta2->AddLoopVar(lv2.pre);
330 auto p3 = theta2->AddLoopVar(lv3.pre);
331 auto p4 = theta2->AddLoopVar(lv4.pre);
332 theta2->set_predicate(p.pre);
333
334 auto u1 = TestOperation::createNode(r1, { p2.output }, { vt });
335 auto b1 = TestOperation::createNode(r1, { p3.output, p3.output }, { vt });
336 auto u2 = TestOperation::createNode(r1, { p4.output }, { vt });
337
338 lv2.post->divert_to(u1->output(0));
339 lv3.post->divert_to(b1->output(0));
340 lv4.post->divert_to(u1->output(0));
341
342 theta1->set_predicate(lv1.pre);
343
344 jlm::rvsdg::GraphExport::Create(*lv2.output, "lv2");
345 jlm::rvsdg::GraphExport::Create(*lv3.output, "lv3");
346 jlm::rvsdg::GraphExport::Create(*lv4.output, "lv4");
347
348 // jlm::rvsdg::view(graph, stdout);
350 cne.Run(rm, statisticsCollector);
351 // jlm::rvsdg::view(graph, stdout);
352
353 EXPECT_EQ(r1->result(2)->origin(), r1->result(4)->origin());
354 EXPECT_EQ(u1->input(0)->origin(), u2->input(0)->origin());
355 EXPECT_EQ(r2->result(2)->origin(), r2->result(4)->origin());
356 EXPECT_EQ(theta2->input(1)->origin(), theta2->input(3)->origin());
357 EXPECT_NE(r1->result(3)->origin(), r1->result(4)->origin());
358 EXPECT_NE(r2->result(3)->origin(), r2->result(4)->origin());
359}
360
361TEST(CommonNodeEliminationTests, test_theta4)
362{
363 using namespace jlm::llvm;
364 using namespace jlm::rvsdg;
365
368
370 auto & graph = rm.Rvsdg();
371
372 auto c = &jlm::rvsdg::GraphImport::Create(graph, ct, "c");
373 auto x = &jlm::rvsdg::GraphImport::Create(graph, vt, "x");
374 auto y = &jlm::rvsdg::GraphImport::Create(graph, vt, "y");
375
376 auto theta = jlm::rvsdg::ThetaNode::create(&graph.GetRootRegion());
377 auto region = theta->subregion();
378
379 auto lv1 = theta->AddLoopVar(c);
380 auto lv2 = theta->AddLoopVar(x);
381 auto lv3 = theta->AddLoopVar(x);
382 auto lv4 = theta->AddLoopVar(y);
383 auto lv5 = theta->AddLoopVar(y);
384 auto lv6 = theta->AddLoopVar(x);
385 auto lv7 = theta->AddLoopVar(x);
386
387 auto u1 = TestOperation::createNode(region, { lv2.pre }, { vt });
388 auto b1 = TestOperation::createNode(region, { lv3.pre, lv3.pre }, { vt });
389
390 lv2.post->divert_to(lv4.pre);
391 lv3.post->divert_to(lv5.pre);
392 lv4.post->divert_to(u1->output(0));
393 lv5.post->divert_to(b1->output(0));
394
395 theta->set_predicate(lv1.pre);
396
397 auto & ex1 = jlm::rvsdg::GraphExport::Create(*theta->output(1), "lv2");
398 auto & ex2 = jlm::rvsdg::GraphExport::Create(*theta->output(2), "lv3");
399 jlm::rvsdg::GraphExport::Create(*theta->output(3), "lv4");
400 jlm::rvsdg::GraphExport::Create(*theta->output(4), "lv5");
401
402 // jlm::rvsdg::view(graph, stdout);
404 cne.Run(rm, statisticsCollector);
405 // jlm::rvsdg::view(graph, stdout);
406
407 EXPECT_NE(ex1.origin(), ex2.origin());
408 EXPECT_NE(lv2.pre->nusers(), 0u);
409 EXPECT_NE(lv3.pre->nusers(), 0u);
410 EXPECT_EQ(lv6.post->origin(), lv7.post->origin());
411}
412
413TEST(CommonNodeEliminationTests, test_theta5)
414{
415 using namespace jlm::llvm;
416
419
420 LlvmRvsdgModule rm(jlm::util::FilePath(""), "", "");
421 auto & graph = rm.Rvsdg();
422
423 auto c = &jlm::rvsdg::GraphImport::Create(graph, ct, "c");
424 auto x = &jlm::rvsdg::GraphImport::Create(graph, vt, "x");
425 auto y = &jlm::rvsdg::GraphImport::Create(graph, vt, "y");
426
427 auto theta = jlm::rvsdg::ThetaNode::create(&graph.GetRootRegion());
428 auto region = theta->subregion();
429
430 auto lv0 = theta->AddLoopVar(c);
431 auto lv1 = theta->AddLoopVar(x);
432 auto lv2 = theta->AddLoopVar(x);
433 auto lv3 = theta->AddLoopVar(y);
434 auto lv4 = theta->AddLoopVar(y);
435
436 lv1.post->divert_to(lv3.pre);
437 lv2.post->divert_to(lv4.pre);
438
439 theta->set_predicate(lv0.pre);
440
441 auto & ex1 = jlm::rvsdg::GraphExport::Create(*theta->output(1), "lv1");
442 auto & ex2 = jlm::rvsdg::GraphExport::Create(*theta->output(2), "lv2");
443 auto & ex3 = jlm::rvsdg::GraphExport::Create(*theta->output(3), "lv3");
444 auto & ex4 = jlm::rvsdg::GraphExport::Create(*theta->output(4), "lv4");
445
446 // jlm::rvsdg::view(graph, stdout);
448 cne.Run(rm, statisticsCollector);
449 // jlm::rvsdg::view(graph, stdout);
450
451 EXPECT_EQ(ex1.origin(), ex2.origin());
452 EXPECT_EQ(ex3.origin(), ex4.origin());
453 EXPECT_EQ(region->result(4)->origin(), region->result(5)->origin());
454 EXPECT_EQ(region->result(2)->origin(), region->result(3)->origin());
455}
456
457TEST(CommonNodeEliminationTests, MultipleThetas)
458{
459 using namespace jlm::llvm;
460 using namespace jlm::rvsdg;
461
462 // Arrange
463 const auto valueType = TestType::createValueType();
464
465 jlm::llvm::LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
466 auto & rvsdg = rvsdgModule.Rvsdg();
467
468 auto & i0 = jlm::rvsdg::GraphImport::Create(rvsdg, valueType, "i0");
469
470 // Loop 1
471 auto thetaNode1 = ThetaNode::create(&rvsdg.GetRootRegion());
472 auto loopVariable1 = thetaNode1->AddLoopVar(&i0);
473 auto node1 =
474 TestOperation::createNode(thetaNode1->subregion(), { loopVariable1.pre }, { valueType });
475 loopVariable1.post->divert_to(node1->output(0));
476
477 // Loop 2
478 auto thetaNode2 = ThetaNode::create(&rvsdg.GetRootRegion());
479 auto predicate = &ControlConstantOperation::create(*thetaNode2->subregion(), 2, 1);
480 thetaNode2->set_predicate(predicate);
481 auto loopVariable2 = thetaNode2->AddLoopVar(&i0);
482 auto node2 =
483 TestOperation::createNode(thetaNode1->subregion(), { loopVariable2.pre }, { valueType });
484 loopVariable2.post->divert_to(node2->output(0));
485
486 // Loop 3
487 auto thetaNode3 = ThetaNode::create(&rvsdg.GetRootRegion());
488 auto loopVariable3 = thetaNode3->AddLoopVar(loopVariable1.output);
489 auto loopVariable4 = thetaNode3->AddLoopVar(loopVariable2.output);
490
491 auto & x1 = jlm::rvsdg::GraphExport::Create(*loopVariable3.output, "x1");
492 auto & x2 = jlm::rvsdg::GraphExport::Create(*loopVariable4.output, "x2");
493
494 view(rvsdg, stdout);
495
496 // Act
497 CommonNodeElimination commonNodeElimination;
498 commonNodeElimination.Run(rvsdgModule, statisticsCollector);
499
500 view(rvsdg, stdout);
501
502 // Assert
503 // The origins from x1 and x2 are ultimately from two different loops with different iteration
504 // counts. They are NOT congruent.
505 EXPECT_NE(x1.origin(), x2.origin());
506}
507
508TEST(CommonNodeEliminationTests, MultipleThetasPassthrough)
509{
510 using namespace jlm::llvm;
511 using namespace jlm::rvsdg;
512
513 // Arrange
514 const auto valueType = TestType::createValueType();
515
516 jlm::llvm::LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
517 auto & rvsdg = rvsdgModule.Rvsdg();
518
519 auto & i0 = jlm::rvsdg::GraphImport::Create(rvsdg, valueType, "i0");
520
521 // Loop 1
522 auto thetaNode1 = ThetaNode::create(&rvsdg.GetRootRegion());
523 auto loopVariable1 = thetaNode1->AddLoopVar(&i0);
524
525 // Loop 2
526 auto thetaNode2 = ThetaNode::create(&rvsdg.GetRootRegion());
527 auto predicate = &ControlConstantOperation::create(*thetaNode2->subregion(), 2, 1);
528 thetaNode2->set_predicate(predicate);
529 auto loopVariable2 = thetaNode2->AddLoopVar(&i0);
530
531 // Loop 3
532 auto thetaNode3 = ThetaNode::create(&rvsdg.GetRootRegion());
533 auto loopVariable3 = thetaNode3->AddLoopVar(loopVariable1.output);
534 auto loopVariable4 = thetaNode3->AddLoopVar(loopVariable2.output);
535
536 auto & x1 = jlm::rvsdg::GraphExport::Create(*loopVariable3.output, "x1");
537 auto & x2 = jlm::rvsdg::GraphExport::Create(*loopVariable4.output, "x2");
538
539 view(rvsdg, stdout);
540
541 // Act
542 CommonNodeElimination commonNodeElimination;
543 commonNodeElimination.Run(rvsdgModule, statisticsCollector);
544
545 view(rvsdg, stdout);
546
547 // Assert
548 // The origins from x1 and x2 are ultimately from two different loops with different iteration
549 // counts, BUT the values in these loops are only passthrough values. Thus, we would expect them
550 // to be congruent.
551 EXPECT_EQ(x1.origin(), x2.origin());
552}
553
554TEST(CommonNodeEliminationTests, test_lambda)
555{
556 using namespace jlm::llvm;
557 using namespace jlm::rvsdg;
558
560 auto ft = jlm::rvsdg::FunctionType::Create({ vt, vt }, { vt });
561
563 auto & graph = rm.Rvsdg();
564
565 auto x = &jlm::rvsdg::GraphImport::Create(graph, vt, "x");
566
567 auto lambda = jlm::rvsdg::LambdaNode::Create(
568 graph.GetRootRegion(),
569 LlvmLambdaOperation::Create(ft, "f", Linkage::externalLinkage));
570
571 auto d1 = lambda->AddContextVar(*x).inner;
572 auto d2 = lambda->AddContextVar(*x).inner;
573
574 auto b1 = TestOperation::createNode(lambda->subregion(), { d1, d2 }, { vt })->output(0);
575
576 auto output = lambda->finalize({ b1 });
577
579
580 // jlm::rvsdg::view(graph.GetRootRegion(), stdout);
582 cne.Run(rm, statisticsCollector);
583 // jlm::rvsdg::view(graph.GetRootRegion(), stdout);
584
586 EXPECT_EQ(bn1->input(0)->origin(), bn1->input(1)->origin());
587}
588
589TEST(CommonNodeEliminationTests, test_phi)
590{
591 using namespace jlm::llvm;
592
594 auto ft = jlm::rvsdg::FunctionType::Create({ vt, vt }, { vt });
595
596 LlvmRvsdgModule rm(jlm::util::FilePath(""), "", "");
597 auto & graph = rm.Rvsdg();
598
599 auto & x = jlm::rvsdg::GraphImport::Create(graph, vt, "x");
600
602 pb.begin(&graph.GetRootRegion());
603 auto region = pb.subregion();
604
605 auto d1 = pb.AddContextVar(x);
606 auto d2 = pb.AddContextVar(x);
607
608 auto r1 = pb.AddFixVar(ft);
609 auto r2 = pb.AddFixVar(ft);
610
611 auto lambda1 = jlm::rvsdg::LambdaNode::Create(
612 *region,
613 LlvmLambdaOperation::Create(ft, "f", Linkage::externalLinkage));
614 auto cv1 = lambda1->AddContextVar(*d1.inner).inner;
615 auto f1 = lambda1->finalize({ cv1 });
616
617 auto lambda2 = jlm::rvsdg::LambdaNode::Create(
618 *region,
619 LlvmLambdaOperation::Create(ft, "f", Linkage::externalLinkage));
620 auto cv2 = lambda2->AddContextVar(*d2.inner).inner;
621 auto f2 = lambda2->finalize({ cv2 });
622
623 r1.result->divert_to(f1);
624 r2.result->divert_to(f2);
625
626 auto phi = pb.end();
627
628 jlm::rvsdg::GraphExport::Create(*phi->output(0), "f1");
629 jlm::rvsdg::GraphExport::Create(*phi->output(1), "f2");
630
631 // jlm::rvsdg::view(graph.GetRootRegion(), stdout);
633 cne.Run(rm, statisticsCollector);
634 // jlm::rvsdg::view(graph.GetRootRegion(), stdout);
635
636 EXPECT_EQ(
639}
640
641TEST(CommonNodeEliminationTests, EmptyTheta)
642{
643 using namespace jlm::llvm;
644 using namespace jlm::rvsdg;
645
646 // Arrange
647 auto valueType = TestType::createValueType();
648 auto controlType = ControlType::Create(2);
649
650 LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
651 auto & rvsdg = rvsdgModule.Rvsdg();
652
653 auto thetaNode = ThetaNode::create(&rvsdg.GetRootRegion());
654
655 auto node1 = TestOperation::createNode(thetaNode->subregion(), {}, { valueType });
656 auto node2 =
657 TestOperation::createNode(thetaNode->subregion(), { node1->output(0) }, { valueType });
658 auto node3 =
659 TestOperation::createNode(thetaNode->subregion(), { node1->output(0) }, { valueType });
660 auto node4 = TestOperation::createNode(
661 thetaNode->subregion(),
662 { node2->output(0), node3->output(0) },
663 { controlType });
664
665 thetaNode->set_predicate(node4->output(0));
666
667 view(rvsdg, stdout);
668
669 // Act
670 CommonNodeElimination commonNodeElimination;
671 commonNodeElimination.Run(rvsdgModule, statisticsCollector);
672
673 thetaNode->subregion()->prune(false);
674
675 view(rvsdg, stdout);
676
677 // Assert
678 // We expect that node2 and node3 are unified in the theta subregion
679 EXPECT_EQ(thetaNode->subregion()->numNodes(), 3u);
680}
681
682TEST(CommonNodeEliminationTests, GammaInTheta)
683{
708 using namespace jlm::llvm;
709 using namespace jlm::rvsdg;
710
711 // Arrange
712 const auto valueType = TestType::createValueType();
713
714 LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
715 auto & rvsdg = rvsdgModule.Rvsdg();
716
717 auto & constant10 = BitConstantOperation::create(rvsdg.GetRootRegion(), { 32, 10 });
718
719 auto thetaNode = ThetaNode::create(&rvsdg.GetRootRegion());
720 auto loopVar1 = thetaNode->AddLoopVar(&constant10);
721 auto loopVar2 = thetaNode->AddLoopVar(&constant10);
722 auto & thetaRegion = *thetaNode->subregion();
723
724 auto & control0 = ControlConstantOperation::create(thetaRegion, 2, 0);
725 auto gammaNode = GammaNode::create(&control0, 2);
726 auto entryVar1 = gammaNode->AddEntryVar(loopVar1.pre);
727 auto entryVar2 = gammaNode->AddEntryVar(loopVar2.pre);
728 auto gammaOutput =
729 gammaNode->AddExitVar({ entryVar1.branchArgument[0], entryVar2.branchArgument[1] }).output;
730
731 auto user1 = TestOperation::createNode(&thetaRegion, { gammaOutput }, {});
732
733 auto & constant6 = BitConstantOperation::create(thetaRegion, { 32, 6 });
734 auto & constant7 = BitConstantOperation::create(thetaRegion, { 32, 7 });
735 loopVar1.post->divert_to(&constant6);
736 loopVar2.post->divert_to(&constant7);
737
738 // Act
739 CommonNodeElimination commonNodeElimination;
740 commonNodeElimination.Run(rvsdgModule, statisticsCollector);
741
742 // Assert
743 const auto & user1Origin = *user1->input(0)->origin();
744 EXPECT_EQ(TryGetOwnerNode<GammaNode>(user1Origin), gammaNode);
745}
746
747TEST(CommonNodeEliminationTests, InvariantThetaInTheta)
748{
798 // Arrange
799 using namespace jlm::llvm;
800 using namespace jlm::rvsdg;
801
802 LlvmRvsdgModule rm(jlm::util::FilePath(""), "", "");
803 auto & graph = rm.Rvsdg();
804
805 auto controlType = ControlType::Create(2);
806
807 auto & zero = *IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 0).output(0);
808
809 auto & theta0 = *ThetaNode::create(&graph.GetRootRegion());
810 auto loopVarX0 = theta0.AddLoopVar(&zero);
811 auto loopVarY0 = theta0.AddLoopVar(&zero);
812
813 // Create the inner theta
814 auto & five = *IntegerConstantOperation::Create(*theta0.subregion(), 32, 5).output(0);
815 auto & theta1 = *ThetaNode::create(theta0.subregion());
816 auto loopVarZ1 = theta1.AddLoopVar(&five);
817 auto loopVarY1 = theta1.AddLoopVar(loopVarY0.pre);
818 auto & predicate1 = ControlConstantOperation::create(*theta1.subregion(), 2, 0);
819 theta1.set_predicate(&predicate1);
820
821 auto & one = *IntegerConstantOperation::Create(*theta0.subregion(), 32, 1).output(0);
822 auto & plus1Node = IntegerAddOperation::createNode(32, *loopVarX0.pre, one);
823 auto & xPlus1 = *plus1Node.output(0);
824
825 auto & two = *IntegerConstantOperation::Create(*theta0.subregion(), 32, 2).output(0);
826 auto & plus2Node = IntegerAddOperation::createNode(32, *loopVarY1.output, two);
827 auto & yPlus2 = *plus2Node.output(0);
828
829 auto & ten = *IntegerConstantOperation::Create(*theta0.subregion(), 32, 10).output(0);
830 auto & slt = *IntegerSltOperation::createNode(32, xPlus1, ten).output(0);
831 auto & predicate0 = *MatchOperation::CreateNode(slt, { { 1, 1 } }, 0, 2).output(0);
832
833 theta0.set_predicate(&predicate0);
834 loopVarX0.post->divert_to(&xPlus1);
835 loopVarY0.post->divert_to(&yPlus2);
836
837 jlm::rvsdg::GraphExport::Create(*loopVarX0.output, "x");
838 jlm::rvsdg::GraphExport::Create(*loopVarY0.output, "y");
839
840 // Act
842 cne.Run(rm, statisticsCollector);
843
844 // Assert
845
846 // The inner theta's loop varibales should have no users
847 EXPECT_TRUE(loopVarZ1.output->IsDead());
848 EXPECT_TRUE(loopVarY1.output->IsDead());
849
850 // The add operations should take the corresponding loop variables as input
851 EXPECT_EQ(plus1Node.input(0)->origin(), loopVarX0.pre);
852 EXPECT_EQ(plus2Node.input(0)->origin(), loopVarY0.pre);
853}
854
855TEST(CommonNodeEliminationTests, InvariantLoopOutputs)
856{
887 // Arrange
888 using namespace jlm::llvm;
889 using namespace jlm::rvsdg;
890
891 LlvmRvsdgModule rm(jlm::util::FilePath(""), "", "");
892 auto & graph = rm.Rvsdg();
893
894 const auto bit32 = BitType::Create(32);
895
896 auto & zero = *IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 0).output(0);
897 auto & undefValue = *UndefValueOperation::Create(graph.GetRootRegion(), bit32);
898
899 auto theta = ThetaNode::create(&graph.GetRootRegion());
900 auto region = theta->subregion();
901
902 auto lvX = theta->AddLoopVar(&undefValue);
903 auto lvY = theta->AddLoopVar(&zero);
904 auto lvZ = theta->AddLoopVar(&undefValue);
905
906 auto & controlGamma = ControlConstantOperation::create(*region, 2, 0);
907 auto gamma = GammaNode::create(&controlGamma, 2);
908
909 auto entryY = gamma->AddEntryVar(lvY.pre);
910 auto & exitY = *gamma->AddExitVar({ entryY.branchArgument[0], entryY.branchArgument[1] }).output;
911
912 lvX.post->divert_to(&exitY);
913 lvY.post->divert_to(&exitY);
914 lvZ.post->divert_to(lvY.pre);
915
916 auto & exportX = GraphExport::Create(*lvX.output, "x");
917 auto & exportY = GraphExport::Create(*lvY.output, "y");
918 auto & exportZ = GraphExport::Create(*lvZ.output, "z");
919
920 // Act
922 cne.Run(rm, statisticsCollector);
923
924 // Assert
925 EXPECT_EQ(exportX.origin(), &zero);
926 EXPECT_EQ(exportY.origin(), &zero);
927 EXPECT_EQ(exportZ.origin(), &zero);
928}
TEST(CommonNodeEliminationTests, test_simple)
static jlm::util::StatisticsCollector statisticsCollector
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 std::shared_ptr< const ControlType > Create(std::size_t nalternatives)
Instantiates control type.
Definition control.cpp:50
static std::shared_ptr< const FunctionType > Create(std::vector< std::shared_ptr< const jlm::rvsdg::Type > > argumentTypes, std::vector< std::shared_ptr< const jlm::rvsdg::Type > > resultTypes)
static GammaNode * create(jlm::rvsdg::Output *predicate, size_t nalternatives)
Definition gamma.hpp:161
static GraphExport & Create(Output &origin, std::string name)
Definition graph.cpp:62
static GraphImport & Create(Graph &graph, std::shared_ptr< const rvsdg::Type > type, std::string name)
Definition graph.cpp:36
static LambdaNode * Create(rvsdg::Region &parent, std::unique_ptr< LambdaOperation > operation)
Definition lambda.cpp:141
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
Represents the argument of a region.
Definition region.hpp:41
Graph & Rvsdg() noexcept
static std::shared_ptr< const TestType > createValueType()
Definition TestType.cpp:67
static ThetaNode * create(rvsdg::Region *parent)
Definition theta.hpp:73
Global memory state passed between functions.
NodeType * TryGetOwnerNode(const rvsdg::Input &input) noexcept
Checks if this is an input to a node of specified type.
Definition node.hpp:872