Jlm
Loading...
Searching...
No Matches
AgnosticModRefSummarizer.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2022 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
18#include <jlm/util/common.hpp>
19
20#include <unordered_map>
21
23{
24
28class AgnosticModRefSet final : public ModRefSet
29{
30public:
31 void
33 {
34 JLM_ASSERT(modRefEffect != ModRefEffect::NoEffect);
35 modRefNodes_[memoryNode] |= modRefEffect;
36 }
37};
38
43{
44public:
45 ~AgnosticModRefSummary() noexcept override = default;
46
47private:
48 AgnosticModRefSummary(const PointsToGraph & pointsToGraph, AgnosticModRefSet allMemoryNodes)
49 : PointsToGraph_(pointsToGraph),
50 AllMemoryNodes_(std::move(allMemoryNodes))
51 {}
52
53public:
55
57
60
63
64 [[nodiscard]] const PointsToGraph &
65 GetPointsToGraph() const noexcept override
66 {
67 return PointsToGraph_;
68 }
69
70 void
72 {
74 SimpleNodeModRefs_.insert({ &node, std::move(modRefSet) });
75 }
76
77 [[nodiscard]] const ModRefSet &
78 GetSimpleNodeModRef(const rvsdg::SimpleNode & node) const override
79 {
80 if (const auto it = SimpleNodeModRefs_.find(&node); it != SimpleNodeModRefs_.end())
81 {
82 return it->second;
83 }
84 if (is<CallOperation>(node.GetOperation()))
85 {
86 return AllMemoryNodes_;
87 }
88 throw std::logic_error("Unhandled node type.");
89 }
90
91 [[nodiscard]] const ModRefSet &
92 GetGammaEntryModRef([[maybe_unused]] const rvsdg::GammaNode & gamma) const override
93 {
94 return AllMemoryNodes_;
95 }
96
97 [[nodiscard]] const ModRefSet &
98 GetGammaExitModRef([[maybe_unused]] const rvsdg::GammaNode & gamma) const override
99 {
100 return AllMemoryNodes_;
101 }
102
103 [[nodiscard]] const ModRefSet &
104 GetThetaModRef([[maybe_unused]] const rvsdg::ThetaNode & theta) const override
105 {
106 return AllMemoryNodes_;
107 }
108
109 [[nodiscard]] const ModRefSet &
110 GetLambdaEntryModRef([[maybe_unused]] const rvsdg::LambdaNode & lambda) const override
111 {
112 return AllMemoryNodes_;
113 }
114
115 [[nodiscard]] const ModRefSet &
116 GetLambdaExitModRef([[maybe_unused]] const rvsdg::LambdaNode & lambda) const override
117 {
118 return AllMemoryNodes_;
119 }
120
121 static std::unique_ptr<AgnosticModRefSummary>
122 Create(const PointsToGraph & pointsToGraph, AgnosticModRefSet allMemoryNodes)
123 {
124 return std::unique_ptr<AgnosticModRefSummary>(
125 new AgnosticModRefSummary(pointsToGraph, std::move(allMemoryNodes)));
126 }
127
128private:
130 std::unordered_map<const rvsdg::SimpleNode *, AgnosticModRefSet> SimpleNodeModRefs_;
132};
133
135
137
138std::unique_ptr<ModRefSummary>
140 const rvsdg::RvsdgModule & rvsdgModule,
141 const PointsToGraph & pointsToGraph,
143{
144 auto statistics =
145 Statistics::Create(rvsdgModule.SourceFilePath().value(), statisticsCollector, pointsToGraph);
146 statistics->StartCollecting();
147
148 auto allMemoryNodes = GetAllMemoryNodes(pointsToGraph);
149 ModRefSummary_ = AgnosticModRefSummary::Create(pointsToGraph, std::move(allMemoryNodes));
150
151 // Create ModRefSets for SimpleNodes that affect memory
152 AnnotateRegion(rvsdgModule.Rvsdg().GetRootRegion());
153
154 statistics->StopCollecting();
155
156 // Perform the collection of the memory state distribution AFTER we invoked StopCollecting() such
157 // that it does not count into the timing measurements
158 if (statisticsCollector.IsDemanded(statistics->GetId()))
159 {
160 const auto summaries = collectMemoryStateDistribution(rvsdgModule.Rvsdg(), *ModRefSummary_);
161 statistics->addMemoryStateDistribution(summaries);
162 }
163
164 statisticsCollector.CollectDemandedStatistics(std::move(statistics));
165
166 return std::move(ModRefSummary_);
167}
168
171{
172 AgnosticModRefSet modRefSet;
173 for (const auto allocaNode : pointsToGraph.allocaNodes())
174 modRefSet.addMemoryNode(allocaNode, ModRefEffect::ModRef);
175
176 for (const auto deltaNode : pointsToGraph.deltaNodes())
177 modRefSet.addMemoryNode(deltaNode, ModRefEffect::ModRef);
178
179 for (const auto lambdaNode : pointsToGraph.lambdaNodes())
180 modRefSet.addMemoryNode(lambdaNode, ModRefEffect::ModRef);
181
182 for (const auto mallocNode : pointsToGraph.mallocNodes())
183 modRefSet.addMemoryNode(mallocNode, ModRefEffect::ModRef);
184
185 for (const auto importNode : pointsToGraph.importNodes())
186 modRefSet.addMemoryNode(importNode, ModRefEffect::ModRef);
187
188 modRefSet.addMemoryNode(pointsToGraph.getExternalMemoryNode(), ModRefEffect::ModRef);
189
190 JLM_ASSERT(modRefSet.getModRefNodes().size() == pointsToGraph.numMemoryNodes());
191
192 return modRefSet;
193}
194
195void
197{
198 for (const auto & node : region.Nodes())
199 {
201 node,
202 [&](const rvsdg::SimpleNode & simpleNode)
203 {
204 AnnotateSimpleNode(simpleNode);
205 },
206 [&](const rvsdg::StructuralNode & structuralNode)
207 {
208 for (const auto & subregion : structuralNode.Subregions())
209 {
210 AnnotateRegion(subregion);
211 }
212 });
213 }
214}
215
216void
218 const rvsdg::Output & output,
219 ModRefEffect modRefEffect,
220 AgnosticModRefSet & modRefSet) const
221{
222 const auto & pointsToGraph = ModRefSummary_->GetPointsToGraph();
224 const auto & addressReg = pointsToGraph.getNodeForRegister(output);
225 for (const auto target : pointsToGraph.getExplicitTargets(addressReg).Items())
226 {
227 modRefSet.addMemoryNode(target, modRefEffect);
228 }
229 if (pointsToGraph.isTargetingAllExternallyAvailable(addressReg))
230 {
231 // Add all externally available memory nodes
232 for (const auto implicitTarget : pointsToGraph.getExternallyAvailableNodes())
233 {
234 modRefSet.addMemoryNode(implicitTarget, modRefEffect);
235 }
236 }
237}
238
239void
241{
242 MatchTypeWithDefault(
243 node.GetOperation(),
244 [&](const StoreOperation &)
245 {
246 const auto & address = *StoreOperation::AddressInput(node).origin();
247 AgnosticModRefSet modRefSet;
248 AddPointerTargetsToModRefSet(address, ModRefEffect::ModOnly, modRefSet);
249 ModRefSummary_->SetSimpleNodeModRef(node, std::move(modRefSet));
250 },
251 [&](const LoadOperation &)
252 {
253 const auto & address = *LoadOperation::AddressInput(node).origin();
254 AgnosticModRefSet modRefSet;
255 AddPointerTargetsToModRefSet(address, ModRefEffect::RefOnly, modRefSet);
256 ModRefSummary_->SetSimpleNodeModRef(node, std::move(modRefSet));
257 },
258 [&](const MemCpyOperation &)
259 {
260 AgnosticModRefSet modRefSet;
261 const auto & srcAddress = *MemCpyOperation::sourceInput(node).origin();
262 const auto & dstAddress = *MemCpyOperation::destinationInput(node).origin();
263 AddPointerTargetsToModRefSet(srcAddress, ModRefEffect::RefOnly, modRefSet);
264 AddPointerTargetsToModRefSet(dstAddress, ModRefEffect::ModOnly, modRefSet);
265 ModRefSummary_->SetSimpleNodeModRef(node, std::move(modRefSet));
266 },
267 [&](const MemMoveOperation &)
268 {
269 AgnosticModRefSet modRefSet;
270 const auto & srcAddress = *MemMoveOperation::sourceInput(node).origin();
271 const auto & dstAddress = *MemMoveOperation::destinationInput(node).origin();
272 AddPointerTargetsToModRefSet(srcAddress, RefOnly, modRefSet);
273 AddPointerTargetsToModRefSet(dstAddress, ModOnly, modRefSet);
274 ModRefSummary_->SetSimpleNodeModRef(node, std::move(modRefSet));
275 },
276 [&](const MemSetOperation &)
277 {
278 AgnosticModRefSet modRefSet;
279 const auto & dstAddress = *MemSetOperation::destinationInput(node).origin();
280 AddPointerTargetsToModRefSet(dstAddress, ModRefEffect::ModOnly, modRefSet);
281 ModRefSummary_->SetSimpleNodeModRef(node, std::move(modRefSet));
282 },
283 [&](const FreeOperation &)
284 {
285 AgnosticModRefSet modRefSet;
286 const auto & freeAddress = *FreeOperation::getAddressInput(node).origin();
287 AddPointerTargetsToModRefSet(freeAddress, ModRefEffect::ModOnly, modRefSet);
288 ModRefSummary_->SetSimpleNodeModRef(node, std::move(modRefSet));
289 },
290 [&](const AllocaOperation &)
291 {
292 const auto allocaMemoryNode = ModRefSummary_->GetPointsToGraph().getNodeForAlloca(node);
293 AgnosticModRefSet modRefSet;
294 // The alloca operation does not assign to the allocated memory, so Ref is more precise
295 modRefSet.addMemoryNode(allocaMemoryNode, ModRefEffect::RefOnly);
296 ModRefSummary_->SetSimpleNodeModRef(node, std::move(modRefSet));
297 },
298 [&](const MallocOperation &)
299 {
300 const auto mallocMemoryNode = ModRefSummary_->GetPointsToGraph().getNodeForMalloc(node);
301 AgnosticModRefSet modRefSet;
302 // The malloc operation does not assign to the allocated memory, so Ref is more precise
303 modRefSet.addMemoryNode(mallocMemoryNode, ModRefEffect::RefOnly);
304 ModRefSummary_->SetSimpleNodeModRef(node, std::move(modRefSet));
305 },
306 [&](const CallOperation &)
307 {
308 // CallOperations are omitted on purpose, as calls use the AllMemoryNodes as their ModRef
309 // set.
310 },
311 [&](const MemoryStateOperation &)
312 {
313 // Memory state operations are only used to route memory state edges
314 },
315 [&]()
316 {
317 // Any remaining type of node should not involve any memory states
318 JLM_ASSERT(!hasMemoryState(node));
319 });
320}
321
322std::unique_ptr<ModRefSummary>
324 const rvsdg::RvsdgModule & rvsdgModule,
325 const PointsToGraph & pointsToGraph,
327{
328 AgnosticModRefSummarizer summarizer;
329 return summarizer.SummarizeModRefs(rvsdgModule, pointsToGraph, statisticsCollector);
330}
331
332std::unique_ptr<ModRefSummary>
334 const rvsdg::RvsdgModule & rvsdgModule,
335 const PointsToGraph & pointsToGraph)
336{
338 return Create(rvsdgModule, pointsToGraph, statisticsCollector);
339}
340
341}
Call operation class.
Definition call.hpp:251
class returned by the Agnostic ModRefSummarizer
void addMemoryNode(PointsToGraph::NodeIndex memoryNode, ModRefEffect modRefEffect)
static std::unique_ptr< Statistics > Create(const util::FilePath &sourceFile, const util::StatisticsCollector &statisticsCollector, const PointsToGraph &pointsToGraph)
std::unique_ptr< ModRefSummary > SummarizeModRefs(const rvsdg::RvsdgModule &rvsdgModule, const PointsToGraph &pointsToGraph, util::StatisticsCollector &statisticsCollector) override
static std::unique_ptr< ModRefSummary > Create(const rvsdg::RvsdgModule &rvsdgModule, const PointsToGraph &pointsToGraph, util::StatisticsCollector &statisticsCollector)
void AddPointerTargetsToModRefSet(const rvsdg::Output &output, ModRefEffect modRefEffect, AgnosticModRefSet &modRefSet) const
static AgnosticModRefSet GetAllMemoryNodes(const PointsToGraph &pointsToGraph)
void AnnotateRegion(const rvsdg::Region &region)
void AnnotateSimpleNode(const rvsdg::SimpleNode &node)
std::unique_ptr< AgnosticModRefSummary > ModRefSummary_
Mod/Ref summary of agnostic mod/ref summarizer.
AgnosticModRefSummary(AgnosticModRefSummary &&)=delete
const ModRefSet & GetGammaEntryModRef(const rvsdg::GammaNode &gamma) const override
const ModRefSet & GetGammaExitModRef(const rvsdg::GammaNode &gamma) const override
~AgnosticModRefSummary() noexcept override=default
const ModRefSet & GetSimpleNodeModRef(const rvsdg::SimpleNode &node) const override
AgnosticModRefSummary & operator=(const AgnosticModRefSummary &)=delete
AgnosticModRefSummary & operator=(AgnosticModRefSummary &&)=delete
const ModRefSet & GetLambdaEntryModRef(const rvsdg::LambdaNode &lambda) const override
void SetSimpleNodeModRef(const rvsdg::SimpleNode &node, AgnosticModRefSet modRefSet)
const PointsToGraph & GetPointsToGraph() const noexcept override
std::unordered_map< const rvsdg::SimpleNode *, AgnosticModRefSet > SimpleNodeModRefs_
AgnosticModRefSummary(const AgnosticModRefSummary &)=delete
const ModRefSet & GetLambdaExitModRef(const rvsdg::LambdaNode &lambda) const override
static std::unique_ptr< AgnosticModRefSummary > Create(const PointsToGraph &pointsToGraph, AgnosticModRefSet allMemoryNodes)
const ModRefSet & GetThetaModRef(const rvsdg::ThetaNode &theta) const override
std::unordered_map< PointsToGraph::NodeIndex, ModRefEffect > modRefNodes_
const std::unordered_map< PointsToGraph::NodeIndex, ModRefEffect > & getModRefNodes() const
size_t numMemoryNodes() const noexcept
AllocaNodeRange allocaNodes() const noexcept
NodeIndex getExternalMemoryNode() const noexcept
LambdaNodeRange lambdaNodes() const noexcept
DeltaNodeRange deltaNodes() const noexcept
MallocNodeRange mallocNodes() const noexcept
ImportNodeRange importNodes() const noexcept
Conditional operator / pattern matching.
Definition gamma.hpp:99
Region & GetRootRegion() const noexcept
Definition graph.hpp:99
Represent acyclic RVSDG subgraphs.
Definition region.hpp:213
NodeRange Nodes() noexcept
Definition region.hpp:375
const std::optional< util::FilePath > & SourceFilePath() const noexcept
Graph & Rvsdg() noexcept
const SimpleOperation & GetOperation() const noexcept override
bool IsDemanded(Statistics::Id id) const noexcept
void CollectDemandedStatistics(std::unique_ptr< Statistics > statistics)
#define JLM_ASSERT(x)
Definition common.hpp:16
bool IsPointerCompatible(const rvsdg::Output &value)
std::vector< MemoryStateSummary > collectMemoryStateDistribution(const rvsdg::Graph &rvsdg, const ModRefSummary &modRefSummary)
static util::StatisticsCollector statisticsCollector
void MatchTypeOrFail(T &obj, const Fns &... fns)
Pattern match over subclass type of given object.