Jlm
Loading...
Searching...
No Matches
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
14#include <jlm/rvsdg/delta.hpp>
17
22{
23public:
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>
41
42 static std::unique_ptr<jlm::llvm::aa::PointsToGraph>
44 {
45 TestAnalysis analysis;
46 return analysis.Analyze(rvsdgModule);
47 }
48
49private:
50 void
52 {
53 using namespace jlm::llvm;
54
55 for (auto & node : region.Nodes())
56 {
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
114TEST(PointsToGraphTests, TestNodeIterators)
115{
116 // Arrange
118 auto pointsToGraph = TestAnalysis::CreateAndAnalyze(test.module());
119
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
194TEST(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
288TEST(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), 4u);
304 EXPECT_EQ(ptg->tryGetNodeSize(deltaG2), 8u);
305 EXPECT_EQ(ptg->tryGetNodeSize(f), 0u);
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), 4u);
319 EXPECT_EQ(ptg->tryGetNodeSize(allocaC), 8u); // 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), 8u);
336 EXPECT_EQ(ptg->tryGetNodeSize(mallocNode), 4u);
337 EXPECT_EQ(ptg->tryGetNodeSize(deltaNode), 8u);
338 EXPECT_EQ(ptg->tryGetNodeSize(importNode), 4u);
339 // Function nodes have size 0
340 EXPECT_EQ(ptg->tryGetNodeSize(lambdaNode), 0u);
341 }
342}
343
344TEST(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 LlvmDeltaOperation::Create(
395 intType,
396 "constGlobal",
397 Linkage::internalLinkage,
398 "data",
399 true,
400 4));
401 const auto & int2 = IntegerConstantOperation::Create(*constDelta.subregion(), 32, 2);
402 constDelta.finalize(int2.output(0));
403
404 auto & nonConstDelta = *jlm::rvsdg::DeltaNode::Create(
405 &graph.GetRootRegion(),
406 LlvmDeltaOperation::Create(intType, "global", Linkage::internalLinkage, "data", false, 4));
407 const auto & int8 = IntegerConstantOperation::Create(*nonConstDelta.subregion(), 32, 8);
408 nonConstDelta.finalize(int8.output(0));
409
410 auto ptg = aa::PointsToGraph::create();
411 const auto constImportMemoryNode = ptg->addNodeForImport(constImport, true);
412 const auto nonConstImportMemoryNode = ptg->addNodeForImport(nonConstImport, true);
413
414 const auto & constDeltaMemoryNode = ptg->addNodeForDelta(constDelta, false);
415 const auto & nonConstDeltaMemoryNode = ptg->addNodeForDelta(nonConstDelta, false);
416
417 // Assert
418 EXPECT_TRUE(ptg->isNodeConstant(constImportMemoryNode));
419 EXPECT_FALSE(ptg->isNodeConstant(nonConstImportMemoryNode));
420 EXPECT_TRUE(ptg->isNodeConstant(constDeltaMemoryNode));
421 EXPECT_FALSE(ptg->isNodeConstant(nonConstDeltaMemoryNode));
422 }
423}
static jlm::util::StatisticsCollector statisticsCollector
TEST(PointsToGraphTests, TestNodeIterators)
jlm::llvm::aa::PointsToGraph::NodeIndex NodeIndex
static std::unique_ptr< jlm::llvm::aa::PointsToGraph > CreateAndAnalyze(const jlm::llvm::LlvmRvsdgModule &rvsdgModule)
std::unique_ptr< jlm::llvm::aa::PointsToGraph > Analyze(const jlm::llvm::LlvmRvsdgModule &rvsdgModule)
std::unique_ptr< jlm::llvm::aa::PointsToGraph > pointsToGraph_
void AnalyzeRegion(jlm::rvsdg::Region &region)
void AnalyzeImports(const jlm::rvsdg::Graph &rvsdg)
std::unique_ptr< jlm::llvm::aa::PointsToGraph > Analyze(const jlm::rvsdg::RvsdgModule &rvsdgModule, jlm::util::StatisticsCollector &) override
Analyze RVSDG module.
RVSDG module with one of each memory node type.
const rvsdg::SimpleNode & GetMallocNode() const noexcept
const jlm::rvsdg::Output & GetMallocOutput() const noexcept
const jlm::rvsdg::DeltaNode & GetDeltaNode() const noexcept
const rvsdg::SimpleNode & GetAllocaNode() const noexcept
const rvsdg::Output & GetDeltaOutput() const noexcept
const jlm::rvsdg::Output & GetAllocaOutput() const noexcept
const llvm::LlvmGraphImport & GetImportOutput() const noexcept
const jlm::rvsdg::LambdaNode & GetLambdaNode() const noexcept
const rvsdg::Output & GetLambdaOutput() 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()
StoreTest1 class.
rvsdg::SimpleNode * alloca_c
rvsdg::SimpleNode * alloca_d
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
static DeltaNode * Create(rvsdg::Region *parent, std::unique_ptr< DeltaOperation > op)
Definition delta.hpp:313
Region & GetRootRegion() const noexcept
Definition graph.hpp:99
Represent acyclic RVSDG subgraphs.
Definition region.hpp:213
NodeRange Nodes() noexcept
Definition region.hpp:375
Graph & Rvsdg() noexcept
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.
NodeType * TryGetOwnerNode(const rvsdg::Input &input) noexcept
Checks if this is an input to a node of specified type.
Definition node.hpp:872