Jlm
Loading...
Searching...
No Matches
InvariantValueRedirectionTests.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2017 Nico Reißmann <nico.reissmann@gmail.com>
3 * See COPYING for terms of redistribution.
4 */
5
6#include <gtest/gtest.h>
7
20#include <jlm/rvsdg/control.hpp>
21#include <jlm/rvsdg/gamma.hpp>
24#include <jlm/rvsdg/theta.hpp>
25#include <jlm/rvsdg/view.hpp>
27
28namespace jlm::llvm
29{
30
31static void
33{
34 jlm::rvsdg::view(rvsdgModule.Rvsdg(), stdout);
35
38 jlm::llvm::InvariantValueRedirection invariantValueRedirection(std::move(configuration));
39 invariantValueRedirection.Run(rvsdgModule, statisticsCollector);
40
41 jlm::rvsdg::view(rvsdgModule.Rvsdg(), stdout);
42}
43
44TEST(InvariantValueRedirectionTests, TestGamma)
45{
46 using namespace jlm::llvm;
47
48 // Arrange
50 auto controlType = jlm::rvsdg::ControlType::Create(2);
51 auto functionType = jlm::rvsdg::FunctionType::Create(
52 { controlType, valueType, valueType },
53 { valueType, valueType });
54
55 auto rvsdgModule = LlvmRvsdgModule::Create(jlm::util::FilePath(""), "", "");
56 auto & rvsdg = rvsdgModule->Rvsdg();
57
58 auto lambdaNode = jlm::rvsdg::LambdaNode::Create(
59 rvsdg.GetRootRegion(),
61
62 auto c = lambdaNode->GetFunctionArguments()[0];
63 auto x = lambdaNode->GetFunctionArguments()[1];
64 auto y = lambdaNode->GetFunctionArguments()[2];
65
66 auto gammaNode1 = jlm::rvsdg::GammaNode::create(c, 2);
67 auto gammaInput1 = gammaNode1->AddEntryVar(c);
68 auto gammaInput2 = gammaNode1->AddEntryVar(x);
69 auto gammaInput3 = gammaNode1->AddEntryVar(y);
70
71 auto gammaNode2 = jlm::rvsdg::GammaNode::create(gammaInput1.branchArgument[0], 2);
72 auto gammaInput4 = gammaNode2->AddEntryVar(gammaInput2.branchArgument[0]);
73 auto gammaInput5 = gammaNode2->AddEntryVar(gammaInput3.branchArgument[0]);
74 gammaNode2->AddExitVar(gammaInput4.branchArgument);
75 gammaNode2->AddExitVar(gammaInput5.branchArgument);
76
77 gammaNode1->AddExitVar({ gammaNode2->output(0), gammaInput2.branchArgument[1] });
78 gammaNode1->AddExitVar({ gammaNode2->output(1), gammaInput3.branchArgument[1] });
79
80 auto lambdaOutput = lambdaNode->finalize({ gammaNode1->output(0), gammaNode1->output(1) });
81
82 jlm::rvsdg::GraphExport::Create(*lambdaOutput, "test");
83
84 // Act
85 RunInvariantValueRedirection(*rvsdgModule);
86
87 // Assert
88 EXPECT_EQ(lambdaNode->GetFunctionResults()[0]->origin(), x);
89 EXPECT_EQ(lambdaNode->GetFunctionResults()[1]->origin(), y);
90}
91
92TEST(InvariantValueRedirectionTests, testGammaControlConstantRedirection_Success)
93{
94 using namespace jlm::rvsdg;
95
96 // Arrange
97 auto valueType = TestType::createValueType();
98 auto controlType = ControlType::Create(2);
99 auto functionType = FunctionType::Create({}, { controlType });
100
101 auto rvsdgModule = LlvmRvsdgModule::Create(util::FilePath(""), "", "");
102 auto & rvsdg = rvsdgModule->Rvsdg();
103
104 auto lambdaNode = LambdaNode::Create(
105 rvsdg.GetRootRegion(),
107
108 auto outerPredicate = TestOperation::createNode(lambdaNode->subregion(), {}, { controlType });
109 auto outerGammaNode = GammaNode::create(outerPredicate->output(0), 2);
110
111 // outerGammaNode - subregion 0
112 auto innerPredicate0 =
113 TestOperation::createNode(outerGammaNode->subregion(0), {}, { controlType });
114 auto innerGammaNode0 = GammaNode::create(innerPredicate0->output(0), 2);
115
116 // innerGammaNode0 - subregion 0
117 auto & ctlConstant00 = ControlConstantOperation::createFalse(*innerGammaNode0->subregion(0));
118
119 // innerGammaNode0 - subregion 1
120 auto & ctlConstant01 = *UndefValueOperation::Create(*innerGammaNode0->subregion(1), controlType);
121
122 // innerGammaNode0 - finalize
123 auto innerGammeNode0ExitVar = innerGammaNode0->AddExitVar({ &ctlConstant00, &ctlConstant01 });
124
125 // outerGammaNode - subregion 1
126 auto innerPredicate1 =
127 TestOperation::createNode(outerGammaNode->subregion(1), {}, { controlType });
128 auto innerGammaNode1 = GammaNode::create(innerPredicate1->output(0), 2);
129
130 // innerGammaNode1 - subregion 0
131 auto & ctlConstant10 = ControlConstantOperation::createFalse(*innerGammaNode1->subregion(0));
132
133 // innerGammaNode1 - subregion 1
134 auto & ctlConstant11 = *UndefValueOperation::Create(*innerGammaNode1->subregion(1), controlType);
135
136 // innerGammaNode1 - finalize
137 auto innerGammeNode1ExitVar = innerGammaNode1->AddExitVar({ &ctlConstant10, &ctlConstant11 });
138
139 // outerGammaNode - finalize
140 auto outerGammaNodeExitVar =
141 outerGammaNode->AddExitVar({ innerGammeNode0ExitVar.output, innerGammeNode1ExitVar.output });
142
143 auto lambdaOutput = lambdaNode->finalize({ outerGammaNodeExitVar.output });
144
145 GraphExport::Create(*lambdaOutput, "test");
146
147 // Act
148 RunInvariantValueRedirection(*rvsdgModule);
149
150 // Assert
151 // We expect that the transformation could be applied and consequently the gamma node was pruned
152 EXPECT_FALSE(Region::containsNodeType<GammaNode>(*lambdaNode->subregion(), false));
153
154 // We expect that the origin of the lambda result should be connected to a
155 // ControlConstantOperation node
156 auto [ctlConstantNode, ctlConstantOp] = TryGetSimpleNodeAndOptionalOp<ControlConstantOperation>(
157 *lambdaNode->GetFunctionResults()[0]->origin());
158 EXPECT_NE(ctlConstantOp, nullptr);
159 EXPECT_EQ(ctlConstantOp->value().nalternatives(), 2);
160 EXPECT_EQ(ctlConstantOp->value().alternative(), 0);
161}
162
163TEST(InvariantValueRedirectionTests, testGammaControlConstantRedirection_Failure)
164{
165 using namespace jlm::rvsdg;
166
167 // Arrange
168 auto valueType = TestType::createValueType();
169 auto controlType = ControlType::Create(2);
170 auto functionType = FunctionType::Create({}, { controlType });
171
172 auto rvsdgModule = LlvmRvsdgModule::Create(util::FilePath(""), "", "");
173 auto & rvsdg = rvsdgModule->Rvsdg();
174
175 auto lambdaNode = LambdaNode::Create(
176 rvsdg.GetRootRegion(),
178
179 auto outerPredicate = TestOperation::createNode(lambdaNode->subregion(), {}, { controlType });
180 auto outerGammaNode = GammaNode::create(outerPredicate->output(0), 2);
181
182 // outerGammaNode - subregion 0
183 auto innerPredicate0 =
184 TestOperation::createNode(outerGammaNode->subregion(0), {}, { controlType });
185 auto innerGammaNode0 = GammaNode::create(innerPredicate0->output(0), 2);
186
187 // innerGammaNode0 - subregion 0
188 auto & ctlConstant00 = ControlConstantOperation::createTrue(*innerGammaNode0->subregion(0));
189
190 // innerGammaNode0 - subregion 1
191 auto & ctlConstant01 = *UndefValueOperation::Create(*innerGammaNode0->subregion(1), controlType);
192
193 // innerGammaNode0 - finalize
194 auto innerGammeNode0ExitVar = innerGammaNode0->AddExitVar({ &ctlConstant00, &ctlConstant01 });
195
196 // outerGammaNode - subregion 1
197 auto innerPredicate1 =
198 TestOperation::createNode(outerGammaNode->subregion(1), {}, { controlType });
199 auto innerGammaNode1 = GammaNode::create(innerPredicate1->output(0), 2);
200
201 // innerGammaNode1 - subregion 0
202 auto & ctlConstant10 = ControlConstantOperation::createFalse(*innerGammaNode1->subregion(0));
203
204 // innerGammaNode1 - subregion 1
205 auto & ctlConstant11 = *UndefValueOperation::Create(*innerGammaNode1->subregion(1), controlType);
206
207 // innerGammaNode1 - finalize
208 auto innerGammeNode1ExitVar = innerGammaNode1->AddExitVar({ &ctlConstant10, &ctlConstant11 });
209
210 // outerGammaNode - finalize
211 auto outerGammaNodeExitVar =
212 outerGammaNode->AddExitVar({ innerGammeNode0ExitVar.output, innerGammeNode1ExitVar.output });
213
214 auto lambdaOutput = lambdaNode->finalize({ outerGammaNodeExitVar.output });
215
216 GraphExport::Create(*lambdaOutput, "test");
217
218 // Act
219 RunInvariantValueRedirection(*rvsdgModule);
220
221 // Assert
222
223 // We expect that the transformation could not be applied and consequently the gamma node is still
224 // existent
225 EXPECT_TRUE(Region::containsNodeType<GammaNode>(*lambdaNode->subregion(), false));
226
227 // The origin of the lambda result should not have been diverted
228 EXPECT_EQ(lambdaNode->GetFunctionResults()[0]->origin(), outerGammaNodeExitVar.output);
229}
230
231TEST(InvariantValueRedirectionTests, testGammaIntegerConstantRedirection_Success)
232{
233 using namespace jlm::rvsdg;
234
235 // Arrange
236 auto i32Type = BitType::Create(32);
237 auto valueType = TestType::createValueType();
238 auto controlType = ControlType::Create(2);
239 auto functionType = FunctionType::Create({}, { i32Type });
240
241 auto rvsdgModule = LlvmRvsdgModule::Create(util::FilePath(""), "", "");
242 auto & rvsdg = rvsdgModule->Rvsdg();
243
244 auto lambdaNode = LambdaNode::Create(
245 rvsdg.GetRootRegion(),
247
248 auto outerPredicate = TestOperation::createNode(lambdaNode->subregion(), {}, { controlType });
249 auto outerGammaNode = GammaNode::create(outerPredicate->output(0), 2);
250
251 // outerGammaNode - subregion 0
252 auto innerPredicate0 =
253 TestOperation::createNode(outerGammaNode->subregion(0), {}, { controlType });
254 auto innerGammaNode0 = GammaNode::create(innerPredicate0->output(0), 2);
255
256 // innerGammaNode0 - subregion 0
257 auto & intConstant00 =
258 *IntegerConstantOperation::Create(*innerGammaNode0->subregion(0), 32, 0).output(0);
259
260 // innerGammaNode0 - subregion 1
261 auto & intConstant01 = *UndefValueOperation::Create(*innerGammaNode0->subregion(1), i32Type);
262
263 // innerGammaNode0 - finalize
264 auto innerGammeNode0ExitVar = innerGammaNode0->AddExitVar({ &intConstant00, &intConstant01 });
265
266 // outerGammaNode - subregion 1
267 auto innerPredicate1 =
268 TestOperation::createNode(outerGammaNode->subregion(1), {}, { controlType });
269 auto innerGammaNode1 = GammaNode::create(innerPredicate1->output(0), 2);
270
271 // innerGammaNode1 - subregion 0
272 auto & intConstant10 =
273 *IntegerConstantOperation::Create(*innerGammaNode1->subregion(0), 32, 0).output(0);
274
275 // innerGammaNode1 - subregion 1
276 auto & intConstant11 = *UndefValueOperation::Create(*innerGammaNode1->subregion(1), i32Type);
277
278 // innerGammaNode1 - finalize
279 auto innerGammeNode1ExitVar = innerGammaNode1->AddExitVar({ &intConstant10, &intConstant11 });
280
281 // outerGammaNode - finalize
282 auto outerGammaNodeExitVar =
283 outerGammaNode->AddExitVar({ innerGammeNode0ExitVar.output, innerGammeNode1ExitVar.output });
284
285 auto lambdaOutput = lambdaNode->finalize({ outerGammaNodeExitVar.output });
286
287 GraphExport::Create(*lambdaOutput, "test");
288
289 // Act
290 RunInvariantValueRedirection(*rvsdgModule);
291
292 // Assert
293 // We expect that the transformation could be applied and consequently the gamma node was pruned
294 EXPECT_FALSE(Region::containsNodeType<GammaNode>(*lambdaNode->subregion(), false));
295
296 // We expect that the origin of the lambda result should be connected to a
297 // IntegerConstantOperation node
298 auto [intConstantNode, intConstantOp] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(
299 *lambdaNode->GetFunctionResults()[0]->origin());
300 EXPECT_NE(intConstantOp, nullptr);
301 EXPECT_EQ(intConstantOp->Representation().nbits(), 32);
302 EXPECT_EQ(intConstantOp->Representation().to_uint(), 0);
303}
304
305TEST(InvariantValueRedirectionTests, testGammaIntegerConstantRedirection_Failure)
306{
307 using namespace jlm::rvsdg;
308
309 // Arrange
310 auto i32Type = BitType::Create(32);
311 auto valueType = TestType::createValueType();
312 auto controlType = ControlType::Create(2);
313 auto functionType = FunctionType::Create({}, { i32Type });
314
315 auto rvsdgModule = LlvmRvsdgModule::Create(util::FilePath(""), "", "");
316 auto & rvsdg = rvsdgModule->Rvsdg();
317
318 auto lambdaNode = LambdaNode::Create(
319 rvsdg.GetRootRegion(),
321
322 auto outerPredicate = TestOperation::createNode(lambdaNode->subregion(), {}, { controlType });
323 auto outerGammaNode = GammaNode::create(outerPredicate->output(0), 2);
324
325 // outerGammaNode - subregion 0
326 auto innerPredicate0 =
327 TestOperation::createNode(outerGammaNode->subregion(0), {}, { controlType });
328 auto innerGammaNode0 = GammaNode::create(innerPredicate0->output(0), 2);
329
330 // innerGammaNode0 - subregion 0
331 auto & intConstant00 =
332 *IntegerConstantOperation::Create(*innerGammaNode0->subregion(0), 32, 1).output(0);
333
334 // innerGammaNode0 - subregion 1
335 auto & intConstant01 = *UndefValueOperation::Create(*innerGammaNode0->subregion(1), i32Type);
336
337 // innerGammaNode0 - finalize
338 auto innerGammeNode0ExitVar = innerGammaNode0->AddExitVar({ &intConstant00, &intConstant01 });
339
340 // outerGammaNode - subregion 1
341 auto innerPredicate1 =
342 TestOperation::createNode(outerGammaNode->subregion(1), {}, { controlType });
343 auto innerGammaNode1 = GammaNode::create(innerPredicate1->output(0), 2);
344
345 // innerGammaNode1 - subregion 0
346 auto & intConstant10 =
347 *IntegerConstantOperation::Create(*innerGammaNode1->subregion(0), 32, 0).output(0);
348
349 // innerGammaNode1 - subregion 1
350 auto & intConstant11 = *UndefValueOperation::Create(*innerGammaNode1->subregion(1), i32Type);
351
352 // innerGammaNode1 - finalize
353 auto innerGammeNode1ExitVar = innerGammaNode1->AddExitVar({ &intConstant10, &intConstant11 });
354
355 // outerGammaNode - finalize
356 auto outerGammaNodeExitVar =
357 outerGammaNode->AddExitVar({ innerGammeNode0ExitVar.output, innerGammeNode1ExitVar.output });
358
359 auto lambdaOutput = lambdaNode->finalize({ outerGammaNodeExitVar.output });
360
361 GraphExport::Create(*lambdaOutput, "test");
362
363 // Act
364 RunInvariantValueRedirection(*rvsdgModule);
365
366 // Assert
367
368 // We expect that the transformation could not be applied and consequently the gamma node is still
369 // existent
370 EXPECT_TRUE(Region::containsNodeType<GammaNode>(*lambdaNode->subregion(), false));
371
372 // The origin of the lambda result should not have been diverted
373 EXPECT_EQ(lambdaNode->GetFunctionResults()[0]->origin(), outerGammaNodeExitVar.output);
374}
375
376TEST(InvariantValueRedirectionTests, TestTheta)
377{
378 // Arrange
379 using namespace jlm::llvm;
380
381 auto ioStateType = IOStateType::Create();
382 auto valueType = jlm::rvsdg::TestType::createValueType();
383 auto controlType = jlm::rvsdg::ControlType::Create(2);
384 auto functionType = jlm::rvsdg::FunctionType::Create(
385 { controlType, valueType, ioStateType },
386 { controlType, valueType, ioStateType });
387
388 auto rvsdgModule = LlvmRvsdgModule::Create(jlm::util::FilePath(""), "", "");
389 auto & rvsdg = rvsdgModule->Rvsdg();
390
391 auto lambdaNode = jlm::rvsdg::LambdaNode::Create(
392 rvsdg.GetRootRegion(),
394
395 auto c = lambdaNode->GetFunctionArguments()[0];
396 auto x = lambdaNode->GetFunctionArguments()[1];
397 auto l = lambdaNode->GetFunctionArguments()[2];
398
399 auto thetaNode1 = jlm::rvsdg::ThetaNode::create(lambdaNode->subregion());
400 auto thetaVar1 = thetaNode1->AddLoopVar(c);
401 auto thetaVar2 = thetaNode1->AddLoopVar(x);
402 auto thetaVar3 = thetaNode1->AddLoopVar(l);
403
404 auto thetaNode2 = jlm::rvsdg::ThetaNode::create(thetaNode1->subregion());
405 auto thetaVar4 = thetaNode2->AddLoopVar(thetaVar1.pre);
406 thetaNode2->AddLoopVar(thetaVar2.pre);
407 auto thetaVar5 = thetaNode2->AddLoopVar(thetaVar3.pre);
408 thetaNode2->set_predicate(thetaVar4.pre);
409
410 thetaVar3.post->divert_to(thetaVar5.output);
411 thetaNode1->set_predicate(thetaVar1.pre);
412
413 auto lambdaOutput =
414 lambdaNode->finalize({ thetaVar1.output, thetaVar2.output, thetaVar3.output });
415
416 jlm::rvsdg::GraphExport::Create(*lambdaOutput, "test");
417
418 // Act
419 RunInvariantValueRedirection(*rvsdgModule);
420
421 // Assert
422 EXPECT_EQ(lambdaNode->GetFunctionResults()[0]->origin(), c);
423 EXPECT_EQ(lambdaNode->GetFunctionResults()[1]->origin(), x);
424 EXPECT_EQ(lambdaNode->GetFunctionResults()[2]->origin(), thetaVar3.output);
425}
426
427TEST(InvariantValueRedirectionTests, testThetaConstantRedirection)
428{
429 // Arrange
430 using namespace jlm::rvsdg;
431
432 auto i32Type = BitType::Create(32);
433 auto ctlType = ControlType::Create(2);
435 auto valueType = TestType::createValueType();
436 auto functionType = FunctionType::Create(
437 { i32Type, ctlType, fpType, valueType },
438 { i32Type, ctlType, fpType, valueType });
439
440 auto rvsdgModule = LlvmRvsdgModule::Create(jlm::util::FilePath(""), "", "");
441 auto & rvsdg = rvsdgModule->Rvsdg();
442
443 auto lambdaNode = LambdaNode::Create(
444 rvsdg.GetRootRegion(),
446 auto lambdaArguments = lambdaNode->GetFunctionArguments();
447
448 auto thetaNode = ThetaNode::create(lambdaNode->subregion());
449 auto thetaVar1 = thetaNode->AddLoopVar(lambdaArguments[0]);
450 auto thetaVar2 = thetaNode->AddLoopVar(lambdaArguments[1]);
451 auto thetaVar3 = thetaNode->AddLoopVar(lambdaArguments[2]);
452 auto thetaVar4 = thetaNode->AddLoopVar(lambdaArguments[3]);
453
454 auto & intConstant = IntegerConstantOperation::Create(*thetaNode->subregion(), 32, 1);
455 auto & ctlConstant = ControlConstantOperation::createFalse(*thetaNode->subregion());
456 auto & fpConstant =
457 ConstantFP::createNode(*thetaNode->subregion(), fpsize::dbl, ::llvm::APFloat(0.0));
458 auto undefConstant = UndefValueOperation::Create(*thetaNode->subregion(), valueType);
459
460 thetaVar1.post->divert_to(intConstant.output(0));
461 thetaVar2.post->divert_to(&ctlConstant);
462 thetaVar3.post->divert_to(fpConstant.output(0));
463 thetaVar4.post->divert_to(undefConstant);
464
465 auto lambdaOutput = lambdaNode->finalize(
466 { thetaVar1.output, thetaVar2.output, thetaVar3.output, thetaVar4.output });
467
468 GraphExport::Create(*lambdaOutput, "test");
469
470 // Act
471 RunInvariantValueRedirection(*rvsdgModule);
472
473 // Assert
474 {
475 auto [constantNode, constantOp] =
477 *lambdaNode->GetFunctionResults()[0]->origin());
478 EXPECT_NE(constantOp, nullptr);
479 EXPECT_EQ(constantOp->Representation().to_uint(), 1);
480 }
481
482 {
483 auto [constantNode, constantOp] =
485 *lambdaNode->GetFunctionResults()[1]->origin());
486 EXPECT_NE(constantOp, nullptr);
487 EXPECT_EQ(constantOp->value().nalternatives(), 2);
488 EXPECT_EQ(constantOp->value().alternative(), 0);
489 }
490
491 {
492 auto [constantNode, constantOp] = rvsdg::TryGetSimpleNodeAndOptionalOp<ConstantFP>(
493 *lambdaNode->GetFunctionResults()[2]->origin());
494 EXPECT_NE(constantOp, nullptr);
495 EXPECT_EQ(constantOp->constant().convertToDouble(), 0.0);
496 }
497
498 {
499 auto [constantNode, constantOp] = rvsdg::TryGetSimpleNodeAndOptionalOp<UndefValueOperation>(
500 *lambdaNode->GetFunctionResults()[3]->origin());
501 EXPECT_NE(constantOp, nullptr);
502 EXPECT_EQ(constantOp->GetType(), *valueType);
503 }
504}
505
506TEST(InvariantValueRedirectionTests, TestCall)
507{
508 // Arrange
509 using namespace jlm::llvm;
510
511 auto ioStateType = IOStateType::Create();
512 auto memoryStateType = MemoryStateType::Create();
513 auto valueType = jlm::rvsdg::TestType::createValueType();
514 auto controlType = jlm::rvsdg::ControlType::Create(2);
515 auto functionTypeTest1 = jlm::rvsdg::FunctionType::Create(
516 { controlType, valueType, valueType, ioStateType, memoryStateType },
517 { valueType, valueType, ioStateType, memoryStateType });
518
519 auto rvsdgModule = LlvmRvsdgModule::Create(jlm::util::FilePath(""), "", "");
520 auto & rvsdg = rvsdgModule->Rvsdg();
521
522 jlm::rvsdg::Output * lambdaOutputTest1 = nullptr;
523 {
524 auto lambdaNode = jlm::rvsdg::LambdaNode::Create(
525 rvsdg.GetRootRegion(),
526 LlvmLambdaOperation::Create(functionTypeTest1, "test1", Linkage::externalLinkage));
527
528 auto controlArgument = lambdaNode->GetFunctionArguments()[0];
529 auto xArgument = lambdaNode->GetFunctionArguments()[1];
530 auto yArgument = lambdaNode->GetFunctionArguments()[2];
531 auto ioStateArgument = lambdaNode->GetFunctionArguments()[3];
532 auto memoryStateArgument = lambdaNode->GetFunctionArguments()[4];
533
534 auto gammaNode = jlm::rvsdg::GammaNode::create(controlArgument, 2);
535 auto gammaInputX = gammaNode->AddEntryVar(xArgument);
536 auto gammaInputY = gammaNode->AddEntryVar(yArgument);
537 auto gammaInputIOState = gammaNode->AddEntryVar(ioStateArgument);
538 auto gammaInputMemoryState = gammaNode->AddEntryVar(memoryStateArgument);
539 auto gammaOutputX =
540 gammaNode->AddExitVar({ gammaInputY.branchArgument[0], gammaInputY.branchArgument[1] });
541 auto gammaOutputY =
542 gammaNode->AddExitVar({ gammaInputX.branchArgument[0], gammaInputX.branchArgument[1] });
543 auto gammaOutputIOState = gammaNode->AddExitVar(
544 { gammaInputIOState.branchArgument[0], gammaInputIOState.branchArgument[1] });
545 auto gammaOutputMemoryState = gammaNode->AddExitVar(
546 { gammaInputMemoryState.branchArgument[0], gammaInputMemoryState.branchArgument[1] });
547
548 lambdaOutputTest1 = lambdaNode->finalize({ gammaOutputX.output,
549 gammaOutputY.output,
550 gammaOutputIOState.output,
551 gammaOutputMemoryState.output });
552 }
553
554 jlm::rvsdg::Output * lambdaOutputTest2 = nullptr;
555 {
556 auto functionType = jlm::rvsdg::FunctionType::Create(
557 { valueType, valueType, ioStateType, memoryStateType },
558 { valueType, valueType, ioStateType, memoryStateType });
559
560 auto lambdaNode = jlm::rvsdg::LambdaNode::Create(
561 rvsdg.GetRootRegion(),
563 auto xArgument = lambdaNode->GetFunctionArguments()[0];
564 auto yArgument = lambdaNode->GetFunctionArguments()[1];
565 auto ioStateArgument = lambdaNode->GetFunctionArguments()[2];
566 auto memoryStateArgument = lambdaNode->GetFunctionArguments()[3];
567 auto lambdaArgumentTest1 = lambdaNode->AddContextVar(*lambdaOutputTest1).inner;
568
569 auto controlResult =
570 &jlm::rvsdg::ControlConstantOperation::create(*lambdaNode->subregion(), 2, 0);
571
572 auto & callNode = CallOperation::CreateNode(
573 lambdaArgumentTest1,
574 functionTypeTest1,
575 { controlResult, xArgument, yArgument, ioStateArgument, memoryStateArgument });
576
577 lambdaOutputTest2 = lambdaNode->finalize(outputs(&callNode));
578 jlm::rvsdg::GraphExport::Create(*lambdaOutputTest2, "test2");
579 }
580
581 // Act
582 RunInvariantValueRedirection(*rvsdgModule);
583
584 // Assert
585 auto & lambdaNode = jlm::rvsdg::AssertGetOwnerNode<jlm::rvsdg::LambdaNode>(*lambdaOutputTest2);
586 EXPECT_EQ(lambdaNode.GetFunctionResults().size(), 4u);
587 EXPECT_EQ(lambdaNode.GetFunctionResults()[0]->origin(), lambdaNode.GetFunctionArguments()[1]);
588 EXPECT_EQ(lambdaNode.GetFunctionResults()[1]->origin(), lambdaNode.GetFunctionArguments()[0]);
589 EXPECT_EQ(lambdaNode.GetFunctionResults()[2]->origin(), lambdaNode.GetFunctionArguments()[2]);
590 EXPECT_EQ(lambdaNode.GetFunctionResults()[3]->origin(), lambdaNode.GetFunctionArguments()[3]);
591}
592
593TEST(InvariantValueRedirectionTests, TestCallWithMemoryStateNodes)
594{
595 // Arrange
596 using namespace jlm::llvm;
597
629 // The memory node representing external has index 0, and is avoided in this test
631
632 auto ioStateType = IOStateType::Create();
633 auto memoryStateType = MemoryStateType::Create();
634 auto valueType = jlm::rvsdg::TestType::createValueType();
635 auto controlType = jlm::rvsdg::ControlType::Create(2);
636 auto functionTypeTest1 = jlm::rvsdg::FunctionType::Create(
637 { controlType, valueType, ioStateType, memoryStateType },
638 { valueType, ioStateType, memoryStateType });
639
640 auto rvsdgModule = LlvmRvsdgModule::Create(jlm::util::FilePath(""), "", "");
641 auto & rvsdg = rvsdgModule->Rvsdg();
642
643 jlm::rvsdg::Output * lambdaOutputTest1 = nullptr;
644 {
645 auto lambdaNode = jlm::rvsdg::LambdaNode::Create(
646 rvsdg.GetRootRegion(),
647 LlvmLambdaOperation::Create(functionTypeTest1, "test1", Linkage::externalLinkage));
648
649 auto controlArgument = lambdaNode->GetFunctionArguments()[0];
650 auto xArgument = lambdaNode->GetFunctionArguments()[1];
651 auto ioStateArgument = lambdaNode->GetFunctionArguments()[2];
652 auto memoryStateArgument = lambdaNode->GetFunctionArguments()[3];
653
654 auto & lambdaEntrySplitNode =
655 LambdaEntryMemoryStateSplitOperation::CreateNode(*memoryStateArgument, { 1, 2 });
656
657 auto gammaNode = jlm::rvsdg::GammaNode::create(controlArgument, 2);
658
659 auto gammaInputX = gammaNode->AddEntryVar(xArgument);
660 auto gammaInputMemoryState1 = gammaNode->AddEntryVar(lambdaEntrySplitNode.output(0));
661 auto gammaInputMemoryState2 = gammaNode->AddEntryVar(lambdaEntrySplitNode.output(1));
662
663 auto gammaOutputX = gammaNode->AddExitVar(gammaInputX.branchArgument);
664 auto gammaOutputMemoryState1 = gammaNode->AddExitVar(gammaInputMemoryState1.branchArgument);
665 auto gammaOutputMemoryState2 = gammaNode->AddExitVar(gammaInputMemoryState2.branchArgument);
666
667 auto & lambdaExitMergeNode = LambdaExitMemoryStateMergeOperation::CreateNode(
668 *lambdaNode->subregion(),
669 { gammaOutputMemoryState1.output, gammaOutputMemoryState2.output },
670 { 1, 2 });
671
672 lambdaOutputTest1 = lambdaNode->finalize(
673 { gammaOutputX.output, ioStateArgument, lambdaExitMergeNode.output(0) });
674 }
675
676 jlm::rvsdg::Output * lambdaOutputTest2 = nullptr;
677 {
678 auto functionType = jlm::rvsdg::FunctionType::Create(
679 { valueType, ioStateType, memoryStateType },
680 { valueType, ioStateType, memoryStateType });
681
682 auto lambdaNode = jlm::rvsdg::LambdaNode::Create(
683 rvsdg.GetRootRegion(),
685 auto xArgument = lambdaNode->GetFunctionArguments()[0];
686 auto ioStateArgument = lambdaNode->GetFunctionArguments()[1];
687 auto memoryStateArgument = lambdaNode->GetFunctionArguments()[2];
688 auto lambdaArgumentTest1 = lambdaNode->AddContextVar(*lambdaOutputTest1).inner;
689
690 auto & lambdaEntrySplitNode =
691 LambdaEntryMemoryStateSplitOperation::CreateNode(*memoryStateArgument, { 1, 2 });
692
693 auto & callEntryMergeNode = CallEntryMemoryStateMergeOperation::CreateNode(
694 *lambdaNode->subregion(),
695 outputs(&lambdaEntrySplitNode),
696 { 1, 2 });
697
698 auto controlResult =
699 &jlm::rvsdg::ControlConstantOperation::create(*lambdaNode->subregion(), 2, 0);
700
701 auto & callNode = CallOperation::CreateNode(
702 lambdaArgumentTest1,
703 functionTypeTest1,
704 { controlResult, xArgument, ioStateArgument, callEntryMergeNode.output(0) });
705
706 auto & callExitSplitNode = CallExitMemoryStateSplitOperation::CreateNode(
708 { 2, 1 });
709
710 auto & lambdaExitMergeNode = LambdaExitMemoryStateMergeOperation::CreateNode(
711 *lambdaNode->subregion(),
712 outputs(&callExitSplitNode),
713 { 2, 1 });
714
715 lambdaOutputTest2 = lambdaNode->finalize({ callNode.output(0),
717 lambdaExitMergeNode.output(0) });
718 jlm::rvsdg::GraphExport::Create(*lambdaOutputTest2, "test2");
719 }
720
721 // Act
722 RunInvariantValueRedirection(*rvsdgModule);
723
724 // Assert
725 auto & lambdaNode = jlm::rvsdg::AssertGetOwnerNode<jlm::rvsdg::LambdaNode>(*lambdaOutputTest2);
726 EXPECT_EQ(lambdaNode.GetFunctionResults().size(), 3u);
727 EXPECT_EQ(lambdaNode.GetFunctionResults()[0]->origin(), lambdaNode.GetFunctionArguments()[0]);
728 EXPECT_EQ(lambdaNode.GetFunctionResults()[1]->origin(), lambdaNode.GetFunctionArguments()[1]);
729
730 auto lambdaEntrySplit = tryGetMemoryStateEntrySplit(lambdaNode);
731 auto lambdaExitMerge = tryGetMemoryStateExitMerge(lambdaNode);
732
733 EXPECT_TRUE(lambdaEntrySplit && lambdaEntrySplit->noutputs() == 2);
734 EXPECT_TRUE(lambdaExitMerge && lambdaExitMerge->ninputs() == 2);
735 EXPECT_EQ(lambdaExitMerge->input(0)->origin(), lambdaEntrySplit->output(1));
736 EXPECT_EQ(lambdaExitMerge->input(1)->origin(), lambdaEntrySplit->output(0));
737}
738
739TEST(InvariantValueRedirectionTests, TestCallWithMissingMemoryStateNodes)
740{
741 // Arrange
742 using namespace jlm::llvm;
743 using namespace jlm::rvsdg;
744
745 // The memory node representing external has index 0, and is avoided in this test
747
748 auto ioStateType = IOStateType::Create();
749 auto memoryStateType = MemoryStateType::Create();
750 auto valueType = TestType::createValueType();
751 auto int32Type = BitType::Create(32);
752 auto functionType = FunctionType::Create(
753 { valueType, ioStateType, memoryStateType },
754 { int32Type, ioStateType, memoryStateType });
755
756 auto rvsdgModule = jlm::llvm::LlvmRvsdgModule::Create(jlm::util::FilePath(""), "", "");
757 auto & rvsdg = rvsdgModule->Rvsdg();
758
759 Output * lambdaOutputTest1 = nullptr;
760 {
761 auto lambdaNode = LambdaNode::Create(
762 rvsdg.GetRootRegion(),
764
765 auto xArgument = lambdaNode->GetFunctionArguments()[0];
766 auto ioStateArgument = lambdaNode->GetFunctionArguments()[1];
767 auto memoryStateArgument = lambdaNode->GetFunctionArguments()[2];
768
769 auto & zeroNode = IntegerConstantOperation::Create(*lambdaNode->subregion(), 32, 0);
770 auto & oneNode = IntegerConstantOperation::Create(*lambdaNode->subregion(), 32, 1);
771 auto allocaResults = AllocaOperation::create(valueType, oneNode.output(0), 4);
772
773 auto & storeNode = StoreNonVolatileOperation::CreateNode(
774 *allocaResults[0],
775 *xArgument,
776 { memoryStateArgument },
777 4);
778
779 auto & lambdaExitMergeNode = LambdaExitMemoryStateMergeOperation::CreateNode(
780 *lambdaNode->subregion(),
781 { storeNode.output(0) },
782 { 1 });
783
784 lambdaOutputTest1 = lambdaNode->finalize(
785 { zeroNode.output(0), ioStateArgument, lambdaExitMergeNode.output(0) });
786 }
787
788 Output * lambdaOutputTest2 = nullptr;
789 {
790 auto lambdaNode = LambdaNode::Create(
791 rvsdg.GetRootRegion(),
793 auto xArgument = lambdaNode->GetFunctionArguments()[0];
794 auto ioStateArgument = lambdaNode->GetFunctionArguments()[1];
795 auto memoryStateArgument = lambdaNode->GetFunctionArguments()[2];
796 auto lambdaArgumentTest = lambdaNode->AddContextVar(*lambdaOutputTest1).inner;
797
798 auto & lambdaEntrySplitNode =
799 LambdaEntryMemoryStateSplitOperation::CreateNode(*memoryStateArgument, { 1 });
800
801 auto & callEntryMergeNode = CallEntryMemoryStateMergeOperation::CreateNode(
802 *lambdaNode->subregion(),
803 outputs(&lambdaEntrySplitNode),
804 { 1 });
805
806 auto & callNode = CallOperation::CreateNode(
807 lambdaArgumentTest,
808 functionType,
809 { xArgument, ioStateArgument, callEntryMergeNode.output(0) });
810
811 auto & callExitSplitNode = CallExitMemoryStateSplitOperation::CreateNode(
813 { 1 });
814
815 auto & lambdaExitMergeNode = LambdaExitMemoryStateMergeOperation::CreateNode(
816 *lambdaNode->subregion(),
817 outputs(&callExitSplitNode),
818 { 1 });
819
820 lambdaOutputTest2 = lambdaNode->finalize({ callNode.output(0),
822 lambdaExitMergeNode.output(0) });
823 GraphExport::Create(*lambdaOutputTest2, "test2");
824 }
825
826 std::cout << view(&rvsdg.GetRootRegion()) << std::flush;
827
828 // Act
829 RunInvariantValueRedirection(*rvsdgModule);
830 std::cout << view(&rvsdg.GetRootRegion()) << std::flush;
831
832 // Assert
833 // Nothing should have been redirected
834 const auto & lambdaNode1 = AssertGetOwnerNode<LambdaNode>(*lambdaOutputTest1);
835 const auto lambdaEntrySplit1 = tryGetMemoryStateEntrySplit(lambdaNode1);
836 const auto lambdaExitMerge1 = tryGetMemoryStateExitMerge(lambdaNode1);
837 EXPECT_EQ(lambdaEntrySplit1, nullptr);
838 EXPECT_TRUE(lambdaExitMerge1 && lambdaExitMerge1->ninputs() == 1);
839
840 const auto & lambdaNode2 = AssertGetOwnerNode<LambdaNode>(*lambdaOutputTest2);
841 const auto lambdaEntrySplit2 = tryGetMemoryStateEntrySplit(lambdaNode2);
842 const auto lambdaExitMerge2 = tryGetMemoryStateExitMerge(lambdaNode2);
843 EXPECT_TRUE(lambdaEntrySplit2 && lambdaEntrySplit2->noutputs() == 1);
844 EXPECT_TRUE(lambdaExitMerge2 && lambdaExitMerge2->ninputs() == 1);
845 const auto & [callExitSplitNode, _] =
846 TryGetSimpleNodeAndOptionalOp<CallExitMemoryStateSplitOperation>(
847 *lambdaExitMerge2->input(0)->origin());
848 EXPECT_EQ(callExitSplitNode->noutputs(), 1u);
849 const auto & [callNode, calOperation] =
850 TryGetSimpleNodeAndOptionalOp<CallOperation>(*callExitSplitNode->input(0)->origin());
851 EXPECT_EQ(callNode->noutputs(), 3u);
852 EXPECT_EQ(callNode->ninputs(), 4u);
853 const auto & memoryStateInput = CallOperation::GetMemoryStateInput(*callNode);
854 const auto & [callEntryMergeNode, callEntryMergeOperation] =
855 TryGetSimpleNodeAndOptionalOp<CallEntryMemoryStateMergeOperation>(*memoryStateInput.origin());
856 EXPECT_EQ(callEntryMergeNode->ninputs(), 1u);
857 EXPECT_EQ(callEntryMergeNode->input(0)->origin(), lambdaEntrySplit2->output(0));
858}
859
860TEST(InvariantValueRedirectionTests, TestCallWithDifferentExternalCompression)
861{
862 // Arrange
863 using namespace jlm::llvm;
864 using namespace jlm::rvsdg;
865
910 // The memory node representing external has index 0
912
913 const auto ioStateType = IOStateType::Create();
914 const auto memoryStateType = MemoryStateType::Create();
915 const auto functionType =
916 FunctionType::Create({ ioStateType, memoryStateType }, { ioStateType, memoryStateType });
917
918 auto rvsdgModule = LlvmRvsdgModule::Create(jlm::util::FilePath(""), "", "");
919 auto & rvsdg = rvsdgModule->Rvsdg();
920
921 Output * callee0Output = nullptr;
922 {
923 auto lambdaNode = LambdaNode::Create(
924 rvsdg.GetRootRegion(),
925 LlvmLambdaOperation::Create(functionType, "callee0", Linkage::externalLinkage));
926
927 auto ioStateArgument = lambdaNode->GetFunctionArguments()[0];
928 auto memoryStateArgument = lambdaNode->GetFunctionArguments()[1];
929
930 auto & lambdaEntrySplitNode =
931 LambdaEntryMemoryStateSplitOperation::CreateNode(*memoryStateArgument, { 0, 1, 3 });
932 auto modifiedExternal = TestOperation::createNode(
933 lambdaNode->subregion(),
934 { lambdaEntrySplitNode.output(0) },
935 { memoryStateType });
936 auto & lambdaExitMergeNode = LambdaExitMemoryStateMergeOperation::CreateNode(
937 *lambdaNode->subregion(),
938 { modifiedExternal->output(0),
939 lambdaEntrySplitNode.output(1),
940 lambdaEntrySplitNode.output(2) },
941 { 0, 1, 3 });
942
943 callee0Output = lambdaNode->finalize({ ioStateArgument, lambdaExitMergeNode.output(0) });
944 }
945
946 Output * callee3Output = nullptr;
947 {
948 auto lambdaNode = LambdaNode::Create(
949 rvsdg.GetRootRegion(),
950 LlvmLambdaOperation::Create(functionType, "callee3", Linkage::externalLinkage));
951
952 auto ioStateArgument = lambdaNode->GetFunctionArguments()[0];
953 auto memoryStateArgument = lambdaNode->GetFunctionArguments()[1];
954
955 auto & lambdaEntrySplitNode =
956 LambdaEntryMemoryStateSplitOperation::CreateNode(*memoryStateArgument, { 0, 1, 3 });
957 auto modifiedMemory3 = TestOperation::createNode(
958 lambdaNode->subregion(),
959 { lambdaEntrySplitNode.output(2) },
960 { memoryStateType });
961 auto & lambdaExitMergeNode = LambdaExitMemoryStateMergeOperation::CreateNode(
962 *lambdaNode->subregion(),
963 { lambdaEntrySplitNode.output(0),
964 lambdaEntrySplitNode.output(1),
965 modifiedMemory3->output(0) },
966 { 0, 1, 3 });
967
968 callee3Output = lambdaNode->finalize({ ioStateArgument, lambdaExitMergeNode.output(0) });
969 }
970
971 SimpleNode * lambdaEntrySplitNode = nullptr;
972 SimpleNode * callEntryMergeNodeA = nullptr;
973 SimpleNode * callExitSplitNodeA = nullptr;
974 SimpleNode * callEntryMergeNodeB = nullptr;
975 SimpleNode * callExitSplitNodeB = nullptr;
976 SimpleNode * lambdaExitMergeNode = nullptr;
977 {
978 auto lambdaNode = LambdaNode::Create(
979 rvsdg.GetRootRegion(),
981
982 auto ioStateArgument = lambdaNode->GetFunctionArguments()[0];
983 auto memoryStateArgument = lambdaNode->GetFunctionArguments()[1];
984 auto callee0Argument = lambdaNode->AddContextVar(*callee0Output).inner;
985 auto callee3Argument = lambdaNode->AddContextVar(*callee3Output).inner;
986
987 lambdaEntrySplitNode =
988 &LambdaEntryMemoryStateSplitOperation::CreateNode(*memoryStateArgument, { 0, 1, 2 });
989
991 *lambdaNode->subregion(),
992 outputs(lambdaEntrySplitNode),
993 { 0, 1, 2 });
994 auto & callNodeA = CallOperation::CreateNode(
995 callee0Argument,
996 functionType,
997 { ioStateArgument, callEntryMergeNodeA->output(0) });
1000 { 0, 1, 2 });
1001
1003 *lambdaNode->subregion(),
1004 outputs(callExitSplitNodeA),
1005 { 0, 1, 2 });
1006 auto & callNodeB = CallOperation::CreateNode(
1007 callee3Argument,
1008 functionType,
1009 { &CallOperation::GetIOStateOutput(callNodeA), callEntryMergeNodeB->output(0) });
1012 { 0, 1, 2 });
1013
1015 *lambdaNode->subregion(),
1016 outputs(callExitSplitNodeB),
1017 { 0, 1, 2 });
1018
1019 lambdaNode->finalize(
1020 { &CallOperation::GetIOStateOutput(callNodeB), lambdaExitMergeNode->output(0) });
1021 }
1022
1023 // Act
1024 RunInvariantValueRedirection(*rvsdgModule);
1025
1026 // Assert
1027 ASSERT_EQ(lambdaEntrySplitNode->noutputs(), 3u);
1028 ASSERT_EQ(callEntryMergeNodeA->ninputs(), 3u);
1029 ASSERT_EQ(callExitSplitNodeA->noutputs(), 3u);
1030 ASSERT_EQ(callEntryMergeNodeB->ninputs(), 3u);
1031 ASSERT_EQ(callExitSplitNodeB->noutputs(), 3u);
1032 ASSERT_EQ(lambdaExitMergeNode->ninputs(), 3u);
1033
1034 // the memory state edge representing the external node has not been re-routed around anything
1035 EXPECT_EQ(callEntryMergeNodeA->input(0)->origin(), lambdaEntrySplitNode->output(0));
1036 EXPECT_EQ(callEntryMergeNodeB->input(0)->origin(), callExitSplitNodeA->output(0));
1037 EXPECT_EQ(lambdaExitMergeNode->input(0)->origin(), callExitSplitNodeB->output(0));
1038
1039 // the memory state edge representing memory node 1 has been re-routed to the entry
1040 EXPECT_EQ(callEntryMergeNodeA->input(1)->origin(), lambdaEntrySplitNode->output(1));
1041 EXPECT_EQ(callEntryMergeNodeB->input(1)->origin(), lambdaEntrySplitNode->output(1));
1042 EXPECT_EQ(lambdaExitMergeNode->input(1)->origin(), lambdaEntrySplitNode->output(1));
1043
1044 // the memory state edge representing memory node 2 only been re-routed around callee3
1045 EXPECT_EQ(callEntryMergeNodeA->input(2)->origin(), lambdaEntrySplitNode->output(2));
1046 EXPECT_EQ(callEntryMergeNodeB->input(2)->origin(), callExitSplitNodeA->output(2));
1047 EXPECT_EQ(lambdaExitMergeNode->input(2)->origin(), callExitSplitNodeA->output(2));
1048}
1049
1050TEST(InvariantValueRedirectionTests, TestLambdaCallArgumentMismatch)
1051{
1052 // Arrange
1054
1055 // Act
1057
1058 // Assert
1059 auto & callNode = test.GetCall();
1060 auto & lambdaNode = test.GetLambdaMain();
1061
1062 EXPECT_EQ(lambdaNode.GetFunctionResults().size(), 3u);
1063 EXPECT_EQ(lambdaNode.GetFunctionResults().size(), callNode.noutputs());
1064 EXPECT_EQ(lambdaNode.GetFunctionResults()[0]->origin(), callNode.output(0));
1065 EXPECT_EQ(lambdaNode.GetFunctionResults()[1]->origin(), callNode.output(1));
1066 EXPECT_EQ(lambdaNode.GetFunctionResults()[2]->origin(), callNode.output(2));
1067}
1068
1069TEST(InvariantValueRedirectionTests, testThetaGammaRedirection)
1070{
1071 // Arrange
1072 using namespace jlm::llvm;
1073 using namespace jlm::rvsdg;
1074
1075 auto valueType = TestType::createValueType();
1076 auto controlType = ControlType::Create(2);
1077 const auto functionType = FunctionType::Create({ valueType, valueType }, { valueType });
1078
1079 auto rvsdgModule = jlm::llvm::LlvmRvsdgModule::Create(jlm::util::FilePath(""), "", "");
1080 auto & rvsdg = rvsdgModule->Rvsdg();
1081
1082 auto lambdaNode = LambdaNode::Create(
1083 rvsdg.GetRootRegion(),
1085
1086 auto functionArgument0 = lambdaNode->GetFunctionArguments()[0];
1087 auto functionArgument1 = lambdaNode->GetFunctionArguments()[1];
1088
1089 auto thetaNode = ThetaNode::create(lambdaNode->subregion());
1090 auto loopVar0 = thetaNode->AddLoopVar(functionArgument0);
1091 auto loopVar1 = thetaNode->AddLoopVar(functionArgument1);
1092
1093 auto dummyNodeTheta = TestOperation::createNode(thetaNode->subregion(), {}, { valueType });
1094
1095 auto predicate =
1096 TestOperation::createNode(thetaNode->subregion(), {}, { controlType })->output(0);
1097 auto gammaNode = GammaNode::create(predicate, 2);
1098 auto entryVar0 = gammaNode->AddEntryVar(loopVar0.pre);
1099 auto entryVar1 = gammaNode->AddEntryVar(dummyNodeTheta->output(0));
1100
1101 auto dummyNodeGamma0 = TestOperation::createNode(gammaNode->subregion(0), {}, { valueType });
1102 auto dummyNodeGamma1 = TestOperation::createNode(gammaNode->subregion(1), {}, { valueType });
1103
1104 auto controlConstant0 =
1105 &ControlConstantOperation::create(*gammaNode->subregion(0), ControlValueRepresentation(0, 2));
1106 auto controlConstant1 =
1107 &ControlConstantOperation::create(*gammaNode->subregion(1), ControlValueRepresentation(1, 2));
1108
1109 auto controlExitVar = gammaNode->AddExitVar({ controlConstant0, controlConstant1 });
1110 auto exitVar0 =
1111 gammaNode->AddExitVar({ dummyNodeGamma0->output(0), entryVar0.branchArgument[1] });
1112 auto exitVar1 =
1113 gammaNode->AddExitVar({ entryVar1.branchArgument[0], dummyNodeGamma1->output(0) });
1114
1115 thetaNode->predicate()->divert_to(controlExitVar.output);
1116 loopVar0.post->divert_to(exitVar0.output);
1117 loopVar1.post->divert_to(exitVar1.output);
1118
1119 auto lambdaOutput = lambdaNode->finalize({ loopVar1.output });
1120
1121 GraphExport::Create(*lambdaOutput, "test");
1122
1123 // Act
1124 RunInvariantValueRedirection(*rvsdgModule);
1125
1126 // Assert
1127 // We expect that the post value of both loop variables does not originate from the gamma any
1128 // longer.
1129 auto loopVars = thetaNode->GetLoopVars();
1130 EXPECT_EQ(loopVars.size(), 2u);
1131
1132 // Loop variable 0 was dead after the loop, which means it is irrelevant what happens to it in
1133 // the last iteration of the loop. As the loop predicate originates from a control constant in
1134 // one of the gamma nodes' subregions, the loop variables' value is always the same as the one
1135 // from the gamma subregion with control constant 1 (i.e. loop repetition). This means we could
1136 // redirect the loop variable from the gamma to the respective entry variables' origin.
1137 EXPECT_EQ(loopVars[0].post->origin(), loopVars[0].pre);
1138
1139 // Loop variable 1 was dead at the beginning of each loop iteration, which means it is irrelevant
1140 // what happens to it except in the last iteration of the loop. As the loop predicate originates
1141 // from a control constant in a one of the gamma nodes' subregions, the loop variables' value is
1142 // always the same as the one from the gamma subregion with control constant 0 (i.e. loop exit).
1143 // This means we could redirect the loop variable from the gamma to the respective entry
1144 // variables' origin.
1145 EXPECT_EQ(loopVars[1].post->origin(), dummyNodeTheta->output(0));
1146}
1147
1148TEST(InvariantValueRedirectionTests, testLoadWithDeadLoadedValue)
1149{
1150 // Arrange
1151 using namespace jlm::llvm;
1152 using namespace jlm::rvsdg;
1153
1154 const auto valueType = TestType::createValueType();
1155 const auto pointerType = PointerType::Create();
1156 const auto memoryStateType = MemoryStateType::Create();
1157 const auto functionType = FunctionType::Create(
1158 { pointerType, memoryStateType, memoryStateType },
1159 { memoryStateType, memoryStateType });
1160
1161 auto rvsdgModule = LlvmRvsdgModule::Create(jlm::util::FilePath(""), "", "");
1162 auto & rvsdg = rvsdgModule->Rvsdg();
1163
1164 auto lambdaNode = LambdaNode::Create(
1165 rvsdg.GetRootRegion(),
1167
1168 auto addressArgument = lambdaNode->GetFunctionArguments()[0];
1169 auto memoryStateArgument1 = lambdaNode->GetFunctionArguments()[1];
1170 auto memoryStateArgument2 = lambdaNode->GetFunctionArguments()[2];
1171
1172 auto & loadNode = LoadNonVolatileOperation::CreateNode(
1173 *addressArgument,
1174 { memoryStateArgument1, memoryStateArgument2 },
1175 valueType,
1176 4);
1177
1178 auto lambdaOutput = lambdaNode->finalize({ loadNode.output(1), loadNode.output(2) });
1179
1180 GraphExport::Create(*lambdaOutput, "test");
1181
1182 // Act
1183 RunInvariantValueRedirection(*rvsdgModule);
1184
1185 // Assert
1186 // We expect that the users of the memory state outputs of the load node were redirected to the
1187 // origins of the respective inputs, which in turn rendered the load node dead. Consequently, it
1188 // was pruned from the lambda subregion.
1189 EXPECT_EQ(lambdaNode->subregion()->numNodes(), 0u);
1190 EXPECT_EQ(lambdaNode->GetFunctionResults()[0]->origin(), memoryStateArgument1);
1191 EXPECT_EQ(lambdaNode->GetFunctionResults()[1]->origin(), memoryStateArgument2);
1192}
1193
1194}
static std::vector< rvsdg::Output * > create(std::shared_ptr< const rvsdg::Type > allocatedType, rvsdg::Output *count, const size_t alignment)
Definition alloca.hpp:131
static rvsdg::SimpleNode & CreateNode(rvsdg::Region &region, const std::vector< rvsdg::Output * > &operands, std::vector< MemoryNodeId > memoryNodeIds)
static rvsdg::SimpleNode & CreateNode(rvsdg::Output &operand, std::vector< MemoryNodeId > memoryNodeIds)
static rvsdg::Output & GetMemoryStateOutput(const rvsdg::Node &node) noexcept
Definition call.hpp:378
static rvsdg::Input & GetMemoryStateInput(const rvsdg::Node &node) noexcept
Definition call.hpp:366
static rvsdg::SimpleNode & CreateNode(rvsdg::Region &region, std::unique_ptr< CallOperation > callOperation, const std::vector< rvsdg::Output * > &operands)
Definition call.hpp:507
static rvsdg::Output & GetIOStateOutput(const rvsdg::Node &node) noexcept
Definition call.hpp:345
static rvsdg::Node & createNode(rvsdg::Region &region, fpsize size, const ::llvm::APFloat &constant)
static std::shared_ptr< const FloatingPointType > Create(fpsize size)
Definition types.cpp:117
static std::shared_ptr< const IOStateType > Create()
Definition types.cpp:343
static rvsdg::Node & Create(rvsdg::Region &region, IntegerValueRepresentation representation)
void Run(rvsdg::RvsdgModule &module, util::StatisticsCollector &statisticsCollector) override
Perform RVSDG transformation.
RVSDG module containing a static function that is called with the wrong number of arguments.
const rvsdg::SimpleNode & GetCall() const noexcept
const rvsdg::LambdaNode & GetLambdaMain() const noexcept
static rvsdg::SimpleNode & CreateNode(rvsdg::Output &operand, std::vector< MemoryNodeId > memoryNodeIds)
static rvsdg::SimpleNode & CreateNode(rvsdg::Region &region, const std::vector< rvsdg::Output * > &operands, const std::vector< MemoryNodeId > &memoryNodeIds)
static std::unique_ptr< LlvmLambdaOperation > Create(std::shared_ptr< const jlm::rvsdg::FunctionType > type, std::string name, const jlm::llvm::Linkage &linkage, jlm::llvm::CallingConvention callingConvention, jlm::llvm::AttributeSet attributes)
Definition lambda.hpp:84
static std::unique_ptr< LlvmRvsdgModule > Create(const util::FilePath &sourceFileName, const std::string &targetTriple, const std::string &dataLayout)
static rvsdg::SimpleNode & CreateNode(rvsdg::Region &region, std::unique_ptr< LoadNonVolatileOperation > loadOperation, const std::vector< rvsdg::Output * > &operands)
Definition Load.hpp:470
static std::shared_ptr< const MemoryStateType > Create()
Definition types.cpp:379
static std::shared_ptr< const PointerType > Create()
Definition types.cpp:45
jlm::llvm::LlvmRvsdgModule & module()
static rvsdg::SimpleNode & CreateNode(rvsdg::Output &address, rvsdg::Output &value, const std::vector< rvsdg::Output * > &memoryStates, size_t alignment)
Definition Store.hpp:360
static jlm::rvsdg::Output * Create(rvsdg::Region &region, std::shared_ptr< const jlm::rvsdg::Type > type)
static constexpr NodeIndex externalMemoryNode
static Output & create(Region &region, ControlValueRepresentation value)
Definition control.hpp:122
static std::shared_ptr< const ControlType > Create(std::size_t nalternatives)
Instantiates control type.
Definition control.cpp:50
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 GammaNode * create(jlm::rvsdg::Output *predicate, size_t nalternatives)
Definition gamma.hpp:161
static GraphExport & Create(Output &origin, std::string name)
Definition graph.cpp:62
Output * origin() const noexcept
Definition node.hpp:58
static LambdaNode * Create(rvsdg::Region &parent, std::unique_ptr< LambdaOperation > operation)
Definition lambda.cpp:141
NodeOutput * output(size_t index) const noexcept
Definition node.hpp:650
size_t ninputs() const noexcept
Definition node.hpp:609
size_t noutputs() const noexcept
Definition node.hpp:644
Graph & Rvsdg() noexcept
NodeInput * input(size_t index) const noexcept
NodeOutput * output(size_t index) const noexcept
static std::shared_ptr< const TestType > createValueType()
Definition TestType.cpp:67
static ThetaNode * create(rvsdg::Region *parent)
Definition theta.hpp:84
Global memory state passed between functions.
static util::StatisticsCollector statisticsCollector
rvsdg::SimpleNode * tryGetMemoryStateEntrySplit(const rvsdg::LambdaNode &lambdaNode) noexcept
rvsdg::SimpleNode * tryGetMemoryStateExitMerge(const rvsdg::LambdaNode &lambdaNode) noexcept
static void RunInvariantValueRedirection(jlm::llvm::LlvmRvsdgModule &rvsdgModule)
TEST(ControlOperationsTests, foldConstants)
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