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 statisticsCollector.CollectDemandedStatistics(std::move(statistics));
156
157 return std::move(ModRefSummary_);
158}
159
162{
163 AgnosticModRefSet modRefSet;
164 for (const auto allocaNode : pointsToGraph.allocaNodes())
165 modRefSet.addMemoryNode(allocaNode, ModRefEffect::ModRef);
166
167 for (const auto deltaNode : pointsToGraph.deltaNodes())
168 modRefSet.addMemoryNode(deltaNode, ModRefEffect::ModRef);
169
170 for (const auto lambdaNode : pointsToGraph.lambdaNodes())
171 modRefSet.addMemoryNode(lambdaNode, ModRefEffect::ModRef);
172
173 for (const auto mallocNode : pointsToGraph.mallocNodes())
174 modRefSet.addMemoryNode(mallocNode, ModRefEffect::ModRef);
175
176 for (const auto importNode : pointsToGraph.importNodes())
177 modRefSet.addMemoryNode(importNode, ModRefEffect::ModRef);
178
179 modRefSet.addMemoryNode(pointsToGraph.getExternalMemoryNode(), ModRefEffect::ModRef);
180
181 JLM_ASSERT(modRefSet.getModRefNodes().size() == pointsToGraph.numMemoryNodes());
182
183 return modRefSet;
184}
185
186void
188{
189 for (const auto & node : region.Nodes())
190 {
192 node,
193 [&](const rvsdg::SimpleNode & simpleNode)
194 {
195 AnnotateSimpleNode(simpleNode);
196 },
197 [&](const rvsdg::StructuralNode & structuralNode)
198 {
199 for (const auto & subregion : structuralNode.Subregions())
200 {
201 AnnotateRegion(subregion);
202 }
203 });
204 }
205}
206
207void
209 const rvsdg::Output & output,
210 ModRefEffect modRefEffect,
211 AgnosticModRefSet & modRefSet) const
212{
213 const auto & pointsToGraph = ModRefSummary_->GetPointsToGraph();
215 const auto & addressReg = pointsToGraph.getNodeForRegister(output);
216 for (const auto target : pointsToGraph.getExplicitTargets(addressReg).Items())
217 {
218 modRefSet.addMemoryNode(target, modRefEffect);
219 }
220 if (pointsToGraph.isTargetingAllExternallyAvailable(addressReg))
221 {
222 // Add all externally available memory nodes
223 for (const auto implicitTarget : pointsToGraph.getExternallyAvailableNodes())
224 {
225 modRefSet.addMemoryNode(implicitTarget, modRefEffect);
226 }
227 }
228}
229
230void
232{
233 MatchTypeWithDefault(
234 node.GetOperation(),
235 [&](const StoreOperation &)
236 {
237 const auto & address = *StoreOperation::AddressInput(node).origin();
238 AgnosticModRefSet modRefSet;
239 AddPointerTargetsToModRefSet(address, ModRefEffect::ModOnly, modRefSet);
240 ModRefSummary_->SetSimpleNodeModRef(node, std::move(modRefSet));
241 },
242 [&](const LoadOperation &)
243 {
244 const auto & address = *LoadOperation::AddressInput(node).origin();
245 AgnosticModRefSet modRefSet;
246 AddPointerTargetsToModRefSet(address, ModRefEffect::RefOnly, modRefSet);
247 ModRefSummary_->SetSimpleNodeModRef(node, std::move(modRefSet));
248 },
249 [&](const MemCpyOperation &)
250 {
251 AgnosticModRefSet modRefSet;
252 const auto & srcAddress = *MemCpyOperation::sourceInput(node).origin();
253 const auto & dstAddress = *MemCpyOperation::destinationInput(node).origin();
254 AddPointerTargetsToModRefSet(srcAddress, ModRefEffect::RefOnly, modRefSet);
255 AddPointerTargetsToModRefSet(dstAddress, ModRefEffect::ModOnly, modRefSet);
256 ModRefSummary_->SetSimpleNodeModRef(node, std::move(modRefSet));
257 },
258 [&](const MemSetOperation &)
259 {
260 AgnosticModRefSet modRefSet;
261 const auto & dstAddress = *MemSetOperation::destinationInput(node).origin();
262 AddPointerTargetsToModRefSet(dstAddress, ModRefEffect::ModOnly, modRefSet);
263 ModRefSummary_->SetSimpleNodeModRef(node, std::move(modRefSet));
264 },
265 [&](const FreeOperation &)
266 {
267 AgnosticModRefSet modRefSet;
268 const auto & freeAddress = *FreeOperation::addressInput(node).origin();
269 AddPointerTargetsToModRefSet(freeAddress, ModRefEffect::ModOnly, modRefSet);
270 ModRefSummary_->SetSimpleNodeModRef(node, std::move(modRefSet));
271 },
272 [&](const AllocaOperation &)
273 {
274 const auto allocaMemoryNode = ModRefSummary_->GetPointsToGraph().getNodeForAlloca(node);
275 AgnosticModRefSet modRefSet;
276 // The alloca operation does not assign to the allocated memory, so Ref is more precise
277 modRefSet.addMemoryNode(allocaMemoryNode, ModRefEffect::RefOnly);
278 ModRefSummary_->SetSimpleNodeModRef(node, std::move(modRefSet));
279 },
280 [&](const MallocOperation &)
281 {
282 const auto mallocMemoryNode = ModRefSummary_->GetPointsToGraph().getNodeForMalloc(node);
283 AgnosticModRefSet modRefSet;
284 // The malloc operation does not assign to the allocated memory, so Ref is more precise
285 modRefSet.addMemoryNode(mallocMemoryNode, ModRefEffect::RefOnly);
286 ModRefSummary_->SetSimpleNodeModRef(node, std::move(modRefSet));
287 },
288 [&](const CallOperation &)
289 {
290 // CallOperations are omitted on purpose, as calls use the AllMemoryNodes as their ModRef
291 // set.
292 },
293 [&](const MemoryStateOperation &)
294 {
295 // Memory state operations are only used to route memory state edges
296 },
297 [&]()
298 {
299 // Any remaining type of node should not involve any memory states
300 JLM_ASSERT(!hasMemoryState(node));
301 });
302}
303
304std::unique_ptr<ModRefSummary>
306 const rvsdg::RvsdgModule & rvsdgModule,
307 const PointsToGraph & pointsToGraph,
309{
310 AgnosticModRefSummarizer summarizer;
311 return summarizer.SummarizeModRefs(rvsdgModule, pointsToGraph, statisticsCollector);
312}
313
314std::unique_ptr<ModRefSummary>
316 const rvsdg::RvsdgModule & rvsdgModule,
317 const PointsToGraph & pointsToGraph)
318{
320 return Create(rvsdgModule, pointsToGraph, statisticsCollector);
321}
322
323}
static jlm::util::StatisticsCollector statisticsCollector
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
void CollectDemandedStatistics(std::unique_ptr< Statistics > statistics)
#define JLM_ASSERT(x)
Definition common.hpp:16
bool IsPointerCompatible(const rvsdg::Output &value)
void MatchTypeOrFail(T &obj, const Fns &... fns)
Pattern match over subclass type of given object.