Jlm
Loading...
Searching...
No Matches
ScalarEvolutionTests.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2025 Andreas Lilleby Hjulstad <andreas.lilleby.hjulstad@gmail.com>
3 * See COPYING for terms of redistribution.
4 */
5
15#include <jlm/rvsdg/view.hpp>
16
17#include <gtest/gtest.h>
18
19static std::pair<
20 std::unordered_map<const jlm::rvsdg::Output *, std::unique_ptr<jlm::llvm::SCEVChainRecurrence>>,
21 std::unordered_map<const jlm::rvsdg::ThetaNode *, size_t>>
23{
24 jlm::llvm::ScalarEvolution scalarEvolution;
26 scalarEvolution.Run(rvsdgModule, statisticsCollector);
27 return { scalarEvolution.GetChrecMap(), scalarEvolution.GetTripCountMap() };
28}
29
30TEST(ScalarEvolutionTests, NonEvolvingVariable)
31{
32 using namespace jlm::llvm;
33
34 // Arrange
35 const auto intType = jlm::rvsdg::BitType::Create(32);
36
37 LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
38 const auto & graph = rvsdgModule.Rvsdg();
39
40 const auto & c0 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 0);
41
42 const auto theta = jlm::rvsdg::ThetaNode::create(&graph.GetRootRegion());
43 const auto lv1 = theta->AddLoopVar(c0.output(0));
44
45 const auto & c1 = IntegerConstantOperation::Create(*theta->subregion(), 32, 1);
46
47 lv1.post->divert_to(c1.output(0));
48
49 const auto & c5 = IntegerConstantOperation::Create(*theta->subregion(), 32, 5);
50 auto & sltNode = jlm::rvsdg::CreateOpNode<IntegerSltOperation>({ lv1.pre, c5.output(0) }, 32);
51 const auto matchResult =
52 jlm::rvsdg::MatchOperation::Create(*sltNode.output(0), { { 1, 1 } }, 0, 2);
53
54 theta->set_predicate(matchResult);
55
56 jlm::rvsdg::view(graph, stdout);
57
58 // Act
59 const auto & chrecMap = RunScalarEvolution(rvsdgModule).first;
60
61 // Assert
62
63 // Since lv1 is a variable which does not depend on the previous value (no evolution). There
64 // should be no computed chrec for it
65 EXPECT_EQ(chrecMap.find(lv1.pre), chrecMap.end());
66}
67
68TEST(ScalarEvolutionTests, InductionVariable)
69{
70 using namespace jlm::llvm;
71
72 // Arrange
73 const auto intType = jlm::rvsdg::BitType::Create(32);
74
75 LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
76 const auto & graph = rvsdgModule.Rvsdg();
77
78 const auto & c0 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 0);
79 const auto & c2 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 2);
80
81 const auto theta = jlm::rvsdg::ThetaNode::create(&graph.GetRootRegion());
82 const auto lv1 = theta->AddLoopVar(c0.output(0));
83 const auto lv2 = theta->AddLoopVar(c2.output(0));
84
85 const auto & c1 = IntegerConstantOperation::Create(*theta->subregion(), 32, 1);
86 auto & addNode = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv1.pre, c1.output(0) }, 32);
87 const auto result = addNode.output(0);
88
89 const auto & c5 = IntegerConstantOperation::Create(*theta->subregion(), 32, 5);
90 auto & sltNode = jlm::rvsdg::CreateOpNode<IntegerSltOperation>({ result, c5.output(0) }, 32);
91 const auto matchResult =
92 jlm::rvsdg::MatchOperation::Create(*sltNode.output(0), { { 1, 1 } }, 0, 2);
93
94 theta->set_predicate(matchResult);
95 lv1.post->divert_to(result);
96
97 jlm::rvsdg::view(graph, stdout);
98
99 // Act
100 const auto & chrecMap = RunScalarEvolution(rvsdgModule).first;
101
102 // Assert
103 EXPECT_NE(chrecMap.find(lv1.pre), chrecMap.end());
104 EXPECT_NE(chrecMap.find(lv2.pre), chrecMap.end());
105
106 // lv1 is a simple induction variable with the recurrence {0,+,1}
107 auto lv1TestChrec = SCEVChainRecurrence(*theta, *lv1.pre);
108 lv1TestChrec.AddOperand(SCEVConstant::Create(0));
109 lv1TestChrec.AddOperand(SCEVConstant::Create(1));
110 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv1TestChrec, *chrecMap.at(lv1.pre)));
111
112 // lv2 is a constant with the recurrence {2}
113 auto lv2TestChrec = SCEVChainRecurrence(*theta, *lv2.pre);
114 lv2TestChrec.AddOperand(SCEVConstant::Create(2));
115 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv2TestChrec, *chrecMap.at(lv2.pre)));
116}
117
118TEST(ScalarEvolutionTests, RecursiveInductionVariable)
119{
120 using namespace jlm::llvm;
121
122 // Arrange
123 const auto intType = jlm::rvsdg::BitType::Create(32);
124
125 LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
126 const auto & graph = rvsdgModule.Rvsdg();
127
128 const auto & c0 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 0);
129 const auto & c4 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 4);
130
131 const auto theta = jlm::rvsdg::ThetaNode::create(&graph.GetRootRegion());
132 const auto lv1 = theta->AddLoopVar(c0.output(0));
133 const auto lv2 = theta->AddLoopVar(c4.output(0));
134
135 const auto & c1 = IntegerConstantOperation::Create(*theta->subregion(), 32, 1);
136 auto & addNode = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv1.pre, c1.output(0) }, 32);
137 const auto res1 = addNode.output(0);
138
139 const auto & c5 = IntegerConstantOperation::Create(*theta->subregion(), 32, 5);
140 auto & sltNode = jlm::rvsdg::CreateOpNode<IntegerSltOperation>({ res1, c5.output(0) }, 32);
141 const auto matchResult =
142 jlm::rvsdg::MatchOperation::Create(*sltNode.output(0), { { 1, 1 } }, 0, 2);
143
144 const auto & c2 = IntegerConstantOperation::Create(*theta->subregion(), 32, 2);
145 auto & addNode2 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv2.pre, c2.output(0) }, 32);
146 const auto res2 = addNode2.output(0);
147
148 const auto & c3 = IntegerConstantOperation::Create(*theta->subregion(), 32, 3);
149 auto & addNode3 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ res2, c3.output(0) }, 32);
150 const auto res3 = addNode3.output(0);
151
152 theta->set_predicate(matchResult);
153 lv1.post->divert_to(res1);
154 lv2.post->divert_to(res3);
155
156 jlm::rvsdg::view(graph, stdout);
157
158 // Act
159 const auto & chrecMap = RunScalarEvolution(rvsdgModule).first;
160
161 // Assert
162 EXPECT_NE(chrecMap.find(lv1.pre), chrecMap.end());
163 EXPECT_NE(chrecMap.find(lv2.pre), chrecMap.end());
164
165 // lv1 is a simple induction variable with the recurrence {0,+,1}
166 auto lv1TestChrec = SCEVChainRecurrence(*theta, *lv1.pre);
167 lv1TestChrec.AddOperand(SCEVConstant::Create(0));
168 lv1TestChrec.AddOperand(SCEVConstant::Create(1));
169 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv1TestChrec, *chrecMap.at(lv1.pre)));
170
171 // lv2 is a recursive induction variable, which should be folded to {4,+,5}
172 auto lv2TestChrec = SCEVChainRecurrence(*theta, *lv2.pre);
173 lv2TestChrec.AddOperand(SCEVConstant::Create(4));
174 lv2TestChrec.AddOperand(SCEVConstant::Create(5));
175 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv2TestChrec, *chrecMap.at(lv2.pre)));
176}
177
178TEST(ScalarEvolutionTests, PolynomialInductionVariable)
179{
180 using namespace jlm::llvm;
181
182 // Arrange
183 const auto intType = jlm::rvsdg::BitType::Create(32);
184
185 LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
186 const auto & graph = rvsdgModule.Rvsdg();
187
188 const auto & c0 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 0);
189 const auto & c2 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 2);
190
191 const auto theta = jlm::rvsdg::ThetaNode::create(&graph.GetRootRegion());
192 const auto lv1 = theta->AddLoopVar(c0.output(0));
193 const auto lv2 = theta->AddLoopVar(c2.output(0));
194
195 const auto & c1 = IntegerConstantOperation::Create(*theta->subregion(), 32, 1);
196 auto & addNode = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv1.pre, c1.output(0) }, 32);
197 const auto res1 = addNode.output(0);
198
199 const auto & c5 = IntegerConstantOperation::Create(*theta->subregion(), 32, 5);
200 auto & sltNode = jlm::rvsdg::CreateOpNode<IntegerSltOperation>({ res1, c5.output(0) }, 32);
201 const auto matchResult =
202 jlm::rvsdg::MatchOperation::Create(*sltNode.output(0), { { 1, 1 } }, 0, 2);
203
204 auto & addNode2 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv2.pre, res1 }, 32);
205 const auto res2 = addNode2.output(0);
206
207 theta->set_predicate(matchResult);
208 lv1.post->divert_to(res1);
209 lv2.post->divert_to(res2);
210
211 jlm::rvsdg::view(graph, stdout);
212
213 // Act
214 const auto & chrecMap = RunScalarEvolution(rvsdgModule).first;
215
216 // Assert
217 EXPECT_NE(chrecMap.find(lv1.pre), chrecMap.end());
218 EXPECT_NE(chrecMap.find(lv2.pre), chrecMap.end());
219
220 // lv1 is a simple induction variable with the recurrence {0,+,1}
221 auto lv1TestChrec = SCEVChainRecurrence(*theta, *lv1.pre);
222 lv1TestChrec.AddOperand(SCEVConstant::Create(0));
223 lv1TestChrec.AddOperand(SCEVConstant::Create(1));
224 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv1TestChrec, *chrecMap.at(lv1.pre)));
225
226 // lv2 is a (second degree) polynomial induction variable with three operands,
227 // Recurrence: {2,+,1,+,1}
228 auto lv2TestChrec = SCEVChainRecurrence(*theta, *lv2.pre);
229 lv2TestChrec.AddOperand(SCEVConstant::Create(2));
230 lv2TestChrec.AddOperand(SCEVConstant::Create(1));
231 lv2TestChrec.AddOperand(SCEVConstant::Create(1));
232 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv2TestChrec, *chrecMap.at(lv2.pre)));
233}
234
235TEST(ScalarEvolutionTests, ThirdDegreePolynomialInductionVariable)
236{
237 using namespace jlm::llvm;
238
239 // Arrange
240 const auto intType = jlm::rvsdg::BitType::Create(32);
241
242 LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
243 const auto & graph = rvsdgModule.Rvsdg();
244
245 const auto & c2 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 2);
246 const auto & c3 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 3);
247 const auto & c4 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 4);
248
249 const auto theta = jlm::rvsdg::ThetaNode::create(&graph.GetRootRegion());
250 const auto lv1 = theta->AddLoopVar(c2.output(0));
251 const auto lv2 = theta->AddLoopVar(c3.output(0));
252 const auto lv3 = theta->AddLoopVar(c4.output(0));
253
254 const auto & c1 = IntegerConstantOperation::Create(*theta->subregion(), 32, 1);
255
256 auto & addNode_1 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv1.pre, c1.output(0) }, 32);
257 const auto result_1 = addNode_1.output(0);
258
259 auto & addNode_2 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv1.pre, lv2.pre }, 32);
260 const auto result_2 = addNode_2.output(0);
261
262 auto & addNode_3 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv3.pre, lv2.pre }, 32);
263 const auto result_3 = addNode_3.output(0);
264
265 const auto & c5 = IntegerConstantOperation::Create(*theta->subregion(), 32, 5);
266 auto & sltNode = jlm::rvsdg::CreateOpNode<IntegerSltOperation>({ result_1, c5.output(0) }, 32);
267 const auto matchResult =
268 jlm::rvsdg::MatchOperation::Create(*sltNode.output(0), { { 1, 1 } }, 0, 2);
269
270 theta->set_predicate(matchResult);
271 lv1.post->divert_to(result_1);
272 lv2.post->divert_to(result_2);
273 lv3.post->divert_to(result_3);
274
275 jlm::rvsdg::view(graph, stdout);
276
277 // Act
278 const auto & chrecMap = RunScalarEvolution(rvsdgModule).first;
279
280 // Assert
281 EXPECT_NE(chrecMap.find(lv1.pre), chrecMap.end());
282 EXPECT_NE(chrecMap.find(lv2.pre), chrecMap.end());
283 EXPECT_NE(chrecMap.find(lv3.pre), chrecMap.end());
284
285 // lv1 is a simple induction variable with the recurrence {2,+,1}
286 auto lv1TestChrec = SCEVChainRecurrence(*theta, *lv1.pre);
287 lv1TestChrec.AddOperand(SCEVConstant::Create(2));
288 lv1TestChrec.AddOperand(SCEVConstant::Create(1));
289 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv1TestChrec, *chrecMap.at(lv1.pre)));
290
291 // lv2 is a second degree polynomial induction variable with three operands, {3,+,2,+,1}
292 auto lv2TestChrec = SCEVChainRecurrence(*theta, *lv2.pre);
293 lv2TestChrec.AddOperand(SCEVConstant::Create(3));
294 lv2TestChrec.AddOperand(SCEVConstant::Create(2));
295 lv2TestChrec.AddOperand(SCEVConstant::Create(1));
296 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv2TestChrec, *chrecMap.at(lv2.pre)));
297
298 // lv2 is a third degree polynomial induction variable with three operands,
299 // Recurrence: {4,+,3,+,2,+,1}
300 auto lv3TestChrec = SCEVChainRecurrence(*theta, *lv3.pre);
301 lv3TestChrec.AddOperand(SCEVConstant::Create(4));
302 lv3TestChrec.AddOperand(SCEVConstant::Create(3));
303 lv3TestChrec.AddOperand(SCEVConstant::Create(2));
304 lv3TestChrec.AddOperand(SCEVConstant::Create(1));
305 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv3TestChrec, *chrecMap.at(lv3.pre)));
306}
307
308TEST(ScalarEvolutionTests, InductionVariableWithMultiplication)
309{
310 using namespace jlm::llvm;
311
312 // Arrange
313 const auto intType = jlm::rvsdg::BitType::Create(32);
314
315 LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
316 const auto & graph = rvsdgModule.Rvsdg();
317
318 const auto & c0 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 0);
319 const auto & c2 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 2);
320
321 const auto theta = jlm::rvsdg::ThetaNode::create(&graph.GetRootRegion());
322 const auto lv1 = theta->AddLoopVar(c0.output(0));
323 const auto lv2 = theta->AddLoopVar(c2.output(0));
324
325 const auto & c1 = IntegerConstantOperation::Create(*theta->subregion(), 32, 1);
326 auto & addNode1 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv1.pre, c1.output(0) }, 32);
327 auto res1 = addNode1.output(0);
328
329 const auto & c3 = IntegerConstantOperation::Create(*theta->subregion(), 32, 3);
330 auto & mulNode = jlm::rvsdg::CreateOpNode<IntegerMulOperation>({ res1, c3.output(0) }, 32);
331
332 auto & addNode2 =
333 jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv2.pre, mulNode.output(0) }, 32);
334 auto res2 = addNode2.output(0);
335
336 const auto & c5 = IntegerConstantOperation::Create(*theta->subregion(), 32, 5);
337 auto & sltNode = jlm::rvsdg::CreateOpNode<IntegerSltOperation>({ res1, c5.output(0) }, 32);
338 const auto matchResult =
339 jlm::rvsdg::MatchOperation::Create(*sltNode.output(0), { { 1, 1 } }, 0, 2);
340
341 theta->set_predicate(matchResult);
342 lv1.post->divert_to(res1);
343 lv2.post->divert_to(res2);
344
345 jlm::rvsdg::view(graph, stdout);
346
347 // Act
348 const auto & chrecMap = RunScalarEvolution(rvsdgModule).first;
349
350 // Assert
351 EXPECT_NE(chrecMap.find(lv1.pre), chrecMap.end());
352 EXPECT_NE(chrecMap.find(lv2.pre), chrecMap.end());
353
354 // lv1 is a simple induction variable with the recurrence {0,+,1}
355 auto lv1TestChrec = SCEVChainRecurrence(*theta, *lv1.pre);
356 lv1TestChrec.AddOperand(SCEVConstant::Create(0));
357 lv1TestChrec.AddOperand(SCEVConstant::Create(1));
358 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv1TestChrec, *chrecMap.at(lv1.pre)));
359
360 // lv2 is incremented with 3 * {1,+,1} (lv1 + 1) each iteration. With the starting value of 2,
361 // this should give us the recurrence {2,+,3,+,3}
362 auto lv2TestChrec = SCEVChainRecurrence(*theta, *lv2.pre);
363 lv2TestChrec.AddOperand(SCEVConstant::Create(2));
364 lv2TestChrec.AddOperand(SCEVConstant::Create(3));
365 lv2TestChrec.AddOperand(SCEVConstant::Create(3));
366 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv2TestChrec, *chrecMap.at(lv2.pre)));
367}
368
369TEST(ScalarEvolutionTests, InvalidInductionVariableWithMultiplication)
370{
371 using namespace jlm::llvm;
372
373 // Arrange
374 const auto intType = jlm::rvsdg::BitType::Create(32);
375
376 LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
377 const auto & graph = rvsdgModule.Rvsdg();
378
379 const auto & c1 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 1);
380
381 const auto theta = jlm::rvsdg::ThetaNode::create(&graph.GetRootRegion());
382 const auto lv1 = theta->AddLoopVar(c1.output(0));
383
384 const auto & c2 = IntegerConstantOperation::Create(*theta->subregion(), 32, 2);
385 auto & mulNode = jlm::rvsdg::CreateOpNode<IntegerMulOperation>({ lv1.pre, c2.output(0) }, 32);
386 const auto res1 = mulNode.output(0);
387
388 const auto & c5 = IntegerConstantOperation::Create(*theta->subregion(), 32, 5);
389 auto & sltNode = jlm::rvsdg::CreateOpNode<IntegerSltOperation>({ res1, c5.output(0) }, 32);
390 const auto matchResult =
391 jlm::rvsdg::MatchOperation::Create(*sltNode.output(0), { { 1, 1 } }, 0, 2);
392
393 theta->set_predicate(matchResult);
394 lv1.post->divert_to(res1);
395
396 jlm::rvsdg::view(graph, stdout);
397
398 // Act
399 const auto & chrecMap = RunScalarEvolution(rvsdgModule).first;
400
401 // Assert
402 EXPECT_NE(chrecMap.find(lv1.pre), chrecMap.end());
403
404 // lv1 is not an induction variable because of illegal mult operation
405 // (results in quadratic recurrence). It should therefore be modeled as {Unknown}
406 auto lv1TestChrec = SCEVChainRecurrence(*theta, *lv1.pre);
407 lv1TestChrec.AddOperand(SCEVUnknown::Create());
408 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv1TestChrec, *chrecMap.at(lv1.pre)));
409}
410
411TEST(ScalarEvolutionTests, MultiplicationOfTwoAffineChrecs)
412{
413 using namespace jlm::llvm;
414
415 // Arrange
416 const auto intType = jlm::rvsdg::BitType::Create(32);
417
418 LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
419 const auto & graph = rvsdgModule.Rvsdg();
420
421 const auto & c0 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 0);
422 const auto & c3 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 3);
423
424 const auto theta = jlm::rvsdg::ThetaNode::create(&graph.GetRootRegion());
425 const auto lv1 = theta->AddLoopVar(c0.output(0));
426 const auto lv2 = theta->AddLoopVar(c3.output(0));
427
428 const auto & c1 = IntegerConstantOperation::Create(*theta->subregion(), 32, 1);
429 auto & addNode1 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv1.pre, c1.output(0) }, 32);
430 auto res1 = addNode1.output(0);
431
432 auto & mulNode = jlm::rvsdg::CreateOpNode<IntegerMulOperation>({ lv1.pre, lv1.pre }, 32);
433
434 auto & addNode2 =
435 jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv2.pre, mulNode.output(0) }, 32);
436 auto res2 = addNode2.output(0);
437
438 const auto & c5 = IntegerConstantOperation::Create(*theta->subregion(), 32, 5);
439 auto & sltNode = jlm::rvsdg::CreateOpNode<IntegerSltOperation>({ res1, c5.output(0) }, 32);
440 const auto matchResult =
441 jlm::rvsdg::MatchOperation::Create(*sltNode.output(0), { { 1, 1 } }, 0, 2);
442
443 theta->set_predicate(matchResult);
444 lv1.post->divert_to(res1);
445 lv2.post->divert_to(res2);
446
447 jlm::rvsdg::view(graph, stdout);
448
449 // Act
450 const auto & chrecMap = RunScalarEvolution(rvsdgModule).first;
451
452 // Assert
453 EXPECT_NE(chrecMap.find(lv1.pre), chrecMap.end());
454 EXPECT_NE(chrecMap.find(lv2.pre), chrecMap.end());
455
456 // lv1 is a simple induction variable with the recurrence {0,+,1}
457 auto lv1TestChrec = SCEVChainRecurrence(*theta, *lv1.pre);
458 lv1TestChrec.AddOperand(SCEVConstant::Create(0));
459 lv1TestChrec.AddOperand(SCEVConstant::Create(1));
460 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv1TestChrec, *chrecMap.at(lv1.pre)));
461
462 // {0,+,1} * {0,+,1} folded together should be {0,+,1,+,2}, so adding this to lv2, should give us
463 // {3,+,0,+,1,+,2} as the recurrence for lv2
464 auto lv2TestChrec = SCEVChainRecurrence(*theta, *lv2.pre);
465 lv2TestChrec.AddOperand(SCEVConstant::Create(3));
466 lv2TestChrec.AddOperand(SCEVConstant::Create(0));
467 lv2TestChrec.AddOperand(SCEVConstant::Create(1));
468 lv2TestChrec.AddOperand(SCEVConstant::Create(2));
469 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv2TestChrec, *chrecMap.at(lv2.pre)));
470}
471
472TEST(ScalarEvolutionTests, MultiplicationOfTwoQuadraticChrecs)
473{
474 using namespace jlm::llvm;
475
476 // Arrange
477 const auto intType = jlm::rvsdg::BitType::Create(32);
478
479 LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
480 const auto & graph = rvsdgModule.Rvsdg();
481
482 const auto & c0 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 0);
483 const auto & c1_1 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 1);
484 const auto & c2 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 2);
485
486 const auto theta = jlm::rvsdg::ThetaNode::create(&graph.GetRootRegion());
487 const auto lv1 = theta->AddLoopVar(c0.output(0));
488 const auto lv2 = theta->AddLoopVar(c1_1.output(0));
489 const auto lv3 = theta->AddLoopVar(c2.output(0));
490
491 const auto & c1_2 = IntegerConstantOperation::Create(*theta->subregion(), 32, 1);
492 auto & addNode1 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv1.pre, c1_2.output(0) }, 32);
493 auto res1 = addNode1.output(0);
494
495 auto & addNode2 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv2.pre, lv1.pre }, 32);
496 auto res2 = addNode2.output(0);
497
498 auto & mulNode = jlm::rvsdg::CreateOpNode<IntegerMulOperation>({ lv2.pre, lv2.pre }, 32);
499 auto & addNode3 =
500 jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv3.pre, mulNode.output(0) }, 32);
501 auto res3 = addNode3.output(0);
502
503 const auto & c5 = IntegerConstantOperation::Create(*theta->subregion(), 32, 5);
504 auto & sltNode = jlm::rvsdg::CreateOpNode<IntegerSltOperation>({ res1, c5.output(0) }, 32);
505 const auto matchResult =
506 jlm::rvsdg::MatchOperation::Create(*sltNode.output(0), { { 1, 1 } }, 0, 2);
507
508 theta->set_predicate(matchResult);
509 lv1.post->divert_to(res1);
510 lv2.post->divert_to(res2);
511 lv3.post->divert_to(res3);
512
513 jlm::rvsdg::view(graph, stdout);
514
515 // Act
516 const auto & chrecMap = RunScalarEvolution(rvsdgModule).first;
517
518 // Assert
519 EXPECT_NE(chrecMap.find(lv1.pre), chrecMap.end());
520 EXPECT_NE(chrecMap.find(lv2.pre), chrecMap.end());
521 EXPECT_NE(chrecMap.find(lv3.pre), chrecMap.end());
522
523 // lv1 is a simple induction variable with the affine recurrence {0,+,1}
524 auto lv1TestChrec = SCEVChainRecurrence(*theta, *lv1.pre);
525 lv1TestChrec.AddOperand(SCEVConstant::Create(0));
526 lv1TestChrec.AddOperand(SCEVConstant::Create(1));
527 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv1TestChrec, *chrecMap.at(lv1.pre)));
528
529 // lv2 is a polynomial induction variable with the quadratic recurrence {1,+,0,+,1}
530 auto lv2TestChrec = SCEVChainRecurrence(*theta, *lv2.pre);
531 lv2TestChrec.AddOperand(SCEVConstant::Create(1));
532 lv2TestChrec.AddOperand(SCEVConstant::Create(0));
533 lv2TestChrec.AddOperand(SCEVConstant::Create(1));
534 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv2TestChrec, *chrecMap.at(lv2.pre)));
535
536 // {1,+,0,+,1} * {1,+,0,+,1} foled together is {1,+,0,+,3,+,6,+,6}, adding that to lv3, we get the
537 // recurrence {2,+,1,+,0,+,3,+,6,+,6}
538 auto lv3TestChrec = SCEVChainRecurrence(*theta, *lv3.pre);
539 lv3TestChrec.AddOperand(SCEVConstant::Create(2));
540 lv3TestChrec.AddOperand(SCEVConstant::Create(1));
541 lv3TestChrec.AddOperand(SCEVConstant::Create(0));
542 lv3TestChrec.AddOperand(SCEVConstant::Create(3));
543 lv3TestChrec.AddOperand(SCEVConstant::Create(6));
544 lv3TestChrec.AddOperand(SCEVConstant::Create(6));
545 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv3TestChrec, *chrecMap.at(lv3.pre)));
546}
547
548TEST(ScalarEvolutionTests, InvalidPolynomialInductionVariableWithMultiplication)
549{
550 using namespace jlm::llvm;
551
552 // Arrange
553 const auto intType = jlm::rvsdg::BitType::Create(32);
554
555 LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
556 const auto & graph = rvsdgModule.Rvsdg();
557
558 const auto & c0 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 0);
559 const auto & c3 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 3);
560
561 const auto theta = jlm::rvsdg::ThetaNode::create(&graph.GetRootRegion());
562 const auto lv1 = theta->AddLoopVar(c0.output(0));
563 const auto lv2 = theta->AddLoopVar(c3.output(0));
564
565 const auto & c1 = IntegerConstantOperation::Create(*theta->subregion(), 32, 1);
566 auto & addNode1 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv1.pre, c1.output(0) }, 32);
567 auto res1 = addNode1.output(0);
568
569 const auto & c2 = IntegerConstantOperation::Create(*theta->subregion(), 32, 1);
570 auto & addNode2 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv1.pre, c2.output(0) }, 32);
571 auto & mulNode =
572 jlm::rvsdg::CreateOpNode<IntegerMulOperation>({ lv2.pre, addNode2.output(0) }, 32);
573 const auto res2 = mulNode.output(0);
574
575 const auto & c5 = IntegerConstantOperation::Create(*theta->subregion(), 32, 5);
576 auto & sltNode = jlm::rvsdg::CreateOpNode<IntegerSltOperation>({ res1, c5.output(0) }, 32);
577 const auto matchResult =
578 jlm::rvsdg::MatchOperation::Create(*sltNode.output(0), { { 1, 1 } }, 0, 2);
579
580 theta->set_predicate(matchResult);
581 lv1.post->divert_to(res1);
582 lv2.post->divert_to(res2);
583
584 jlm::rvsdg::view(graph, stdout);
585
586 // Act
587 const auto & chrecMap = RunScalarEvolution(rvsdgModule).first;
588
589 // Assert
590 EXPECT_NE(chrecMap.find(lv1.pre), chrecMap.end());
591 EXPECT_NE(chrecMap.find(lv2.pre), chrecMap.end());
592
593 // lv1 is a simple induction variable with the recurrence {0,+,1}
594 auto lv1TestChrec = SCEVChainRecurrence(*theta, *lv1.pre);
595 lv1TestChrec.AddOperand(SCEVConstant::Create(0));
596 lv1TestChrec.AddOperand(SCEVConstant::Create(1));
597 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv1TestChrec, *chrecMap.at(lv1.pre)));
598
599 // lv2 is not an induction variable because of illegal mult operation
600 // (results in quadratic recurrence). It should therefore be modeled as {Unknown}
601 auto lv2TestChrec = SCEVChainRecurrence(*theta, *lv2.pre);
602 lv2TestChrec.AddOperand(SCEVUnknown::Create());
603 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv2TestChrec, *chrecMap.at(lv2.pre)));
604}
605
606TEST(ScalarEvolutionTests, InductionVariableWithSubtraction)
607{
608 using namespace jlm::llvm;
609
610 // Arrange
611 const auto intType = jlm::rvsdg::BitType::Create(32);
612
613 LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
614 const auto & graph = rvsdgModule.Rvsdg();
615
616 const auto & c10 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 10);
617
618 const auto theta = jlm::rvsdg::ThetaNode::create(&graph.GetRootRegion());
619 const auto lv1 = theta->AddLoopVar(c10.output(0));
620
621 const auto & c1 = IntegerConstantOperation::Create(*theta->subregion(), 32, 1);
622
623 auto & subNode = jlm::rvsdg::CreateOpNode<IntegerSubOperation>({ lv1.pre, c1.output(0) }, 32);
624 const auto & res1 = subNode.output(0);
625
626 const auto & c5 = IntegerConstantOperation::Create(*theta->subregion(), 32, 5);
627 auto & sltNode = jlm::rvsdg::CreateOpNode<IntegerSgtOperation>({ res1, c5.output(0) }, 32);
628 const auto matchResult =
629 jlm::rvsdg::MatchOperation::Create(*sltNode.output(0), { { 1, 1 } }, 0, 2);
630
631 theta->set_predicate(matchResult);
632 lv1.post->divert_to(res1);
633
634 jlm::rvsdg::view(graph, stdout);
635
636 // Act
637 const auto & chrecMap = RunScalarEvolution(rvsdgModule).first;
638
639 // Assert
640 EXPECT_NE(chrecMap.find(lv1.pre), chrecMap.end());
641
642 // lv1 is a simple negative induction variable with the recurrence {10,+,-1}
643 auto lv1TestChrec = SCEVChainRecurrence(*theta, *lv1.pre);
644 lv1TestChrec.AddOperand(SCEVConstant::Create(10));
645 lv1TestChrec.AddOperand(SCEVConstant::Create(-1));
646 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv1TestChrec, *chrecMap.at(lv1.pre)));
647}
648
649TEST(ScalarEvolutionTests, PolynomialInductionVariableWithSubtraction)
650{
651 using namespace jlm::llvm;
652
653 // Arrange
654 const auto intType = jlm::rvsdg::BitType::Create(32);
655
656 LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
657 const auto & graph = rvsdgModule.Rvsdg();
658
659 const auto & c0 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 0);
660 const auto & c3 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 3);
661
662 const auto theta = jlm::rvsdg::ThetaNode::create(&graph.GetRootRegion());
663 const auto lv1 = theta->AddLoopVar(c0.output(0));
664 const auto lv2 = theta->AddLoopVar(c3.output(0));
665
666 const auto & c1 = IntegerConstantOperation::Create(*theta->subregion(), 32, 1);
667 auto & addNode = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv1.pre, c1.output(0) }, 32);
668 const auto res1 = addNode.output(0);
669
670 auto & subNode = jlm::rvsdg::CreateOpNode<IntegerSubOperation>({ lv2.pre, res1 }, 32);
671 const auto res2 = subNode.output(0);
672
673 const auto & c5 = IntegerConstantOperation::Create(*theta->subregion(), 32, 5);
674 auto & sltNode = jlm::rvsdg::CreateOpNode<IntegerSltOperation>({ res1, c5.output(0) }, 32);
675 const auto matchResult =
676 jlm::rvsdg::MatchOperation::Create(*sltNode.output(0), { { 1, 1 } }, 0, 2);
677
678 theta->set_predicate(matchResult);
679 lv1.post->divert_to(res1);
680 lv2.post->divert_to(res2);
681
682 jlm::rvsdg::view(graph, stdout);
683
684 // Act
685 const auto & chrecMap = RunScalarEvolution(rvsdgModule).first;
686
687 // Assert
688 EXPECT_NE(chrecMap.find(lv1.pre), chrecMap.end());
689 EXPECT_NE(chrecMap.find(lv2.pre), chrecMap.end());
690
691 // lv1 is a simple induction variable with the recurrence {0,+,1}
692 auto lv1TestChrec = SCEVChainRecurrence(*theta, *lv1.pre);
693 lv1TestChrec.AddOperand(SCEVConstant::Create(0));
694 lv1TestChrec.AddOperand(SCEVConstant::Create(1));
695 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv1TestChrec, *chrecMap.at(lv1.pre)));
696
697 // lv2 is decremented with {1,+,1} every iteration (lv1 + 1), and has a start value of 3, this
698 // results in the recurrence {3,+,-1,+,-1}
699 auto lv2TestChrec = SCEVChainRecurrence(*theta, *lv2.pre);
700 lv2TestChrec.AddOperand(SCEVConstant::Create(3));
701 lv2TestChrec.AddOperand(SCEVConstant::Create(-1));
702 lv2TestChrec.AddOperand(SCEVConstant::Create(-1));
703 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv2TestChrec, *chrecMap.at(lv2.pre)));
704}
705
706TEST(ScalarEvolutionTests, InductionVariablesWithNonConstantInitialValues)
707{
708 // This test checks the functionality of the folding rules for variables that have start values
709 // that are not constants. These will get a SCEVInit node instead, which cannot be folded like a
710 // constant.
711 using namespace jlm::llvm;
712
713 // Arrange
714 const auto intType = jlm::rvsdg::BitType::Create(32);
715
716 LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
717 jlm::rvsdg::Graph & graph = rvsdgModule.Rvsdg();
718
719 auto x = &jlm::rvsdg::GraphImport::Create(graph, intType, "x");
720 auto y = &jlm::rvsdg::GraphImport::Create(graph, intType, "y");
721 auto z = &jlm::rvsdg::GraphImport::Create(graph, intType, "z");
722 auto w = &jlm::rvsdg::GraphImport::Create(graph, intType, "w");
723 auto lambda = jlm::rvsdg::LambdaNode::Create(
724 graph.GetRootRegion(),
725 LlvmLambdaOperation::Create(
726 jlm::rvsdg::FunctionType::Create({ intType }, { intType }),
727 "f",
728 Linkage::externalLinkage));
729
730 // We wrap the theta in a lambda node to get init nodes in the SCEV tree
731
732 auto cv1 = lambda->AddContextVar(*x).inner;
733 auto cv2 = lambda->AddContextVar(*y).inner;
734 auto cv3 = lambda->AddContextVar(*z).inner;
735 auto cv4 = lambda->AddContextVar(*w).inner;
736
737 const auto theta = jlm::rvsdg::ThetaNode::create(lambda->subregion());
738 auto lv1 = theta->AddLoopVar(cv1);
739 auto lv2 = theta->AddLoopVar(cv2);
740 auto lv3 = theta->AddLoopVar(cv3);
741 auto lv4 = theta->AddLoopVar(cv4);
742
743 auto & addNode1 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv2.pre, lv1.pre }, 32);
744 const auto res1 = addNode1.output(0);
745
746 auto & addNode2 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv3.pre, res1 }, 32);
747 const auto res2 = addNode2.output(0);
748
749 auto & addNode3 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ res2, res1 }, 32);
750 const auto res3 = addNode3.output(0);
751
752 auto & addNode4 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv4.pre, res3 }, 32);
753 const auto res4 = addNode4.output(0);
754
755 const auto & c5 = IntegerConstantOperation::Create(*theta->subregion(), 32, 5);
756 auto & sltNode = jlm::rvsdg::CreateOpNode<IntegerSltOperation>({ res1, c5.output(0) }, 32);
757 const auto matchResult =
758 jlm::rvsdg::MatchOperation::Create(*sltNode.output(0), { { 1, 1 } }, 0, 2);
759
760 theta->set_predicate(matchResult);
761 lv2.post->divert_to(res1);
762 lv3.post->divert_to(res2);
763 lv4.post->divert_to(res4);
764
765 jlm::rvsdg::view(graph, stdout);
766
767 // Act
768 const auto & chrecMap = RunScalarEvolution(rvsdgModule).first;
769
770 // Assert
771 EXPECT_NE(chrecMap.find(lv1.pre), chrecMap.end());
772 EXPECT_NE(chrecMap.find(lv2.pre), chrecMap.end());
773 EXPECT_NE(chrecMap.find(lv3.pre), chrecMap.end());
774 EXPECT_NE(chrecMap.find(lv4.pre), chrecMap.end());
775
776 // lv1 is a trivial (constant) induction variable.
777 // Recurrence: {Init(a0)}
778 auto lv1TestChrec = SCEVChainRecurrence(*theta, *lv1.pre);
779 lv1TestChrec.AddOperand(SCEVInit::Create(*lv1.pre));
780 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv1TestChrec, *chrecMap.at(lv1.pre)));
781
782 // lv2 is a general induction variable which is incremented by the value of lv1 for each
783 // iteration.
784 // Recurrence: {Init(a1),+,Init(a0)}
785 auto lv2TestChrec = SCEVChainRecurrence(*theta, *lv2.pre);
786 lv2TestChrec.AddOperand(SCEVInit::Create(*lv2.pre));
787 lv2TestChrec.AddOperand(SCEVInit::Create(*lv1.pre));
788 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv2TestChrec, *chrecMap.at(lv2.pre)));
789
790 // Tests that two init nodes folded together creates an NAryAdd expression
791 // Recurrence: {Init(a2),+,(Init(a1) + Init(a0)),+,Init(a0)}
792 auto lv3TestChrec = SCEVChainRecurrence(*theta, *lv3.pre);
793 lv3TestChrec.AddOperand(SCEVInit::Create(*lv3.pre));
794 lv3TestChrec.AddOperand(
795 SCEVNAryAddExpr::Create(SCEVInit::Create(*lv2.pre), SCEVInit::Create(*lv1.pre)));
796 lv3TestChrec.AddOperand(SCEVInit::Create(*lv1.pre));
797 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv3TestChrec, *chrecMap.at(lv3.pre)));
798
799 // Tests that when two NAryAdd expressions are folded together, the operands of the RHS add is
800 // added to the LHS add
801 // Recurrence: {Init(a3),+,(Init(a1) + Init(a0) + Init(a2) + Init(a1) + Init(a0)),+,(Init(a1) +
802 // Init(a0) + Init(a0) + Init(a0)),+,Init(a0)}
803 auto lv4TestChrec = SCEVChainRecurrence(*theta, *lv4.pre);
804 lv4TestChrec.AddOperand(SCEVInit::Create(*lv4.pre));
805 lv4TestChrec.AddOperand(SCEVNAryAddExpr::Create(
806 SCEVInit::Create(*lv2.pre),
807 SCEVInit::Create(*lv1.pre),
808 SCEVInit::Create(*lv3.pre),
809 SCEVInit::Create(*lv2.pre),
810 SCEVInit::Create(*lv1.pre)));
811 lv4TestChrec.AddOperand(SCEVNAryAddExpr::Create(
812 SCEVInit::Create(*lv2.pre),
813 SCEVInit::Create(*lv1.pre),
814 SCEVInit::Create(*lv1.pre),
815 SCEVInit::Create(*lv1.pre)));
816 lv4TestChrec.AddOperand(SCEVInit::Create(*lv1.pre));
817 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv4TestChrec, *chrecMap.at(lv4.pre)));
818}
819
820TEST(ScalarEvolutionTests, InductionVariablesWithNonConstantInitialValuesAndMultiplication)
821{
822 using namespace jlm::llvm;
823
824 // Arrange
825 const auto intType = jlm::rvsdg::BitType::Create(32);
826
827 LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
828 jlm::rvsdg::Graph & graph = rvsdgModule.Rvsdg();
829
830 auto x = &jlm::rvsdg::GraphImport::Create(graph, intType, "x");
831 auto y = &jlm::rvsdg::GraphImport::Create(graph, intType, "y");
832 auto z = &jlm::rvsdg::GraphImport::Create(graph, intType, "z");
833 auto w = &jlm::rvsdg::GraphImport::Create(graph, intType, "w");
834 auto lambda = jlm::rvsdg::LambdaNode::Create(
835 graph.GetRootRegion(),
836 LlvmLambdaOperation::Create(
837 jlm::rvsdg::FunctionType::Create({ intType }, { intType }),
838 "f",
839 Linkage::externalLinkage));
840
841 auto cv1 = lambda->AddContextVar(*x).inner;
842 auto cv2 = lambda->AddContextVar(*y).inner;
843 auto cv3 = lambda->AddContextVar(*z).inner;
844 auto cv4 = lambda->AddContextVar(*w).inner;
845
846 const auto theta = jlm::rvsdg::ThetaNode::create(lambda->subregion());
847 auto lv1 = theta->AddLoopVar(cv1);
848 auto lv2 = theta->AddLoopVar(cv2);
849 auto lv3 = theta->AddLoopVar(cv3);
850 auto lv4 = theta->AddLoopVar(cv4);
851
852 const auto & c1 = IntegerConstantOperation::Create(*theta->subregion(), 32, 1);
853 auto & addNode1 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv2.pre, c1.output(0) }, 32);
854 const auto res1 = addNode1.output(0);
855
856 auto & mulNode1 = jlm::rvsdg::CreateOpNode<IntegerMulOperation>({ lv1.pre, lv2.pre }, 32);
857 const auto res2 = mulNode1.output(0);
858
859 auto & addNode2 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv3.pre, res2 }, 32);
860 const auto res3 = addNode2.output(0);
861
862 auto & mulNode2 = jlm::rvsdg::CreateOpNode<IntegerMulOperation>({ res2, res2 }, 32);
863
864 auto & addNode3 =
865 jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv4.pre, mulNode2.output(0) }, 32);
866 const auto res4 = addNode3.output(0);
867
868 const auto & c5 = IntegerConstantOperation::Create(*theta->subregion(), 32, 5);
869 auto & sltNode = jlm::rvsdg::CreateOpNode<IntegerSltOperation>({ res1, c5.output(0) }, 32);
870 const auto matchResult =
871 jlm::rvsdg::MatchOperation::Create(*sltNode.output(0), { { 1, 1 } }, 0, 2);
872
873 theta->set_predicate(matchResult);
874 lv2.post->divert_to(res1);
875 lv3.post->divert_to(res3);
876 lv4.post->divert_to(res4);
877
878 jlm::rvsdg::view(graph, stdout);
879
880 // Act
881 const auto & chrecMap = RunScalarEvolution(rvsdgModule).first;
882
883 // Assert
884 EXPECT_NE(chrecMap.find(lv1.pre), chrecMap.end());
885 EXPECT_NE(chrecMap.find(lv2.pre), chrecMap.end());
886 EXPECT_NE(chrecMap.find(lv3.pre), chrecMap.end());
887 EXPECT_NE(chrecMap.find(lv4.pre), chrecMap.end());
888
889 // lv1 is a trivial (constant) induction variable.
890 // Recurrence: {Init(a0)}
891 auto lv1TestChrec = SCEVChainRecurrence(*theta, *lv1.pre);
892 lv1TestChrec.AddOperand(SCEVInit::Create(*lv1.pre));
893 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv1TestChrec, *chrecMap.at(lv1.pre)));
894
895 // lv2 is a general induction variable which is incremented by 1 each iteration.
896 // Recurrence: {Init(a1),+,1}
897 auto lv2TestChrec = SCEVChainRecurrence(*theta, *lv2.pre);
898 lv2TestChrec.AddOperand(SCEVInit::Create(*lv2.pre));
899 lv2TestChrec.AddOperand(SCEVConstant::Create(1));
900 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv2TestChrec, *chrecMap.at(lv2.pre)));
901
902 // Tests multiplying two init nodes together creates an n-ary mult expression.
903 // Recurrence: {Init(a2),+,(Init(a0) * Init(a1)),+,Init(a0)}
904 auto lv3TestChrec = SCEVChainRecurrence(*theta, *lv3.pre);
905 lv3TestChrec.AddOperand(SCEVInit::Create(*lv3.pre));
906 lv3TestChrec.AddOperand(
907 SCEVNAryMulExpr::Create(SCEVInit::Create(*lv1.pre), SCEVInit::Create(*lv2.pre)));
908 lv3TestChrec.AddOperand(SCEVInit::Create(*lv1.pre));
909
910 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv3TestChrec, *chrecMap.at(lv3.pre)));
911
912 // Tests that when two n-ary mult expressions are folded together, the operands of the RHS mult is
913 // added to the LHS mult
914 // Recurrence:
915 // {Init(a3),+,(Init(a0) * Init(a1) * Init(a0) * Init(a1)),+,((Init(a0) * Init(a1) * Init(a0)) +
916 // (Init(a0) * Init(a0)) + (Init(a0) * Init(a1) * Init(a0))),+,((Init(a0) * Init(a0)) + (Init(a0)
917 // * Init(a0)))}
918 auto lv4TestChrec = SCEVChainRecurrence(*theta, *lv4.pre);
919 lv4TestChrec.AddOperand(SCEVInit::Create(*lv4.pre));
920 lv4TestChrec.AddOperand(SCEVNAryMulExpr::Create(
921 SCEVInit::Create(*lv1.pre),
922 SCEVInit::Create(*lv2.pre),
923 SCEVInit::Create(*lv1.pre),
924 SCEVInit::Create(*lv2.pre)));
925 lv4TestChrec.AddOperand(SCEVNAryAddExpr::Create(
926 SCEVNAryMulExpr::Create(
927 SCEVInit::Create(*lv1.pre),
928 SCEVInit::Create(*lv2.pre),
929 SCEVInit::Create(*lv1.pre)),
930 SCEVNAryMulExpr::Create(SCEVInit::Create(*lv1.pre), SCEVInit::Create(*lv1.pre)),
931 SCEVNAryMulExpr::Create(
932 SCEVInit::Create(*lv1.pre),
933 SCEVInit::Create(*lv2.pre),
934 SCEVInit::Create(*lv1.pre))));
935 lv4TestChrec.AddOperand(SCEVNAryAddExpr::Create(
936 SCEVNAryMulExpr::Create(SCEVInit::Create(*lv1.pre), SCEVInit::Create(*lv1.pre)),
937 SCEVNAryMulExpr::Create(SCEVInit::Create(*lv1.pre), SCEVInit::Create(*lv1.pre))));
938
939 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv4TestChrec, *chrecMap.at(lv4.pre)));
940}
941
942TEST(ScalarEvolutionTests, SelfRecursiveInductionVariable)
943{
944 using namespace jlm::llvm;
945
946 // Arrange
947 const auto intType = jlm::rvsdg::BitType::Create(32);
948
949 LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
950 const auto & graph = rvsdgModule.Rvsdg();
951
952 const auto & c0 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 0);
953
954 const auto theta = jlm::rvsdg::ThetaNode::create(&graph.GetRootRegion());
955 const auto lv1 = theta->AddLoopVar(c0.output(0));
956
957 auto & addNode = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv1.pre, lv1.pre }, 32);
958 const auto result = addNode.output(0);
959
960 const auto & c5 = IntegerConstantOperation::Create(*theta->subregion(), 32, 5);
961 auto & sltNode = jlm::rvsdg::CreateOpNode<IntegerSltOperation>({ result, c5.output(0) }, 32);
962 const auto matchResult =
963 jlm::rvsdg::MatchOperation::Create(*sltNode.output(0), { { 1, 1 } }, 0, 2);
964
965 theta->set_predicate(matchResult);
966 lv1.post->divert_to(result);
967
968 jlm::rvsdg::view(graph, stdout);
969
970 // Act
971 const auto & chrecMap = RunScalarEvolution(rvsdgModule).first;
972
973 // Assert
974 EXPECT_NE(chrecMap.find(lv1.pre), chrecMap.end());
975
976 // lv1 is not an induction variable because of self dependency. Should be {Unknown}
977 auto lv1TestChrec = SCEVChainRecurrence(*theta, *lv1.pre);
978 lv1TestChrec.AddOperand(SCEVUnknown::Create());
979 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv1TestChrec, *chrecMap.at(lv1.pre)));
980}
981
982TEST(ScalarEvolutionTests, DependentOnInvalidInductionVariable)
983{
984 using namespace jlm::llvm;
985
986 // Arrange
987 const auto intType = jlm::rvsdg::BitType::Create(32);
988
989 LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
990 const auto & graph = rvsdgModule.Rvsdg();
991
992 const auto & c0 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 0);
993 const auto & c1 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 0);
994
995 const auto theta = jlm::rvsdg::ThetaNode::create(&graph.GetRootRegion());
996 const auto lv1 = theta->AddLoopVar(c0.output(0));
997 const auto lv2 = theta->AddLoopVar(c1.output(0));
998
999 auto & addNode_1 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv1.pre, lv1.pre }, 32);
1000 const auto result_1 = addNode_1.output(0);
1001
1002 auto & addNode_2 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv2.pre, lv1.pre }, 32);
1003 const auto result_2 = addNode_2.output(0);
1004
1005 const auto & c5 = IntegerConstantOperation::Create(*theta->subregion(), 32, 5);
1006 auto & sltNode = jlm::rvsdg::CreateOpNode<IntegerSltOperation>({ result_1, c5.output(0) }, 32);
1007 const auto matchResult =
1008 jlm::rvsdg::MatchOperation::Create(*sltNode.output(0), { { 1, 1 } }, 0, 2);
1009
1010 theta->set_predicate(matchResult);
1011 lv1.post->divert_to(result_1);
1012 lv2.post->divert_to(result_2);
1013
1014 jlm::rvsdg::view(graph, stdout);
1015
1016 // Act
1017 const auto & chrecMap = RunScalarEvolution(rvsdgModule).first;
1018
1019 // Assert
1020 EXPECT_NE(chrecMap.find(lv1.pre), chrecMap.end());
1021 EXPECT_NE(chrecMap.find(lv2.pre), chrecMap.end());
1022
1023 // lv1 is not an induction variable because of self dependency. Should be {Unknown}
1024 auto lv1TestChrec = SCEVChainRecurrence(*theta, *lv1.pre);
1025 lv1TestChrec.AddOperand(SCEVUnknown::Create());
1026 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv1TestChrec, *chrecMap.at(lv1.pre)));
1027
1028 // lv2 has the recurrence {0,+,Unknown} due to the dependency of lv1
1029 auto lv2TestChrec = SCEVChainRecurrence(*theta, *lv2.pre);
1030 lv2TestChrec.AddOperand(SCEVConstant::Create(0));
1031 lv2TestChrec.AddOperand(SCEVUnknown::Create());
1032 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv2TestChrec, *chrecMap.at(lv2.pre)));
1033}
1034
1035TEST(ScalarEvolutionTests, MutuallyDependentInductionVariables)
1036{
1037 // Testing mutually dependent variables (A->B->A)
1038 using namespace jlm::llvm;
1039
1040 // Arrange
1041 const auto intType = jlm::rvsdg::BitType::Create(32);
1042
1043 LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
1044 const auto & graph = rvsdgModule.Rvsdg();
1045
1046 const auto & c0 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 0);
1047 const auto & c1 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 1);
1048
1049 const auto theta = jlm::rvsdg::ThetaNode::create(&graph.GetRootRegion());
1050 const auto lv1 = theta->AddLoopVar(c0.output(0)); // A
1051 const auto lv2 = theta->AddLoopVar(c1.output(0)); // B
1052
1053 auto & addNode_1 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv1.pre, lv2.pre }, 32);
1054 const auto result_1 = addNode_1.output(0);
1055
1056 auto & addNode_2 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv1.pre, lv2.pre }, 32);
1057 const auto result_2 = addNode_2.output(0);
1058
1059 const auto & c5 = IntegerConstantOperation::Create(*theta->subregion(), 32, 5);
1060 auto & sltNode = jlm::rvsdg::CreateOpNode<IntegerSltOperation>({ result_1, c5.output(0) }, 32);
1061 const auto matchResult =
1062 jlm::rvsdg::MatchOperation::Create(*sltNode.output(0), { { 1, 1 } }, 0, 2);
1063
1064 theta->set_predicate(matchResult);
1065 lv1.post->divert_to(result_1);
1066 lv2.post->divert_to(result_2);
1067
1068 jlm::rvsdg::view(graph, stdout);
1069
1070 // Act
1071 const auto & chrecMap = RunScalarEvolution(rvsdgModule).first;
1072
1073 // Assert
1074 EXPECT_NE(chrecMap.find(lv1.pre), chrecMap.end());
1075 EXPECT_NE(chrecMap.find(lv2.pre), chrecMap.end());
1076
1077 // Both lv1 and lv2 should be {Unknown} due to mutual dependency (A->B->A)
1078 auto lv1TestChrec = SCEVChainRecurrence(*theta, *lv1.pre);
1079 lv1TestChrec.AddOperand(SCEVUnknown::Create());
1080 auto lv2TestChrec = SCEVChainRecurrence(*theta, *lv2.pre);
1081 lv2TestChrec.AddOperand(SCEVUnknown::Create());
1082 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv1TestChrec, *chrecMap.at(lv1.pre)));
1083 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv2TestChrec, *chrecMap.at(lv2.pre)));
1084}
1085
1086TEST(ScalarEvolutionTests, MultiLayeredMutuallyDependentInductionVariables)
1087{
1088 // Testing chains of mutually dependent IVs (A->B->C->D->A)
1089 using namespace jlm::llvm;
1090
1091 // Arrange
1092 const auto intType = jlm::rvsdg::BitType::Create(32);
1093
1094 LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
1095 const auto & graph = rvsdgModule.Rvsdg();
1096
1097 const auto & c0 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 0);
1098 const auto & c1 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 1);
1099 const auto & c2 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 2);
1100 const auto & c3 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 3);
1101
1102 const auto theta = jlm::rvsdg::ThetaNode::create(&graph.GetRootRegion());
1103 const auto lv1 = theta->AddLoopVar(c0.output(0)); // A
1104 const auto lv2 = theta->AddLoopVar(c1.output(0)); // B
1105 const auto lv3 = theta->AddLoopVar(c2.output(0)); // C
1106 const auto lv4 = theta->AddLoopVar(c3.output(0)); // D
1107
1108 auto & addNode_1 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv1.pre, lv2.pre }, 32);
1109 const auto result_1 = addNode_1.output(0);
1110 auto & addNode_2 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv2.pre, lv3.pre }, 32);
1111 const auto result_2 = addNode_2.output(0);
1112 auto & addNode_3 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv3.pre, lv4.pre }, 32);
1113 const auto result_3 = addNode_3.output(0);
1114 auto & addNode_4 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv4.pre, lv1.pre }, 32);
1115 const auto result_4 = addNode_4.output(0);
1116
1117 const auto & c5 = IntegerConstantOperation::Create(*theta->subregion(), 32, 5);
1118 auto & sltNode = jlm::rvsdg::CreateOpNode<IntegerSltOperation>({ result_1, c5.output(0) }, 32);
1119 const auto matchResult =
1120 jlm::rvsdg::MatchOperation::Create(*sltNode.output(0), { { 1, 1 } }, 0, 2);
1121
1122 theta->set_predicate(matchResult);
1123 lv1.post->divert_to(result_1);
1124 lv2.post->divert_to(result_2);
1125 lv3.post->divert_to(result_3);
1126 lv4.post->divert_to(result_4);
1127
1128 jlm::rvsdg::view(graph, stdout);
1129
1130 // Act
1131 const auto & chrecMap = RunScalarEvolution(rvsdgModule).first;
1132
1133 // Assert
1134 EXPECT_NE(chrecMap.find(lv1.pre), chrecMap.end());
1135 EXPECT_NE(chrecMap.find(lv2.pre), chrecMap.end());
1136 EXPECT_NE(chrecMap.find(lv3.pre), chrecMap.end());
1137 EXPECT_NE(chrecMap.find(lv4.pre), chrecMap.end());
1138
1139 // All variables should be {Unknown} due to mutual dependency chain (A->B->C->D->A)
1140 auto lv1TestChrec = SCEVChainRecurrence(*theta, *lv1.pre);
1141 lv1TestChrec.AddOperand(SCEVUnknown::Create());
1142 auto lv2TestChrec = SCEVChainRecurrence(*theta, *lv2.pre);
1143 lv2TestChrec.AddOperand(SCEVUnknown::Create());
1144 auto lv3TestChrec = SCEVChainRecurrence(*theta, *lv3.pre);
1145 lv3TestChrec.AddOperand(SCEVUnknown::Create());
1146 auto lv4TestChrec = SCEVChainRecurrence(*theta, *lv4.pre);
1147 lv4TestChrec.AddOperand(SCEVUnknown::Create());
1148
1149 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv1TestChrec, *chrecMap.at(lv1.pre)));
1150 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv2TestChrec, *chrecMap.at(lv2.pre)));
1151 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv3TestChrec, *chrecMap.at(lv3.pre)));
1152 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv4TestChrec, *chrecMap.at(lv4.pre)));
1153}
1154
1155TEST(ScalarEvolutionTests, InductionVariablesInNestedLoops)
1156{
1157 // Tests "stitching" of induction variables in outer loops
1158 using namespace jlm::llvm;
1159
1160 // Arrange
1161 const auto intType = jlm::rvsdg::BitType::Create(32);
1162
1163 LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
1164 const auto & graph = rvsdgModule.Rvsdg();
1165
1166 const auto & c0 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 0);
1167 const auto theta1 = jlm::rvsdg::ThetaNode::create(&graph.GetRootRegion());
1168 const auto lv1 = theta1->AddLoopVar(c0.output(0));
1169
1170 const auto & c1 = IntegerConstantOperation::Create(*theta1->subregion(), 32, 1);
1171 auto & addNode1 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv1.pre, c1.output(0) }, 32);
1172 const auto res1 = addNode1.output(0);
1173
1174 const auto & c5 = IntegerConstantOperation::Create(*theta1->subregion(), 32, 5);
1175 auto & sltNode1 = jlm::rvsdg::CreateOpNode<IntegerSltOperation>({ res1, c5.output(0) }, 32);
1176 const auto matchResult1 =
1177 jlm::rvsdg::MatchOperation::Create(*sltNode1.output(0), { { 1, 1 } }, 0, 2);
1178
1179 const auto theta2 = jlm::rvsdg::ThetaNode::create(theta1->subregion());
1180 const auto lv2 = theta2->AddLoopVar(c1.output(0));
1181 const auto lv3 = theta2->AddLoopVar(lv1.pre);
1182
1183 auto & addNode2 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv2.pre, lv3.pre }, 32);
1184 const auto & res2 = addNode2.output(0);
1185
1186 const auto & c10 = IntegerConstantOperation::Create(*theta2->subregion(), 32, 10);
1187 auto & sltNode2 = jlm::rvsdg::CreateOpNode<IntegerSltOperation>({ res2, c10.output(0) }, 32);
1188
1189 const auto matchResult2 =
1190 jlm::rvsdg::MatchOperation::Create(*sltNode2.output(0), { { 1, 1 } }, 0, 2);
1191
1192 theta1->set_predicate(matchResult1);
1193 lv1.post->divert_to(res1);
1194
1195 theta2->set_predicate(matchResult2);
1196 lv2.post->divert_to(res2);
1197
1198 jlm::rvsdg::view(graph, stdout);
1199
1200 // Act
1201 const auto & chrecMap = RunScalarEvolution(rvsdgModule).first;
1202
1203 // Assert
1204 EXPECT_NE(chrecMap.find(lv1.pre), chrecMap.end());
1205
1206 EXPECT_NE(chrecMap.find(lv2.pre), chrecMap.end());
1207 EXPECT_NE(chrecMap.find(lv3.pre), chrecMap.end());
1208
1209 // lv1 is a simple induction variable with the recurrence {0,+,1}<1>
1210 auto lv1TestChrec = SCEVChainRecurrence(*theta1, *lv1.pre);
1211 lv1TestChrec.AddOperand(SCEVConstant::Create(0));
1212 lv1TestChrec.AddOperand(SCEVConstant::Create(1));
1213 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv1TestChrec, *chrecMap.at(lv1.pre)));
1214
1215 // lv2 is a nested induction variable, which is incremented by the value of lv1 for each
1216 // iteration
1217 auto lv2TestChrec = SCEVChainRecurrence(*theta2, *lv2.pre);
1218 lv2TestChrec.AddOperand(SCEVConstant::Create(1));
1219 lv2TestChrec.AddOperand(lv1TestChrec.Clone());
1220 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv2TestChrec, *chrecMap.at(lv2.pre)));
1221
1222 // lv3 has the same value as lv1, but for the inner loop
1223 auto lv3TestChrec = SCEVChainRecurrence(*theta2, *lv3.pre);
1224 lv3TestChrec.AddOperand(lv1TestChrec.Clone());
1225 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv3TestChrec, *chrecMap.at(lv3.pre)));
1226}
1227
1228TEST(ScalarEvolutionTests, InductionVariablesInNestedLoopsWithFolding)
1229{
1230 using namespace jlm::llvm;
1231
1232 // Arrange
1233 const auto intType = jlm::rvsdg::BitType::Create(32);
1234
1235 LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
1236 const auto & graph = rvsdgModule.Rvsdg();
1237
1238 const auto & c0_1 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 0);
1239 const auto & c2_1 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 2);
1240 const auto & c3_1 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 3);
1241
1242 const auto theta1 = jlm::rvsdg::ThetaNode::create(&graph.GetRootRegion());
1243 const auto lv1_1 = theta1->AddLoopVar(c0_1.output(0));
1244 const auto lv2_1 = theta1->AddLoopVar(c2_1.output(0));
1245 const auto lv3_1 = theta1->AddLoopVar(c3_1.output(0));
1246
1247 const auto & c1_2 = IntegerConstantOperation::Create(*theta1->subregion(), 32, 1);
1248 const auto & c2_2 = IntegerConstantOperation::Create(*theta1->subregion(), 32, 2);
1249 const auto & c3_2 = IntegerConstantOperation::Create(*theta1->subregion(), 32, 3);
1250
1251 auto & addNode1 =
1252 jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv1_1.pre, c1_2.output(0) }, 32);
1253 auto & addNode2 =
1254 jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv2_1.pre, c2_2.output(0) }, 32);
1255 auto & addNode3 =
1256 jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv3_1.pre, c3_2.output(0) }, 32);
1257 const auto res1 = addNode1.output(0);
1258 const auto res2 = addNode2.output(0);
1259 const auto res3 = addNode3.output(0);
1260
1261 const auto & c5 = IntegerConstantOperation::Create(*theta1->subregion(), 32, 5);
1262 auto & sltNode1 = jlm::rvsdg::CreateOpNode<IntegerSltOperation>({ res1, c5.output(0) }, 32);
1263 const auto matchResult1 =
1264 jlm::rvsdg::MatchOperation::Create(*sltNode1.output(0), { { 1, 1 } }, 0, 2);
1265
1266 const auto theta2 = jlm::rvsdg::ThetaNode::create(theta1->subregion());
1267 const auto lv1_2 = theta2->AddLoopVar(res1);
1268 const auto lv2_2 = theta2->AddLoopVar(res2);
1269 const auto lv3_2 = theta2->AddLoopVar(res3);
1270 const auto lv4 = theta2->AddLoopVar(c1_2.output(0));
1271 const auto lv5 = theta2->AddLoopVar(c1_2.output(0));
1272
1273 auto & addNode4 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv1_2.pre, lv2_2.pre }, 32);
1274 auto & addNode5 =
1275 jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ addNode4.output(0), lv3_2.pre }, 32);
1276 auto & addNode6 =
1277 jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv4.pre, addNode5.output(0) }, 32);
1278 const auto & res4 = addNode6.output(0);
1279
1280 auto & mulNode1 = jlm::rvsdg::CreateOpNode<IntegerMulOperation>({ lv1_2.pre, lv2_2.pre }, 32);
1281 auto & addNode7 =
1282 jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv5.pre, mulNode1.output(0) }, 32);
1283 const auto & res5 = addNode7.output(0);
1284
1285 const auto & c10 = IntegerConstantOperation::Create(*theta2->subregion(), 32, 10);
1286 auto & sltNode2 = jlm::rvsdg::CreateOpNode<IntegerSltOperation>({ res4, c10.output(0) }, 32);
1287
1288 const auto matchResult2 =
1289 jlm::rvsdg::MatchOperation::Create(*sltNode2.output(0), { { 1, 1 } }, 0, 2);
1290
1291 // Outer loop
1292 theta1->set_predicate(matchResult1);
1293 lv1_1.post->divert_to(res1);
1294 lv2_1.post->divert_to(res2);
1295 lv3_1.post->divert_to(res3);
1296
1297 // Inner loop
1298 theta2->set_predicate(matchResult2);
1299 lv4.post->divert_to(res4);
1300 lv5.post->divert_to(res5);
1301
1302 jlm::rvsdg::view(graph, stdout);
1303
1304 // Act
1305 const auto & chrecMap = RunScalarEvolution(rvsdgModule).first;
1306
1307 // Assert
1308 EXPECT_NE(chrecMap.find(lv1_1.pre), chrecMap.end());
1309 EXPECT_NE(chrecMap.find(lv2_1.pre), chrecMap.end());
1310 EXPECT_NE(chrecMap.find(lv3_1.pre), chrecMap.end());
1311
1312 EXPECT_NE(chrecMap.find(lv1_2.pre), chrecMap.end());
1313 EXPECT_NE(chrecMap.find(lv2_2.pre), chrecMap.end());
1314 EXPECT_NE(chrecMap.find(lv3_2.pre), chrecMap.end());
1315 EXPECT_NE(chrecMap.find(lv4.pre), chrecMap.end());
1316 EXPECT_NE(chrecMap.find(lv5.pre), chrecMap.end());
1317
1318 // lv1 is a simple induction variable with the recurrence {0,+,1}<1>
1319 auto lv1TestChrec = SCEVChainRecurrence(*theta1, *lv1_1.pre);
1320 lv1TestChrec.AddOperand(SCEVConstant::Create(0));
1321 lv1TestChrec.AddOperand(SCEVConstant::Create(1));
1322 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv1TestChrec, *chrecMap.at(lv1_1.pre)));
1323
1324 // lv2 is a simple induction variable with the recurrence {2,+,2}<1>
1325 auto lv2TestChrec = SCEVChainRecurrence(*theta1, *lv2_1.pre);
1326 lv2TestChrec.AddOperand(SCEVConstant::Create(2));
1327 lv2TestChrec.AddOperand(SCEVConstant::Create(2));
1328 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv2TestChrec, *chrecMap.at(lv2_1.pre)));
1329
1330 // lv3 is a simple induction variable with the recurrence {3,+,3}<1>
1331 auto lv3TestChrec = SCEVChainRecurrence(*theta1, *lv3_1.pre);
1332 lv3TestChrec.AddOperand(SCEVConstant::Create(3));
1333 lv3TestChrec.AddOperand(SCEVConstant::Create(3));
1334 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv3TestChrec, *chrecMap.at(lv3_1.pre)));
1335
1336 // lv1_2 is lv1_1 incremented by 1 but in the inner loop
1337 auto lv1_2TestChrec = SCEVChainRecurrence(*theta2, *lv1_2.pre);
1338 const auto lv1_2InnerChrec = SCEVChainRecurrence::Create(*theta1, *lv1_1.post->origin());
1339 lv1_2InnerChrec->AddOperand(SCEVConstant::Create(1));
1340 lv1_2InnerChrec->AddOperand(SCEVConstant::Create(1));
1341 lv1_2TestChrec.AddOperand(lv1_2InnerChrec->Clone());
1342 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv1_2TestChrec, *chrecMap.at(lv1_2.pre)));
1343
1344 // lv2_2 is lv2_1 incremented by 2 but in the inner loop
1345 auto lv2_2TestChrec = SCEVChainRecurrence(*theta2, *lv2_2.pre);
1346 const auto lv2_2InnerChrec = SCEVChainRecurrence::Create(*theta1, *lv2_1.post->origin());
1347 lv2_2InnerChrec->AddOperand(SCEVConstant::Create(4));
1348 lv2_2InnerChrec->AddOperand(SCEVConstant::Create(2));
1349 lv2_2TestChrec.AddOperand(lv2_2InnerChrec->Clone());
1350 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv2_2TestChrec, *chrecMap.at(lv2_2.pre)));
1351
1352 // lv3_2 is lv3_1 incremented by 3 but in the inner loop
1353 auto lv3_2TestChrec = SCEVChainRecurrence(*theta2, *lv3_2.pre);
1354 const auto lv3_2InnerChrec = SCEVChainRecurrence::Create(*theta1, *lv3_1.post->origin());
1355 lv3_2InnerChrec->AddOperand(SCEVConstant::Create(6));
1356 lv3_2InnerChrec->AddOperand(SCEVConstant::Create(3));
1357 lv3_2TestChrec.AddOperand(lv3_2InnerChrec->Clone());
1358 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv3_2TestChrec, *chrecMap.at(lv3_2.pre)));
1359
1360 // lv4 is in the inner loop and has a start value of 1 which is incremented by the result of
1361 // folding ({1,+,1}<1> + {4,+,2}<1> + {6,+,3}<1>) = {11,+,6}<1>. Recurrence:
1362 // { 1, +, { 11, +, 6 } < 1 > } < 2 >
1363 auto lv4TestChrec = SCEVChainRecurrence(*theta2, *lv4.pre);
1364 lv4TestChrec.AddOperand(SCEVConstant::Create(1));
1365 const auto lv4InnerChrec = SCEVChainRecurrence::Create(*theta1, *lv4.pre);
1366 lv4InnerChrec->AddOperand(SCEVConstant::Create(11));
1367 lv4InnerChrec->AddOperand(SCEVConstant::Create(6));
1368 lv4TestChrec.AddOperand(lv4InnerChrec->Clone());
1369 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv4TestChrec, *chrecMap.at(lv4.pre)));
1370
1371 // lv5 is in the inner loop and has a start value of 1 which is incremented by the result of
1372 // folding ({1,+,1}<1> * {4,+,2}<1>) = {4,+,8,+,4}<1>. Recurrence: {1,+,{4,+,8,+,4}<1>}<2>
1373 auto lv5TestChrec = SCEVChainRecurrence(*theta2, *lv5.pre);
1374 lv5TestChrec.AddOperand(SCEVConstant::Create(1));
1375 const auto lv5InnerChrec = SCEVChainRecurrence::Create(*theta1, *lv5.pre);
1376 lv5InnerChrec->AddOperand(SCEVConstant::Create(4));
1377 lv5InnerChrec->AddOperand(SCEVConstant::Create(8));
1378 lv5InnerChrec->AddOperand(SCEVConstant::Create(4));
1379 lv5TestChrec.AddOperand(lv5InnerChrec->Clone());
1380 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv5TestChrec, *chrecMap.at(lv5.pre)));
1381}
1382
1383TEST(ScalarEvolutionTests, InductionVariablesInSisterLoops)
1384{
1385 // Tests "stitching" of induction variables in other loops that are on the same level, AKA
1386 // "sister loops"
1387 using namespace jlm::llvm;
1388
1389 // Arrange
1390 const auto intType = jlm::rvsdg::BitType::Create(32);
1391
1392 LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
1393 const auto & graph = rvsdgModule.Rvsdg();
1394
1395 const auto & c0 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 0);
1396 const auto theta1 = jlm::rvsdg::ThetaNode::create(&graph.GetRootRegion());
1397 const auto lv1 = theta1->AddLoopVar(c0.output(0));
1398
1399 const auto & c1 = IntegerConstantOperation::Create(*theta1->subregion(), 32, 1);
1400 auto & addNode1 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv1.pre, c1.output(0) }, 32);
1401 const auto res1 = addNode1.output(0);
1402
1403 const auto & c5 = IntegerConstantOperation::Create(*theta1->subregion(), 32, 5);
1404 auto & sltNode1 = jlm::rvsdg::CreateOpNode<IntegerSltOperation>({ res1, c5.output(0) }, 32);
1405 const auto matchResult1 =
1406 jlm::rvsdg::MatchOperation::Create(*sltNode1.output(0), { { 1, 1 } }, 0, 2);
1407
1408 const auto & c2 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 2);
1409 const auto theta2 = jlm::rvsdg::ThetaNode::create(&graph.GetRootRegion());
1410 const auto lv2 = theta2->AddLoopVar(c2.output(0));
1411 const auto lv3 = theta2->AddLoopVar(theta1->output(0));
1412
1413 auto & addNode2 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv2.pre, lv3.pre }, 32);
1414 const auto & res2 = addNode2.output(0);
1415
1416 const auto & c10 = IntegerConstantOperation::Create(*theta2->subregion(), 32, 10);
1417 auto & sltNode2 = jlm::rvsdg::CreateOpNode<IntegerSltOperation>({ res2, c10.output(0) }, 32);
1418
1419 const auto matchResult2 =
1420 jlm::rvsdg::MatchOperation::Create(*sltNode2.output(0), { { 1, 1 } }, 0, 2);
1421
1422 theta1->set_predicate(matchResult1);
1423 lv1.post->divert_to(res1);
1424
1425 theta2->set_predicate(matchResult2);
1426 lv2.post->divert_to(res2);
1427
1428 jlm::rvsdg::view(graph, stdout);
1429
1430 // Act
1431 const auto & chrecMap = RunScalarEvolution(rvsdgModule).first;
1432
1433 // Assert
1434 EXPECT_NE(chrecMap.find(lv1.pre), chrecMap.end());
1435
1436 EXPECT_NE(chrecMap.find(lv2.pre), chrecMap.end());
1437 EXPECT_NE(chrecMap.find(lv3.pre), chrecMap.end());
1438
1439 // lv1 is a simple induction variable with the recurrence {0,+,1}<1>
1440 auto lv1TestChrec = SCEVChainRecurrence(*theta1, *lv1.pre);
1441 lv1TestChrec.AddOperand(SCEVConstant::Create(0));
1442 lv1TestChrec.AddOperand(SCEVConstant::Create(1));
1443 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv1TestChrec, *chrecMap.at(lv1.pre)));
1444
1445 // lv2 is a nested induction variable, which is incremented by the post iteration value of lv1
1446 // ({1,+,1}<1>) for each iteration
1447 auto lv2TestChrec = SCEVChainRecurrence(*theta2, *lv2.pre);
1448 lv2TestChrec.AddOperand(SCEVConstant::Create(2));
1449 auto lv2InnerChrec = SCEVChainRecurrence(*theta1, *lv1.output);
1450 lv2InnerChrec.AddOperand(SCEVConstant::Create(1));
1451 lv2InnerChrec.AddOperand(SCEVConstant::Create(1));
1452 lv2TestChrec.AddOperand(lv2InnerChrec.Clone());
1453 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv2TestChrec, *chrecMap.at(lv2.pre)));
1454
1455 // lv3 has the same value as the post iteration value of lv1, but wrapped in the inner loop
1456 auto lv3TestChrec = SCEVChainRecurrence(*theta2, *lv3.pre);
1457 lv3TestChrec.AddOperand(lv2InnerChrec.Clone());
1458 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv3TestChrec, *chrecMap.at(lv3.pre)));
1459}
1460
1461TEST(ScalarEvolutionTests, ComputeRecurrenceForArrayGEP)
1462{
1463 using namespace jlm::llvm;
1464
1465 // Arrange
1466 const auto intType = jlm::rvsdg::BitType::Create(32);
1467 const auto intArrayType = ArrayType::Create(intType, 5);
1468 const auto pointerType = PointerType::Create();
1469 const auto memoryStateType = MemoryStateType::Create();
1470
1471 LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
1472 const auto & graph = rvsdgModule.Rvsdg();
1473
1474 auto lambda = jlm::rvsdg::LambdaNode::Create(
1475 graph.GetRootRegion(),
1476 LlvmLambdaOperation::Create(
1478 { pointerType, memoryStateType },
1479 { intType, memoryStateType }),
1480 "f",
1481 Linkage::externalLinkage));
1482
1483 const auto & delta = jlm::rvsdg::DeltaNode::Create(
1484 &graph.GetRootRegion(),
1485 LlvmDeltaOperation::Create(intArrayType, "", Linkage::externalLinkage, "", false, 4));
1486
1487 const auto & arrayC1 = IntegerConstantOperation::Create(*delta->subregion(), 32, 1);
1488 const auto & arrayC2 = IntegerConstantOperation::Create(*delta->subregion(), 32, 2);
1489 const auto & arrayC3 = IntegerConstantOperation::Create(*delta->subregion(), 32, 3);
1490 const auto & arrayC4 = IntegerConstantOperation::Create(*delta->subregion(), 32, 4);
1491 const auto & arrayC5 = IntegerConstantOperation::Create(*delta->subregion(), 32, 5);
1492
1493 const auto & constantArray = ConstantDataArrayOperation::Create({ arrayC1.output(0),
1494 arrayC2.output(0),
1495 arrayC3.output(0),
1496 arrayC4.output(0),
1497 arrayC5.output(0) });
1498 delta->finalize(constantArray);
1499
1500 const auto cv1 = lambda->AddContextVar(delta->output());
1501
1502 const auto & c0_1 = IntegerConstantOperation::Create(*lambda->subregion(), 32, 0);
1503 const auto & c1_1 = IntegerConstantOperation::Create(*lambda->subregion(), 32, 1);
1504 const auto & theta = jlm::rvsdg::ThetaNode::create(lambda->subregion());
1505
1506 const auto memoryState = theta->AddLoopVar(lambda->GetFunctionArguments()[1]);
1507 const auto lv1 = theta->AddLoopVar(c0_1.output(0)); // i
1508 const auto lv2 = theta->AddLoopVar(c1_1.output(0)); // sum
1509 const auto lv3 = theta->AddLoopVar(cv1.inner); // arr ptr
1510
1511 const auto & c1_2 = IntegerConstantOperation::Create(*theta->subregion(), 32, 1);
1512
1513 auto & addNode1 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv1.pre, c1_2.output(0) }, 32);
1514 const auto res1 = addNode1.output(0);
1515
1516 const auto & c0_2 = IntegerConstantOperation::Create(*theta->subregion(), 64, 0);
1517 auto & lv1SExt = SExtOperation::create(64, *lv1.pre);
1518
1519 const auto gep =
1520 GetElementPtrOperation::create(lv3.pre, { c0_2.output(0), &lv1SExt }, intArrayType);
1521
1522 auto loadedValue = LoadNonVolatileOperation::Create(gep, { memoryState.pre }, intType, 32)[0];
1523
1524 auto & addNode2 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv2.pre, loadedValue }, 32);
1525 const auto res2 = addNode2.output(0);
1526
1527 const auto & c4 = IntegerConstantOperation::Create(*theta->subregion(), 32, 4);
1528 auto & sltNode = jlm::rvsdg::CreateOpNode<IntegerSltOperation>({ res1, c4.output(0) }, 32);
1529 const auto matchResult =
1530 jlm::rvsdg::MatchOperation::Create(*sltNode.output(0), { { 1, 1 } }, 0, 2);
1531
1532 theta->set_predicate(matchResult);
1533
1534 lv1.post->divert_to(res1);
1535 lv2.post->divert_to(res2);
1536
1537 jlm::rvsdg::view(graph, stdout);
1538
1539 // Act
1540 const auto & chrecMap = RunScalarEvolution(rvsdgModule).first;
1541
1542 // Assert
1543 EXPECT_NE(chrecMap.find(lv1.pre), chrecMap.end());
1544 EXPECT_NE(chrecMap.find(lv2.pre), chrecMap.end());
1545 EXPECT_NE(chrecMap.find(lv3.pre), chrecMap.end());
1546 EXPECT_NE(chrecMap.find(gep), chrecMap.end());
1547
1548 // lv1 is a simple induction variable with the recurrence {0,+,1}
1549 auto lv1TestChrec = SCEVChainRecurrence(*theta, *lv1.pre);
1550 lv1TestChrec.AddOperand(SCEVConstant::Create(0));
1551 lv1TestChrec.AddOperand(SCEVConstant::Create(1));
1552 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv1TestChrec, *chrecMap.at(lv1.pre)));
1553
1554 // lv2 is reliant on the result from a LOAD operation, and should therefore be {1,+,Unknown}
1555 auto lv2TestChrec = SCEVChainRecurrence(*theta, *lv2.pre);
1556 lv2TestChrec.AddOperand(SCEVConstant::Create(1));
1557 lv2TestChrec.AddOperand(SCEVUnknown::Create());
1558 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv2TestChrec, *chrecMap.at(lv2.pre)));
1559
1560 // lv3 (base pointer in GEP) is unchanged, it's recurrence should be {Init(a3)}
1561 auto lv3TestChrec = SCEVChainRecurrence(*theta, *lv3.pre);
1562 lv3TestChrec.AddOperand(SCEVInit::Create(*lv3.pre));
1563 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv3TestChrec, *chrecMap.at(lv3.pre)));
1564
1565 // The GEP should have the following SCEV: (PH(a3) + ((0 * 20) + (PH(a1) * 4)))
1566 // Replacing the placeholders gives us ({Init(a3)} + (0 * 20) + ({0,+,1} * 4)})
1567 // Folding constants together gives us ({Init(a3)} + {0,+,4}) = {Init(a3),+,4} which is the
1568 // resulting recurrence
1569 auto gepTestChrec = SCEVChainRecurrence(*theta, *gep);
1570 gepTestChrec.AddOperand(SCEVInit::Create(*lv3.pre));
1571 gepTestChrec.AddOperand(SCEVConstant::Create(4));
1572 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(gepTestChrec, *chrecMap.at(gep)));
1573}
1574
1575TEST(ScalarEvolutionTests, ComputeRecurrenceForStructGEP)
1576{
1577 using namespace jlm::llvm;
1578
1579 // Arrange
1580 const auto intType = jlm::rvsdg::BitType::Create(32);
1581 const auto intStructType =
1582 StructType::CreateLiteral({ intType, intType, intType, intType, intType }, false);
1583 const auto pointerType = PointerType::Create();
1584 const auto memoryStateType = MemoryStateType::Create();
1585
1586 LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
1587 const auto & graph = rvsdgModule.Rvsdg();
1588
1589 auto lambda = jlm::rvsdg::LambdaNode::Create(
1590 graph.GetRootRegion(),
1591 LlvmLambdaOperation::Create(
1593 { pointerType, memoryStateType },
1594 { intType, memoryStateType }),
1595 "f",
1596 Linkage::externalLinkage));
1597
1598 const auto & delta = jlm::rvsdg::DeltaNode::Create(
1599 &graph.GetRootRegion(),
1600 LlvmDeltaOperation::Create(intStructType, "", Linkage::externalLinkage, "", false, 4));
1601
1602 const auto & structC1 = IntegerConstantOperation::Create(*delta->subregion(), 32, 1);
1603 const auto & structC2 = IntegerConstantOperation::Create(*delta->subregion(), 32, 2);
1604 const auto & structC3 = IntegerConstantOperation::Create(*delta->subregion(), 32, 3);
1605 const auto & structC4 = IntegerConstantOperation::Create(*delta->subregion(), 32, 4);
1606 const auto & structC5 = IntegerConstantOperation::Create(*delta->subregion(), 32, 5);
1607
1608 auto & constantStruct = ConstantStructOperation::Create(
1609 *delta->subregion(),
1610 { structC1.output(0),
1611 structC2.output(0),
1612 structC3.output(0),
1613 structC4.output(0),
1614 structC5.output(0) },
1615 intStructType);
1616 delta->finalize(&constantStruct);
1617
1618 const auto cv1 = lambda->AddContextVar(delta->output());
1619
1620 const auto & c0_1 = IntegerConstantOperation::Create(*lambda->subregion(), 32, 0);
1621 const auto & c1_1 = IntegerConstantOperation::Create(*lambda->subregion(), 32, 1);
1622 const auto & theta = jlm::rvsdg::ThetaNode::create(lambda->subregion());
1623
1624 const auto memoryState = theta->AddLoopVar(lambda->GetFunctionArguments()[1]);
1625 const auto lv1 = theta->AddLoopVar(c0_1.output(0)); // i
1626 const auto lv2 = theta->AddLoopVar(c1_1.output(0)); // sum
1627 const auto lv3 = theta->AddLoopVar(cv1.inner); // struct ptr
1628
1629 const auto & c1_2 = IntegerConstantOperation::Create(*theta->subregion(), 32, 1);
1630
1631 auto & addNode1 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv1.pre, c1_2.output(0) }, 32);
1632 const auto res1 = addNode1.output(0);
1633
1634 auto & lv1SExt = SExtOperation::create(64, *lv1.pre);
1635 const auto gep = GetElementPtrOperation::create(lv3.pre, { &lv1SExt }, intType);
1636
1637 auto loadedValue = LoadNonVolatileOperation::Create(gep, { memoryState.pre }, intType, 32)[0];
1638
1639 auto & addNode2 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv2.pre, loadedValue }, 32);
1640 const auto res2 = addNode2.output(0);
1641
1642 const auto & c4 = IntegerConstantOperation::Create(*theta->subregion(), 32, 4);
1643 auto & sltNode = jlm::rvsdg::CreateOpNode<IntegerSltOperation>({ res1, c4.output(0) }, 32);
1644 const auto matchResult =
1645 jlm::rvsdg::MatchOperation::Create(*sltNode.output(0), { { 1, 1 } }, 0, 2);
1646
1647 theta->set_predicate(matchResult);
1648
1649 lv1.post->divert_to(res1);
1650 lv2.post->divert_to(res2);
1651
1652 jlm::rvsdg::view(graph, stdout);
1653
1654 // Act
1655 const auto & chrecMap = RunScalarEvolution(rvsdgModule).first;
1656
1657 // Assert
1658 EXPECT_NE(chrecMap.find(lv1.pre), chrecMap.end());
1659 EXPECT_NE(chrecMap.find(lv2.pre), chrecMap.end());
1660 EXPECT_NE(chrecMap.find(lv3.pre), chrecMap.end());
1661 EXPECT_NE(chrecMap.find(gep), chrecMap.end());
1662
1663 // lv1 is a simple induction variable with the recurrence {0,+,1}
1664 auto lv1TestChrec = SCEVChainRecurrence(*theta, *lv1.pre);
1665 lv1TestChrec.AddOperand(SCEVConstant::Create(0));
1666 lv1TestChrec.AddOperand(SCEVConstant::Create(1));
1667 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv1TestChrec, *chrecMap.at(lv1.pre)));
1668
1669 // lv2 is reliant on the result from a LOAD operation, and should therefore be {1,+,Unknown}
1670 auto lv2TestChrec = SCEVChainRecurrence(*theta, *lv2.pre);
1671 lv2TestChrec.AddOperand(SCEVConstant::Create(1));
1672 lv2TestChrec.AddOperand(SCEVUnknown::Create());
1673 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv2TestChrec, *chrecMap.at(lv2.pre)));
1674
1675 // lv3 (base pointer in GEP) is unchanged, it's recurrence should be {Init(a3)}
1676 auto lv3TestChrec = SCEVChainRecurrence(*theta, *lv3.pre);
1677 lv3TestChrec.AddOperand(SCEVInit::Create(*lv3.pre));
1678 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(lv3TestChrec, *chrecMap.at(lv3.pre)));
1679
1680 // The GEP should have the following SCEV: (PH(a3) + (PH(a1) * 4))
1681 // Replacing the placeholders gives us ({Init(a3)} + ({0,+,1} * 4))
1682 // Folding constants together gives us ({Init(a3)} + {0,+,4}) = {Init(a3),+,4} which is the
1683 // resulting recurrence
1684 auto gepTestChrec = SCEVChainRecurrence(*theta, *gep);
1685 gepTestChrec.AddOperand(SCEVInit::Create(*lv3.pre));
1686 gepTestChrec.AddOperand(SCEVConstant::Create(4));
1687 EXPECT_TRUE(ScalarEvolution::StructurallyEqual(gepTestChrec, *chrecMap.at(gep)));
1688}
1689
1690TEST(ScalarEvolutionTests, ComputeTripCountForSLTComparisonWithAffineRecurrence)
1691{
1692 using namespace jlm::llvm;
1693
1694 // Arrange
1695 const auto intType = jlm::rvsdg::BitType::Create(32);
1696
1697 LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
1698 const auto & graph = rvsdgModule.Rvsdg();
1699
1700 const auto & c0 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 0);
1701
1702 const auto theta = jlm::rvsdg::ThetaNode::create(&graph.GetRootRegion());
1703 const auto lv1 = theta->AddLoopVar(c0.output(0));
1704
1705 const auto & c1 = IntegerConstantOperation::Create(*theta->subregion(), 32, 1);
1706 auto & addNode = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv1.pre, c1.output(0) }, 32);
1707 const auto result = addNode.output(0);
1708
1709 const auto & c5 = IntegerConstantOperation::Create(*theta->subregion(), 32, 5);
1710 auto & sltNode = jlm::rvsdg::CreateOpNode<IntegerSltOperation>({ result, c5.output(0) }, 32);
1711 const auto matchResult =
1712 jlm::rvsdg::MatchOperation::Create(*sltNode.output(0), { { 1, 1 } }, 0, 2);
1713
1714 theta->set_predicate(matchResult);
1715 lv1.post->divert_to(result);
1716
1717 jlm::rvsdg::view(graph, stdout);
1718
1719 // Act
1720 const auto & tripCountMap = RunScalarEvolution(rvsdgModule).second;
1721
1722 // Assert
1723 EXPECT_NE(tripCountMap.find(theta), tripCountMap.end());
1724 const auto tripCount = tripCountMap.at(theta);
1725 EXPECT_TRUE(tripCount == 5);
1726}
1727
1728TEST(ScalarEvolutionTests, ComputeTripCountForSLEComparisonWithAffineRecurrence)
1729{
1730 using namespace jlm::llvm;
1731
1732 // Arrange
1733 const auto intType = jlm::rvsdg::BitType::Create(32);
1734
1735 LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
1736 const auto & graph = rvsdgModule.Rvsdg();
1737
1738 const auto & c0 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 0);
1739
1740 const auto theta = jlm::rvsdg::ThetaNode::create(&graph.GetRootRegion());
1741 const auto lv1 = theta->AddLoopVar(c0.output(0));
1742
1743 const auto & c1 = IntegerConstantOperation::Create(*theta->subregion(), 32, 1);
1744 auto & addNode = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv1.pre, c1.output(0) }, 32);
1745 const auto result = addNode.output(0);
1746
1747 const auto & c5 = IntegerConstantOperation::Create(*theta->subregion(), 32, 5);
1748 auto & sleNode = jlm::rvsdg::CreateOpNode<IntegerSleOperation>({ result, c5.output(0) }, 32);
1749 const auto matchResult =
1750 jlm::rvsdg::MatchOperation::Create(*sleNode.output(0), { { 1, 1 } }, 0, 2);
1751
1752 theta->set_predicate(matchResult);
1753 lv1.post->divert_to(result);
1754
1755 jlm::rvsdg::view(graph, stdout);
1756
1757 // Act
1758 const auto & tripCountMap = RunScalarEvolution(rvsdgModule).second;
1759
1760 // Assert
1761 EXPECT_NE(tripCountMap.find(theta), tripCountMap.end());
1762 // For equals, we expect an extra iteration compared to strict lesser than
1763 const auto tripCount = tripCountMap.at(theta);
1764
1765 EXPECT_TRUE(tripCount == 6);
1766}
1767
1768TEST(ScalarEvolutionTests, ComputeTripCountForSGTComparisonWithAffineRecurrence)
1769{
1770 using namespace jlm::llvm;
1771
1772 // Arrange
1773 const auto intType = jlm::rvsdg::BitType::Create(32);
1774
1775 LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
1776 const auto & graph = rvsdgModule.Rvsdg();
1777
1778 const auto & c5 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 5);
1779
1780 const auto theta = jlm::rvsdg::ThetaNode::create(&graph.GetRootRegion());
1781 const auto lv1 = theta->AddLoopVar(c5.output(0));
1782
1783 const auto & c1 = IntegerConstantOperation::Create(*theta->subregion(), 32, 1);
1784 auto & subNode = jlm::rvsdg::CreateOpNode<IntegerSubOperation>({ lv1.pre, c1.output(0) }, 32);
1785 const auto result = subNode.output(0);
1786
1787 const auto & c0 = IntegerConstantOperation::Create(*theta->subregion(), 32, 0);
1788 auto & sgtNode = jlm::rvsdg::CreateOpNode<IntegerSgtOperation>({ result, c0.output(0) }, 32);
1789 const auto matchResult =
1790 jlm::rvsdg::MatchOperation::Create(*sgtNode.output(0), { { 1, 1 } }, 0, 2);
1791
1792 theta->set_predicate(matchResult);
1793 lv1.post->divert_to(result);
1794
1795 jlm::rvsdg::view(graph, stdout);
1796
1797 // Act
1798 const auto & tripCountMap = RunScalarEvolution(rvsdgModule).second;
1799
1800 // Assert
1801 EXPECT_NE(tripCountMap.find(theta), tripCountMap.end());
1802 const auto tripCount = tripCountMap.at(theta);
1803 EXPECT_TRUE(tripCount == 5);
1804}
1805
1806TEST(ScalarEvolutionTests, ComputeTripCountForSGEComparisonWithAffineRecurrence)
1807{
1808 using namespace jlm::llvm;
1809
1810 // Arrange
1811 const auto intType = jlm::rvsdg::BitType::Create(32);
1812
1813 LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
1814 const auto & graph = rvsdgModule.Rvsdg();
1815
1816 const auto & c5 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 5);
1817
1818 const auto theta = jlm::rvsdg::ThetaNode::create(&graph.GetRootRegion());
1819 const auto lv1 = theta->AddLoopVar(c5.output(0));
1820
1821 const auto & c1 = IntegerConstantOperation::Create(*theta->subregion(), 32, 1);
1822 auto & subNode = jlm::rvsdg::CreateOpNode<IntegerSubOperation>({ lv1.pre, c1.output(0) }, 32);
1823 const auto result = subNode.output(0);
1824
1825 const auto & c0 = IntegerConstantOperation::Create(*theta->subregion(), 32, 0);
1826 auto & sgeNode = jlm::rvsdg::CreateOpNode<IntegerSgeOperation>({ result, c0.output(0) }, 32);
1827 const auto matchResult =
1828 jlm::rvsdg::MatchOperation::Create(*sgeNode.output(0), { { 1, 1 } }, 0, 2);
1829
1830 theta->set_predicate(matchResult);
1831 lv1.post->divert_to(result);
1832
1833 jlm::rvsdg::view(graph, stdout);
1834
1835 // Act
1836 const auto & tripCountMap = RunScalarEvolution(rvsdgModule).second;
1837
1838 // Assert
1839 EXPECT_NE(tripCountMap.find(theta), tripCountMap.end());
1840 // For equals, we expect an extra iteration compared to strict greater than
1841 const auto tripCount = tripCountMap.at(theta);
1842 EXPECT_TRUE(tripCount == 6);
1843}
1844
1845TEST(ScalarEvolutionTests, ComputeTripCountForNEComparisonWithAffineRecurrence)
1846{
1847 using namespace jlm::llvm;
1848
1849 // Arrange
1850 const auto intType = jlm::rvsdg::BitType::Create(32);
1851
1852 LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
1853 const auto & graph = rvsdgModule.Rvsdg();
1854
1855 const auto & c0 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 0);
1856
1857 const auto theta = jlm::rvsdg::ThetaNode::create(&graph.GetRootRegion());
1858 const auto lv1 = theta->AddLoopVar(c0.output(0));
1859
1860 const auto & c1 = IntegerConstantOperation::Create(*theta->subregion(), 32, 1);
1861 auto & addNode = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv1.pre, c1.output(0) }, 32);
1862 const auto result = addNode.output(0);
1863
1864 const auto & c5 = IntegerConstantOperation::Create(*theta->subregion(), 32, 5);
1865 auto & neNode = jlm::rvsdg::CreateOpNode<IntegerNeOperation>({ result, c5.output(0) }, 32);
1866 const auto matchResult =
1867 jlm::rvsdg::MatchOperation::Create(*neNode.output(0), { { 1, 1 } }, 0, 2);
1868
1869 theta->set_predicate(matchResult);
1870 lv1.post->divert_to(result);
1871
1872 jlm::rvsdg::view(graph, stdout);
1873
1874 // Act
1875 const auto & tripCountMap = RunScalarEvolution(rvsdgModule).second;
1876
1877 // Assert
1878 EXPECT_NE(tripCountMap.find(theta), tripCountMap.end());
1879 const auto tripCount = tripCountMap.at(theta);
1880 EXPECT_TRUE(tripCount == 5);
1881}
1882
1883TEST(ScalarEvolutionTests, ComputeTripCountForEQComparisonWithAffineRecurrence)
1884{
1885 using namespace jlm::llvm;
1886
1887 // Arrange
1888 const auto intType = jlm::rvsdg::BitType::Create(32);
1889
1890 LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
1891 const auto & graph = rvsdgModule.Rvsdg();
1892
1893 const auto & c0 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 0);
1894
1895 const auto theta = jlm::rvsdg::ThetaNode::create(&graph.GetRootRegion());
1896 const auto lv1 = theta->AddLoopVar(c0.output(0));
1897
1898 const auto & c1_1 = IntegerConstantOperation::Create(*theta->subregion(), 32, 1);
1899 auto & addNode = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv1.pre, c1_1.output(0) }, 32);
1900 const auto result = addNode.output(0);
1901
1902 const auto & c1_2 = IntegerConstantOperation::Create(*theta->subregion(), 32, 1);
1903 auto & eqNode = jlm::rvsdg::CreateOpNode<IntegerEqOperation>({ result, c1_2.output(0) }, 32);
1904 const auto matchResult =
1905 jlm::rvsdg::MatchOperation::Create(*eqNode.output(0), { { 1, 1 } }, 0, 2);
1906
1907 theta->set_predicate(matchResult);
1908 lv1.post->divert_to(result);
1909
1910 jlm::rvsdg::view(graph, stdout);
1911
1912 // Act
1913 const auto & tripCountMap = RunScalarEvolution(rvsdgModule).second;
1914
1915 // Assert
1916 EXPECT_NE(tripCountMap.find(theta), tripCountMap.end());
1917 const auto tripCount = tripCountMap.at(theta);
1918 EXPECT_TRUE(tripCount == 2);
1919}
1920
1921TEST(ScalarEvolutionTests, ComputeTripCountForInfiniteSLTComparisonWithAffineRecurrence)
1922{
1923 using namespace jlm::llvm;
1924
1925 // Arrange
1926 const auto intType = jlm::rvsdg::BitType::Create(32);
1927
1928 LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
1929 const auto & graph = rvsdgModule.Rvsdg();
1930
1931 const auto & c0 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 0);
1932
1933 const auto theta = jlm::rvsdg::ThetaNode::create(&graph.GetRootRegion());
1934 const auto lv1 = theta->AddLoopVar(c0.output(0));
1935
1936 const auto & c1 = IntegerConstantOperation::Create(*theta->subregion(), 32, 1);
1937 auto & subNode = jlm::rvsdg::CreateOpNode<IntegerSubOperation>({ lv1.pre, c1.output(0) }, 32);
1938 const auto result = subNode.output(0);
1939
1940 const auto & c5 = IntegerConstantOperation::Create(*theta->subregion(), 32, 5);
1941 auto & sltNode = jlm::rvsdg::CreateOpNode<IntegerSltOperation>({ result, c5.output(0) }, 32);
1942 const auto matchResult =
1943 jlm::rvsdg::MatchOperation::Create(*sltNode.output(0), { { 1, 1 } }, 0, 2);
1944
1945 theta->set_predicate(matchResult);
1946 lv1.post->divert_to(result);
1947
1948 jlm::rvsdg::view(graph, stdout);
1949
1950 // Act
1951 const auto & tripCountMap = RunScalarEvolution(rvsdgModule).second;
1952
1953 // Assert
1954 // Negative increment. Since the start value of lv1 (0) is already less than the comparison value
1955 // (5), we get an infinite loop.
1956 EXPECT_EQ(tripCountMap.find(theta), tripCountMap.end());
1957}
1958
1959TEST(ScalarEvolutionTests, ComputeTripCountForInfiniteSGTComparisonWithAffineRecurrence)
1960{
1961 using namespace jlm::llvm;
1962
1963 // Arrange
1964 const auto intType = jlm::rvsdg::BitType::Create(32);
1965
1966 LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
1967 const auto & graph = rvsdgModule.Rvsdg();
1968
1969 const auto & c5 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 5);
1970
1971 const auto theta = jlm::rvsdg::ThetaNode::create(&graph.GetRootRegion());
1972 const auto lv1 = theta->AddLoopVar(c5.output(0));
1973
1974 const auto & c1 = IntegerConstantOperation::Create(*theta->subregion(), 32, 1);
1975 auto & addNode = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv1.pre, c1.output(0) }, 32);
1976 const auto result = addNode.output(0);
1977
1978 const auto & c0 = IntegerConstantOperation::Create(*theta->subregion(), 32, 0);
1979 auto & sgeNode = jlm::rvsdg::CreateOpNode<IntegerSgeOperation>({ result, c0.output(0) }, 32);
1980 const auto matchResult =
1981 jlm::rvsdg::MatchOperation::Create(*sgeNode.output(0), { { 1, 1 } }, 0, 2);
1982
1983 theta->set_predicate(matchResult);
1984 lv1.post->divert_to(result);
1985
1986 jlm::rvsdg::view(graph, stdout);
1987
1988 // Act
1989 const auto & tripCountMap = RunScalarEvolution(rvsdgModule).second;
1990
1991 // Assert
1992 // Positive increment. Since the start value of lv1 (5) is already greater than the comparison
1993 // value (0), we get an infinite loop.
1994 EXPECT_EQ(tripCountMap.find(theta), tripCountMap.end());
1995}
1996
1997TEST(ScalarEvolutionTests, ComputeTripCountForInfiniteNEComparisonWithAffineRecurrence)
1998{
1999 using namespace jlm::llvm;
2000
2001 // Arrange
2002 const auto intType = jlm::rvsdg::BitType::Create(32);
2003
2004 LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
2005 const auto & graph = rvsdgModule.Rvsdg();
2006
2007 const auto & c0 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 0);
2008
2009 const auto theta = jlm::rvsdg::ThetaNode::create(&graph.GetRootRegion());
2010 const auto lv1 = theta->AddLoopVar(c0.output(0));
2011
2012 const auto & c2 = IntegerConstantOperation::Create(*theta->subregion(), 32, 2);
2013 auto & addNode = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv1.pre, c2.output(0) }, 32);
2014 const auto result = addNode.output(0);
2015
2016 const auto & c5 = IntegerConstantOperation::Create(*theta->subregion(), 32, 5);
2017 auto & neNode = jlm::rvsdg::CreateOpNode<IntegerNeOperation>({ result, c5.output(0) }, 32);
2018 const auto matchResult =
2019 jlm::rvsdg::MatchOperation::Create(*neNode.output(0), { { 1, 1 } }, 0, 2);
2020
2021 theta->set_predicate(matchResult);
2022 lv1.post->divert_to(result);
2023
2024 jlm::rvsdg::view(graph, stdout);
2025
2026 // Act
2027 const auto & tripCountMap = RunScalarEvolution(rvsdgModule).second;
2028
2029 // Assert
2030 // Start value of 0, increment by 2. This means that lv1 will never have the value of 5, which
2031 // is the value in the "not equals" comparison. Therefore, we get an infinite loop.
2032 EXPECT_EQ(tripCountMap.find(theta), tripCountMap.end());
2033}
2034
2035TEST(ScalarEvolutionTests, ComputeTripCountForSimpleQuadraticRecurrence)
2036{
2037 using namespace jlm::llvm;
2038
2039 // Arrange
2040 const auto intType = jlm::rvsdg::BitType::Create(32);
2041
2042 LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
2043 const auto & graph = rvsdgModule.Rvsdg();
2044
2045 const auto & c0 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 0);
2046 const auto & c1_1 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 1);
2047
2048 const auto theta = jlm::rvsdg::ThetaNode::create(&graph.GetRootRegion());
2049 const auto lv1 = theta->AddLoopVar(c0.output(0));
2050 const auto lv2 = theta->AddLoopVar(c1_1.output(0));
2051
2052 const auto & c1_2 = IntegerConstantOperation::Create(*theta->subregion(), 32, 1);
2053 auto & addNode = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv1.pre, c1_2.output(0) }, 32);
2054 const auto res1 = addNode.output(0);
2055
2056 auto & addNode2 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv2.pre, res1 }, 32);
2057 const auto res2 = addNode2.output(0);
2058
2059 const auto & c10 = IntegerConstantOperation::Create(*theta->subregion(), 32, 10);
2060 auto & sltNode = jlm::rvsdg::CreateOpNode<IntegerSltOperation>({ res2, c10.output(0) }, 32);
2061 const auto matchResult =
2062 jlm::rvsdg::MatchOperation::Create(*sltNode.output(0), { { 1, 1 } }, 0, 2);
2063
2064 theta->set_predicate(matchResult);
2065 lv1.post->divert_to(res1);
2066 lv2.post->divert_to(res2);
2067
2068 jlm::rvsdg::view(graph, stdout);
2069
2070 // Act
2071 const auto & tripCountMap = RunScalarEvolution(rvsdgModule).second;
2072
2073 // Assert
2074 EXPECT_NE(tripCountMap.find(theta), tripCountMap.end());
2075 const auto tripCount = tripCountMap.at(theta);
2076 EXPECT_TRUE(tripCount == 4);
2077}
2078
2079TEST(ScalarEvolutionTests, TestTripCountCouldNotCompute)
2080{
2081 using namespace jlm::llvm;
2082
2083 // Arrange
2084 const auto intType = jlm::rvsdg::BitType::Create(32);
2085
2086 LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
2087 const auto & graph = rvsdgModule.Rvsdg();
2088
2089 const auto & c2 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 2);
2090 const auto & c3 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 3);
2091 const auto & c4 = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 4);
2092
2093 const auto theta = jlm::rvsdg::ThetaNode::create(&graph.GetRootRegion());
2094 const auto lv1 = theta->AddLoopVar(c2.output(0));
2095 const auto lv2 = theta->AddLoopVar(c3.output(0));
2096 const auto lv3 = theta->AddLoopVar(c4.output(0));
2097
2098 const auto & c1 = IntegerConstantOperation::Create(*theta->subregion(), 32, 1);
2099 auto & addNode1 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv1.pre, c1.output(0) }, 32);
2100 const auto res1 = addNode1.output(0);
2101
2102 auto & addNode2 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv2.pre, res1 }, 32);
2103 const auto res2 = addNode2.output(0);
2104
2105 auto & addNode3 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv3.pre, res2 }, 32);
2106 const auto res3 = addNode3.output(0);
2107
2108 const auto & c50 = IntegerConstantOperation::Create(*theta->subregion(), 32, 50);
2109 auto & sltNode = jlm::rvsdg::CreateOpNode<IntegerSltOperation>({ res3, c50.output(0) }, 32);
2110 const auto matchResult =
2111 jlm::rvsdg::MatchOperation::Create(*sltNode.output(0), { { 1, 1 } }, 0, 2);
2112
2113 theta->set_predicate(matchResult);
2114 lv1.post->divert_to(res1);
2115 lv2.post->divert_to(res2);
2116 lv3.post->divert_to(res3);
2117
2118 jlm::rvsdg::view(graph, stdout);
2119
2120 // Act
2121 const auto & tripCountMap = RunScalarEvolution(rvsdgModule).second;
2122
2123 // Assert
2124 // The recurrence is a third degree polynomial ({a,+,b,+,c,+,d}). For these cases, we return could
2125 // not compute, as there is no implementation for solving recurrences with an order greater
2126 // than 2.
2127 EXPECT_EQ(tripCountMap.find(theta), tripCountMap.end());
2128}
static jlm::util::StatisticsCollector statisticsCollector
std::int64_t c1
std::int64_t c2
TEST(ScalarEvolutionTests, NonEvolvingVariable)
static std::pair< std::unordered_map< const jlm::rvsdg::Output *, std::unique_ptr< jlm::llvm::SCEVChainRecurrence > >, std::unordered_map< const jlm::rvsdg::ThetaNode *, size_t > > RunScalarEvolution(jlm::rvsdg::RvsdgModule &rvsdgModule)
std::unordered_map< const rvsdg::Output *, std::unique_ptr< SCEVChainRecurrence > > GetChrecMap() const
void Run(rvsdg::RvsdgModule &rvsdgModule, util::StatisticsCollector &statisticsCollector) override
Perform RVSDG transformation.
std::unordered_map< const rvsdg::ThetaNode *, size_t > GetTripCountMap() const noexcept
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
static std::shared_ptr< const FunctionType > Create(std::vector< std::shared_ptr< const jlm::rvsdg::Type > > argumentTypes, std::vector< std::shared_ptr< const jlm::rvsdg::Type > > resultTypes)
static GraphImport & Create(Graph &graph, std::shared_ptr< const rvsdg::Type > type, std::string name)
Definition graph.cpp:36
Region & GetRootRegion() const noexcept
Definition graph.hpp:99
static LambdaNode * Create(rvsdg::Region &parent, std::unique_ptr< LambdaOperation > operation)
Definition lambda.cpp:141
static Output * Create(Output &predicate, const std::unordered_map< uint64_t, uint64_t > &mapping, const uint64_t defaultAlternative, const size_t numAlternatives)
Definition control.hpp:236
Graph & Rvsdg() noexcept
static ThetaNode * create(rvsdg::Region *parent)
Definition theta.hpp:73
Global memory state passed between functions.
std::string view(const rvsdg::Region *region)
Definition view.cpp:142
NodeType * TryGetOwnerNode(const rvsdg::Input &input) noexcept
Checks if this is an input to a node of specified type.
Definition node.hpp:872