Jlm
PointsToGraphTests.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2023 Nico Reißmann <nico.reissmann@gmail.com>
3  * See COPYING for terms of redistribution.
4  */
5 
6 #include <gtest/gtest.h>
7 
13 #include <jlm/llvm/TestRvsdgs.hpp>
14 #include <jlm/rvsdg/delta.hpp>
16 #include <jlm/util/Statistics.hpp>
17 
22 {
23 public:
24  std::unique_ptr<jlm::llvm::aa::PointsToGraph>
26  {
28 
29  AnalyzeImports(rvsdgModule.Rvsdg());
30  AnalyzeRegion(rvsdgModule.Rvsdg().GetRootRegion());
31 
32  return std::move(pointsToGraph_);
33  }
34 
35  std::unique_ptr<jlm::llvm::aa::PointsToGraph>
36  Analyze(const jlm::llvm::LlvmRvsdgModule & rvsdgModule)
37  {
39  return Analyze(rvsdgModule, statisticsCollector);
40  }
41 
42  static std::unique_ptr<jlm::llvm::aa::PointsToGraph>
44  {
45  TestAnalysis analysis;
46  return analysis.Analyze(rvsdgModule);
47  }
48 
49 private:
50  void
52  {
53  using namespace jlm::llvm;
54 
55  for (auto & node : region.Nodes())
56  {
57  if (jlm::rvsdg::is<AllocaOperation>(&node))
58  {
59  auto simpleNode = jlm::util::assertedCast<jlm::rvsdg::SimpleNode>(&node);
60  auto ptgAllocaNode = pointsToGraph_->addNodeForAlloca(*simpleNode, false);
61  auto ptgRegisterNode = pointsToGraph_->addNodeForRegisters();
62  pointsToGraph_->mapRegisterToNode(*node.output(0), ptgRegisterNode);
63  pointsToGraph_->addTarget(ptgRegisterNode, ptgAllocaNode);
64  }
65  else if (jlm::rvsdg::is<MallocOperation>(&node))
66  {
67  auto simpleNode = jlm::util::assertedCast<jlm::rvsdg::SimpleNode>(&node);
68  auto ptgMallocNode = pointsToGraph_->addNodeForMalloc(*simpleNode, true);
69  auto ptgRegisterNode = pointsToGraph_->addNodeForRegisters();
70  pointsToGraph_->mapRegisterToNode(MallocOperation::addressOutput(node), ptgRegisterNode);
71  pointsToGraph_->addTarget(ptgRegisterNode, ptgMallocNode);
72  }
73  else if (auto deltaNode = dynamic_cast<const jlm::rvsdg::DeltaNode *>(&node))
74  {
75  auto ptgDeltaNode = pointsToGraph_->addNodeForDelta(*deltaNode, true);
76  auto ptgRegisterNode = pointsToGraph_->addNodeForRegisters();
77  pointsToGraph_->mapRegisterToNode(*node.output(0), ptgRegisterNode);
78  pointsToGraph_->addTarget(ptgRegisterNode, ptgDeltaNode);
79 
80  AnalyzeRegion(*deltaNode->subregion());
81  }
82  else if (auto lambdaNode = dynamic_cast<const jlm::rvsdg::LambdaNode *>(&node))
83  {
84  auto ptgLambdaNode = pointsToGraph_->addNodeForLambda(*lambdaNode, true);
85  auto ptgRegisterNode = pointsToGraph_->addNodeForRegisters();
86  pointsToGraph_->mapRegisterToNode(*node.output(0), ptgRegisterNode);
87  pointsToGraph_->addTarget(ptgRegisterNode, ptgLambdaNode);
88 
89  AnalyzeRegion(*lambdaNode->subregion());
90  }
91  }
92  }
93 
94  void
96  {
97  using namespace jlm::llvm;
98 
99  auto & rootRegion = rvsdg.GetRootRegion();
100  for (size_t n = 0; n < rootRegion.narguments(); n++)
101  {
102  auto & graphImport = *jlm::util::assertedCast<const LlvmGraphImport>(rootRegion.argument(n));
103 
104  const auto ptgImportNode = pointsToGraph_->addNodeForImport(graphImport, true);
105  const auto ptgRegisterNode = pointsToGraph_->addNodeForRegisters();
106  pointsToGraph_->mapRegisterToNode(graphImport, ptgRegisterNode);
107  pointsToGraph_->addTarget(ptgRegisterNode, ptgImportNode);
108  }
109  }
110 
111  std::unique_ptr<jlm::llvm::aa::PointsToGraph> pointsToGraph_;
112 };
113 
114 TEST(PointsToGraphTests, TestNodeIterators)
115 {
116  // Arrange
118  auto pointsToGraph = TestAnalysis::CreateAndAnalyze(test.module());
119 
120  using NodeIndex = jlm::llvm::aa::PointsToGraph::NodeIndex;
122 
123  // Act and Assert
124  EXPECT_EQ(pointsToGraph->numImportNodes(), 1u);
125  for (auto importNode : pointsToGraph->importNodes())
126  {
127  EXPECT_EQ(pointsToGraph->getNodeKind(importNode), NodeKind::ImportNode);
128  EXPECT_EQ(&pointsToGraph->getImportForNode(importNode), &test.GetImportOutput());
129  }
130 
131  EXPECT_EQ(pointsToGraph->numLambdaNodes(), 1u);
132  for (auto & lambdaNode : pointsToGraph->lambdaNodes())
133  {
134  EXPECT_EQ(pointsToGraph->getNodeKind(lambdaNode), NodeKind::LambdaNode);
135  EXPECT_EQ(&pointsToGraph->getLambdaForNode(lambdaNode), &test.GetLambdaNode());
136  }
137 
138  EXPECT_EQ(pointsToGraph->numDeltaNodes(), 1u);
139  for (auto & deltaNode : pointsToGraph->deltaNodes())
140  {
141  EXPECT_EQ(pointsToGraph->getNodeKind(deltaNode), NodeKind::DeltaNode);
142  EXPECT_EQ(&pointsToGraph->getDeltaForNode(deltaNode), &test.GetDeltaNode());
143  }
144 
145  EXPECT_EQ(pointsToGraph->numAllocaNodes(), 1u);
146  for (auto & allocaNode : pointsToGraph->allocaNodes())
147  {
148  EXPECT_EQ(pointsToGraph->getNodeKind(allocaNode), NodeKind::AllocaNode);
149  EXPECT_EQ(&pointsToGraph->getAllocaForNode(allocaNode), &test.GetAllocaNode());
150  }
151 
152  EXPECT_EQ(pointsToGraph->numMallocNodes(), 1u);
153  for (auto & mallocNode : pointsToGraph->mallocNodes())
154  {
155  EXPECT_EQ(pointsToGraph->getNodeKind(mallocNode), NodeKind::MallocNode);
156  EXPECT_EQ(&pointsToGraph->getMallocForNode(mallocNode), &test.GetMallocNode());
157  }
158 
159  // Check that each register is seen
160  EXPECT_EQ(pointsToGraph->numRegisterNodes(), 5u);
161  jlm::util::HashSet<NodeIndex> seenRegisterNodes;
162  for (auto & registerNode : pointsToGraph->registerNodes())
163  {
164  EXPECT_EQ(pointsToGraph->getNodeKind(registerNode), NodeKind::RegisterNode);
165  EXPECT_EQ(pointsToGraph->getExplicitTargets(registerNode).Size(), 1u);
166  seenRegisterNodes.insert(registerNode);
167  }
168  EXPECT_EQ(seenRegisterNodes.Size(), 5u);
169 
170  const auto ptgImportRegister = pointsToGraph->getNodeForRegister(test.GetImportOutput());
171  EXPECT_TRUE(seenRegisterNodes.Contains(ptgImportRegister));
172  const auto ptgLambdaRegister = pointsToGraph->getNodeForRegister(test.GetLambdaOutput());
173  EXPECT_TRUE(seenRegisterNodes.Contains(ptgLambdaRegister));
174  const auto ptgDeltaRegister = pointsToGraph->getNodeForRegister(test.GetDeltaOutput());
175  EXPECT_TRUE(seenRegisterNodes.Contains(ptgDeltaRegister));
176  const auto ptgAllocaRegister = pointsToGraph->getNodeForRegister(test.GetAllocaOutput());
177  EXPECT_TRUE(seenRegisterNodes.Contains(ptgAllocaRegister));
178  const auto ptgMallocRegister = pointsToGraph->getNodeForRegister(test.GetMallocOutput());
179  EXPECT_TRUE(seenRegisterNodes.Contains(ptgMallocRegister));
180 
181  // Check that the target of each register node is correct
182  const auto ptgImportNode = pointsToGraph->getNodeForImport(test.GetImportOutput());
183  EXPECT_TRUE(pointsToGraph->getExplicitTargets(ptgImportRegister).Contains(ptgImportNode));
184  const auto ptgLambdaNode = pointsToGraph->getNodeForLambda(test.GetLambdaNode());
185  EXPECT_TRUE(pointsToGraph->getExplicitTargets(ptgLambdaRegister).Contains(ptgLambdaNode));
186  const auto ptgDeltaNode = pointsToGraph->getNodeForDelta(test.GetDeltaNode());
187  EXPECT_TRUE(pointsToGraph->getExplicitTargets(ptgDeltaRegister).Contains(ptgDeltaNode));
188  const auto ptgAllocaNode = pointsToGraph->getNodeForAlloca(test.GetAllocaNode());
189  EXPECT_TRUE(pointsToGraph->getExplicitTargets(ptgAllocaRegister).Contains(ptgAllocaNode));
190  const auto ptgMallocNode = pointsToGraph->getNodeForMalloc(test.GetMallocNode());
191  EXPECT_TRUE(pointsToGraph->getExplicitTargets(ptgMallocRegister).Contains(ptgMallocNode));
192 }
193 
194 TEST(PointsToGraphTests, TestIsSupergraphOf)
195 {
196  using namespace jlm::llvm::aa;
197  auto graph0 = PointsToGraph::create();
198  auto graph1 = PointsToGraph::create();
199 
200  // Empty graphs are identical, and are both subgraphs of each other
201  EXPECT_TRUE(graph0->isSupergraphOf(*graph1));
202  EXPECT_TRUE(graph1->isSupergraphOf(*graph0));
203 
205  rvsdg.InitializeTest();
206 
207  // Adding an alloca node to only graph0, makes graph1 NOT a subgraph
208  const auto alloca0 = graph0->addNodeForAlloca(rvsdg.GetAllocaNode(), false);
209  EXPECT_TRUE(graph0->isSupergraphOf(*graph1));
210  EXPECT_FALSE(graph1->isSupergraphOf(*graph0));
211 
212  // Adding a corresponding alloca node to graph1, they are now equal
213  const auto alloca1 = graph1->addNodeForAlloca(rvsdg.GetAllocaNode(), false);
214  EXPECT_TRUE(graph0->isSupergraphOf(*graph1));
215  EXPECT_TRUE(graph1->isSupergraphOf(*graph0));
216 
217  // Adding register0 makes graph1 NOT a subgraph
218  const auto register0 = graph0->addNodeForRegisters();
219  graph0->mapRegisterToNode(rvsdg.GetAllocaOutput(), register0);
220  EXPECT_TRUE(graph0->isSupergraphOf(*graph1));
221  EXPECT_FALSE(graph1->isSupergraphOf(*graph0));
222 
223  // Adding register1 that covers both the alloca and delta outputs makes graph0 NOT a subgraph
224  const auto register1 = graph1->addNodeForRegisters();
225  graph1->mapRegisterToNode(rvsdg.GetAllocaOutput(), register1);
226  graph1->mapRegisterToNode(rvsdg.GetDeltaOutput(), register1);
227  EXPECT_FALSE(graph0->isSupergraphOf(*graph1));
228  EXPECT_TRUE(graph1->isSupergraphOf(*graph0));
229 
230  // Adding a deltaRegister0 to make the graphs identical again
231  const auto deltaRegister0 = graph0->addNodeForRegisters();
232  graph0->mapRegisterToNode(rvsdg.GetDeltaOutput(), deltaRegister0);
233  EXPECT_TRUE(graph0->isSupergraphOf(*graph1));
234  EXPECT_TRUE(graph1->isSupergraphOf(*graph0));
235 
236  // Adding an edge from register0 to the alloca makes graph1 NOT a subgraph
237  graph0->addTarget(register0, alloca0);
238  EXPECT_TRUE(graph0->isSupergraphOf(*graph1));
239  EXPECT_FALSE(graph1->isSupergraphOf(*graph0));
240 
241  // By adding an edge from register1 (delta+alloca output), graph0 is now a subgraph of graph1
242  graph1->addTarget(register1, alloca1);
243  EXPECT_FALSE(graph0->isSupergraphOf(*graph1));
244  EXPECT_TRUE(graph1->isSupergraphOf(*graph0));
245 
246  // To make them identical, the both the delta and alloca registers must point to the alloca
247  graph0->addTarget(deltaRegister0, alloca0);
248  EXPECT_TRUE(graph0->isSupergraphOf(*graph1));
249  EXPECT_TRUE(graph1->isSupergraphOf(*graph0));
250 
251  // Adding an edge from alloca0 to external that is NOT in graph1
252  graph0->markAsTargetsAllExternallyAvailable(alloca0);
253  EXPECT_TRUE(graph0->isSupergraphOf(*graph1));
254  EXPECT_FALSE(graph1->isSupergraphOf(*graph0));
255 
256  // Adding the same edge to alloca1 makes the graphs identical again
257  graph1->markAsTargetsAllExternallyAvailable(alloca1);
258  EXPECT_TRUE(graph0->isSupergraphOf(*graph1));
259  EXPECT_TRUE(graph1->isSupergraphOf(*graph0));
260 
261  // Finally test all the other memory node types
262  graph0->addNodeForDelta(rvsdg.GetDeltaNode(), false);
263  graph1->addNodeForDelta(rvsdg.GetDeltaNode(), false);
264  const auto import0 = graph0->addNodeForImport(rvsdg.GetImportOutput(), true);
265  const auto import1 = graph1->addNodeForImport(rvsdg.GetImportOutput(), true);
266  const auto lambda0 = graph0->addNodeForLambda(rvsdg.GetLambdaNode(), false);
267  const auto lambda1 = graph1->addNodeForLambda(rvsdg.GetLambdaNode(), false);
268  const auto malloc0 = graph0->addNodeForMalloc(rvsdg.GetMallocNode(), false);
269  const auto malloc1 = graph1->addNodeForMalloc(rvsdg.GetMallocNode(), false);
270  EXPECT_TRUE(graph0->isSupergraphOf(*graph1));
271  EXPECT_TRUE(graph1->isSupergraphOf(*graph0));
272 
273  // Add some arbitrary edges between memory nodes
274  graph0->addTarget(malloc0, import0);
275  EXPECT_TRUE(graph0->isSupergraphOf(*graph1));
276  EXPECT_FALSE(graph1->isSupergraphOf(*graph0));
277 
278  graph1->addTarget(import1, lambda1);
279  EXPECT_FALSE(graph0->isSupergraphOf(*graph1));
280 
281  // Make them equal again by adding the same edges to the opposite graph
282  graph1->addTarget(malloc1, import1);
283  graph0->addTarget(import0, lambda0);
284  EXPECT_TRUE(graph0->isSupergraphOf(*graph1));
285  EXPECT_TRUE(graph1->isSupergraphOf(*graph0));
286 }
287 
288 TEST(PointsToGraphTests, testMemoryNodeSize)
289 {
290  using namespace jlm::llvm;
291 
292  {
293  // Arrange
295  test.InitializeTest();
296 
297  auto ptg = aa::PointsToGraph::create();
298  const auto deltaG1 = ptg->addNodeForDelta(test.DeltaG1(), false);
299  const auto deltaG2 = ptg->addNodeForDelta(test.DeltaG2(), false);
300  const auto f = ptg->addNodeForLambda(test.LambdaF(), false);
301 
302  // Assert
303  EXPECT_EQ(ptg->tryGetNodeSize(deltaG1), 4);
304  EXPECT_EQ(ptg->tryGetNodeSize(deltaG2), 8);
305  EXPECT_EQ(ptg->tryGetNodeSize(f), 0);
306  }
307 
308  {
309  // Arrange 2
311  test.InitializeTest();
312 
313  auto ptg = aa::PointsToGraph::create();
314  const auto allocaD = ptg->addNodeForAlloca(*test.alloca_d, false);
315  const auto allocaC = ptg->addNodeForAlloca(*test.alloca_c, false);
316 
317  // Assert 2
318  EXPECT_EQ(ptg->tryGetNodeSize(allocaD), 4);
319  EXPECT_EQ(ptg->tryGetNodeSize(allocaC), 8); // Pointers are 8 bytes
320  }
321 
322  {
323  // Arrange 3
325  test.InitializeTest();
326 
327  auto ptg = aa::PointsToGraph::create();
328  const auto allocaNode = ptg->addNodeForAlloca(test.GetAllocaNode(), false);
329  const auto mallocNode = ptg->addNodeForMalloc(test.GetMallocNode(), false);
330  const auto deltaNode = ptg->addNodeForDelta(test.GetDeltaNode(), true);
331  const auto lambdaNode = ptg->addNodeForLambda(test.GetLambdaNode(), true);
332  const auto importNode = ptg->addNodeForImport(test.GetImportOutput(), true);
333 
334  // Assert 3
335  EXPECT_EQ(ptg->tryGetNodeSize(allocaNode), 8);
336  EXPECT_EQ(ptg->tryGetNodeSize(mallocNode), 4);
337  EXPECT_EQ(ptg->tryGetNodeSize(deltaNode), 8);
338  EXPECT_EQ(ptg->tryGetNodeSize(importNode), 4);
339  // Function nodes have size 0
340  EXPECT_EQ(ptg->tryGetNodeSize(lambdaNode), 0);
341  }
342 }
343 
344 TEST(PointsToGraphTests, testIsMemoryNodeConstant)
345 {
346  using namespace jlm::llvm;
347 
348  {
349  // Arrange
351  test.InitializeTest();
352 
353  auto ptg = aa::PointsToGraph::create();
354  const auto allocaNode = ptg->addNodeForAlloca(test.GetAllocaNode(), false);
355  const auto mallocNode = ptg->addNodeForMalloc(test.GetMallocNode(), false);
356  const auto deltaNode = ptg->addNodeForDelta(test.GetDeltaNode(), true);
357  const auto lambdaNode = ptg->addNodeForLambda(test.GetLambdaNode(), true);
358  const auto importNode = ptg->addNodeForImport(test.GetImportOutput(), true);
359 
360  // Assert
361  EXPECT_FALSE(ptg->isNodeConstant(allocaNode));
362  EXPECT_FALSE(ptg->isNodeConstant(mallocNode));
363  EXPECT_FALSE(ptg->isNodeConstant(deltaNode));
364  EXPECT_FALSE(ptg->isNodeConstant(importNode));
365  // Functions are always constant
366  EXPECT_TRUE(ptg->isNodeConstant(lambdaNode));
367  }
368 
369  {
370  // Arrange 2
371  jlm::rvsdg::Graph graph;
372  const auto intType = jlm::rvsdg::BitType::Create(32);
373  const auto pointerType = jlm::llvm::PointerType::Create();
374 
375  auto & constImport = LlvmGraphImport::createGlobalImport(
376  graph,
377  intType,
378  pointerType,
379  "test",
380  Linkage::externalLinkage,
381  true,
382  4);
383  auto & nonConstImport = LlvmGraphImport::createGlobalImport(
384  graph,
385  intType,
386  pointerType,
387  "test",
388  Linkage::externalLinkage,
389  false,
390  4);
391 
392  auto & constDelta = *jlm::rvsdg::DeltaNode::Create(
393  &graph.GetRootRegion(),
394  DeltaOperation::Create(intType, "constGlobal", Linkage::internalLinkage, "data", true, 4));
395  const auto & int2 = IntegerConstantOperation::Create(*constDelta.subregion(), 32, 2);
396  constDelta.finalize(int2.output(0));
397 
398  auto & nonConstDelta = *jlm::rvsdg::DeltaNode::Create(
399  &graph.GetRootRegion(),
400  DeltaOperation::Create(intType, "global", Linkage::internalLinkage, "data", false, 4));
401  const auto & int8 = IntegerConstantOperation::Create(*nonConstDelta.subregion(), 32, 8);
402  nonConstDelta.finalize(int8.output(0));
403 
404  auto ptg = aa::PointsToGraph::create();
405  const auto constImportMemoryNode = ptg->addNodeForImport(constImport, true);
406  const auto nonConstImportMemoryNode = ptg->addNodeForImport(nonConstImport, true);
407 
408  const auto & constDeltaMemoryNode = ptg->addNodeForDelta(constDelta, false);
409  const auto & nonConstDeltaMemoryNode = ptg->addNodeForDelta(nonConstDelta, false);
410 
411  // Assert
412  EXPECT_TRUE(ptg->isNodeConstant(constImportMemoryNode));
413  EXPECT_FALSE(ptg->isNodeConstant(nonConstImportMemoryNode));
414  EXPECT_TRUE(ptg->isNodeConstant(constDeltaMemoryNode));
415  EXPECT_FALSE(ptg->isNodeConstant(nonConstDeltaMemoryNode));
416  }
417 }
static jlm::util::StatisticsCollector statisticsCollector
TEST(PointsToGraphTests, TestNodeIterators)
std::unique_ptr< jlm::llvm::aa::PointsToGraph > pointsToGraph_
std::unique_ptr< jlm::llvm::aa::PointsToGraph > Analyze(const jlm::rvsdg::RvsdgModule &rvsdgModule, jlm::util::StatisticsCollector &) override
Analyze RVSDG module.
static std::unique_ptr< jlm::llvm::aa::PointsToGraph > CreateAndAnalyze(const jlm::llvm::LlvmRvsdgModule &rvsdgModule)
void AnalyzeRegion(jlm::rvsdg::Region &region)
void AnalyzeImports(const jlm::rvsdg::Graph &rvsdg)
std::unique_ptr< jlm::llvm::aa::PointsToGraph > Analyze(const jlm::llvm::LlvmRvsdgModule &rvsdgModule)
RVSDG module with one of each memory node type.
const rvsdg::SimpleNode & GetAllocaNode() const noexcept
const rvsdg::Output & GetLambdaOutput() const noexcept
const jlm::rvsdg::LambdaNode & GetLambdaNode() const noexcept
const jlm::rvsdg::Output & GetAllocaOutput() const noexcept
const rvsdg::Output & GetDeltaOutput() const noexcept
const llvm::LlvmGraphImport & GetImportOutput() const noexcept
const rvsdg::SimpleNode & GetMallocNode() const noexcept
const jlm::rvsdg::DeltaNode & GetDeltaNode() const noexcept
const jlm::rvsdg::Output & GetMallocOutput() const noexcept
DeltaTest3 class.
const jlm::rvsdg::DeltaNode & DeltaG2() const noexcept
const jlm::rvsdg::DeltaNode & DeltaG1() const noexcept
const jlm::rvsdg::LambdaNode & LambdaF() const noexcept
static std::shared_ptr< const PointerType > Create()
Definition: types.cpp:45
jlm::llvm::LlvmRvsdgModule & module()
Definition: TestRvsdgs.hpp:34
StoreTest1 class.
Definition: TestRvsdgs.hpp:89
rvsdg::SimpleNode * alloca_c
Definition: TestRvsdgs.hpp:101
rvsdg::SimpleNode * alloca_d
Definition: TestRvsdgs.hpp:102
Points-to Analysis Interface.
static std::unique_ptr< PointsToGraph > create()
static std::shared_ptr< const BitType > Create(std::size_t nbits)
Creates bit type of specified width.
Definition: type.cpp:45
Delta node.
Definition: delta.hpp:129
static DeltaNode * Create(rvsdg::Region *parent, std::unique_ptr< DeltaOperation > op)
Definition: delta.hpp:313
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
Graph & Rvsdg() noexcept
Definition: RvsdgModule.hpp:57
bool insert(ItemType item)
Definition: HashSet.hpp:210
std::size_t Size() const noexcept
Definition: HashSet.hpp:187
bool Contains(const ItemType &item) const noexcept
Definition: HashSet.hpp:150
Global memory state passed between functions.