Jlm
Loading...
Searching...
No Matches
RegionAwareModRefSummarizerTests.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2020 Nico Reißmann <nico.reissmann@gmail.com>
3 * Copyright 2025 Håvard Krogstie <krogstie.havard@gmail.com>
4 * See COPYING for terms of redistribution.
5 */
6
7#include <gtest/gtest.h>
8
22#include <jlm/rvsdg/view.hpp>
23#include <jlm/util/common.hpp>
25#include <unordered_map>
26
29
30static std::unique_ptr<jlm::llvm::aa::PointsToGraph>
32{
34 return andersen.Analyze(rvsdgModule);
35}
36
37static const char *
38effectToString(ModRefEffect effect)
39{
40 switch (effect)
41 {
42 case ModRefEffect::ModRef:
43 return "ModRef";
44 case ModRefEffect::ModOnly:
45 return "ModOnly";
46 case ModRefEffect::RefOnly:
47 return "RefOnly";
48 case ModRefEffect::NoEffect:
49 return "NoEffect";
50 default:
51 JLM_UNREACHABLE("Unknown effect");
52 }
53}
54
55// Helper for creating a map where all memory nodes are mapped to the same effect
56static std::unordered_map<NodeIndex, ModRefEffect>
57allWithEffect(const jlm::util::HashSet<NodeIndex> & memoryNodes, ModRefEffect effect)
58{
59 std::unordered_map<NodeIndex, ModRefEffect> expectedEffects;
60 for (auto memoryNode : memoryNodes.Items())
61 expectedEffects.emplace(memoryNode, effect);
62 return expectedEffects;
63}
64
65// Helper for comparing HashSets of MemoryNodes without needing explicit constructors
66static bool
68 const jlm::llvm::aa::ModRefSet & receivedMemoryNodes,
69 std::unordered_map<NodeIndex, ModRefEffect> expectedEffects)
70{
71 bool result = true;
72
73 for (auto [memoryNode, modRefEffect] : receivedMemoryNodes.getModRefNodes())
74 {
75 auto it = expectedEffects.find(memoryNode);
76 if (it == expectedEffects.end())
77 {
78 result = false;
79 std::cerr << "ModRefSet contained unexpected node " << memoryNode << " with effect "
80 << effectToString(modRefEffect) << std::endl;
81 continue;
82 }
83
84 if (it->second != modRefEffect)
85 {
86 result = false;
87 std::cerr << "ModRefSet contained " << memoryNode << " with effect "
88 << effectToString(modRefEffect) << " but expected effect "
89 << effectToString(it->second) << std::endl;
90 }
91 expectedEffects.erase(it);
92 }
93
94 // Any remaining expected memory nodes indicate an error
95 for (auto [memoryNode, modRefEffect] : expectedEffects)
96 {
97 result = false;
98 std::cerr << "ModRefSet did not contain node " << memoryNode << " with expected effect "
99 << effectToString(modRefEffect) << std::endl;
100 }
101
102 return result;
103}
104
105TEST(RegionAwareModRefSummarizerTests, TestStore1)
106{
107 /*
108 * Arrange
109 */
110 auto ValidateProvider = [](const jlm::llvm::StoreTest1 & test,
111 const jlm::llvm::aa::ModRefSummary & modRefSummary,
112 const jlm::llvm::aa::PointsToGraph & pointsToGraph)
113 {
114 auto allocaAMemoryNode = pointsToGraph.getNodeForAlloca(*test.alloca_a);
115
116 // Every alloca in the lambda is non-reentrant, so they are left out of the lambda ModRefSet
117 auto & lambdaEntryNodes = modRefSummary.GetLambdaEntryModRef(*test.lambda);
118 ASSERT_TRUE(assertSetContains(lambdaEntryNodes, {}));
119
120 auto & lambdaExitNodes = modRefSummary.GetLambdaExitModRef(*test.lambda);
121 ASSERT_TRUE(assertSetContains(lambdaExitNodes, {}));
122
123 auto storeANode =
126
127 auto & storeANodes = modRefSummary.GetSimpleNodeModRef(*storeANode);
128 ASSERT_TRUE(assertSetContains(storeANodes, { { allocaAMemoryNode, ModRefEffect::ModOnly } }));
129 };
130
132 // jlm::rvsdg::view(test.graph().GetRootRegion(), stdout);
133
134 auto pointsToGraph = RunAndersen(test.module());
135 // std::cout << jlm::llvm::aa::PointsToGraph::dumpDot(*pointsToGraph);
136
137 /*
138 * Act
139 */
140 auto modRefSummary =
142
143 /*
144 * Assert
145 */
146 ValidateProvider(test, *modRefSummary, *pointsToGraph);
147}
148
149TEST(RegionAwareModRefSummarizerTests, TestStore2)
150{
151 /*
152 * Arrange
153 */
154 auto ValidateProvider = [](const jlm::llvm::StoreTest2 & test,
155 const jlm::llvm::aa::ModRefSummary & modRefSummary,
156 const jlm::llvm::aa::PointsToGraph & pointsToGraph)
157 {
158 auto allocaAMemoryNode = pointsToGraph.getNodeForAlloca(*test.alloca_a);
159 auto allocaBMemoryNode = pointsToGraph.getNodeForAlloca(*test.alloca_b);
160 auto allocaPMemoryNode = pointsToGraph.getNodeForAlloca(*test.alloca_p);
161 auto allocaXMemoryNode = pointsToGraph.getNodeForAlloca(*test.alloca_x);
162 auto allocaYMemoryNode = pointsToGraph.getNodeForAlloca(*test.alloca_y);
163
164 jlm::util::HashSet expectedMemoryNodes{ allocaAMemoryNode,
165 allocaBMemoryNode,
166 allocaPMemoryNode,
167 allocaXMemoryNode,
168 allocaYMemoryNode };
169
170 auto & lambdaEntryNodes = modRefSummary.GetLambdaEntryModRef(*test.lambda);
171 ASSERT_TRUE(assertSetContains(lambdaEntryNodes, {}));
172
173 auto & lambdaExitNodes = modRefSummary.GetLambdaExitModRef(*test.lambda);
174 ASSERT_TRUE(assertSetContains(lambdaExitNodes, {}));
175 };
176
178 // jlm::rvsdg::view(test.graph().GetRootRegion(), stdout);
179
180 auto pointsToGraph = RunAndersen(test.module());
181 // std::cout << jlm::llvm::aa::PointsToGraph::dumpDot(*PointsToGraph);
182
183 /*
184 * Act
185 */
186 auto modRefSummary =
188
189 /*
190 * Assert
191 */
192 ValidateProvider(test, *modRefSummary, *pointsToGraph);
193}
194
195TEST(RegionAwareModRefSummarizerTests, TestLoad1)
196{
197 /*
198 * Arrange
199 */
200 auto ValidateProvider = [](const jlm::llvm::LoadTest1 & test,
201 const jlm::llvm::aa::ModRefSummary & modRefSummary,
202 const jlm::llvm::aa::PointsToGraph & pointsToGraph)
203 {
204 auto externalMemoryNode = pointsToGraph.getExternalMemoryNode();
205
206 // Since the function only contains loads, the external memory node is RefOnly
207 auto & lambdaEntryNodes = modRefSummary.GetLambdaEntryModRef(*test.lambda);
208 ASSERT_TRUE(
209 assertSetContains(lambdaEntryNodes, { { externalMemoryNode, ModRefEffect::RefOnly } }));
210
211 auto & lambdaExitNodes = modRefSummary.GetLambdaExitModRef(*test.lambda);
212 ASSERT_TRUE(
213 assertSetContains(lambdaExitNodes, { { externalMemoryNode, ModRefEffect::RefOnly } }));
214
215 // The loads from *p and **p (aka *x) should both only reference external memory nodes
216 auto & loadPModRefSet = modRefSummary.GetSimpleNodeModRef(
217 *jlm::util::assertedCast<jlm::rvsdg::SimpleNode>(test.load_p));
218 ASSERT_TRUE(
219 assertSetContains(loadPModRefSet, { { externalMemoryNode, ModRefEffect::RefOnly } }));
220
221 auto & loadXModRefSet = modRefSummary.GetSimpleNodeModRef(
222 *jlm::util::assertedCast<jlm::rvsdg::SimpleNode>(test.load_x));
223 ASSERT_TRUE(
224 assertSetContains(loadXModRefSet, { { externalMemoryNode, ModRefEffect::RefOnly } }));
225 };
226
228 // jlm::rvsdg::view(test.graph().GetRootRegion(), stdout);
229
230 auto pointsToGraph = RunAndersen(test.module());
231 // std::cout << jlm::llvm::aa::PointsToGraph::dumpDot(*pointsToGraph);
232
233 /*
234 * Act
235 */
236 auto modRefSummary =
238
239 /*
240 * Assert
241 */
242 ValidateProvider(test, *modRefSummary, *pointsToGraph);
243}
244
245TEST(RegionAwareModRefSummarizerTests, TestLoad2)
246{
247 /*
248 * Arrange
249 */
250 auto ValidateProvider =
251 [](const jlm::llvm::LoadTest2 & test, const jlm::llvm::aa::ModRefSummary & modRefSummary)
252 {
253 auto & lambdaEntryNodes = modRefSummary.GetLambdaEntryModRef(*test.lambda);
254 ASSERT_TRUE(assertSetContains(lambdaEntryNodes, {}));
255
256 auto & lambdaExitNodes = modRefSummary.GetLambdaExitModRef(*test.lambda);
257 ASSERT_TRUE(assertSetContains(lambdaExitNodes, {}));
258 };
259
261 // jlm::rvsdg::view(test.graph().GetRootRegion(), stdout);
262
263 auto pointsToGraph = RunAndersen(test.module());
264 // std::cout << jlm::llvm::aa::PointsToGraph::dumpDot(*pointsToGraph);
265
266 /*
267 * Act
268 */
269 auto modRefSummary =
271
272 /*
273 * Assert
274 */
275 ValidateProvider(test, *modRefSummary);
276}
277
278TEST(RegionAwareModRefSummarizerTests, TestLoadFromUndef)
279{
280 /*
281 * Arrange
282 */
283 auto ValidateProvider = [](const jlm::llvm::LoadFromUndefTest & test,
284 const jlm::llvm::aa::ModRefSummary & modRefSummary,
286 {
287 auto & numLambdaEntryNodes = modRefSummary.GetLambdaEntryModRef(test.Lambda());
288 auto & numLambdaExitNodes = modRefSummary.GetLambdaExitModRef(test.Lambda());
289
290 EXPECT_EQ(numLambdaEntryNodes.getModRefNodes().size(), 0u);
291 EXPECT_EQ(numLambdaExitNodes.getModRefNodes().size(), 0u);
292 };
293
295 // jlm::rvsdg::view(test.graph().GetRootRegion(), stdout);
296
297 auto pointsToGraph = RunAndersen(test.module());
298 // std::cout << jlm::llvm::aa::PointsToGraph::dumpDot(*pointsToGraph);
299
300 /*
301 * Act
302 */
303 auto modRefSummary =
305
306 /*
307 * Assert
308 */
309 ValidateProvider(test, *modRefSummary, *pointsToGraph);
310}
311
312TEST(RegionAwareModRefSummarizerTests, TestCall1)
313{
314 /*
315 * Arrange
316 */
317 auto ValidateProvider = [](const jlm::llvm::CallTest1 & test,
318 const jlm::llvm::aa::ModRefSummary & modRefSummary,
319 const jlm::llvm::aa::PointsToGraph & pointsToGraph)
320 {
321 auto allocaXMemoryNode = pointsToGraph.getNodeForAlloca(*test.alloca_x);
322 auto allocaYMemoryNode = pointsToGraph.getNodeForAlloca(*test.alloca_y);
323 auto allocaZMemoryNode = pointsToGraph.getNodeForAlloca(*test.alloca_z);
324
325 /*
326 * Validate function f
327 */
328 {
329 auto & lambdaFEntryNodes = modRefSummary.GetLambdaEntryModRef(*test.lambda_f);
330 ASSERT_TRUE(assertSetContains(
331 lambdaFEntryNodes,
332 { { allocaXMemoryNode, ModRefEffect::RefOnly },
333 { allocaYMemoryNode, ModRefEffect::RefOnly } }));
334
335 auto & lambdaFExitNodes = modRefSummary.GetLambdaExitModRef(*test.lambda_f);
336 ASSERT_TRUE(assertSetContains(
337 lambdaFExitNodes,
338 { { allocaXMemoryNode, ModRefEffect::RefOnly },
339 { allocaYMemoryNode, ModRefEffect::RefOnly } }));
340 }
341
342 /*
343 * Validate function g
344 */
345 {
346 auto & lambdaGEntryNodes = modRefSummary.GetLambdaEntryModRef(*test.lambda_g);
347 ASSERT_TRUE(
348 assertSetContains(lambdaGEntryNodes, { { allocaZMemoryNode, ModRefEffect::RefOnly } }));
349
350 auto & lambdaGExitNodes = modRefSummary.GetLambdaExitModRef(*test.lambda_g);
351 ASSERT_TRUE(
352 assertSetContains(lambdaGExitNodes, { { allocaZMemoryNode, ModRefEffect::RefOnly } }));
353 }
354
355 /*
356 * Validate function h
357 */
358 {
359 auto & lambdaHEntryNodes = modRefSummary.GetLambdaEntryModRef(*test.lambda_h);
360 ASSERT_TRUE(assertSetContains(lambdaHEntryNodes, {}));
361
362 auto & callFNodes = modRefSummary.GetSimpleNodeModRef(test.CallF());
363 ASSERT_TRUE(assertSetContains(
364 callFNodes,
365 { { allocaXMemoryNode, ModRefEffect::RefOnly },
366 { allocaYMemoryNode, ModRefEffect::RefOnly } }));
367
368 auto & callGNodes = modRefSummary.GetSimpleNodeModRef(test.CallG());
369 ASSERT_TRUE(assertSetContains(callGNodes, { { allocaZMemoryNode, ModRefEffect::RefOnly } }));
370
371 auto & lambdaHExitNodes = modRefSummary.GetLambdaExitModRef(*test.lambda_h);
372 ASSERT_TRUE(assertSetContains(lambdaHExitNodes, {}));
373 }
374 };
375
377 // jlm::rvsdg::view(test.graph().GetRootRegion(), stdout);
378
379 auto pointsToGraph = RunAndersen(test.module());
380 // std::cout << jlm::llvm::aa::PointsToGraph::dumpDot(*PointsToGraph);
381
382 /*
383 * Act
384 */
385 auto modRefSummary =
387
388 /*
389 * Assert
390 */
391 ValidateProvider(test, *modRefSummary, *pointsToGraph);
392}
393
394TEST(RegionAwareModRefSummarizerTests, TestCall2)
395{
396 /*
397 * Arrange
398 */
399 auto ValidateProvider = [](const jlm::llvm::CallTest2 & test,
400 const jlm::llvm::aa::ModRefSummary & modRefSummary,
401 const jlm::llvm::aa::PointsToGraph & pointsToGraph)
402 {
403 auto mallocMemoryNode = pointsToGraph.getNodeForMalloc(*test.malloc);
404
405 /*
406 * Validate function create
407 */
408 {
409 auto & lambdaCreateEntryNodes = modRefSummary.GetLambdaEntryModRef(*test.lambda_create);
410 ASSERT_TRUE(assertSetContains(
411 lambdaCreateEntryNodes,
412 { { mallocMemoryNode, ModRefEffect::RefOnly } }));
413
414 auto & lambdaCreateExitNodes = modRefSummary.GetLambdaExitModRef(*test.lambda_create);
415 ASSERT_TRUE(assertSetContains(
416 lambdaCreateExitNodes,
417 { { mallocMemoryNode, ModRefEffect::RefOnly } }));
418 }
419
420 /*
421 * Validate function destroy
422 */
423 {
424 auto & lambdaDestroyEntryNodes = modRefSummary.GetLambdaEntryModRef(*test.lambda_destroy);
425 ASSERT_TRUE(assertSetContains(
426 lambdaDestroyEntryNodes,
427 { { mallocMemoryNode, ModRefEffect::ModOnly } }));
428
429 auto & lambdaDestroyExitNodes = modRefSummary.GetLambdaExitModRef(*test.lambda_destroy);
430 ASSERT_TRUE(assertSetContains(
431 lambdaDestroyExitNodes,
432 { { mallocMemoryNode, ModRefEffect::ModOnly } }));
433 }
434
435 /*
436 * Validate function test
437 */
438 {
439 auto & lambdaTestEntryNodes = modRefSummary.GetLambdaEntryModRef(*test.lambda_test);
440 ASSERT_TRUE(
441 assertSetContains(lambdaTestEntryNodes, { { mallocMemoryNode, ModRefEffect::ModRef } }));
442
443 auto & callCreate1Nodes = modRefSummary.GetSimpleNodeModRef(test.CallCreate1());
444 ASSERT_TRUE(
445 assertSetContains(callCreate1Nodes, { { mallocMemoryNode, ModRefEffect::RefOnly } }));
446
447 auto & callCreate2Nodes = modRefSummary.GetSimpleNodeModRef(test.CallCreate2());
448 ASSERT_TRUE(
449 assertSetContains(callCreate2Nodes, { { mallocMemoryNode, ModRefEffect::RefOnly } }));
450
451 auto & callDestroy1Nodes = modRefSummary.GetSimpleNodeModRef(test.CallDestroy1());
452 ASSERT_TRUE(
453 assertSetContains(callDestroy1Nodes, { { mallocMemoryNode, ModRefEffect::ModOnly } }));
454
455 auto & callDestroy2Nodes = modRefSummary.GetSimpleNodeModRef(test.CallDestroy2());
456 ASSERT_TRUE(
457 assertSetContains(callDestroy2Nodes, { { mallocMemoryNode, ModRefEffect::ModOnly } }));
458
459 auto & lambdaTestExitNodes = modRefSummary.GetLambdaExitModRef(*test.lambda_test);
460 ASSERT_TRUE(
461 assertSetContains(lambdaTestExitNodes, { { mallocMemoryNode, ModRefEffect::ModRef } }));
462 }
463 };
464
466 // jlm::rvsdg::view(test.graph().GetRootRegion(), stdout);
467
468 auto pointsToGraph = RunAndersen(test.module());
469 // std::cout << jlm::llvm::aa::PointsToGraph::dumpDot(*PointsToGraph);
470
471 /*
472 * Act
473 */
474 auto modRefSummary =
476
477 /*
478 * Assert
479 */
480 ValidateProvider(test, *modRefSummary, *pointsToGraph);
481}
482
483TEST(RegionAwareModRefSummarizerTests, TestIndirectCall)
484{
485 /*
486 * Arrange
487 */
488 auto ValidateProvider = [](const jlm::llvm::IndirectCallTest1 & test,
489 const jlm::llvm::aa::ModRefSummary & modRefSummary,
490 [[maybe_unused]] const jlm::llvm::aa::PointsToGraph & pointsToGraph)
491 {
492 /*
493 * Validate function four
494 */
495 {
496 auto & lambdaEntryNodes = modRefSummary.GetLambdaEntryModRef(test.GetLambdaFour());
497 ASSERT_TRUE(assertSetContains(lambdaEntryNodes, {}));
498
499 auto & lambdaExitNodes = modRefSummary.GetLambdaExitModRef(test.GetLambdaFour());
500 ASSERT_TRUE(assertSetContains(lambdaExitNodes, {}));
501 }
502
503 /*
504 * Validate function three
505 */
506 {
507 auto & lambdaEntryNodes = modRefSummary.GetLambdaEntryModRef(test.GetLambdaThree());
508 ASSERT_TRUE(assertSetContains(lambdaEntryNodes, {}));
509
510 auto & lambdaExitNodes = modRefSummary.GetLambdaExitModRef(test.GetLambdaThree());
511 ASSERT_TRUE(assertSetContains(lambdaExitNodes, {}));
512 }
513
514 /*
515 * Validate function indcall
516 */
517 {
518 auto & lambdaEntryNodes = modRefSummary.GetLambdaEntryModRef(test.GetLambdaIndcall());
519 ASSERT_TRUE(assertSetContains(lambdaEntryNodes, {}));
520
521 auto & callNodes = modRefSummary.GetSimpleNodeModRef(test.CallIndcall());
522 ASSERT_TRUE(assertSetContains(callNodes, {}));
523
524 auto & lambdaExitNodes = modRefSummary.GetLambdaExitModRef(test.GetLambdaIndcall());
525 ASSERT_TRUE(assertSetContains(lambdaExitNodes, {}));
526 }
527
528 /*
529 * Validate function test
530 */
531 {
532 auto & lambdaEntryNodes = modRefSummary.GetLambdaEntryModRef(test.GetLambdaTest());
533 ASSERT_TRUE(assertSetContains(lambdaEntryNodes, {}));
534
535 auto & callFourNodes = modRefSummary.GetSimpleNodeModRef(test.CallFour());
536 ASSERT_TRUE(assertSetContains(callFourNodes, {}));
537
538 auto & callThreeNodes = modRefSummary.GetSimpleNodeModRef(test.CallThree());
539 ASSERT_TRUE(assertSetContains(callThreeNodes, {}));
540
541 auto & lambdaExitNodes = modRefSummary.GetLambdaExitModRef(test.GetLambdaTest());
542 ASSERT_TRUE(assertSetContains(lambdaExitNodes, {}));
543 }
544 };
545
547 // jlm::rvsdg::view(test.graph().GetRootRegion(), stdout);
548
549 auto pointsToGraph = RunAndersen(test.module());
550 // std::cout << jlm::llvm::aa::PointsToGraph::dumpDot(*PointsToGraph);
551
552 /*
553 * Act
554 */
555 auto modRefSummary =
557
558 /*
559 * Assert
560 */
561 ValidateProvider(test, *modRefSummary, *pointsToGraph);
562}
563
564TEST(RegionAwareModRefSummarizerTests, TestIndirectCall2)
565{
566 /*
567 * Arrange
568 */
569 auto ValidateProvider = [](const jlm::llvm::IndirectCallTest2 & test,
570 const jlm::llvm::aa::ModRefSummary & modRefSummary,
571 const jlm::llvm::aa::PointsToGraph & pointsToGraph)
572 {
573 auto allocaPxMemoryNode = pointsToGraph.getNodeForAlloca(test.GetAllocaPx());
574 auto allocaPyMemoryNode = pointsToGraph.getNodeForAlloca(test.GetAllocaPy());
575 auto allocaPzMemoryNode = pointsToGraph.getNodeForAlloca(test.GetAllocaPz());
576
577 /*
578 * Validate function four()
579 */
580 {
581 auto & lambdaEntryNodes = modRefSummary.GetLambdaEntryModRef(test.GetLambdaFour());
582 ASSERT_TRUE(assertSetContains(lambdaEntryNodes, {}));
583
584 auto & lambdaExitNodes = modRefSummary.GetLambdaExitModRef(test.GetLambdaFour());
585 ASSERT_TRUE(assertSetContains(lambdaExitNodes, {}));
586 }
587
588 /*
589 * Validate function three()
590 */
591 {
592 auto & lambdaEntryNodes = modRefSummary.GetLambdaEntryModRef(test.GetLambdaThree());
593 ASSERT_TRUE(assertSetContains(lambdaEntryNodes, {}));
594
595 auto & lambdaExitNodes = modRefSummary.GetLambdaExitModRef(test.GetLambdaThree());
596 ASSERT_TRUE(assertSetContains(lambdaExitNodes, {}));
597 }
598
599 /*
600 * Validate function i()
601 */
602 {
603 auto & lambdaEntryNodes = modRefSummary.GetLambdaEntryModRef(test.GetLambdaI());
604 ASSERT_TRUE(assertSetContains(lambdaEntryNodes, {}));
605
606 auto & callNodes = modRefSummary.GetSimpleNodeModRef(test.GetIndirectCall());
607 ASSERT_TRUE(assertSetContains(callNodes, {}));
608
609 auto & lambdaExitNodes = modRefSummary.GetLambdaExitModRef(test.GetLambdaI());
610 ASSERT_TRUE(assertSetContains(lambdaExitNodes, {}));
611 }
612
613 /*
614 * Validate function x()
615 */
616 {
617 auto & lambdaEntryNodes = modRefSummary.GetLambdaEntryModRef(test.GetLambdaX());
618 ASSERT_TRUE(assertSetContains(
619 lambdaEntryNodes,
620 { { allocaPxMemoryNode, ModRefEffect::ModOnly },
621 { allocaPzMemoryNode, ModRefEffect::ModOnly } }));
622
623 auto & lambdaExitNodes = modRefSummary.GetLambdaExitModRef(test.GetLambdaX());
624 ASSERT_TRUE(assertSetContains(
625 lambdaExitNodes,
626 { { allocaPxMemoryNode, ModRefEffect::ModOnly },
627 { allocaPzMemoryNode, ModRefEffect::ModOnly } }));
628 }
629
630 /*
631 * Validate function y()
632 */
633 {
634 auto & lambdaEntryNodes = modRefSummary.GetLambdaEntryModRef(test.GetLambdaY());
635 ASSERT_TRUE(
636 assertSetContains(lambdaEntryNodes, { { allocaPyMemoryNode, ModRefEffect::ModOnly } }));
637
638 auto & lambdaExitNodes = modRefSummary.GetLambdaExitModRef(test.GetLambdaY());
639 ASSERT_TRUE(
640 assertSetContains(lambdaExitNodes, { { allocaPyMemoryNode, ModRefEffect::ModOnly } }));
641 }
642
643 /*
644 * Validate function test()
645 */
646 {
647 // g1 and g2 are effectively read-only so they get omitted from the lambda's set
648 auto & lambdaEntryNodes = modRefSummary.GetLambdaEntryModRef(test.GetLambdaTest());
649 ASSERT_TRUE(assertSetContains(lambdaEntryNodes, {}));
650
651 auto & callXNodes = modRefSummary.GetSimpleNodeModRef(test.GetTestCallX());
652 ASSERT_TRUE(assertSetContains(callXNodes, { { allocaPxMemoryNode, ModRefEffect::ModOnly } }));
653
654 auto & callYNodes = modRefSummary.GetSimpleNodeModRef(test.GetCallY());
655 ASSERT_TRUE(assertSetContains(callYNodes, { { allocaPyMemoryNode, ModRefEffect::ModOnly } }));
656
657 auto & lambdaExitNodes = modRefSummary.GetLambdaExitModRef(test.GetLambdaTest());
658 ASSERT_TRUE(assertSetContains(lambdaExitNodes, {}));
659 }
660
661 /*
662 * Validate function test2()
663 */
664 {
665 auto & lambdaEntryNodes = modRefSummary.GetLambdaEntryModRef(test.GetLambdaTest2());
666 ASSERT_TRUE(assertSetContains(lambdaEntryNodes, {}));
667
668 auto & callXNodes = modRefSummary.GetSimpleNodeModRef(test.GetTest2CallX());
669 ASSERT_TRUE(assertSetContains(callXNodes, { { allocaPzMemoryNode, ModRefEffect::ModOnly } }));
670
671 auto & lambdaExitNodes = modRefSummary.GetLambdaExitModRef(test.GetLambdaTest2());
672 ASSERT_TRUE(assertSetContains(lambdaExitNodes, {}));
673 }
674 };
675
677 // jlm::rvsdg::view(test.graph().GetRootRegion(), stdout);
678
679 auto pointsToGraph = RunAndersen(test.module());
680 // std::cout << jlm::llvm::aa::PointsToGraph::dumpDot(*PointsToGraph);
681
682 /*
683 * Act
684 */
685 auto modRefSummary =
687
688 /*
689 * Assert
690 */
691 ValidateProvider(test, *modRefSummary, *pointsToGraph);
692}
693
694TEST(RegionAwareModRefSummarizerTests, TestGamma)
695{
696 /*
697 * Arrange
698 */
699 auto ValidateProvider = [](const jlm::llvm::GammaTest & test,
700 const jlm::llvm::aa::ModRefSummary & modRefSummary,
701 const jlm::llvm::aa::PointsToGraph & pointsToGraph)
702 {
703 auto externalMemoryNode = pointsToGraph.getExternalMemoryNode();
704
705 auto & lambdaEntryNodes = modRefSummary.GetLambdaEntryModRef(*test.lambda);
706 ASSERT_TRUE(
707 assertSetContains(lambdaEntryNodes, { { externalMemoryNode, ModRefEffect::RefOnly } }));
708
709 auto & gammaEntryNodes = modRefSummary.GetGammaEntryModRef(*test.gamma);
710 ASSERT_TRUE(assertSetContains(gammaEntryNodes, {}));
711
712 auto & gammaExitNodes = modRefSummary.GetGammaExitModRef(*test.gamma);
713 ASSERT_TRUE(assertSetContains(gammaExitNodes, {}));
714
715 auto & lambdaExitNodes = modRefSummary.GetLambdaExitModRef(*test.lambda);
716 ASSERT_TRUE(
717 assertSetContains(lambdaExitNodes, { { externalMemoryNode, ModRefEffect::RefOnly } }));
718 };
719
721 // jlm::rvsdg::view(test.graph().GetRootRegion(), stdout);
722
723 auto pointsToGraph = RunAndersen(test.module());
724 // std::cout << jlm::llvm::aa::PointsToGraph::dumpDot(*pointsToGraph);
725
726 /*
727 * Act
728 */
729 auto modRefSummary =
731
732 /*
733 * Assert
734 */
735 ValidateProvider(test, *modRefSummary, *pointsToGraph);
736}
737
738TEST(RegionAwareModRefSummarizerTests, TestTheta)
739{
740 /*
741 * Arrange
742 */
743 auto ValidateProvider = [](const jlm::llvm::ThetaTest & test,
744 const jlm::llvm::aa::ModRefSummary & modRefSummary,
745 const jlm::llvm::aa::PointsToGraph & pointsToGraph)
746 {
747 auto externalMemoryNode = pointsToGraph.getExternalMemoryNode();
748
749 auto & lambdaEntryNodes = modRefSummary.GetLambdaEntryModRef(*test.lambda);
750 ASSERT_TRUE(
751 assertSetContains(lambdaEntryNodes, { { externalMemoryNode, ModRefEffect::ModOnly } }));
752
753 auto & thetaEntryExitNodes = modRefSummary.GetThetaModRef(*test.theta);
754 ASSERT_TRUE(
755 assertSetContains(thetaEntryExitNodes, { { externalMemoryNode, ModRefEffect::ModOnly } }));
756
757 auto & lambdaExitNodes = modRefSummary.GetLambdaExitModRef(*test.lambda);
758 ASSERT_TRUE(
759 assertSetContains(lambdaExitNodes, { { externalMemoryNode, ModRefEffect::ModOnly } }));
760 };
761
763 // jlm::rvsdg::view(test.graph().GetRootRegion(), stdout);
764
765 auto pointsToGraph = RunAndersen(test.module());
766 // std::cout << jlm::llvm::aa::PointsToGraph::dumpDot(*pointsToGraph);
767
768 /*
769 * Act
770 */
771 auto modRefSummary =
773
774 /*
775 * Assert
776 */
777 ValidateProvider(test, *modRefSummary, *pointsToGraph);
778}
779
780TEST(RegionAwareModRefSummarizerTests, TestDelta1)
781{
782 /*
783 * Arrange
784 */
785 auto ValidateProvider = [](const jlm::llvm::DeltaTest1 & test,
786 const jlm::llvm::aa::ModRefSummary & modRefSummary,
787 const jlm::llvm::aa::PointsToGraph & pointsToGraph)
788 {
789 auto deltaFNode = pointsToGraph.getNodeForDelta(*test.delta_f);
790
791 /*
792 * Validate function g
793 */
794 {
795 // g() only reads, and it does not get any unknown pointers
796 auto & lambdaEntryNodes = modRefSummary.GetLambdaEntryModRef(*test.lambda_g);
797 ASSERT_TRUE(assertSetContains(lambdaEntryNodes, { { deltaFNode, ModRefEffect::RefOnly } }));
798
799 auto & lambdaExitNodes = modRefSummary.GetLambdaExitModRef(*test.lambda_g);
800 ASSERT_TRUE(assertSetContains(lambdaExitNodes, { { deltaFNode, ModRefEffect::RefOnly } }));
801 }
802
803 /*
804 * Validate function h
805 */
806 {
807 auto & lambdaEntryNodes = modRefSummary.GetLambdaEntryModRef(*test.lambda_h);
808 ASSERT_TRUE(assertSetContains(lambdaEntryNodes, { { deltaFNode, ModRefEffect::ModRef } }));
809
810 auto & callEntryNodes = modRefSummary.GetSimpleNodeModRef(test.CallG());
811 ASSERT_TRUE(assertSetContains(callEntryNodes, { { deltaFNode, ModRefEffect::RefOnly } }));
812
813 auto & lambdaExitNodes = modRefSummary.GetLambdaExitModRef(*test.lambda_h);
814 ASSERT_TRUE(assertSetContains(lambdaExitNodes, { { deltaFNode, ModRefEffect::ModRef } }));
815 }
816 };
817
819 // jlm::rvsdg::view(test.graph().GetRootRegion(), stdout);
820
821 auto pointsToGraph = RunAndersen(test.module());
822 // std::cout << jlm::llvm::aa::PointsToGraph::dumpDot(*pointsToGraph);
823
824 /*
825 * Act
826 */
827 auto modRefSummary =
829
830 /*
831 * Assert
832 */
833 ValidateProvider(test, *modRefSummary, *pointsToGraph);
834}
835
836TEST(RegionAwareModRefSummarizerTests, TestDelta2)
837{
838 /*
839 * Arrange
840 */
841 auto ValidateProvider = [](const jlm::llvm::DeltaTest2 & test,
842 const jlm::llvm::aa::ModRefSummary & modRefSummary,
843 const jlm::llvm::aa::PointsToGraph & pointsToGraph)
844 {
845 auto deltaD1Node = pointsToGraph.getNodeForDelta(*test.delta_d1);
846 auto deltaD2Node = pointsToGraph.getNodeForDelta(*test.delta_d2);
847
848 /*
849 * Validate function f1
850 */
851 {
852 auto & lambdaEntryNodes = modRefSummary.GetLambdaEntryModRef(*test.lambda_f1);
853 ASSERT_TRUE(assertSetContains(lambdaEntryNodes, { { deltaD1Node, ModRefEffect::ModOnly } }));
854
855 auto & lambdaExitNodes = modRefSummary.GetLambdaExitModRef(*test.lambda_f1);
856 ASSERT_TRUE(assertSetContains(lambdaExitNodes, { { deltaD1Node, ModRefEffect::ModOnly } }));
857 }
858
859 /*
860 * Validate function f2
861 */
862 {
863 auto & lambdaEntryNodes = modRefSummary.GetLambdaEntryModRef(*test.lambda_f2);
864 ASSERT_TRUE(assertSetContains(
865 lambdaEntryNodes,
866 { { deltaD1Node, ModRefEffect::ModOnly }, { deltaD2Node, ModRefEffect::ModOnly } }));
867
868 auto & callEntryNodes = modRefSummary.GetSimpleNodeModRef(test.CallF1());
869 ASSERT_TRUE(assertSetContains(callEntryNodes, { { deltaD1Node, ModRefEffect::ModOnly } }));
870
871 auto & lambdaExitNodes = modRefSummary.GetLambdaExitModRef(*test.lambda_f2);
872 ASSERT_TRUE(assertSetContains(
873 lambdaExitNodes,
874 { { deltaD1Node, ModRefEffect::ModOnly }, { deltaD2Node, ModRefEffect::ModOnly } }));
875 }
876 };
877
879 // jlm::rvsdg::view(test.graph().GetRootRegion(), stdout);
880
881 auto pointsToGraph = RunAndersen(test.module());
882 // std::cout << jlm::llvm::aa::PointsToGraph::dumpDot(*pointsToGraph);
883
884 /*
885 * Act
886 */
887 auto modRefSummary =
889
890 /*
891 * Assert
892 */
893 ValidateProvider(test, *modRefSummary, *pointsToGraph);
894}
895
896TEST(RegionAwareModRefSummarizerTests, TestImports)
897{
898 /*
899 * Arrange
900 */
901 auto ValidateProvider = [](const jlm::llvm::ImportTest & test,
902 const jlm::llvm::aa::ModRefSummary & modRefSummary,
903 const jlm::llvm::aa::PointsToGraph & pointsToGraph)
904 {
905 auto importD1Node = pointsToGraph.getNodeForImport(*test.import_d1);
906 auto importD2Node = pointsToGraph.getNodeForImport(*test.import_d2);
907
908 /*
909 * Validate function f1
910 */
911 {
912 auto & lambdaEntryNodes = modRefSummary.GetLambdaEntryModRef(*test.lambda_f1);
913 ASSERT_TRUE(assertSetContains(lambdaEntryNodes, { { importD1Node, ModRefEffect::ModOnly } }));
914
915 auto & lambdaExitNodes = modRefSummary.GetLambdaExitModRef(*test.lambda_f1);
916 ASSERT_TRUE(assertSetContains(lambdaExitNodes, { { importD1Node, ModRefEffect::ModOnly } }));
917 }
918
919 /*
920 * Validate function f2
921 */
922 {
923 auto & lambdaEntryNodes = modRefSummary.GetLambdaEntryModRef(*test.lambda_f2);
924 ASSERT_TRUE(assertSetContains(
925 lambdaEntryNodes,
926 { { importD1Node, ModRefEffect::ModOnly }, { importD2Node, ModRefEffect::ModOnly } }));
927
928 auto & callNodes = modRefSummary.GetSimpleNodeModRef(test.CallF1());
929 ASSERT_TRUE(assertSetContains(callNodes, { { importD1Node, ModRefEffect::ModOnly } }));
930
931 auto & lambdaExitNodes = modRefSummary.GetLambdaExitModRef(*test.lambda_f2);
932 ASSERT_TRUE(assertSetContains(
933 lambdaExitNodes,
934 { { importD1Node, ModRefEffect::ModOnly }, { importD2Node, ModRefEffect::ModOnly } }));
935 }
936 };
937
939 // jlm::rvsdg::view(test.graph().GetRootRegion(), stdout);
940
941 auto pointsToGraph = RunAndersen(test.module());
942 // std::cout << jlm::llvm::aa::PointsToGraph::dumpDot(*pointsToGraph);
943
944 /*
945 * Act
946 */
947 auto modRefSummary =
949
950 /*
951 * Assert
952 */
953 ValidateProvider(test, *modRefSummary, *pointsToGraph);
954}
955
956TEST(RegionAwareModRefSummarizerTests, TestPhi1)
957{
958 /*
959 * Arrange
960 */
961 auto ValidateProvider = [](const jlm::llvm::PhiTest1 & test,
962 const jlm::llvm::aa::ModRefSummary & modRefSummary,
963 const jlm::llvm::aa::PointsToGraph & pointsToGraph)
964 {
965 auto resultAllocaNode = pointsToGraph.getNodeForAlloca(*test.alloca);
966
967 /*
968 * Validate function fib
969 */
970 {
971 auto & lambdaEntryNodes = modRefSummary.GetLambdaEntryModRef(*test.lambda_fib);
972 ASSERT_TRUE(
973 assertSetContains(lambdaEntryNodes, { { resultAllocaNode, ModRefEffect::ModRef } }));
974
975 auto & callFibM1Nodes = modRefSummary.GetSimpleNodeModRef(test.CallFibm1());
976 ASSERT_TRUE(
977 assertSetContains(callFibM1Nodes, { { resultAllocaNode, ModRefEffect::ModRef } }));
978
979 auto & callFibM2Nodes = modRefSummary.GetSimpleNodeModRef(test.CallFibm2());
980 ASSERT_TRUE(
981 assertSetContains(callFibM2Nodes, { { resultAllocaNode, ModRefEffect::ModRef } }));
982
983 auto & lambdaExitNodes = modRefSummary.GetLambdaExitModRef(*test.lambda_fib);
984 ASSERT_TRUE(
985 assertSetContains(lambdaExitNodes, { { resultAllocaNode, ModRefEffect::ModRef } }));
986 }
987
988 /*
989 * Validate function test
990 */
991 {
992 auto & lambdaEntryNodes = modRefSummary.GetLambdaEntryModRef(*test.lambda_test);
993 ASSERT_TRUE(assertSetContains(lambdaEntryNodes, {}));
994
995 auto & callNodes = modRefSummary.GetSimpleNodeModRef(test.CallFib());
996 ASSERT_TRUE(assertSetContains(callNodes, { { resultAllocaNode, ModRefEffect::ModRef } }));
997
998 auto & lambdaExitNodes = modRefSummary.GetLambdaExitModRef(*test.lambda_test);
999 ASSERT_TRUE(assertSetContains(lambdaExitNodes, {}));
1000 }
1001 };
1002
1004 // jlm::rvsdg::view(test.graph().GetRootRegion(), stdout);
1005
1006 auto pointsToGraph = RunAndersen(test.module());
1007 // std::cout << jlm::llvm::aa::PointsToGraph::dumpDot(*pointsToGraph);
1008
1009 /*
1010 * Act
1011 */
1012 auto modRefSummary =
1014
1015 /*
1016 * Assert
1017 */
1018 ValidateProvider(test, *modRefSummary, *pointsToGraph);
1019}
1020
1021TEST(RegionAwareModRefSummarizerTests, TestPhi2)
1022{
1023 /*
1024 * Arrange
1025 */
1026 auto ValidateProvider = [](const jlm::llvm::PhiTest2 & test,
1027 const jlm::llvm::aa::ModRefSummary & modRefSummary,
1028 const jlm::llvm::aa::PointsToGraph & pointsToGraph)
1029 {
1030 auto pTestAllocaMemoryNode = pointsToGraph.getNodeForAlloca(test.GetPTestAlloca());
1031 auto paAllocaMemoryNode = pointsToGraph.getNodeForAlloca(test.GetPaAlloca());
1032 [[maybe_unused]] auto pbAllocaMemoryNode = pointsToGraph.getNodeForAlloca(test.GetPbAlloca());
1033 auto pcAllocaMemoryNode = pointsToGraph.getNodeForAlloca(test.GetPcAlloca());
1034 auto pdAllocaMemoryNode = pointsToGraph.getNodeForAlloca(test.GetPdAlloca());
1035
1036 jlm::util::HashSet pTestAC({ pTestAllocaMemoryNode, paAllocaMemoryNode, pcAllocaMemoryNode });
1037 jlm::util::HashSet pTestBD({ pTestAllocaMemoryNode, pbAllocaMemoryNode, pdAllocaMemoryNode });
1038 jlm::util::HashSet pTestCD({ pTestAllocaMemoryNode, pcAllocaMemoryNode, pdAllocaMemoryNode });
1039 jlm::util::HashSet pTestAD({ pTestAllocaMemoryNode, paAllocaMemoryNode, pdAllocaMemoryNode });
1040 jlm::util::HashSet pTestACD(
1041 { pTestAllocaMemoryNode, paAllocaMemoryNode, pcAllocaMemoryNode, pdAllocaMemoryNode });
1042
1043 /*
1044 * Validate function eight()
1045 */
1046 {
1047 auto & lambdaEntryNodes = modRefSummary.GetLambdaEntryModRef(test.GetLambdaEight());
1048 ASSERT_TRUE(assertSetContains(lambdaEntryNodes, {}));
1049
1050 auto & lambdaExitNodes = modRefSummary.GetLambdaExitModRef(test.GetLambdaEight());
1051 ASSERT_TRUE(assertSetContains(lambdaExitNodes, {}));
1052 }
1053
1054 /*
1055 * Validate function i()
1056 */
1057 {
1058 auto & lambdaEntryNodes = modRefSummary.GetLambdaEntryModRef(test.GetLambdaI());
1059 ASSERT_TRUE(assertSetContains(lambdaEntryNodes, {}));
1060
1061 auto & callNodes = modRefSummary.GetSimpleNodeModRef(test.GetIndirectCall());
1062 ASSERT_TRUE(assertSetContains(callNodes, {}));
1063
1064 auto & lambdaExitNodes = modRefSummary.GetLambdaExitModRef(test.GetLambdaI());
1065 ASSERT_TRUE(assertSetContains(lambdaExitNodes, {}));
1066 }
1067
1068 /*
1069 * Validate function a()
1070 */
1071 {
1072 auto & lambdaEntryNodes = modRefSummary.GetLambdaEntryModRef(test.GetLambdaA());
1073 ASSERT_TRUE(
1074 assertSetContains(lambdaEntryNodes, allWithEffect(pTestCD, ModRefEffect::ModOnly)));
1075
1076 auto & callBNodes = modRefSummary.GetSimpleNodeModRef(test.GetCallB());
1077 ASSERT_TRUE(assertSetContains(callBNodes, { { paAllocaMemoryNode, ModRefEffect::ModOnly } }));
1078
1079 auto & callDNodes = modRefSummary.GetSimpleNodeModRef(test.GetCallD());
1080 ASSERT_TRUE(assertSetContains(callDNodes, { { paAllocaMemoryNode, ModRefEffect::ModOnly } }));
1081
1082 auto & lambdaExitNodes = modRefSummary.GetLambdaExitModRef(test.GetLambdaA());
1083 ASSERT_TRUE(
1084 assertSetContains(lambdaExitNodes, allWithEffect(pTestCD, ModRefEffect::ModOnly)));
1085 }
1086
1087 /*
1088 * Validate function b()
1089 */
1090 {
1091 auto & lambdaEntryNodes = modRefSummary.GetLambdaEntryModRef(test.GetLambdaB());
1092 ASSERT_TRUE(
1093 assertSetContains(lambdaEntryNodes, { { paAllocaMemoryNode, ModRefEffect::ModOnly } }));
1094
1095 auto & callINodes = modRefSummary.GetSimpleNodeModRef(test.GetCallI());
1096 ASSERT_TRUE(assertSetContains(callINodes, {}));
1097
1098 auto & callCNodes = modRefSummary.GetSimpleNodeModRef(test.GetCallC());
1099 ASSERT_TRUE(assertSetContains(callCNodes, { { pbAllocaMemoryNode, ModRefEffect::ModRef } }));
1100
1101 auto & lambdaExitNodes = modRefSummary.GetLambdaExitModRef(test.GetLambdaB());
1102 ASSERT_TRUE(
1103 assertSetContains(lambdaExitNodes, { { paAllocaMemoryNode, ModRefEffect::ModOnly } }));
1104 }
1105
1106 /*
1107 * Validate function c()
1108 */
1109 {
1110 auto & lambdaEntryNodes = modRefSummary.GetLambdaEntryModRef(test.GetLambdaC());
1111 ASSERT_TRUE(
1112 assertSetContains(lambdaEntryNodes, { { pbAllocaMemoryNode, ModRefEffect::ModRef } }));
1113
1114 auto & callNodes = modRefSummary.GetSimpleNodeModRef(test.GetCallAFromC());
1115 ASSERT_TRUE(assertSetContains(callNodes, { { pcAllocaMemoryNode, ModRefEffect::ModOnly } }));
1116
1117 auto & lambdaExitNodes = modRefSummary.GetLambdaExitModRef(test.GetLambdaC());
1118 ASSERT_TRUE(
1119 assertSetContains(lambdaExitNodes, { { pbAllocaMemoryNode, ModRefEffect::ModRef } }));
1120 }
1121
1122 /*
1123 * Validate function d()
1124 */
1125 {
1126 auto & lambdaEntryNodes = modRefSummary.GetLambdaEntryModRef(test.GetLambdaD());
1127 ASSERT_TRUE(
1128 assertSetContains(lambdaEntryNodes, { { paAllocaMemoryNode, ModRefEffect::ModOnly } }));
1129
1130 auto & callNodes = modRefSummary.GetSimpleNodeModRef(test.GetCallAFromD());
1131 ASSERT_TRUE(assertSetContains(callNodes, { { pdAllocaMemoryNode, ModRefEffect::ModOnly } }));
1132
1133 auto & lambdaExitNodes = modRefSummary.GetLambdaExitModRef(test.GetLambdaD());
1134 ASSERT_TRUE(
1135 assertSetContains(lambdaExitNodes, { { paAllocaMemoryNode, ModRefEffect::ModOnly } }));
1136 }
1137
1138 /*
1139 * Validate function test()
1140 */
1141 {
1142 auto & lambdaEntryNodes = modRefSummary.GetLambdaEntryModRef(test.GetLambdaTest());
1143 ASSERT_TRUE(assertSetContains(lambdaEntryNodes, {}));
1144
1145 auto & callNodes = modRefSummary.GetSimpleNodeModRef(test.GetCallAFromTest());
1146 ASSERT_TRUE(
1147 assertSetContains(callNodes, { { pTestAllocaMemoryNode, ModRefEffect::ModOnly } }));
1148
1149 auto & lambdaExitNodes = modRefSummary.GetLambdaExitModRef(test.GetLambdaTest());
1150 ASSERT_TRUE(assertSetContains(lambdaExitNodes, {}));
1151 }
1152 };
1153
1155 // jlm::rvsdg::view(test.graph().GetRootRegion(), stdout);
1156
1157 auto pointsToGraph = RunAndersen(test.module());
1158 // std::cout << jlm::llvm::aa::PointsToGraph::dumpDot(*pointsToGraph);
1159
1160 /*
1161 * Act
1162 */
1163 auto modRefSummary =
1165
1166 /*
1167 * Assert
1168 */
1169 ValidateProvider(test, *modRefSummary, *pointsToGraph);
1170}
1171
1172TEST(RegionAwareModRefSummarizerTests, TestPhiWithDelta)
1173{
1174 // Assert
1176 std::unordered_map<const jlm::rvsdg::Output *, std::string> outputMap;
1177 // std::cout << jlm::rvsdg::view(&test.graph().GetRootRegion(), outputMap) << std::flush;
1178
1179 auto pointsToGraph = RunAndersen(test.module());
1180 // std::cout << jlm::llvm::aa::PointsToGraph::dumpDot(*pointsToGraph, outputMap) << std::flush;
1181
1182 // Act
1183 auto modRefSummary =
1185
1186 // Assert
1187 // Nothing needs to be validated as there are only phi and delta nodes in the RVSDG.
1188}
1189
1190TEST(RegionAwareModRefSummarizerTests, TestMemcpy)
1191{
1192 /*
1193 * Arrange
1194 */
1195 auto ValidateProvider = [](const jlm::llvm::MemcpyTest & test,
1196 const jlm::llvm::aa::ModRefSummary & modRefSummary,
1197 const jlm::llvm::aa::PointsToGraph & pointsToGraph)
1198 {
1199 auto initArrayMemoryNode = pointsToGraph.getNodeForDelta(test.InitArray());
1200 auto globalArrayMemoryNode = pointsToGraph.getNodeForDelta(test.GlobalArray());
1201
1202 /*
1203 * Validate function f
1204 */
1205 {
1206 auto & lambdaEntryNodes = modRefSummary.GetLambdaEntryModRef(test.LambdaF());
1207 ASSERT_TRUE(
1208 assertSetContains(lambdaEntryNodes, { { globalArrayMemoryNode, ModRefEffect::ModRef } }));
1209
1210 auto & lambdaExitNodes = modRefSummary.GetLambdaExitModRef(test.LambdaF());
1211 ASSERT_TRUE(
1212 assertSetContains(lambdaExitNodes, { { globalArrayMemoryNode, ModRefEffect::ModRef } }));
1213 }
1214
1215 /*
1216 * Validate function g
1217 */
1218 {
1219 auto & lambdaEntryNodes = modRefSummary.GetLambdaEntryModRef(test.LambdaG());
1220 EXPECT_TRUE(assertSetContains(
1221 lambdaEntryNodes,
1222 { { globalArrayMemoryNode, ModRefEffect::ModRef },
1223 { initArrayMemoryNode, ModRefEffect::RefOnly } }));
1224
1225 auto & callNodes = modRefSummary.GetSimpleNodeModRef(test.CallF());
1226 ASSERT_TRUE(
1227 assertSetContains(callNodes, { { globalArrayMemoryNode, ModRefEffect::ModRef } }));
1228
1229 auto & lambdaExitNodes = modRefSummary.GetLambdaExitModRef(test.LambdaG());
1230 EXPECT_TRUE(assertSetContains(
1231 lambdaExitNodes,
1232 { { globalArrayMemoryNode, ModRefEffect::ModRef },
1233 { initArrayMemoryNode, ModRefEffect::RefOnly } }));
1234 }
1235 };
1236
1238 // jlm::rvsdg::view(test.graph().GetRootRegion(), stdout);
1239
1240 auto pointsToGraph = RunAndersen(test.module());
1241 // std::cout << jlm::llvm::aa::PointsToGraph::dumpDot(*PointsToGraph);
1242
1243 /*
1244 * Act
1245 */
1246 auto modRefSummary =
1248
1249 /*
1250 * Assert
1251 */
1252 ValidateProvider(test, *modRefSummary, *pointsToGraph);
1253}
1254
1255TEST(RegionAwareModRefSummarizerTests, TestEscapedMemory1)
1256{
1257 /*
1258 * Arrange
1259 */
1260 auto ValidateProvider = [](const jlm::llvm::EscapedMemoryTest1 & test,
1261 const jlm::llvm::aa::ModRefSummary & modRefSummary,
1262 const jlm::llvm::aa::PointsToGraph & pointsToGraph)
1263 {
1264 auto deltaBMemoryNode = pointsToGraph.getNodeForDelta(*test.DeltaB);
1265 // Delta A, X and Y have been compressed into the external memory node
1266 auto externalMemoryNode = pointsToGraph.getExternalMemoryNode();
1267
1268 auto & lambdaEntryNodes = modRefSummary.GetLambdaEntryModRef(*test.LambdaTest);
1269 ASSERT_TRUE(assertSetContains(
1270 lambdaEntryNodes,
1271 { { deltaBMemoryNode, ModRefEffect::ModOnly },
1272 { externalMemoryNode, ModRefEffect::RefOnly } }));
1273
1274 auto & lambdaExitNodes = modRefSummary.GetLambdaExitModRef(*test.LambdaTest);
1275 ASSERT_TRUE(assertSetContains(
1276 lambdaExitNodes,
1277 { { deltaBMemoryNode, ModRefEffect::ModOnly },
1278 { externalMemoryNode, ModRefEffect::RefOnly } }));
1279 };
1280
1282 // jlm::rvsdg::view(test.graph().GetRootRegion(), stdout);
1283
1284 auto pointsToGraph = RunAndersen(test.module());
1285 // std::cout << jlm::llvm::aa::PointsToGraph::dumpDot(*pointsToGraph);
1286
1287 /*
1288 * Act
1289 */
1290 auto modRefSummary =
1292
1293 /*
1294 * Assert
1295 */
1296 ValidateProvider(test, *modRefSummary, *pointsToGraph);
1297}
1298
1299TEST(RegionAwareModRefSummarizerTests, TestEscapedMemory2)
1300{
1301 /*
1302 * Arrange
1303 */
1304 auto ValidateProvider = [](const jlm::llvm::EscapedMemoryTest2 & test,
1305 const jlm::llvm::aa::ModRefSummary & modRefSummary,
1306 const jlm::llvm::aa::PointsToGraph & pointsToGraph)
1307 {
1308 auto returnAddressMallocMemoryNode = pointsToGraph.getNodeForMalloc(*test.ReturnAddressMalloc);
1309 auto callExternalFunction1MallocMemoryNode =
1310 pointsToGraph.getNodeForMalloc(*test.CallExternalFunction1Malloc);
1311
1312 auto externalMemoryNode = pointsToGraph.getExternalMemoryNode();
1313
1314 /*
1315 * Validate ReturnAddress function
1316 */
1317 {
1318 auto & lambdaEntryNodes = modRefSummary.GetLambdaEntryModRef(*test.ReturnAddressFunction);
1319 ASSERT_TRUE(assertSetContains(
1320 lambdaEntryNodes,
1321 { { returnAddressMallocMemoryNode, ModRefEffect::RefOnly } }));
1322
1323 auto & lambdaExitNodes = modRefSummary.GetLambdaExitModRef(*test.ReturnAddressFunction);
1324 ASSERT_TRUE(assertSetContains(
1325 lambdaExitNodes,
1326 { { returnAddressMallocMemoryNode, ModRefEffect::RefOnly } }));
1327 }
1328
1329 /*
1330 * Validate CallExternalFunction1 function
1331 */
1332 {
1333 // The returnAddressMallocMemoryNode is compressed into the external node
1334 jlm::util::HashSet expectedMemoryNodes{ callExternalFunction1MallocMemoryNode,
1335 externalMemoryNode };
1336
1337 auto & lambdaEntryNodes = modRefSummary.GetLambdaEntryModRef(*test.CallExternalFunction1);
1338 ASSERT_TRUE(assertSetContains(
1339 lambdaEntryNodes,
1340 allWithEffect(expectedMemoryNodes, ModRefEffect::ModRef)));
1341
1342 auto & callNodes = modRefSummary.GetSimpleNodeModRef(*test.ExternalFunction1Call);
1343 ASSERT_TRUE(
1344 assertSetContains(callNodes, allWithEffect(expectedMemoryNodes, ModRefEffect::ModRef)));
1345
1346 auto & lambdaExitNodes = modRefSummary.GetLambdaExitModRef(*test.CallExternalFunction1);
1347 ASSERT_TRUE(assertSetContains(
1348 lambdaExitNodes,
1349 allWithEffect(expectedMemoryNodes, ModRefEffect::ModRef)));
1350 }
1351
1352 /*
1353 * Validate CallExternalFunction2 function
1354 */
1355 {
1356 // The function only does a call, and a load of unknown, so everything can be compressed
1358 externalMemoryNode
1359 };
1360
1361 auto & lambdaEntryNodes = modRefSummary.GetLambdaEntryModRef(*test.CallExternalFunction2);
1362 ASSERT_TRUE(assertSetContains(
1363 lambdaEntryNodes,
1364 allWithEffect(expectedMemoryNodes, ModRefEffect::ModRef)));
1365
1366 auto & callNodes = modRefSummary.GetSimpleNodeModRef(*test.ExternalFunction2Call);
1367 ASSERT_TRUE(
1368 assertSetContains(callNodes, allWithEffect(expectedMemoryNodes, ModRefEffect::ModRef)));
1369
1370 auto & lambdaExitNodes = modRefSummary.GetLambdaExitModRef(*test.CallExternalFunction2);
1371 ASSERT_TRUE(assertSetContains(
1372 lambdaExitNodes,
1373 allWithEffect(expectedMemoryNodes, ModRefEffect::ModRef)));
1374 }
1375 };
1376
1378 // jlm::rvsdg::view(test.graph().GetRootRegion(), stdout);
1379
1380 auto pointsToGraph = RunAndersen(test.module());
1381 // std::cout << jlm::llvm::aa::PointsToGraph::dumpDot(*pointsToGraph);
1382
1383 /*
1384 * Act
1385 */
1386 auto modRefSummary =
1388
1389 /*
1390 * Assert
1391 */
1392 ValidateProvider(test, *modRefSummary, *pointsToGraph);
1393}
1394
1395TEST(RegionAwareModRefSummarizerTests, TestEscapedMemory3)
1396{
1397 /*
1398 * Arrange
1399 */
1400 auto ValidateProvider = [](const jlm::llvm::EscapedMemoryTest3 & test,
1401 const jlm::llvm::aa::ModRefSummary & modRefSummary,
1402 const jlm::llvm::aa::PointsToGraph & pointsToGraph)
1403 {
1404 auto externalMemoryNode = pointsToGraph.getExternalMemoryNode();
1405
1406 // DeltaGlobal has been compressed into the externalMemoryNode
1407 jlm::util::HashSet expectedMemoryNodes{ externalMemoryNode };
1408
1409 auto & lambdaEntryNodes = modRefSummary.GetLambdaEntryModRef(*test.LambdaTest);
1410 ASSERT_TRUE(assertSetContains(
1411 lambdaEntryNodes,
1412 allWithEffect(expectedMemoryNodes, ModRefEffect::ModRef)));
1413
1414 auto & callNodes = modRefSummary.GetSimpleNodeModRef(*test.CallExternalFunction);
1415 ASSERT_TRUE(
1416 assertSetContains(callNodes, allWithEffect(expectedMemoryNodes, ModRefEffect::ModRef)));
1417
1418 auto & lambdaExitNodes = modRefSummary.GetLambdaExitModRef(*test.LambdaTest);
1419 ASSERT_TRUE(assertSetContains(
1420 lambdaExitNodes,
1421 allWithEffect(expectedMemoryNodes, ModRefEffect::ModRef)));
1422 };
1423
1425 // jlm::rvsdg::view(test.graph().GetRootRegion(), stdout);
1426
1427 auto pointsToGraph = RunAndersen(test.module());
1428 // std::cout << jlm::llvm::aa::PointsToGraph::dumpDot(*pointsToGraph);
1429
1430 /*
1431 * Act
1432 */
1433 auto modRefSummary =
1435
1436 /*
1437 * Assert
1438 */
1439 ValidateProvider(test, *modRefSummary, *pointsToGraph);
1440}
1441
1442TEST(RegionAwareModRefSummarizerTests, testSetjmpHandling)
1443{
1444 using namespace jlm;
1445 using namespace jlm::llvm;
1446
1447 // Creates the RVSDG equivalent of the program
1448 //
1449 // void opaque();
1450 // int _setjmp(jmp_buf*);
1451 //
1452 // jmp_buf buf;
1453 //
1454 // static void h() {
1455 // opaque(); // This call should have a in its Mod/Ref set
1456 // }
1457 //
1458 // static void k() {
1459 // // This call does nothing
1460 // }
1461 //
1462 // static void g(int* p) {
1463 // if (_setjmp(&buf))
1464 // return;
1465 // else {
1466 // *p = 10;
1467 // h(); // This call should have a in its Mod/Ref set
1468 // k(); // Nothing should be routed into this call
1469 // }
1470 // }
1471 //
1472 // int f() {
1473 // int a;
1474 // g(a);
1475 // return a;
1476 // }
1477
1478 // Arrange
1479 LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
1480 auto & graph = rvsdgModule.Rvsdg();
1481 auto & rootRegion = graph.GetRootRegion();
1482
1483 const auto ioStateType = IOStateType::Create();
1484 const auto memoryStateType = MemoryStateType::Create();
1485 const auto pointerType = PointerType::Create();
1486 const auto int32Type = rvsdg::BitType::Create(32);
1487 // We don't care about the type of the jmp_buf, just use an array
1488 const auto jmpBufType = ArrayType::Create(int32Type, 34);
1489 const auto unitType = rvsdg::UnitType::Create();
1490
1491 const auto unitFunctionType = rvsdg::FunctionType::Create(
1492 { ioStateType, memoryStateType },
1493 { ioStateType, memoryStateType });
1494
1495 const auto setjmpFunctionType = rvsdg::FunctionType::Create(
1496 { pointerType, ioStateType, memoryStateType },
1497 { int32Type, ioStateType, memoryStateType });
1498
1499 const auto gFunctionType = rvsdg::FunctionType::Create(
1500 { pointerType, ioStateType, memoryStateType },
1501 { ioStateType, memoryStateType });
1502
1503 const auto fFunctionType = rvsdg::FunctionType::Create(
1504 { ioStateType, memoryStateType },
1505 { int32Type, ioStateType, memoryStateType });
1506
1507 auto & opaqueImport = LlvmGraphImport::createFunctionImport(
1508 graph,
1509 unitFunctionType,
1510 "opaque",
1511 Linkage::externalLinkage,
1512 CallingConvention::Default);
1513
1514 auto & setjmpImport = LlvmGraphImport::createFunctionImport(
1515 graph,
1516 setjmpFunctionType,
1517 "_setjmp",
1518 Linkage::externalLinkage,
1519 CallingConvention::Default);
1520
1521 auto & bufGlobal = *rvsdg::DeltaNode::Create(
1522 &rootRegion,
1523 LlvmDeltaOperation::Create(jmpBufType, "buf", Linkage::externalLinkage, "", false, 4));
1524 bufGlobal.finalize(UndefValueOperation::Create(*bufGlobal.subregion(), jmpBufType));
1525
1526 rvsdg::SimpleNode * callOpaqueNode = nullptr;
1527 rvsdg::SimpleNode * callHNode = nullptr;
1528 rvsdg::SimpleNode * callKNode = nullptr;
1529 rvsdg::SimpleNode * allocaNode = nullptr;
1530
1531 auto & hLambdaNode = *rvsdg::LambdaNode::Create(
1532 rootRegion,
1533 LlvmLambdaOperation::Create(unitFunctionType, "h", Linkage::internalLinkage));
1534 {
1535 const auto arguments = hLambdaNode.GetFunctionArguments();
1536 auto ioState = arguments.at(0);
1537 auto memoryState = arguments.at(1);
1538
1539 const auto opaqueCtxVar = hLambdaNode.AddContextVar(opaqueImport);
1540
1541 const auto call =
1542 CallOperation::Create(opaqueCtxVar.inner, unitFunctionType, { ioState, memoryState });
1543 callOpaqueNode = rvsdg::TryGetOwnerNode<rvsdg::SimpleNode>(*call[0]);
1544 ioState = call[0];
1545 memoryState = call[1];
1546
1547 hLambdaNode.finalize({ ioState, memoryState });
1548 }
1549
1550 auto & kLambdaNode = *rvsdg::LambdaNode::Create(
1551 rootRegion,
1552 LlvmLambdaOperation::Create(unitFunctionType, "k", Linkage::internalLinkage));
1553 {
1554 const auto arguments = kLambdaNode.GetFunctionArguments();
1555 kLambdaNode.finalize({ arguments.at(0), arguments.at(1) });
1556 }
1557
1558 auto & gLambdaNode = *rvsdg::LambdaNode::Create(
1559 rootRegion,
1560 LlvmLambdaOperation::Create(gFunctionType, "g", Linkage::internalLinkage));
1561 {
1562 const auto arguments = gLambdaNode.GetFunctionArguments();
1563 const auto p = arguments.at(0);
1564 auto ioState = arguments.at(1);
1565 auto memoryState = arguments.at(2);
1566
1567 const auto setjmpCtxVar = gLambdaNode.AddContextVar(setjmpImport);
1568 const auto bufCtxVar = gLambdaNode.AddContextVar(bufGlobal.output());
1569 const auto hCtxVar = gLambdaNode.AddContextVar(*hLambdaNode.output());
1570 const auto kCtxVar = gLambdaNode.AddContextVar(*kLambdaNode.output());
1571
1572 const auto setjmpCall = CallOperation::Create(
1573 setjmpCtxVar.inner,
1574 setjmpFunctionType,
1575 { bufCtxVar.inner, ioState, memoryState });
1576 auto & setjmpResult = *setjmpCall[0];
1577 ioState = setjmpCall[1];
1578 memoryState = setjmpCall[2];
1579
1580 auto & matchOutput = *rvsdg::MatchOperation::Create(setjmpResult, { { 0, 0 } }, 1, 2);
1581 auto & gammaNode = rvsdg::GammaNode::Create(matchOutput, 2, { unitType, unitType });
1582 auto pEntryVar = gammaNode.AddEntryVar(p);
1583 auto hEntryVar = gammaNode.AddEntryVar(hCtxVar.inner);
1584 auto kEntryVar = gammaNode.AddEntryVar(kCtxVar.inner);
1585 auto ioStateEntryVar = gammaNode.AddEntryVar(ioState);
1586 auto memoryStateEntryVar = gammaNode.AddEntryVar(memoryState);
1587 auto & elseRegion = *gammaNode.subregion(0);
1588 const auto constant10 = IntegerConstantOperation::Create(elseRegion, 32, 10).output(0);
1589 const auto storeOutputs = StoreNonVolatileOperation::Create(
1590 pEntryVar.branchArgument[0],
1591 constant10,
1592 { memoryStateEntryVar.branchArgument[0] },
1593 4);
1594
1595 const auto hCall = CallOperation::Create(
1596 hEntryVar.branchArgument[0],
1597 unitFunctionType,
1598 { ioStateEntryVar.branchArgument[0], storeOutputs[0] });
1599 callHNode = rvsdg::TryGetOwnerNode<rvsdg::SimpleNode>(*hCall[0]);
1600
1601 const auto kCall = CallOperation::Create(
1602 kEntryVar.branchArgument[0],
1603 unitFunctionType,
1604 { hCall[0], hCall[1] });
1605 callKNode = rvsdg::TryGetOwnerNode<rvsdg::SimpleNode>(*kCall[0]);
1606
1607 ioState = gammaNode.AddExitVar({ kCall[0], ioStateEntryVar.branchArgument[1] }).output;
1608 memoryState = gammaNode.AddExitVar({ kCall[1], memoryStateEntryVar.branchArgument[1] }).output;
1609
1610 gLambdaNode.finalize({ ioState, memoryState });
1611 }
1612
1613 auto & fLambdaNode = *rvsdg::LambdaNode::Create(
1614 rootRegion,
1615 LlvmLambdaOperation::Create(fFunctionType, "f", Linkage::externalLinkage));
1616 {
1617 const auto arguments = fLambdaNode.GetFunctionArguments();
1618 const auto ioStateIn = arguments.at(0);
1619 const auto memoryStateIn = arguments.at(1);
1620
1621 const auto gCtxVar = fLambdaNode.AddContextVar(*gLambdaNode.output());
1622
1623 const auto constant1 =
1624 IntegerConstantOperation::Create(*fLambdaNode.subregion(), 32, 1).output(0);
1625 const auto aAlloca = AllocaOperation::create(int32Type, constant1, 4);
1626 allocaNode = rvsdg::TryGetOwnerNode<rvsdg::SimpleNode>(*aAlloca[0]);
1627
1628 auto & memoryStateJoin =
1629 rvsdg::CreateOpNode<MemoryStateJoinOperation>({ memoryStateIn, aAlloca[1] }, 2);
1630
1631 const auto gCall = CallOperation::Create(
1632 gCtxVar.inner,
1633 gFunctionType,
1634 { aAlloca[0], ioStateIn, memoryStateJoin.output(0) });
1635
1636 auto loadOutputs = LoadNonVolatileOperation::Create(aAlloca[0], { gCall[1] }, int32Type, 4);
1637
1638 fLambdaNode.finalize({ loadOutputs[0], gCall[0], loadOutputs[1] });
1639 }
1640
1641 rvsdg::GraphExport::Create(*fLambdaNode.output(), "f");
1642
1644 LlvmDotWriter writer;
1645 writer.WriteGraphs(gw, rootRegion, true);
1646 // gw.outputAllGraphs(std::cout, util::graph::OutputFormat::Dot);
1647
1648 // Act
1649 util::StatisticsCollectorSettings settings({ util::Statistics::Id::RegionAwareModRefSummarizer });
1650 util::StatisticsCollector collector(settings);
1651 const auto ptg = RunAndersen(rvsdgModule);
1652 const auto modRefSummary = aa::RegionAwareModRefSummarizer::Create(rvsdgModule, *ptg, collector);
1653
1654 // Assert
1655 EXPECT_NE(callOpaqueNode, nullptr);
1656 EXPECT_NE(callHNode, nullptr);
1657 EXPECT_NE(callKNode, nullptr);
1658 EXPECT_NE(allocaNode, nullptr);
1659
1660 const auto allocaPtgNode = ptg->getNodeForAlloca(*allocaNode);
1661
1662 // The call to h() within g() should contain a in its Mod/Ref set
1663 const auto & callHModRef = modRefSummary->GetSimpleNodeModRef(*callHNode);
1664 EXPECT_TRUE(callHModRef.getModRefNodes().at(allocaPtgNode));
1665
1666 // The call to k() should NOT contain a in its Mod/Ref set
1667 const auto & callKModRef = modRefSummary->GetSimpleNodeModRef(*callKNode);
1668 EXPECT_FALSE(callKModRef.getModRefNodes().count(allocaPtgNode));
1669
1670 // The call to opaque() within h() only contains the external memory node,
1671 // since the memory node representing a has been compressed into it
1672 const auto & callOpaqueModRef = modRefSummary->GetSimpleNodeModRef(*callOpaqueNode);
1673 EXPECT_EQ(callOpaqueModRef.getModRefNodes().size(), 1u);
1674
1675 // Check the statistics to ensure that the right functions in the call graph were marked
1676 auto & statistic = *collector.CollectedStatistics().begin();
1677 // Only k() is not in the same SCC as <external>
1678 EXPECT_EQ(statistic.GetMeasurementValue<uint64_t>("#CallGraphSccs"), 2u);
1679 // g(), k() and h() are the only functions within an active setjmp
1680 EXPECT_EQ(statistic.GetMeasurementValue<uint64_t>("#FunctionsCallingSetjmp"), 1u);
1681}
1682
1683TEST(RegionAwareModRefSummarizerTests, TestEscapedFunction)
1684{
1685 using namespace jlm;
1686 using namespace jlm::llvm;
1687
1704 LlvmRvsdgModule rvsdgModule(util::FilePath(""), "", "");
1705 auto & graph = rvsdgModule.Rvsdg();
1706 auto & rootRegion = graph.GetRootRegion();
1707
1708 const auto ioStateType = IOStateType::Create();
1709 const auto memoryStateType = MemoryStateType::Create();
1710 const auto int32Type = rvsdg::BitType::Create(32);
1711
1712 const auto opaqueFunctionType = rvsdg::FunctionType::Create(
1713 { ioStateType, memoryStateType },
1714 { ioStateType, memoryStateType });
1715
1716 const auto fFunctionType = rvsdg::FunctionType::Create(
1717 { ioStateType, memoryStateType },
1718 { int32Type, ioStateType, memoryStateType });
1719
1720 auto & opaqueImport = LlvmGraphImport::createFunctionImport(
1721 graph,
1722 opaqueFunctionType,
1723 "opaque",
1724 Linkage::externalLinkage,
1725 CallingConvention::Default);
1726
1727 auto & global = *rvsdg::DeltaNode::Create(
1728 &rootRegion,
1729 LlvmDeltaOperation::Create(int32Type, "global", Linkage::internalLinkage, "", false, 4));
1730 global.finalize(IntegerConstantOperation::Create(*global.subregion(), 32, 0).output(0));
1731
1732 rvsdg::SimpleNode * opaqueCallNode = nullptr;
1733 auto & fLambdaNode = *rvsdg::LambdaNode::Create(
1734 rootRegion,
1735 LlvmLambdaOperation::Create(fFunctionType, "f", Linkage::externalLinkage));
1736 {
1737 const auto arguments = fLambdaNode.GetFunctionArguments();
1738 auto ioState = arguments.at(0);
1739 auto memoryState = arguments.at(1);
1740
1741 const auto globalCtxVar = fLambdaNode.AddContextVar(global.output());
1742 const auto opaqueCtxVar = fLambdaNode.AddContextVar(opaqueImport);
1743
1744 const auto loadOutputs =
1745 LoadNonVolatileOperation::Create(globalCtxVar.inner, { memoryState }, int32Type, 4);
1746 const auto one = IntegerConstantOperation::Create(*fLambdaNode.subregion(), 32, 1).output(0);
1747 const auto incrementedGlobal =
1748 rvsdg::CreateOpNode<IntegerAddOperation>({ loadOutputs[0], one }, 32).output(0);
1749 const auto storeOutputs = StoreNonVolatileOperation::Create(
1750 globalCtxVar.inner,
1751 incrementedGlobal,
1752 { loadOutputs[1] },
1753 4);
1754
1755 const auto opaqueCall =
1756 CallOperation::Create(opaqueCtxVar.inner, opaqueFunctionType, { ioState, storeOutputs[0] });
1757 opaqueCallNode = rvsdg::TryGetOwnerNode<rvsdg::SimpleNode>(*opaqueCall[0]);
1758 ioState = opaqueCall[0];
1759 memoryState = opaqueCall[1];
1760
1761 const auto returnLoadOutputs =
1762 LoadNonVolatileOperation::Create(globalCtxVar.inner, { memoryState }, int32Type, 4);
1763
1764 fLambdaNode.finalize({ returnLoadOutputs[0], ioState, returnLoadOutputs[1] });
1765 }
1766
1767 rvsdg::GraphExport::Create(*fLambdaNode.output(), "f");
1768
1769 const auto pointsToGraph = RunAndersen(rvsdgModule);
1770 const auto modRefSummary = aa::RegionAwareModRefSummarizer::Create(rvsdgModule, *pointsToGraph);
1771
1772 const auto globalMemoryNode = pointsToGraph->getNodeForDelta(global);
1773 const auto externalMemoryNode = pointsToGraph->getExternalMemoryNode();
1774 const util::HashSet expectedMemoryNodes{ globalMemoryNode, externalMemoryNode };
1775
1776 const auto & opaqueCallModRef = modRefSummary->GetSimpleNodeModRef(*opaqueCallNode);
1777 ASSERT_TRUE(assertSetContains(
1778 opaqueCallModRef,
1779 allWithEffect(expectedMemoryNodes, ModRefEffect::ModRef)));
1780}
1781
1782TEST(RegionAwareModRefSummarizerTests, TestStatistics)
1783{
1784 using namespace jlm;
1785
1786 // Arrange
1788 auto pointsToGraph = RunAndersen(test.module());
1789
1790 util::StatisticsCollectorSettings statisticsCollectorSettings(
1791 { util::Statistics::Id::RegionAwareModRefSummarizer });
1792 util::StatisticsCollector statisticsCollector(statisticsCollectorSettings);
1793
1794 // Act
1796 test.module(),
1797 *pointsToGraph,
1799
1800 // Assert
1802 auto & statistics = *statisticsCollector.CollectedStatistics().begin();
1803
1804 EXPECT_EQ(statistics.GetMeasurementValue<uint64_t>("#RvsdgNodes"), 18u);
1805 EXPECT_EQ(statistics.GetMeasurementValue<uint64_t>("#RvsdgRegions"), 2u);
1806 EXPECT_EQ(statistics.GetMeasurementValue<uint64_t>("#PointsToGraphMemoryNodes"), 7u);
1807 EXPECT_EQ(statistics.GetMeasurementValue<uint64_t>("#SimpleAllocas"), 5u);
1808 EXPECT_EQ(statistics.GetMeasurementValue<uint64_t>("#NonReentrantAllocas"), 5u);
1809 EXPECT_EQ(statistics.GetMeasurementValue<uint64_t>("#CallGraphSccs"), 2u);
1810
1811 EXPECT_TRUE(statistics.HasTimer("CallGraphTimer"));
1812 EXPECT_TRUE(statistics.HasTimer("SimpleAllocasSetTimer"));
1813 EXPECT_TRUE(statistics.HasTimer("NonReentrantAllocaSetsTimer"));
1814 EXPECT_TRUE(statistics.HasTimer("AnnotationTimer"));
1815 EXPECT_TRUE(statistics.HasTimer("SolvingTimer"));
1816 EXPECT_TRUE(statistics.HasTimer("ModRefSetMaterializationTimer"));
1817}
static jlm::util::StatisticsCollector statisticsCollector
static bool assertSetContains(const jlm::llvm::aa::ModRefSet &receivedMemoryNodes, std::unordered_map< NodeIndex, ModRefEffect > expectedEffects)
static std::unordered_map< NodeIndex, ModRefEffect > allWithEffect(const jlm::util::HashSet< NodeIndex > &memoryNodes, ModRefEffect effect)
static const char * effectToString(ModRefEffect effect)
static std::unique_ptr< jlm::llvm::aa::PointsToGraph > RunAndersen(jlm::llvm::LlvmRvsdgModule &rvsdgModule)
jlm::llvm::aa::PointsToGraph::NodeIndex NodeIndex
TEST(RegionAwareModRefSummarizerTests, TestStore1)
util::HashSet< rvsdg::Output * > arguments
CallTest1 class.
rvsdg::SimpleNode * alloca_y
rvsdg::SimpleNode * alloca_z
const rvsdg::SimpleNode & CallG() const noexcept
jlm::rvsdg::LambdaNode * lambda_g
jlm::rvsdg::LambdaNode * lambda_f
rvsdg::SimpleNode * alloca_x
const rvsdg::SimpleNode & CallF() const noexcept
jlm::rvsdg::LambdaNode * lambda_h
CallTest2 class.
const rvsdg::SimpleNode & CallDestroy1() const noexcept
jlm::rvsdg::LambdaNode * lambda_test
const rvsdg::SimpleNode & CallCreate2() const noexcept
jlm::rvsdg::LambdaNode * lambda_create
jlm::rvsdg::LambdaNode * lambda_destroy
const rvsdg::SimpleNode & CallDestroy2() const noexcept
const rvsdg::SimpleNode & CallCreate1() const noexcept
rvsdg::SimpleNode * malloc
DeltaTest1 class.
jlm::rvsdg::DeltaNode * delta_f
jlm::rvsdg::LambdaNode * lambda_h
const rvsdg::SimpleNode & CallG() const noexcept
jlm::rvsdg::LambdaNode * lambda_g
DeltaTest2 class.
const rvsdg::SimpleNode & CallF1() const noexcept
jlm::rvsdg::LambdaNode * lambda_f2
jlm::rvsdg::LambdaNode * lambda_f1
jlm::rvsdg::DeltaNode * delta_d2
jlm::rvsdg::DeltaNode * delta_d1
EscapedMemoryTest1 class.
jlm::rvsdg::DeltaNode * DeltaB
jlm::rvsdg::LambdaNode * LambdaTest
EscapedMemoryTest2 class.
jlm::rvsdg::LambdaNode * CallExternalFunction2
rvsdg::SimpleNode * ExternalFunction1Call
rvsdg::SimpleNode * ReturnAddressMalloc
jlm::rvsdg::LambdaNode * CallExternalFunction1
rvsdg::SimpleNode * ExternalFunction2Call
jlm::rvsdg::LambdaNode * ReturnAddressFunction
rvsdg::SimpleNode * CallExternalFunction1Malloc
EscapedMemoryTest3 class.
rvsdg::SimpleNode * CallExternalFunction
jlm::rvsdg::LambdaNode * LambdaTest
GammaTest class.
rvsdg::GammaNode * gamma
jlm::rvsdg::LambdaNode * lambda
ImportTest class.
const rvsdg::SimpleNode & CallF1() const noexcept
jlm::rvsdg::LambdaNode * lambda_f1
jlm::rvsdg::LambdaNode * lambda_f2
jlm::rvsdg::GraphImport * import_d2
jlm::rvsdg::GraphImport * import_d1
IndirectCallTest1 class.
const rvsdg::SimpleNode & CallThree() const noexcept
const jlm::rvsdg::LambdaNode & GetLambdaFour() const noexcept
const jlm::rvsdg::LambdaNode & GetLambdaThree() const noexcept
const jlm::rvsdg::LambdaNode & GetLambdaTest() const noexcept
const rvsdg::SimpleNode & CallIndcall() const noexcept
const jlm::rvsdg::LambdaNode & GetLambdaIndcall() const noexcept
const rvsdg::SimpleNode & CallFour() const noexcept
IndirectCallTest2 class.
jlm::rvsdg::SimpleNode & GetAllocaPx() const noexcept
jlm::rvsdg::LambdaNode & GetLambdaY() const noexcept
jlm::rvsdg::LambdaNode & GetLambdaTest2() const noexcept
rvsdg::SimpleNode & GetTestCallX() const noexcept
jlm::rvsdg::LambdaNode & GetLambdaTest() const noexcept
jlm::rvsdg::LambdaNode & GetLambdaFour() const noexcept
rvsdg::SimpleNode & GetIndirectCall() const noexcept
rvsdg::SimpleNode & GetTest2CallX() const noexcept
jlm::rvsdg::LambdaNode & GetLambdaThree() const noexcept
jlm::rvsdg::SimpleNode & GetAllocaPz() const noexcept
rvsdg::SimpleNode & GetCallY() const noexcept
jlm::rvsdg::LambdaNode & GetLambdaX() const noexcept
jlm::rvsdg::LambdaNode & GetLambdaI() const noexcept
jlm::rvsdg::SimpleNode & GetAllocaPy() const noexcept
LoadFromUndefTest class.
const jlm::rvsdg::LambdaNode & Lambda() const noexcept
LoadTest1 class.
jlm::rvsdg::LambdaNode * lambda
rvsdg::Node * load_p
rvsdg::Node * load_x
LoadTest2 class.
jlm::rvsdg::LambdaNode * lambda
MemcpyTest class.
const jlm::rvsdg::DeltaNode & GlobalArray() const noexcept
const jlm::rvsdg::LambdaNode & LambdaG() const noexcept
const jlm::rvsdg::DeltaNode & InitArray() const noexcept
const jlm::rvsdg::LambdaNode & LambdaF() const noexcept
const rvsdg::SimpleNode & CallF() const noexcept
PhiTest1 class.
rvsdg::SimpleNode * alloca
jlm::rvsdg::LambdaNode * lambda_test
jlm::rvsdg::LambdaNode * lambda_fib
const rvsdg::SimpleNode & CallFib() const noexcept
const rvsdg::SimpleNode & CallFibm2() const noexcept
const rvsdg::SimpleNode & CallFibm1() const noexcept
PhiTest2 class.
jlm::rvsdg::SimpleNode & GetPaAlloca() const noexcept
rvsdg::SimpleNode & GetIndirectCall() const noexcept
rvsdg::SimpleNode & GetCallAFromC() const noexcept
jlm::rvsdg::LambdaNode & GetLambdaC() const noexcept
jlm::rvsdg::LambdaNode & GetLambdaI() const noexcept
rvsdg::SimpleNode & GetCallC() const noexcept
jlm::rvsdg::SimpleNode & GetPbAlloca() const noexcept
jlm::rvsdg::LambdaNode & GetLambdaD() const noexcept
jlm::rvsdg::SimpleNode & GetPcAlloca() const noexcept
jlm::rvsdg::LambdaNode & GetLambdaTest() const noexcept
rvsdg::SimpleNode & GetCallAFromTest() const noexcept
jlm::rvsdg::LambdaNode & GetLambdaB() const noexcept
jlm::rvsdg::LambdaNode & GetLambdaA() const noexcept
rvsdg::SimpleNode & GetCallD() const noexcept
jlm::rvsdg::LambdaNode & GetLambdaEight() const noexcept
rvsdg::SimpleNode & GetCallAFromD() const noexcept
jlm::rvsdg::SimpleNode & GetPdAlloca() const noexcept
rvsdg::SimpleNode & GetCallI() const noexcept
rvsdg::SimpleNode & GetCallB() const noexcept
jlm::rvsdg::SimpleNode & GetPTestAlloca() const noexcept
jlm::llvm::LlvmRvsdgModule & module()
StoreTest1 class.
rvsdg::SimpleNode * alloca_a
jlm::rvsdg::LambdaNode * lambda
StoreTest2 class.
rvsdg::SimpleNode * alloca_p
jlm::rvsdg::LambdaNode * lambda
rvsdg::SimpleNode * alloca_y
rvsdg::SimpleNode * alloca_x
rvsdg::SimpleNode * alloca_b
rvsdg::SimpleNode * alloca_a
ThetaTest class.
jlm::rvsdg::LambdaNode * lambda
jlm::rvsdg::ThetaNode * theta
std::unique_ptr< PointsToGraph > Analyze(const rvsdg::RvsdgModule &module, util::StatisticsCollector &statisticsCollector) override
const std::unordered_map< PointsToGraph::NodeIndex, ModRefEffect > & getModRefNodes() const
static std::unique_ptr< ModRefSummary > Create(const rvsdg::RvsdgModule &rvsdgModule, const PointsToGraph &pointsToGraph, util::StatisticsCollector &statisticsCollector)
util::graph::Graph & WriteGraphs(util::graph::Writer &writer, const Region &region, bool emitTypeGraph)
Region & GetRootRegion() const noexcept
Definition graph.hpp:99
rvsdg::Input & SingleUser() noexcept
Definition node.hpp:347
Graph & Rvsdg() noexcept
NodeOutput * output(size_t index) const noexcept
IteratorRange< ItemConstIterator > Items() const noexcept
Definition HashSet.hpp:223
StatisticsRange CollectedStatistics() const noexcept
size_t NumCollectedStatistics() const noexcept
#define JLM_UNREACHABLE(msg)
Definition common.hpp:43
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