Jlm
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 
10 
11 namespace jlm::llvm::aa
12 {
13 
18 {
19 public:
21  std::unordered_map<const rvsdg::SimpleNode *, util::HashSet<PointsToGraph::NodeIndex>>;
22 
23  ~AgnosticModRefSummary() noexcept override = default;
24 
25 private:
27  const PointsToGraph & pointsToGraph,
28  util::HashSet<PointsToGraph::NodeIndex> allMemoryNodes)
29  : PointsToGraph_(pointsToGraph),
30  AllMemoryNodes_(std::move(allMemoryNodes))
31  {}
32 
33 public:
35 
37 
39  operator=(const AgnosticModRefSummary &) = delete;
40 
43 
44  [[nodiscard]] const PointsToGraph &
45  GetPointsToGraph() const noexcept override
46  {
47  return PointsToGraph_;
48  }
49 
50  void
52  const rvsdg::SimpleNode & node,
54  {
55  JLM_ASSERT(SimpleNodeModRefs_.find(&node) == SimpleNodeModRefs_.end());
56  SimpleNodeModRefs_[&node] = std::move(modRefSet);
57  }
58 
59  [[nodiscard]] const util::HashSet<PointsToGraph::NodeIndex> &
60  GetSimpleNodeModRef(const rvsdg::SimpleNode & node) const override
61  {
62  if (const auto it = SimpleNodeModRefs_.find(&node); it != SimpleNodeModRefs_.end())
63  {
64  return it->second;
65  }
66  if (is<CallOperation>(node.GetOperation()))
67  {
68  return AllMemoryNodes_;
69  }
70  throw std::logic_error("Unhandled node type.");
71  }
72 
73  [[nodiscard]] const util::HashSet<PointsToGraph::NodeIndex> &
74  GetGammaEntryModRef([[maybe_unused]] const rvsdg::GammaNode & gamma) const override
75  {
76  return AllMemoryNodes_;
77  }
78 
79  [[nodiscard]] const util::HashSet<PointsToGraph::NodeIndex> &
80  GetGammaExitModRef([[maybe_unused]] const rvsdg::GammaNode & gamma) const override
81  {
82  return AllMemoryNodes_;
83  }
84 
85  [[nodiscard]] const util::HashSet<PointsToGraph::NodeIndex> &
86  GetThetaModRef([[maybe_unused]] const rvsdg::ThetaNode & theta) const override
87  {
88  return AllMemoryNodes_;
89  }
90 
91  [[nodiscard]] const util::HashSet<PointsToGraph::NodeIndex> &
92  GetLambdaEntryModRef([[maybe_unused]] const rvsdg::LambdaNode & lambda) const override
93  {
94  return AllMemoryNodes_;
95  }
96 
97  [[nodiscard]] const util::HashSet<PointsToGraph::NodeIndex> &
98  GetLambdaExitModRef([[maybe_unused]] const rvsdg::LambdaNode & lambda) const override
99  {
100  return AllMemoryNodes_;
101  }
102 
103  static std::unique_ptr<AgnosticModRefSummary>
105  {
106  return std::unique_ptr<AgnosticModRefSummary>(
107  new AgnosticModRefSummary(pointsToGraph, std::move(memoryNodes)));
108  }
109 
110 private:
114 };
115 
117 
119 
120 std::unique_ptr<ModRefSummary>
122  const rvsdg::RvsdgModule & rvsdgModule,
123  const PointsToGraph & pointsToGraph,
124  util::StatisticsCollector & statisticsCollector)
125 {
126  auto statistics =
127  Statistics::Create(rvsdgModule.SourceFilePath().value(), statisticsCollector, pointsToGraph);
128  statistics->StartCollecting();
129 
130  auto allMemoryNodes = GetAllMemoryNodes(pointsToGraph);
131 
132  ModRefSummary_ = AgnosticModRefSummary::Create(pointsToGraph, std::move(allMemoryNodes));
133 
134  // Create ModRefSets for SimpleNodes that affect memory
135  AnnotateRegion(rvsdgModule.Rvsdg().GetRootRegion());
136 
137  statistics->StopCollecting();
138  statisticsCollector.CollectDemandedStatistics(std::move(statistics));
139 
140  return std::move(ModRefSummary_);
141 }
142 
145 {
147  for (const auto allocaNode : pointsToGraph.allocaNodes())
148  memoryNodes.insert(allocaNode);
149 
150  for (const auto deltaNode : pointsToGraph.deltaNodes())
151  memoryNodes.insert(deltaNode);
152 
153  for (const auto lambdaNode : pointsToGraph.lambdaNodes())
154  memoryNodes.insert(lambdaNode);
155 
156  for (const auto mallocNode : pointsToGraph.mallocNodes())
157  memoryNodes.insert(mallocNode);
158 
159  for (const auto importNode : pointsToGraph.importNodes())
160  memoryNodes.insert(importNode);
161 
162  memoryNodes.insert(pointsToGraph.getExternalMemoryNode());
163 
164  JLM_ASSERT(memoryNodes.Size() == pointsToGraph.numMemoryNodes());
165 
166  return memoryNodes;
167 }
168 
169 void
171 {
172  for (const auto & node : region.Nodes())
173  {
175  node,
176  [&](const rvsdg::SimpleNode & simpleNode)
177  {
178  AnnotateSimpleNode(simpleNode);
179  },
180  [&](const rvsdg::StructuralNode & structuralNode)
181  {
182  for (const auto & subregion : structuralNode.Subregions())
183  {
184  AnnotateRegion(subregion);
185  }
186  });
187  }
188 }
189 
190 void
192  const rvsdg::Output & output,
193  util::HashSet<PointsToGraph::NodeIndex> & modRefSet) const
194 {
195  const auto & pointsToGraph = ModRefSummary_->GetPointsToGraph();
197  const auto & addressReg = pointsToGraph.getNodeForRegister(output);
198  for (const auto target : pointsToGraph.getExplicitTargets(addressReg).Items())
199  {
200  modRefSet.insert(target);
201  }
202  if (pointsToGraph.isTargetingAllExternallyAvailable(addressReg))
203  {
204  for (const auto implicitTarget : pointsToGraph.getExternallyAvailableNodes())
205  {
206  modRefSet.insert(implicitTarget);
207  }
208  }
209 }
210 
211 void
213 {
215  node.GetOperation(),
216  [&](const StoreOperation &)
217  {
218  const auto & address = *StoreOperation::AddressInput(node).origin();
219  util::HashSet<PointsToGraph::NodeIndex> modRefSet;
220  AddPointerTargetsToModRefSet(address, modRefSet);
221  ModRefSummary_->SetSimpleNodeModRef(node, std::move(modRefSet));
222  },
223  [&](const LoadOperation &)
224  {
225  const auto & address = *LoadOperation::AddressInput(node).origin();
226  util::HashSet<PointsToGraph::NodeIndex> modRefSet;
227  AddPointerTargetsToModRefSet(address, modRefSet);
228  ModRefSummary_->SetSimpleNodeModRef(node, std::move(modRefSet));
229  },
230  [&](const MemCpyOperation &)
231  {
232  util::HashSet<PointsToGraph::NodeIndex> modRefSet;
233  const auto & srcAddress = *MemCpyOperation::sourceInput(node).origin();
234  const auto & dstAddress = *MemCpyOperation::destinationInput(node).origin();
235  AddPointerTargetsToModRefSet(srcAddress, modRefSet);
236  AddPointerTargetsToModRefSet(dstAddress, modRefSet);
237  ModRefSummary_->SetSimpleNodeModRef(node, std::move(modRefSet));
238  },
239  [&](const FreeOperation &)
240  {
241  util::HashSet<PointsToGraph::NodeIndex> modRefSet;
242  const auto & freeAddress = *FreeOperation::addressInput(node).origin();
243  AddPointerTargetsToModRefSet(freeAddress, modRefSet);
244  ModRefSummary_->SetSimpleNodeModRef(node, std::move(modRefSet));
245  },
246  [&](const AllocaOperation &)
247  {
248  const auto allocaMemoryNode = ModRefSummary_->GetPointsToGraph().getNodeForAlloca(node);
249  ModRefSummary_->SetSimpleNodeModRef(node, { allocaMemoryNode });
250  },
251  [&](const MallocOperation &)
252  {
253  const auto mallocMemoryNode = ModRefSummary_->GetPointsToGraph().getNodeForMalloc(node);
254  ModRefSummary_->SetSimpleNodeModRef(node, { mallocMemoryNode });
255  },
256  [&](const CallOperation &)
257  {
258  // CallOperations are omitted on purpose, as calls use the AllMemoryNodes as their ModRef
259  // set.
260  },
261  [&](const MemoryStateOperation &)
262  {
263  // Memory state operations are only used to route memory state edges
264  },
265  [&]()
266  {
267  // Any remaining type of node should not involve any memory states
268  JLM_ASSERT(!hasMemoryState(node));
269  });
270 }
271 
272 std::unique_ptr<ModRefSummary>
273 AgnosticModRefSummarizer::Create(
274  const rvsdg::RvsdgModule & rvsdgModule,
275  const PointsToGraph & pointsToGraph,
276  util::StatisticsCollector & statisticsCollector)
277 {
278  AgnosticModRefSummarizer summarizer;
279  return summarizer.SummarizeModRefs(rvsdgModule, pointsToGraph, statisticsCollector);
280 }
281 
282 std::unique_ptr<ModRefSummary>
283 AgnosticModRefSummarizer::Create(
284  const rvsdg::RvsdgModule & rvsdgModule,
285  const PointsToGraph & pointsToGraph)
286 {
287  util::StatisticsCollector statisticsCollector;
288  return Create(rvsdgModule, pointsToGraph, statisticsCollector);
289 }
290 
291 }
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
void AddPointerTargetsToModRefSet(const rvsdg::Output &output, util::HashSet< PointsToGraph::NodeIndex > &modRefSet) const
static util::HashSet< PointsToGraph::NodeIndex > 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 util::HashSet< PointsToGraph::NodeIndex > & GetSimpleNodeModRef(const rvsdg::SimpleNode &node) const override
void SetSimpleNodeModRef(const rvsdg::SimpleNode &node, util::HashSet< PointsToGraph::NodeIndex > modRefSet)
const util::HashSet< PointsToGraph::NodeIndex > & GetGammaExitModRef([[maybe_unused]] const rvsdg::GammaNode &gamma) const override
std::unordered_map< const rvsdg::SimpleNode *, util::HashSet< PointsToGraph::NodeIndex > > SimpleNodeModRefMap
~AgnosticModRefSummary() noexcept override=default
const util::HashSet< PointsToGraph::NodeIndex > & GetGammaEntryModRef([[maybe_unused]] const rvsdg::GammaNode &gamma) const override
AgnosticModRefSummary & operator=(const AgnosticModRefSummary &)=delete
const util::HashSet< PointsToGraph::NodeIndex > & GetLambdaExitModRef([[maybe_unused]] const rvsdg::LambdaNode &lambda) const override
static std::unique_ptr< AgnosticModRefSummary > Create(const PointsToGraph &pointsToGraph, util::HashSet< PointsToGraph::NodeIndex > memoryNodes)
const util::HashSet< PointsToGraph::NodeIndex > & GetThetaModRef([[maybe_unused]] const rvsdg::ThetaNode &theta) const override
AgnosticModRefSummary(const AgnosticModRefSummary &)=delete
AgnosticModRefSummary(const PointsToGraph &pointsToGraph, util::HashSet< PointsToGraph::NodeIndex > allMemoryNodes)
AgnosticModRefSummary & operator=(AgnosticModRefSummary &&)=delete
const util::HashSet< PointsToGraph::NodeIndex > & GetLambdaEntryModRef([[maybe_unused]] const rvsdg::LambdaNode &lambda) const override
util::HashSet< PointsToGraph::NodeIndex > AllMemoryNodes_
const PointsToGraph & GetPointsToGraph() const noexcept override
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
Lambda node.
Definition: lambda.hpp:83
Represent acyclic RVSDG subgraphs.
Definition: region.hpp:213
NodeRange Nodes() noexcept
Definition: region.hpp:328
const std::optional< util::FilePath > & SourceFilePath() const noexcept
Definition: RvsdgModule.hpp:73
Graph & Rvsdg() noexcept
Definition: RvsdgModule.hpp:57
const SimpleOperation & GetOperation() const noexcept override
Definition: simple-node.cpp:48
bool insert(ItemType item)
Definition: HashSet.hpp:210
std::size_t Size() const noexcept
Definition: HashSet.hpp:187
void CollectDemandedStatistics(std::unique_ptr< Statistics > statistics)
Definition: Statistics.hpp:563
#define JLM_ASSERT(x)
Definition: common.hpp:16
bool IsPointerCompatible(const rvsdg::Output &value)
bool hasMemoryState(const rvsdg::Node &node)
void MatchTypeWithDefault(T &obj, const Fns &... fns)
Pattern match over subclass type of given object with default handler.
void MatchTypeOrFail(T &obj, const Fns &... fns)
Pattern match over subclass type of given object.