Jlm
Loading...
Searching...
No Matches
MemoryStateEncoder.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2021 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
19#include <jlm/rvsdg/gamma.hpp>
21#include <jlm/rvsdg/theta.hpp>
23#include <jlm/util/common.hpp>
25
26#include <unordered_map>
27
28namespace jlm::llvm::aa
29{
30
31namespace
32{
33
37struct MemoryStateTypeCounter final
38{
39 // The number of entities that have been counted
40 uint64_t NumEntities = 0;
41
42 // Count of total memory states, separated by Ref/Mod/ModRef
43 uint64_t NumRefOnly = 0;
44 uint64_t NumModOnly = 0;
45 uint64_t NumModRef = 0;
46
47 // Count of total memory states, separated by MemoryNode type
48 uint64_t NumAllocas = 0;
49 uint64_t NumMallocs = 0;
50 uint64_t NumDeltas = 0;
51 uint64_t NumImports = 0;
52 uint64_t NumLambdas = 0;
53 uint64_t NumExternalNode = 0;
54
55 // Count of the total memory states, how many are not externally available
56 uint64_t NumNonEscaped = 0;
57
58 // Remember the single entity with the highest number of memory states
60 // Do the same, but only include non-escaped MemoryNodes
62
63 void
64 CountEntity(
65 uint64_t numRefOnly,
66 uint64_t numModOnly,
67 uint64_t numModRef,
68 uint64_t numAllocas,
69 uint64_t numMallocs,
70 uint64_t numDeltas,
71 uint64_t numImports,
72 uint64_t numLambdas,
73 uint64_t numExternalNode,
74 uint64_t numNonEscaped)
75 {
77
78 NumRefOnly += numRefOnly;
79 NumModOnly += numModOnly;
80 NumModRef += numModRef;
81
82 NumAllocas += numAllocas;
83 NumMallocs += numMallocs;
84 NumDeltas += numDeltas;
85 NumImports += numImports;
86 NumLambdas += numLambdas;
87 NumExternalNode += numExternalNode;
88
89 const uint64_t totalMemoryStates = numRefOnly + numModOnly + numModRef;
90 if (totalMemoryStates > MaxMemoryStateEntity)
91 MaxMemoryStateEntity = totalMemoryStates;
92
93 NumNonEscaped += numNonEscaped;
94 if (numNonEscaped > MaxNonEscapedMemoryStateEntity)
95 MaxNonEscapedMemoryStateEntity = numNonEscaped;
96 }
97
98 void
99 CountEntity(const PointsToGraph & pointsToGraph, const ModRefSet & memoryNodes)
100 {
101 uint64_t numRefOnly = 0;
102 uint64_t numModOnly = 0;
103 uint64_t numModRef = 0;
104
105 uint64_t numAllocas = 0;
106 uint64_t numMallocs = 0;
107 uint64_t numDeltas = 0;
108 uint64_t numImports = 0;
109 uint64_t numLambdas = 0;
110 uint64_t numExternalNode = 0;
111
112 uint64_t numNonEscaped = 0;
113
114 for (const auto [memoryNode, modRefEffect] : memoryNodes.getModRefNodes())
115 {
116 switch (modRefEffect)
117 {
119 numRefOnly++;
120 break;
122 numModOnly++;
123 break;
125 numModRef++;
126 break;
127 default:
128 JLM_UNREACHABLE("Unknown ModRefEffect");
129 }
130
131 if (!pointsToGraph.isExternallyAvailable(memoryNode))
132 numNonEscaped++;
133
134 const auto kind = pointsToGraph.getNodeKind(memoryNode);
135 switch (kind)
136 {
138 numAllocas++;
139 break;
141 numDeltas++;
142 break;
144 numLambdas++;
145 break;
147 numImports++;
148 break;
150 numMallocs++;
151 break;
153 numExternalNode++;
154 break;
155 default:
156 throw std::logic_error("Unknown MemoryNode kind");
157 }
158 }
159
160 CountEntity(
161 numRefOnly,
162 numModOnly,
163 numModRef,
164 numAllocas,
165 numMallocs,
166 numDeltas,
167 numImports,
168 numLambdas,
169 numExternalNode,
170 numNonEscaped);
171 }
172};
173
174}
175
177{
178 MemoryStateTypeCounter interProceduralRegionCounter;
179 MemoryStateTypeCounter loadCounter;
180 MemoryStateTypeCounter storeCounter;
181 MemoryStateTypeCounter callEntryMergeCounter;
182
183 size_t numAllocaNodes = 0;
184 size_t numMallocNodes = 0;
185 size_t numLoadNodes = 0;
186 size_t numStoreNodes = 0;
187 size_t numCallNodes = 0;
188 size_t numFreeNodes = 0;
189 size_t numMemCpyNodes = 0;
190 size_t numMemSetNodes = 0;
191 size_t numMemMoveNodes = 0;
192 size_t numGammaNodes = 0;
193 size_t numThetaNodes = 0;
194 size_t numLambdaNodes = 0;
195};
196
201{
202 // Prefixes for statistics that count ModRef vs RefOnly
203 static constexpr auto NumTotalRefOnlyStates_ = "#TotalRefOnlyState";
204 static constexpr auto NumTotalModOnlyStates_ = "#TotalModOnlyState";
205 static constexpr auto NumTotalModRefStates_ = "#TotalModRefState";
206 // These are prefixes for statistics that count MemoryNode types
207 static constexpr auto NumTotalAllocaState_ = "#TotalAllocaState";
208 static constexpr auto NumTotalMallocState_ = "#TotalMallocState";
209 static constexpr auto NumTotalDeltaState_ = "#TotalDeltaState";
210 static constexpr auto NumTotalImportState_ = "#TotalImportState";
211 static constexpr auto NumTotalLambdaState_ = "#TotalLambdaState";
212 static constexpr auto NumTotalExternalNodeState_ = "#TotalExternalNodeState";
213 // Among all the MemoryNodes counted above, how many of them are not externally available
214 static constexpr auto NumTotalNonEscapedState_ = "#TotalNonEscapedState";
215 // Maximums in a single counted entity
216 static constexpr auto NumMaxMemoryState_ = "#MaxMemoryState";
217 static constexpr auto NumMaxNonEscapedMemoryState_ = "#MaxNonEscapedMemoryState";
218
219 // The number of regions that are inside lambda nodes (including the lambda subregion itself)
220 static constexpr auto NumIntraProceduralRegions_ = "#IntraProceduralRegions";
221 // Suffix used when counting region state arguments (or LambdaEntrySplit for lambda subregions)
222 static constexpr auto RegionArgumentStateSuffix_ = "Arguments";
223
224 // Counting both volatile and non-volatile loads
225 static constexpr auto NumLoadOperations_ = "#LoadOperations";
226 // Suffix used when counting memory states routed through loads
227 static constexpr auto LoadStateSuffix_ = "sThroughLoad";
228
229 // Counting both volatile and non-volatile stores
230 static constexpr auto NumStoreOperations_ = "#StoreOperations";
231 // Suffix used when counting memory states routed through stores
232 static constexpr auto StoreStateSuffix_ = "sThroughStore";
233
234 // Counting call entry merges
235 static constexpr auto NumCallEntryMergeOperations_ = "#CallEntryMergeOperations";
236 // Suffix used when counting memory states routed into call entry merges
237 static constexpr auto CallEntryMergeStateSuffix_ = "sIntoCallEntryMerge";
238
239 static constexpr auto EncodingTimerLabel_ = "EncodingTime";
240
241 static constexpr auto NumReplacedLoadsLabel_ = "#ReplacedLoads";
242 static constexpr auto NumRedirectedLoadsLabel_ = "#RedirectedLoads";
243
244 static constexpr auto NumReplacedStoresLabel_ = "#ReplacedStores";
245 static constexpr auto NumRedirectedStoresLabel_ = "#RedirectedStores";
246
247public:
248 ~Statistics() override = default;
249
250 explicit Statistics(const util::FilePath & sourceFile)
251 : util::Statistics(Id::MemoryStateEncoder, sourceFile)
252 {}
253
254 void
256 {
257 AddMeasurement(Label::NumRvsdgNodesBefore, rvsdg::nnodes(&graph.GetRootRegion()));
259 }
260
261 void
270
271 void
273 {
276
278
280
283
284 AddMeasurement("#MSEAllocaNodes", counters.numAllocaNodes);
285 AddMeasurement("#MSEMallocNodes", counters.numMallocNodes);
286 AddMeasurement("#MSELoadNodes", counters.numLoadNodes);
287 AddMeasurement("#MSEStoreNodes", counters.numStoreNodes);
288 AddMeasurement("#MSECallNodes", counters.numCallNodes);
289 AddMeasurement("#MSEFreeNodes", counters.numFreeNodes);
290 AddMeasurement("#MSEMemCpyNodes", counters.numMemCpyNodes);
291 AddMeasurement("#MSEMemSetNodes", counters.numMemSetNodes);
292 AddMeasurement("#MSEMemMoveNodes", counters.numMemMoveNodes);
293 AddMeasurement("#MSEGammaNodes", counters.numGammaNodes);
294 AddMeasurement("#MSEThetaNodes", counters.numThetaNodes);
295 AddMeasurement("#MSELambdaNodes", counters.numLambdaNodes);
296 }
297
298 static std::unique_ptr<Statistics>
299 Create(const util::FilePath & sourceFile)
300 {
301 return std::make_unique<Statistics>(sourceFile);
302 }
303
304private:
305 void
306 AddMemoryStateTypeCounter(const std::string & suffix, const MemoryStateTypeCounter & counter)
307 {
308 AddMeasurement(NumTotalRefOnlyStates_ + suffix, counter.NumRefOnly);
309 AddMeasurement(NumTotalModOnlyStates_ + suffix, counter.NumModOnly);
310 AddMeasurement(NumTotalModRefStates_ + suffix, counter.NumModRef);
311
312 AddMeasurement(NumTotalAllocaState_ + suffix, counter.NumAllocas);
313 AddMeasurement(NumTotalMallocState_ + suffix, counter.NumMallocs);
314 AddMeasurement(NumTotalDeltaState_ + suffix, counter.NumDeltas);
315 AddMeasurement(NumTotalImportState_ + suffix, counter.NumImports);
316 AddMeasurement(NumTotalLambdaState_ + suffix, counter.NumLambdas);
317 AddMeasurement(NumTotalExternalNodeState_ + suffix, counter.NumExternalNode);
318 AddMeasurement(NumTotalNonEscapedState_ + suffix, counter.NumNonEscaped);
319
320 AddMeasurement(NumMaxMemoryState_ + suffix, counter.MaxMemoryStateEntity);
321 AddMeasurement(NumMaxNonEscapedMemoryState_ + suffix, counter.MaxNonEscapedMemoryStateEntity);
322 }
323};
324
328{
329public:
330 StateMap() = default;
331
332 StateMap(const StateMap &) = delete;
333
334 StateMap(StateMap &&) = delete;
335
336 StateMap &
337 operator=(const StateMap &) = delete;
338
339 StateMap &
340 operator=(StateMap &&) = delete;
341
343 tryGetState(const PointsToGraph::NodeIndex modRefNode) noexcept
344 {
345 if (const auto it = states_.find(modRefNode); it != states_.end())
346 return it->second;
347
348 return nullptr;
349 }
350
353 {
354 if (const auto state = tryGetState(modRefNode))
355 return *state;
356 throw std::logic_error("Memory node does not have a state.");
357 }
358
372 std::vector<rvsdg::Output *>
373 getOrCreateStates(const std::vector<MemoryNodeId> & modRefNodes, rvsdg::Region & region)
374 {
375 std::vector<rvsdg::Output *> memoryStates;
376 for (auto & modRefNode : modRefNodes)
377 {
378 if (const auto state = tryGetState(modRefNode))
379 {
380 memoryStates.push_back(state);
381 }
382 else
383 {
384 // If no memory state output exists for the memory node, create an UndefValue for it
385
386 // Using undef for memory states that do not exist yet should only be done for allocas.
387 // TODO: After refactoring, add an assert here like so:
388 // JLM_ASSERT(modRefSummary_->getPointsToGraph().getKind(memoryNode) == NodeKind::Alloca);
389
390 auto & undefOutput = *UndefValueOperation::Create(region, MemoryStateType::Create());
391 insertState(modRefNode, undefOutput);
392 memoryStates.push_back(&undefOutput);
393 }
394 }
395
396 return memoryStates;
397 }
398
399 void
400 updateState(const MemoryNodeId modRefNode, rvsdg::Output & memoryState)
401 {
402 if (!tryGetState(modRefNode))
403 throw std::logic_error("Unknown modRefNode in StateMap");
404
405 states_[modRefNode] = &memoryState;
406 }
407
408 void
410 const std::vector<MemoryNodeId> & modRefNodes,
411 const rvsdg::Node::OutputIteratorRange & memoryStates)
412 {
414 modRefNodes.size()
415 == static_cast<size_t>(std::distance(memoryStates.begin(), memoryStates.end())));
416
417 size_t i = 0;
418 for (auto & memoryState : memoryStates)
419 {
420 auto & modRefNode = modRefNodes[i++];
421 updateState(modRefNode, memoryState);
422 }
423 }
424
432 void
434 {
435 if (auto [_, added] = states_.insert({ modRefNode, &state }); !added)
436 throw std::logic_error("Memory node already has a state.");
437 }
438
439private:
440 std::unordered_map<PointsToGraph::NodeIndex, rvsdg::Output *> states_;
441};
442
443static std::vector<MemoryNodeId>
444getModRefSetNodes(const ModRefSet & modRefSet)
445{
446 std::vector<MemoryNodeId> memoryNodeIds;
447 for (const auto [memoryNode, _] : modRefSet.getModRefNodes())
448 {
449 memoryNodeIds.push_back(memoryNode);
450 }
451
452 return memoryNodeIds;
453}
454
455MemoryStateEncoder::~MemoryStateEncoder() noexcept = default;
456
457MemoryStateEncoder::MemoryStateEncoder() = default;
458
459void
461 rvsdg::RvsdgModule & rvsdgModule,
462 const ModRefSummary & modRefSummary,
463 util::StatisticsCollector & statisticsCollector)
464{
465 modRefSummary_ = &modRefSummary;
466 statistics_ = Statistics::Create(rvsdgModule.SourceFilePath().value());
467 auto & rvsdg = rvsdgModule.Rvsdg();
468
469 // The statistics gathering needs to happen before the encoding as the encoding replaces nodes in
470 // the RVSDG and these new nodes would not have any ModRefSets associated with them.
472 {
473 auto counters = gatherStatistics(rvsdg.GetRootRegion());
474 statistics_->AddCounters(*counters);
475 }
476
477 statistics_->StartEncoding(rvsdg);
478 encodeInterProcedural(rvsdg.GetRootRegion());
479 statistics_->StopEncoding(encodingCounter_);
480 encodingCounter_ = EncodingCounter();
481
482 statisticsCollector.CollectDemandedStatistics(std::move(statistics_));
483}
484
485void
487{
488 for (const auto node : rvsdg::TopDownTraverser(&region))
489 {
490 MatchTypeOrFail(
491 *node,
492 [this](rvsdg::PhiNode & phiNode)
493 {
495 },
496 [](rvsdg::DeltaNode &)
497 {
498 // Nothing needs to be done
499 },
500 [this](rvsdg::LambdaNode & lambdaNode)
501 {
502 encodeLambda(lambdaNode);
503 },
504 [](const rvsdg::SimpleNode &)
505 {
506 // Nothing needs to be done
507 });
508 }
509}
510
511void
513{
514 for (const auto node : rvsdg::TopDownTraverser(&region))
515 {
516 MatchTypeOrFail(
517 *node,
518 [this, &stateMap](rvsdg::ThetaNode & thetaNode)
519 {
520 encodeTheta(thetaNode, stateMap);
521 },
522 [this, &stateMap](rvsdg::GammaNode & gammaNode)
523 {
524 encodeGamma(gammaNode, stateMap);
525 },
526 [this, &stateMap](const rvsdg::SimpleNode & simpleNode)
527 {
528 MatchTypeWithDefault(
529 simpleNode.GetOperation(),
530 [this, &simpleNode, &stateMap](const AllocaOperation &)
531 {
532 encodeAlloca(simpleNode, stateMap);
533 },
534 [this, &simpleNode, &stateMap](const MallocOperation &)
535 {
536 encodeMalloc(simpleNode, stateMap);
537 },
538 [this, &simpleNode, &stateMap](const LoadOperation &)
539 {
540 encodeLoad(simpleNode, stateMap);
541 },
542 [this, &simpleNode, &stateMap](const StoreOperation &)
543 {
544 encodeStore(simpleNode, stateMap);
545 },
546 [this, &simpleNode, &stateMap](const CallOperation &)
547 {
548 encodeCall(simpleNode, stateMap);
549 },
550 [this, &simpleNode, &stateMap](const FreeOperation &)
551 {
552 encodeFree(simpleNode, stateMap);
553 },
554 [this, &simpleNode, &stateMap](const MemCpyOperation &)
555 {
556 encodeMemcpy(simpleNode, stateMap);
557 },
558 [this, &simpleNode, &stateMap](const MemSetOperation &)
559 {
560 encodeMemset(simpleNode, stateMap);
561 },
562 [this, &simpleNode, &stateMap](const MemMoveOperation &)
563 {
564 encodeMemmove(simpleNode, stateMap);
565 },
566 [](const MemoryStateOperation &)
567 {
568 // Nothing needs to be done
569 },
570 [&simpleNode]()
571 {
572 // Ensure we took care of all memory state consuming/producing nodes
573 JLM_ASSERT(!hasMemoryState(simpleNode));
574 });
575 });
576 }
577}
578
579std::unique_ptr<MemoryStateEncoder::MemoryStateTypeCounters>
581{
582 std::function<void(
583 const rvsdg::Region & region,
584 const ModRefSummary & modRefSummary,
585 MemoryStateTypeCounters & counters)>
586 gather = [&](const rvsdg::Region & region,
587 const ModRefSummary & modRefSummary,
588 MemoryStateTypeCounters & counters)
589 {
590 for (const auto & node : region.Nodes())
591 {
592 MatchTypeOrFail(
593 node,
594 [&](const rvsdg::PhiNode & phiNode)
595 {
596 gather(*phiNode.subregion(), modRefSummary, counters);
597 },
598 [](const rvsdg::DeltaNode &)
599 {
600 // Nothing needs to be done
601 },
602 [&](const rvsdg::LambdaNode & lambdaNode)
603 {
604 const auto & modRefSet = modRefSummary.GetLambdaEntryModRef(lambdaNode);
605 counters.interProceduralRegionCounter.CountEntity(
606 modRefSummary.GetPointsToGraph(),
607 modRefSet);
608 counters.numLambdaNodes++;
609 gather(*lambdaNode.subregion(), modRefSummary, counters);
610 },
611 [&](const rvsdg::ThetaNode & thetaNode)
612 {
613 const auto & modRefSet = modRefSummary.GetThetaModRef(thetaNode);
614 counters.interProceduralRegionCounter.CountEntity(
615 modRefSummary.GetPointsToGraph(),
616 modRefSet);
617 counters.numThetaNodes++;
618 gather(*thetaNode.subregion(), modRefSummary, counters);
619 },
620 [&](const rvsdg::GammaNode & gammaNode)
621 {
622 auto & modRefSet = modRefSummary.GetGammaEntryModRef(gammaNode);
623 for (auto & subregion : gammaNode.Subregions())
624 {
625 counters.interProceduralRegionCounter.CountEntity(
626 modRefSummary.GetPointsToGraph(),
627 modRefSet);
628 counters.numGammaNodes++;
629 gather(subregion, modRefSummary, counters);
630 }
631 },
632 [&modRefSummary, &counters](const rvsdg::SimpleNode & simpleNode)
633 {
634 MatchTypeWithDefault(
635 simpleNode.GetOperation(),
636 [&counters](const AllocaOperation &)
637 {
638 counters.numAllocaNodes++;
639 },
640 [&counters](const MallocOperation &)
641 {
642 counters.numMallocNodes++;
643 },
644 [&modRefSummary, &counters, &simpleNode](const LoadOperation &)
645 {
646 const auto & modRefSet = modRefSummary.GetSimpleNodeModRef(simpleNode);
647 counters.loadCounter.CountEntity(modRefSummary.GetPointsToGraph(), modRefSet);
648 counters.numLoadNodes++;
649 },
650 [&modRefSummary, &counters, &simpleNode](const StoreOperation &)
651 {
652 const auto & modRefSet = modRefSummary.GetSimpleNodeModRef(simpleNode);
653 counters.storeCounter.CountEntity(modRefSummary.GetPointsToGraph(), modRefSet);
654 counters.numStoreNodes++;
655 },
656 [&modRefSummary, &counters, &simpleNode](const CallOperation &)
657 {
658 const auto & memoryNodes = modRefSummary.GetSimpleNodeModRef(simpleNode);
659 counters.callEntryMergeCounter.CountEntity(
660 modRefSummary.GetPointsToGraph(),
661 memoryNodes);
662 counters.numCallNodes++;
663 },
664 [&counters](const FreeOperation &)
665 {
666 counters.numFreeNodes++;
667 },
668 [&counters](const MemCpyOperation &)
669 {
670 counters.numMemCpyNodes++;
671 },
672 [&counters](const MemSetOperation &)
673 {
674 counters.numMemSetNodes++;
675 },
676 [&counters](const MemMoveOperation &)
677 {
678 counters.numMemMoveNodes++;
679 },
680 [](const MemoryStateOperation &)
681 {
682 // Nothing needs to be done
683 },
684 [&simpleNode]()
685 {
686 // Ensure we took care of all memory state consuming/producing nodes
687 JLM_ASSERT(!hasMemoryState(simpleNode));
688 });
689 });
690 }
691 };
692
693 auto counters = std::make_unique<MemoryStateTypeCounters>();
694 gather(region, *this->modRefSummary_, *counters);
695 return counters;
696}
697
698void
700{
701 JLM_ASSERT(is<AllocaOperation>(allocaNode.GetOperation()));
702
703 auto & allocaMemoryNodes = modRefSummary_->GetSimpleNodeModRef(allocaNode).getModRefNodes();
704 // It is possible for read-only allocas to not have any associated memory nodes
705 if (allocaMemoryNodes.size() == 0)
706 return;
707 // An alloca can have at most one associated memory node
708 JLM_ASSERT(allocaMemoryNodes.size() == 1);
709 auto allocaMemoryNode = allocaMemoryNodes.begin()->first;
710 auto & allocaNodeStateOutput = *allocaNode.output(1);
711
712 // If a state representing the alloca already exists in the region,
713 // merge it with the state created by the alloca using a MemoryStateJoin node.
714 if (const auto memoryState = stateMap.tryGetState(allocaMemoryNode))
715 {
716 auto & joinNode = MemoryStateJoinOperation::CreateNode({ &allocaNodeStateOutput, memoryState });
717 auto & joinOutput = *joinNode.output(0);
718 stateMap.updateState(allocaMemoryNode, joinOutput);
719 }
720 else
721 {
722 stateMap.insertState(allocaMemoryNode, allocaNodeStateOutput);
723 }
724}
725
726void
728{
729 JLM_ASSERT(is<MallocOperation>(mallocNode.GetOperation()));
730
731 auto & mallocMemoryNodes = modRefSummary_->GetSimpleNodeModRef(mallocNode).getModRefNodes();
732 // It is possible for read-only mallocs to not have any associated memory nodes
733 if (mallocMemoryNodes.size() == 0)
734 return;
735 // A malloc can have at most one associated memory node
736 JLM_ASSERT(mallocMemoryNodes.size() == 1);
737 auto mallocMemoryNode = mallocMemoryNodes.begin()->first;
738
739 auto & mallocNodeStateOutput = MallocOperation::memoryStateOutput(mallocNode);
740
741 // We use a static heap model. This means that multiple invocations of an malloc
742 // at runtime can refer to the same abstract memory location. We therefore need to
743 // merge the previous and the current state to ensure that the previous state
744 // is not just simply replaced and therefore "lost".
745 if (const auto memoryState = stateMap.tryGetState(mallocMemoryNode))
746 {
747 auto & joinNode = MemoryStateJoinOperation::CreateNode({ &mallocNodeStateOutput, memoryState });
748 auto & joinOutput = *joinNode.output(0);
749 stateMap.updateState(mallocMemoryNode, joinOutput);
750 }
751 else
752 {
753 stateMap.insertState(mallocMemoryNode, mallocNodeStateOutput);
754 }
755}
756
757void
759{
760 JLM_ASSERT(is<LoadOperation>(node.GetOperation()));
761
762 const auto & modRefSet = modRefSummary_->GetSimpleNodeModRef(node);
763 const auto modRefNodes = getModRefSetNodes(modRefSet);
764 const auto memStateOperands = stateMap.getOrCreateStates(modRefNodes, *node.region());
765
766 if (memStateOperands.size() == LoadOperation::numMemoryStates(node))
767 {
769 for (auto & memoryStateOutput : LoadOperation::MemoryStateOutputs(node))
770 {
771 const auto memoryStateOperand =
773 memoryStateOutput.divert_users(memoryStateOperand);
774 }
775
776 size_t n = 0;
777 for (auto & memoryStateInput : LoadOperation::MemoryStateInputs(node))
778 memoryStateInput.divert_to(memStateOperands[n++]);
779
780 stateMap.updateStates(modRefNodes, LoadOperation::MemoryStateOutputs(node));
781 }
782 else
783 {
785 const auto & newLoadNode = replaceLoadNode(node, memStateOperands);
786 stateMap.updateStates(modRefNodes, LoadOperation::MemoryStateOutputs(newLoadNode));
787 }
788}
789
790void
792{
793 JLM_ASSERT(is<StoreOperation>(node.GetOperation()));
794
795 const auto & modRefSet = modRefSummary_->GetSimpleNodeModRef(node);
796 const auto modRefNodes = getModRefSetNodes(modRefSet);
797 const auto memStateOperands = stateMap.getOrCreateStates(modRefNodes, *node.region());
798
799 if (memStateOperands.size() == StoreOperation::numMemoryStates(node))
800 {
802 for (auto & memoryStateOutput : StoreOperation::MemoryStateOutputs(node))
803 {
804 const auto memoryStateOperand =
806 memoryStateOutput.divert_users(memoryStateOperand);
807 }
808
809 size_t n = 0;
810 for (auto & memoryStateInput : StoreOperation::getMemoryStateInputs(node))
811 memoryStateInput.divert_to(memStateOperands[n++]);
812
813 stateMap.updateStates(modRefNodes, StoreOperation::MemoryStateOutputs(node));
814 }
815 else
816 {
818 const auto & newStoreNode = replaceStoreNode(node, memStateOperands);
819 stateMap.updateStates(modRefNodes, StoreOperation::MemoryStateOutputs(newStoreNode));
820 }
821}
822
823void
825{
826 JLM_ASSERT(is<FreeOperation>(freeNode.GetOperation()));
827
828 const auto & modRefSet = modRefSummary_->GetSimpleNodeModRef(freeNode);
829 const auto modRefNodes = getModRefSetNodes(modRefSet);
830
831 const auto addressOperand = FreeOperation::getAddressInput(freeNode).origin();
832 const auto ioStateOperand = FreeOperation::getIOStateInput(freeNode).origin();
833 const auto memStateOperands = stateMap.getOrCreateStates(modRefNodes, *freeNode.region());
834
835 auto & newFreeNode =
836 FreeOperation::createNode(*addressOperand, *ioStateOperand, memStateOperands);
837
839 &FreeOperation::getIOStateOutput(newFreeNode));
840
841 for (auto & oldMemStateOutput : FreeOperation::memoryStateOutputs(freeNode))
842 {
843 auto oldMemStateOperand =
845 oldMemStateOutput.divert_users(oldMemStateOperand);
846 }
847 JLM_ASSERT(freeNode.IsDead());
848
849 stateMap.updateStates(modRefNodes, FreeOperation::memoryStateOutputs(newFreeNode));
850}
851
852void
854{
855 JLM_ASSERT(is<CallOperation>(callNode.GetOperation()));
856
857 const auto & modRefSet = modRefSummary_->GetSimpleNodeModRef(callNode);
858 const auto modRefNodes = getModRefSetNodes(modRefSet);
859 const auto memStateOperands = stateMap.getOrCreateStates(modRefNodes, *callNode.region());
860
862 *callNode.region(),
863 memStateOperands,
864 modRefNodes);
865 CallOperation::GetMemoryStateInput(callNode).divert_to(entryMergeNode.output(0));
866
869 modRefNodes);
870
871 stateMap.updateStates(modRefNodes, exitSplitNode.Outputs());
872}
873
874void
876{
877 JLM_ASSERT(is<MemCpyOperation>(memcpyNode.GetOperation()));
878
879 const auto & modRefSet = modRefSummary_->GetSimpleNodeModRef(memcpyNode);
880 const auto modRefNodes = getModRefSetNodes(modRefSet);
881 const auto memStateOperands = stateMap.getOrCreateStates(modRefNodes, *memcpyNode.region());
882
883 const auto & newMemCpyNode = replaceMemcpyNode(memcpyNode, memStateOperands);
884 stateMap.updateStates(modRefNodes, MemCpyOperation::memoryStateOutputs(newMemCpyNode));
885}
886
887void
889{
890 JLM_ASSERT(is<MemSetOperation>(memsetNode.GetOperation()));
891
892 const auto & modRefSet = modRefSummary_->GetSimpleNodeModRef(memsetNode);
893 const auto modRefNodes = getModRefSetNodes(modRefSet);
894 const auto memStateOperands = stateMap.getOrCreateStates(modRefNodes, *memsetNode.region());
895
896 auto & newMemSetNode = replaceMemsetNode(memsetNode, memStateOperands);
897 stateMap.updateStates(modRefNodes, MemSetOperation::memoryStateOutputs(newMemSetNode));
898}
899
900void
902{
903 JLM_ASSERT(is<MemMoveOperation>(memmoveNode.GetOperation()));
904
905 const auto & modRefSet = modRefSummary_->GetSimpleNodeModRef(memmoveNode);
906 const auto modRefNodes = getModRefSetNodes(modRefSet);
907 const auto memStateOperands = stateMap.getOrCreateStates(modRefNodes, *memmoveNode.region());
908
909 auto & newMemMoveNode = replaceMemmoveNode(memmoveNode, memStateOperands);
910 stateMap.updateStates(modRefNodes, MemMoveOperation::memoryStateOutputs(newMemMoveNode));
911}
912
913void
915{
916 StateMap subregionStateMap;
917
918 // Handle lambda entry
919 {
920 const auto & modRefSet = modRefSummary_->GetLambdaEntryModRef(lambdaNode);
921 const auto modRefNodes = getModRefSetNodes(modRefSet);
922 auto & memoryStateArgument = GetMemoryStateRegionArgument(lambdaNode);
923
924 auto & lambdaEntrySplitNode =
925 LambdaEntryMemoryStateSplitOperation::CreateNode(memoryStateArgument, modRefNodes);
926 const auto memStates = rvsdg::outputs(&lambdaEntrySplitNode);
927
928 size_t n = 0;
929 for (const auto modRefNode : modRefNodes)
930 subregionStateMap.insertState(modRefNode, *memStates[n++]);
931
932 if (!memStates.empty())
933 {
934 // This additional MemoryStateMergeOperation node makes all other nodes in the function that
935 // consume the memory state dependent on this node and therefore transitively on the
936 // LambdaEntryMemoryStateSplitOperation. This ensures that the
937 // LambdaEntryMemoryStateSplitOperation is always visited before all other memory state
938 // consuming nodes:
939 //
940 // ... := LAMBDA[f]
941 // [..., a1, ...]
942 // o1, ..., ox := LambdaEntryMemoryStateSplit a1
943 // oy = MemoryStateMerge o1, ..., ox
944 // ....
945 //
946 // No other memory state consuming node aside from the LambdaEntryMemoryStateSplitOperation
947 // should now consume a1.
948 auto state = MemoryStateMergeOperation::Create(memStates);
949 memoryStateArgument.divertUsersWhere(
950 *state,
951 [&lambdaEntrySplitNode](const rvsdg::Input & user)
952 {
953 return rvsdg::TryGetOwnerNode<rvsdg::SimpleNode>(user) != &lambdaEntrySplitNode;
954 });
955 }
956 }
957
958 auto & lambdaSubregion = *lambdaNode.subregion();
959 encodeIntraProcedural(lambdaSubregion, subregionStateMap);
960
961 // Handle lambda exit
962 {
963 const auto & modRefSet = modRefSummary_->GetLambdaExitModRef(lambdaNode);
964 const auto modRefNodes = getModRefSetNodes(modRefSet);
965 const auto memStateOperands = subregionStateMap.getOrCreateStates(modRefNodes, lambdaSubregion);
966 auto & memoryStateResult = GetMemoryStateRegionResult(lambdaNode);
967
968 auto & lambdaExitMergNode = LambdaExitMemoryStateMergeOperation::CreateNode(
969 lambdaSubregion,
970 memStateOperands,
971 modRefNodes);
972 memoryStateResult.divert_to(lambdaExitMergNode.output(0));
973 }
974
975 lambdaSubregion.prune(false);
976}
977
978void
980{
981 std::vector<StateMap> subregionStateMap(gammaNode.nsubregions());
982
983 // Handle gamma entry
984 {
985 auto & modRefSet = modRefSummary_->GetGammaEntryModRef(gammaNode);
986 const auto modRefNodes = getModRefSetNodes(modRefSet);
987 const auto memStateOperands = stateMap.getOrCreateStates(modRefNodes, *gammaNode.region());
988
989 size_t n = 0;
990 for (auto & modRefNode : modRefNodes)
991 {
992 auto gammaInput = gammaNode.AddEntryVar(memStateOperands[n++]);
993 for (auto argument : gammaInput.branchArgument)
994 subregionStateMap[argument->region()->index()].insertState(modRefNode, *argument);
995 }
996 }
997
998 for (auto & subregion : gammaNode.Subregions())
999 encodeIntraProcedural(subregion, subregionStateMap[subregion.index()]);
1000
1001 // Handle gamma exit
1002 {
1003 auto & modRefSet = modRefSummary_->GetGammaExitModRef(gammaNode);
1004 const auto modRefNodes = getModRefSetNodes(modRefSet);
1005
1006 for (auto modRefNode : modRefNodes)
1007 {
1008 std::vector<rvsdg::Output *> memStateOperands;
1009 for (auto & subregion : gammaNode.Subregions())
1010 {
1011 auto & state = subregionStateMap[subregion.index()].getState(modRefNode);
1012 memStateOperands.push_back(&state);
1013 }
1014
1015 auto state = gammaNode.AddExitVar(memStateOperands).output;
1016 stateMap.updateState(modRefNode, *state);
1017 }
1018 }
1019
1020 for (auto & subregion : gammaNode.Subregions())
1021 subregion.prune(false);
1022}
1023
1024void
1026{
1027 StateMap subregionStateMap;
1028 const auto & modRefSet = modRefSummary_->GetThetaModRef(thetaNode);
1029 const auto modRefNodes = getModRefSetNodes(modRefSet);
1030 auto memStateOperands = stateMap.getOrCreateStates(modRefNodes, *thetaNode.region());
1031
1032 // Handle theta entry
1033 std::vector<rvsdg::ThetaNode::LoopVar> loopVars;
1034 {
1035 size_t n = 0;
1036 for (auto & modRefNode : modRefNodes)
1037 {
1038 auto loopVar = thetaNode.AddLoopVar(memStateOperands[n++]);
1039 subregionStateMap.insertState(modRefNode, *loopVar.pre);
1040 loopVars.push_back(loopVar);
1041 }
1042 }
1043
1044 encodeIntraProcedural(*thetaNode.subregion(), subregionStateMap);
1045
1046 // Handle theta exit
1047 {
1048 JLM_ASSERT(modRefNodes.size() == loopVars.size());
1049 JLM_ASSERT(memStateOperands.size() == loopVars.size());
1050 for (size_t n = 0; n < loopVars.size(); n++)
1051 {
1052 const auto loopVar = loopVars[n];
1053 const auto modRefNode = modRefNodes[n];
1054
1055 auto & subregionState = subregionStateMap.getState(modRefNode);
1056 loopVar.post->divert_to(&subregionState);
1057 stateMap.updateState(modRefNode, *loopVar.output);
1058 }
1059 }
1060
1061 thetaNode.subregion()->prune(false);
1062}
1063
1066 const rvsdg::SimpleNode & node,
1067 const std::vector<rvsdg::Output *> & memoryStates)
1068{
1069 JLM_ASSERT(is<LoadOperation>(node.GetOperation()));
1070
1071 if (const auto loadVolatileOperation =
1072 dynamic_cast<const LoadVolatileOperation *>(&node.GetOperation()))
1073 {
1074 auto & newLoadNode = LoadVolatileOperation::CreateNode(
1075 *LoadOperation::AddressInput(node).origin(),
1077 memoryStates,
1078 loadVolatileOperation->GetLoadedType(),
1079 loadVolatileOperation->GetAlignment());
1080 auto & oldLoadedValueOutput = LoadOperation::LoadedValueOutput(node);
1081 auto & newLoadedValueOutput = LoadOperation::LoadedValueOutput(newLoadNode);
1082 auto & oldIOStateOutput = LoadVolatileOperation::IOStateOutput(node);
1083 auto & newIOStateOutput = LoadVolatileOperation::IOStateOutput(newLoadNode);
1084 oldLoadedValueOutput.divert_users(&newLoadedValueOutput);
1085 oldIOStateOutput.divert_users(&newIOStateOutput);
1086 for (auto & oldMemStateOutput : LoadOperation::MemoryStateOutputs(node))
1087 {
1088 const auto oldMemStateOperand =
1090 oldMemStateOutput.divert_users(oldMemStateOperand);
1091 }
1092
1093 JLM_ASSERT(node.IsDead());
1094 return newLoadNode;
1095 }
1096
1097 if (const auto loadNonVolatileOperation =
1098 dynamic_cast<const LoadNonVolatileOperation *>(&node.GetOperation()))
1099 {
1100 auto & newLoadNode = LoadNonVolatileOperation::CreateNode(
1101 *LoadOperation::AddressInput(node).origin(),
1102 memoryStates,
1103 loadNonVolatileOperation->GetLoadedType(),
1104 loadNonVolatileOperation->GetAlignment());
1105 auto & oldLoadedValueOutput = LoadOperation::LoadedValueOutput(node);
1106 auto & newLoadedValueOutput = LoadNonVolatileOperation::LoadedValueOutput(newLoadNode);
1107 oldLoadedValueOutput.divert_users(&newLoadedValueOutput);
1108 for (auto & oldMemStateOutput : LoadOperation::MemoryStateOutputs(node))
1109 {
1110 const auto oldMemStateOperand =
1112 oldMemStateOutput.divert_users(oldMemStateOperand);
1113 }
1114
1115 JLM_ASSERT(node.IsDead());
1116 return newLoadNode;
1117 }
1118
1119 JLM_UNREACHABLE("Unhandled load node type.");
1120}
1121
1124 const rvsdg::SimpleNode & node,
1125 const std::vector<rvsdg::Output *> & memoryStates)
1126{
1127 JLM_ASSERT(is<StoreOperation>(node.GetOperation()));
1128
1129 if (const auto oldStoreVolatileOperation =
1130 dynamic_cast<const StoreVolatileOperation *>(&node.GetOperation()))
1131 {
1132 auto & newStoreNode = StoreVolatileOperation::CreateNode(
1133 *StoreOperation::AddressInput(node).origin(),
1134 *StoreOperation::StoredValueInput(node).origin(),
1136 memoryStates,
1137 oldStoreVolatileOperation->GetAlignment());
1138 auto & oldIOStateOutput = StoreVolatileOperation::IOStateOutput(node);
1139 auto & newIOStateOutput = StoreVolatileOperation::IOStateOutput(newStoreNode);
1140 oldIOStateOutput.divert_users(&newIOStateOutput);
1141 for (auto & oldMemStateOutput : StoreOperation::MemoryStateOutputs(node))
1142 {
1143 const auto oldMemStateOperand =
1145 oldMemStateOutput.divert_users(oldMemStateOperand);
1146 }
1147
1148 JLM_ASSERT(node.IsDead());
1149 return newStoreNode;
1150 }
1151
1152 if (const auto oldStoreNonVolatileOperation =
1153 dynamic_cast<const StoreNonVolatileOperation *>(&node.GetOperation()))
1154 {
1155 for (auto & oldMemStateOutput : StoreOperation::MemoryStateOutputs(node))
1156 {
1157 const auto oldMemStateOperand =
1159 oldMemStateOutput.divert_users(oldMemStateOperand);
1160 }
1161
1162 JLM_ASSERT(node.IsDead());
1164 *StoreOperation::AddressInput(node).origin(),
1165 *StoreOperation::StoredValueInput(node).origin(),
1166 memoryStates,
1167 oldStoreNonVolatileOperation->GetAlignment());
1168 }
1169
1170 JLM_UNREACHABLE("Unhandled store node type.");
1171}
1172
1175 const rvsdg::SimpleNode & memCpyNode,
1176 const std::vector<rvsdg::Output *> & memoryStates)
1177{
1178 JLM_ASSERT(is<MemCpyOperation>(memCpyNode.GetOperation()));
1179
1180 auto & destination = *MemCpyOperation::destinationInput(memCpyNode).origin();
1181 auto & source = *MemCpyOperation::sourceInput(memCpyNode).origin();
1182 auto & length = *MemCpyOperation::countInput(memCpyNode).origin();
1183
1184 if (is<MemCpyVolatileOperation>(memCpyNode.GetOperation()))
1185 {
1186 auto & ioStateOperand = *MemCpyVolatileOperation::getIOStateInput(memCpyNode).origin();
1187 auto & newMemCpyNode = MemCpyVolatileOperation::CreateNode(
1188 destination,
1189 source,
1190 length,
1191 ioStateOperand,
1192 memoryStates);
1193
1196 for (auto & oldMemStateOutput : MemCpyOperation::memoryStateOutputs(memCpyNode))
1197 {
1198 auto oldMemStateOperand =
1200 oldMemStateOutput.divert_users(oldMemStateOperand);
1201 }
1202 JLM_ASSERT(memCpyNode.IsDead());
1203
1204 return newMemCpyNode;
1205 }
1206
1207 if (is<MemCpyNonVolatileOperation>(memCpyNode.GetOperation()))
1208 {
1209 for (auto & oldMemStateOutput : MemCpyOperation::memoryStateOutputs(memCpyNode))
1210 {
1211 auto oldMemStateOperand =
1213 oldMemStateOutput.divert_users(oldMemStateOperand);
1214 }
1215 JLM_ASSERT(memCpyNode.IsDead());
1216
1217 return MemCpyNonVolatileOperation::createNode(destination, source, length, memoryStates);
1218 }
1219
1220 throw std::logic_error("Unhandled memcpy operation type.");
1221}
1222
1225 const rvsdg::SimpleNode & memsetNode,
1226 const std::vector<rvsdg::Output *> & memoryStates)
1227{
1228 JLM_ASSERT(is<MemSetOperation>(memsetNode.GetOperation()));
1229
1230 auto destination = MemSetOperation::destinationInput(memsetNode).origin();
1231 auto value = MemSetOperation::valueInput(memsetNode).origin();
1232 auto length = MemSetOperation::lengthInput(memsetNode).origin();
1233
1234 if (is<MemSetNonVolatileOperation>(memsetNode.GetOperation()))
1235 {
1236 for (auto & oldMemStateOutput : MemSetOperation::memoryStateOutputs(memsetNode))
1237 {
1238 auto oldMemStateOperand =
1240 oldMemStateOutput.divert_users(oldMemStateOperand);
1241 }
1242 JLM_ASSERT(memsetNode.IsDead());
1243
1244 return MemSetNonVolatileOperation::createNode(*destination, *value, *length, memoryStates);
1245 }
1246
1247 throw std::logic_error("Unhandled memset operation type.");
1248}
1249
1252 const rvsdg::SimpleNode & memmoveNode,
1253 const std::vector<rvsdg::Output *> & memoryStates)
1254{
1255 JLM_ASSERT(is<MemMoveOperation>(memmoveNode.GetOperation()));
1256
1257 auto & destOperand = *MemMoveOperation::destinationInput(memmoveNode).origin();
1258 auto & srcOperand = *MemMoveOperation::sourceInput(memmoveNode).origin();
1259 auto & lengthOperand = *MemMoveOperation::lengthInput(memmoveNode).origin();
1260
1261 if (is<MemMoveNonVolatileOperation>(memmoveNode.GetOperation()))
1262 {
1263 for (auto & oldMemStateOutput : MemMoveOperation::memoryStateOutputs(memmoveNode))
1264 {
1265 auto oldMemStateOperand =
1267 oldMemStateOutput.divert_users(oldMemStateOperand);
1268 }
1269 JLM_ASSERT(memmoveNode.IsDead());
1270
1272 destOperand,
1273 srcOperand,
1274 lengthOperand,
1275 memoryStates);
1276 }
1277
1278 throw std::logic_error("Unhandled memmove operation type.");
1279}
1280
1281}
uint64_t NumImports
uint64_t NumMallocs
uint64_t NumModOnly
uint64_t NumExternalNode
uint64_t NumDeltas
uint64_t MaxMemoryStateEntity
uint64_t NumLambdas
uint64_t NumEntities
uint64_t NumRefOnly
uint64_t MaxNonEscapedMemoryStateEntity
uint64_t NumModRef
uint64_t NumNonEscaped
uint64_t NumAllocas
static rvsdg::SimpleNode & CreateNode(rvsdg::Region &region, const std::vector< rvsdg::Output * > &operands, std::vector< MemoryNodeId > memoryNodeIds)
static rvsdg::SimpleNode & CreateNode(rvsdg::Output &operand, std::vector< MemoryNodeId > memoryNodeIds)
Call operation class.
Definition call.hpp:251
static rvsdg::Output & GetMemoryStateOutput(const rvsdg::Node &node) noexcept
Definition call.hpp:378
static rvsdg::Input & GetMemoryStateInput(const rvsdg::Node &node) noexcept
Definition call.hpp:366
static rvsdg::Input & getAddressInput(const rvsdg::Node &node) noexcept
static rvsdg::Node::OutputIteratorRange memoryStateOutputs(const rvsdg::Node &node) noexcept
static rvsdg::Input & getIOStateInput(const rvsdg::Node &node) noexcept
static rvsdg::Output & getIOStateOutput(const rvsdg::Node &node) noexcept
static rvsdg::Input & mapMemoryStateOutputToInput(rvsdg::Output &output) noexcept
static rvsdg::SimpleNode & createNode(rvsdg::Output &pointer, rvsdg::Output &iOState, const std::vector< rvsdg::Output * > &memoryStates)
static rvsdg::SimpleNode & CreateNode(rvsdg::Output &operand, std::vector< MemoryNodeId > memoryNodeIds)
static rvsdg::SimpleNode & CreateNode(rvsdg::Region &region, const std::vector< rvsdg::Output * > &operands, const std::vector< MemoryNodeId > &memoryNodeIds)
static rvsdg::SimpleNode & CreateNode(rvsdg::Region &region, std::unique_ptr< LoadNonVolatileOperation > loadOperation, const std::vector< rvsdg::Output * > &operands)
Definition Load.hpp:470
static size_t numMemoryStates(const rvsdg::SimpleNode &node) noexcept
Definition Load.hpp:101
static rvsdg::Node::OutputIteratorRange MemoryStateOutputs(const rvsdg::Node &node) noexcept
Definition Load.hpp:116
static rvsdg::Output & LoadedValueOutput(const rvsdg::Node &node)
Definition Load.hpp:84
static rvsdg::Input & AddressInput(const rvsdg::Node &node) noexcept
Definition Load.hpp:75
static rvsdg::Node::InputIteratorRange MemoryStateInputs(const rvsdg::Node &node) noexcept
Definition Load.hpp:139
static rvsdg::Input & MapMemoryStateOutputToInput(const rvsdg::Output &output)
Definition Load.hpp:157
static rvsdg::Input & IOStateInput(const rvsdg::Node &node) noexcept
Definition Load.hpp:225
static rvsdg::SimpleNode & CreateNode(rvsdg::Region &region, std::unique_ptr< LoadVolatileOperation > loadOperation, const std::vector< rvsdg::Output * > &operands)
Definition Load.cpp:430
static rvsdg::Output & IOStateOutput(const rvsdg::Node &node)
Definition Load.hpp:234
static rvsdg::Output & memoryStateOutput(const rvsdg::Node &node)
static rvsdg::SimpleNode & createNode(rvsdg::Output &destination, rvsdg::Output &source, rvsdg::Output &length, const std::vector< rvsdg::Output * > &memoryStates)
static rvsdg::Input & sourceInput(const rvsdg::Node &node) noexcept
static rvsdg::Node::OutputIteratorRange memoryStateOutputs(const rvsdg::Node &node) noexcept
static rvsdg::Input & destinationInput(const rvsdg::Node &node) noexcept
static rvsdg::Input & countInput(const rvsdg::Node &node) noexcept
static rvsdg::Input & mapMemoryStateOutputToInput(const rvsdg::Output &output)
static rvsdg::Input & getIOStateInput(const rvsdg::Node &node) noexcept
static rvsdg::Output & getIOStateOutput(const rvsdg::Node &node)
static rvsdg::SimpleNode & CreateNode(rvsdg::Output &destination, rvsdg::Output &source, rvsdg::Output &length, rvsdg::Output &ioState, const std::vector< rvsdg::Output * > &memoryStates)
static rvsdg::SimpleNode & createNode(rvsdg::Output &dest, rvsdg::Output &src, rvsdg::Output &length, const std::vector< rvsdg::Output * > &memoryStates)
static rvsdg::Input & destinationInput(const rvsdg::Node &node) noexcept
static rvsdg::Input & lengthInput(const rvsdg::Node &node) noexcept
static rvsdg::Node::OutputIteratorRange memoryStateOutputs(const rvsdg::Node &node) noexcept
static rvsdg::Input & mapMemoryStateOutputToInput(const rvsdg::Output &output)
static rvsdg::Input & sourceInput(const rvsdg::Node &node) noexcept
static rvsdg::SimpleNode & createNode(rvsdg::Output &destination, rvsdg::Output &value, rvsdg::Output &length, const std::vector< rvsdg::Output * > &memoryStates)
static rvsdg::Input & valueInput(const rvsdg::Node &node) noexcept
static rvsdg::Input & lengthInput(const rvsdg::Node &node) noexcept
static rvsdg::Node::OutputIteratorRange memoryStateOutputs(const rvsdg::Node &node) noexcept
static rvsdg::Input & mapMemoryStateOutputToInput(const rvsdg::Output &output)
static rvsdg::Input & destinationInput(const rvsdg::Node &node) noexcept
static rvsdg::SimpleNode & CreateNode(const std::vector< rvsdg::Output * > &operands)
static rvsdg::Output * Create(const std::vector< rvsdg::Output * > &operands)
static std::shared_ptr< const MemoryStateType > Create()
Definition types.cpp:379
static rvsdg::SimpleNode & CreateNode(rvsdg::Output &address, rvsdg::Output &value, const std::vector< rvsdg::Output * > &memoryStates, size_t alignment)
Definition Store.hpp:360
static rvsdg::Input & StoredValueInput(const rvsdg::Node &node) noexcept
Definition Store.hpp:99
static rvsdg::Input & MapMemoryStateOutputToInput(const rvsdg::Output &output)
Definition Store.hpp:167
static size_t numMemoryStates(const rvsdg::SimpleNode &node) noexcept
Definition Store.hpp:83
static rvsdg::Input & AddressInput(const rvsdg::Node &node) noexcept
Definition Store.hpp:90
static rvsdg::Node::OutputIteratorRange MemoryStateOutputs(const rvsdg::Node &node) noexcept
Definition Store.hpp:108
static rvsdg::Node::InputIteratorRange getMemoryStateInputs(const rvsdg::Node &node) noexcept
Definition Store.hpp:131
static rvsdg::Output & IOStateOutput(const rvsdg::Node &node) noexcept
Definition Store.hpp:467
static rvsdg::Input & IOStateInput(const rvsdg::Node &node) noexcept
Definition Store.hpp:458
static rvsdg::SimpleNode & CreateNode(rvsdg::Region &region, std::unique_ptr< StoreVolatileOperation > storeOperation, const std::vector< rvsdg::Output * > &operands)
Definition Store.hpp:490
static jlm::rvsdg::Output * Create(rvsdg::Region &region, std::shared_ptr< const jlm::rvsdg::Type > type)
Hash map for mapping points-to graph memory nodes to RVSDG memory states.
StateMap & operator=(const StateMap &)=delete
void updateStates(const std::vector< MemoryNodeId > &modRefNodes, const rvsdg::Node::OutputIteratorRange &memoryStates)
void insertState(PointsToGraph::NodeIndex modRefNode, rvsdg::Output &state)
std::unordered_map< PointsToGraph::NodeIndex, rvsdg::Output * > states_
std::vector< rvsdg::Output * > getOrCreateStates(const std::vector< MemoryNodeId > &modRefNodes, rvsdg::Region &region)
rvsdg::Output * tryGetState(const PointsToGraph::NodeIndex modRefNode) noexcept
rvsdg::Output & getState(const PointsToGraph::NodeIndex modRefNode)
void updateState(const MemoryNodeId modRefNode, rvsdg::Output &memoryState)
StateMap & operator=(StateMap &&)=delete
Statistics class for memory state encoder encoding.
void AddMemoryStateTypeCounter(const std::string &suffix, const MemoryStateTypeCounter &counter)
static std::unique_ptr< Statistics > Create(const util::FilePath &sourceFile)
void AddCounters(const MemoryStateTypeCounters &counters)
void StopEncoding(const EncodingCounter &counter)
void encodeMemmove(const rvsdg::SimpleNode &memmoveNode, StateMap &stateMap) const
void encodeStore(const rvsdg::SimpleNode &node, StateMap &stateMap)
void encodeMemcpy(const rvsdg::SimpleNode &memcpyNode, StateMap &stateMap) const
void encodeMalloc(const rvsdg::SimpleNode &mallocNode, StateMap &stateMap) const
void encodeTheta(rvsdg::ThetaNode &thetaNode, StateMap &stateMap)
void encodeIntraProcedural(rvsdg::Region &region, StateMap &stateMap)
static rvsdg::SimpleNode & replaceStoreNode(const rvsdg::SimpleNode &node, const std::vector< rvsdg::Output * > &memoryStates)
static rvsdg::SimpleNode & replaceMemmoveNode(const rvsdg::SimpleNode &memmoveNode, const std::vector< rvsdg::Output * > &memoryStates)
void encodeLambda(const rvsdg::LambdaNode &lambda)
void encodeLoad(const rvsdg::SimpleNode &node, StateMap &stateMap)
static rvsdg::SimpleNode & replaceMemcpyNode(const rvsdg::SimpleNode &memCpyNode, const std::vector< rvsdg::Output * > &memoryStates)
void encodeMemset(const rvsdg::SimpleNode &memsetNode, StateMap &stateMap) const
void encodeCall(const rvsdg::SimpleNode &callNode, StateMap &stateMap) const
static rvsdg::SimpleNode & replaceLoadNode(const rvsdg::SimpleNode &node, const std::vector< rvsdg::Output * > &memoryStates)
void encodeFree(const rvsdg::SimpleNode &freeNode, StateMap &stateMap) const
void encodeAlloca(const rvsdg::SimpleNode &allocaNode, StateMap &stateMap) const
std::unique_ptr< MemoryStateTypeCounters > gatherStatistics(const rvsdg::Region &region) const
void encodeInterProcedural(rvsdg::Region &region)
static rvsdg::SimpleNode & replaceMemsetNode(const rvsdg::SimpleNode &memsetNode, const std::vector< rvsdg::Output * > &memoryStates)
void encodeGamma(rvsdg::GammaNode &gammaNode, StateMap &stateMap)
const std::unordered_map< PointsToGraph::NodeIndex, ModRefEffect > & getModRefNodes() const
virtual const ModRefSet & GetGammaEntryModRef(const rvsdg::GammaNode &gamma) const =0
virtual const ModRefSet & GetThetaModRef(const rvsdg::ThetaNode &theta) const =0
virtual const ModRefSet & GetLambdaExitModRef(const rvsdg::LambdaNode &lambda) const =0
virtual const ModRefSet & GetLambdaEntryModRef(const rvsdg::LambdaNode &lambda) const =0
virtual const PointsToGraph & GetPointsToGraph() const noexcept=0
virtual const ModRefSet & GetGammaExitModRef(const rvsdg::GammaNode &gamma) const =0
virtual const ModRefSet & GetSimpleNodeModRef(const rvsdg::SimpleNode &node) const =0
Conditional operator / pattern matching.
Definition gamma.hpp:99
EntryVar AddEntryVar(rvsdg::Output *origin)
Routes a variable into the gamma branches.
Definition gamma.cpp:260
ExitVar AddExitVar(const std::vector< rvsdg::Output * > &values)
Routes per-branch result of gamma to output.
Definition gamma.cpp:362
Region & GetRootRegion() const noexcept
Definition graph.hpp:99
void divert_to(Output *new_origin)
Definition node.cpp:64
Output * origin() const noexcept
Definition node.hpp:58
rvsdg::Region * subregion() const noexcept
Definition lambda.hpp:138
bool IsDead() const noexcept
Determines whether the node is dead.
Definition node.hpp:688
rvsdg::Region * region() const noexcept
Definition node.hpp:761
void divert_users(jlm::rvsdg::Output *new_origin)
Definition node.hpp:301
A phi node represents the fixpoint of mutually recursive definitions.
Definition Phi.hpp:46
rvsdg::Region * subregion() const noexcept
Definition Phi.hpp:320
Represent acyclic RVSDG subgraphs.
Definition region.hpp:213
void prune(bool recursive)
Definition region.cpp:326
NodeRange Nodes() noexcept
Definition region.hpp:375
const SimpleOperation & GetOperation() const noexcept override
NodeOutput * output(size_t index) const noexcept
SubregionIteratorRange Subregions()
size_t nsubregions() const noexcept
rvsdg::Region * subregion() const noexcept
Definition theta.hpp:90
LoopVar AddLoopVar(rvsdg::Output *origin)
Creates a new loop-carried variable.
Definition theta.cpp:49
bool IsDemanded(Statistics::Id id) const noexcept
void CollectDemandedStatistics(std::unique_ptr< Statistics > statistics)
Statistics Interface.
util::Timer & GetTimer(const std::string &name)
util::Timer & AddTimer(std::string name)
void AddMeasurement(std::string name, T value)
void start() noexcept
Definition time.hpp:54
void stop() noexcept
Definition time.hpp:67
#define JLM_ASSERT(x)
Definition common.hpp:16
#define JLM_UNREACHABLE(msg)
Definition common.hpp:43
static std::vector< MemoryNodeId > getModRefSetNodes(const ModRefSet &modRefSet)
std::size_t MemoryNodeId
static util::StatisticsCollector statisticsCollector
rvsdg::Input & GetMemoryStateRegionResult(const rvsdg::LambdaNode &lambdaNode) noexcept
rvsdg::Output & GetMemoryStateRegionArgument(const rvsdg::LambdaNode &lambdaNode) noexcept
static std::vector< jlm::rvsdg::Output * > outputs(const Node *node)
Definition node.hpp:1058
size_t nnodes(const jlm::rvsdg::Region *region) noexcept
Definition region.cpp:808
NodeType * TryGetOwnerNode(const rvsdg::Input &input) noexcept
Checks if this is an input to a node of specified type.
Definition node.hpp:872
detail::TopDownTraverserGeneric< false > TopDownTraverser
Traverser for visiting every node in a region in a top down order.
rvsdg::Output * output
Output of gamma.
Definition gamma.hpp:154