Jlm
Loading...
Searching...
No Matches
DistributeConstantsTests.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2025 Nico Reißmann <nico.reissmann@gmail.com>
3 * See COPYING for terms of redistribution.
4 */
5
6#include <gtest/gtest.h>
7
12#include <jlm/rvsdg/gamma.hpp>
14#include <jlm/rvsdg/theta.hpp>
15#include <jlm/rvsdg/view.hpp>
17
18TEST(DistributeConstantsTests, GammaSubregionUsage)
19{
20 using namespace jlm::hls;
21 using namespace jlm::llvm;
22 using namespace jlm::rvsdg;
23 using namespace jlm::util;
24
25 // Arrange
26 auto controlType = ControlType::Create(3);
27 auto bit32Type = BitType::Create(32);
28 auto functionType = FunctionType::Create({ controlType }, { bit32Type });
29
30 jlm::llvm::LlvmRvsdgModule rvsdgModule(FilePath(""), "", "");
31 auto & rvsdg = rvsdgModule.Rvsdg();
32
33 auto lambdaNode = LambdaNode::Create(
34 rvsdg.GetRootRegion(),
35 LlvmLambdaOperation::Create(functionType, "f", Linkage::externalLinkage));
36 auto controlArgument = lambdaNode->GetFunctionArguments()[0];
37
38 auto & constantNode = IntegerConstantOperation::Create(*lambdaNode->subregion(), 32, 5);
39
40 auto gammaNode = GammaNode::create(controlArgument, 3);
41 auto entryVariable = gammaNode->AddEntryVar(constantNode.output(0));
42
43 auto testNode0 = TestOperation::createNode(
44 gammaNode->subregion(0),
45 { entryVariable.branchArgument[0] },
46 { bit32Type });
47
48 auto testNode1 = TestOperation::createNode(
49 gammaNode->subregion(1),
50 { entryVariable.branchArgument[1] },
51 { bit32Type });
52
53 auto exitVariable = gammaNode->AddExitVar(
54 { testNode0->output(0), testNode1->output(0), entryVariable.branchArgument[2] });
55
56 auto lambdaOutput = lambdaNode->finalize({ exitVariable.output });
57
58 jlm::rvsdg::GraphExport::Create(*lambdaOutput, "");
59
60 view(rvsdg, stdout);
61
62 // Act
64 ConstantDistribution::CreateAndRun(rvsdgModule, statisticsCollector);
65 view(rvsdg, stdout);
66
67 // Assert
68 EXPECT_EQ(lambdaNode->subregion()->numNodes(), 2u);
69
70 {
71 // check subregion 0 - we expect the constantNode to be distributed into this subregion
72 EXPECT_EQ(gammaNode->subregion(0)->numNodes(), 2u);
73 EXPECT_TRUE(IsOwnerNodeOperation<IntegerConstantOperation>(*testNode0->input(0)->origin()));
74 }
75
76 {
77 // check subregion 1 - we expect the constantNode to be distributed into this subregion
78 EXPECT_EQ(gammaNode->subregion(1)->numNodes(), 2u);
79 EXPECT_TRUE(IsOwnerNodeOperation<IntegerConstantOperation>(*testNode1->input(0)->origin()));
80 }
81
82 {
83 // check subregion 2 - we expect the constantNode to be distributed into this subregion
84 EXPECT_EQ(gammaNode->subregion(2)->numNodes(), 1u);
85 EXPECT_TRUE(
86 IsOwnerNodeOperation<IntegerConstantOperation>(*exitVariable.branchResult[2]->origin()));
87 }
88}
89
90TEST(DistributeConstantsTests, NestedGammas)
91{
92 using namespace jlm::hls;
93 using namespace jlm::llvm;
94 using namespace jlm::rvsdg;
95 using namespace jlm::util;
96
97 // Arrange
98 auto controlType = ControlType::Create(2);
99 auto bit32Type = BitType::Create(32);
100 auto functionType = FunctionType::Create({ controlType }, { bit32Type });
101
102 jlm::llvm::LlvmRvsdgModule rvsdgModule(FilePath(""), "", "");
103 auto & rvsdg = rvsdgModule.Rvsdg();
104
105 auto lambdaNode = LambdaNode::Create(
106 rvsdg.GetRootRegion(),
107 LlvmLambdaOperation::Create(functionType, "f", Linkage::externalLinkage));
108 auto controlArgument = lambdaNode->GetFunctionArguments()[0];
109
110 auto & constantNode = IntegerConstantOperation::Create(*lambdaNode->subregion(), 32, 5);
111
112 auto gammaNodeOuter = GammaNode::create(controlArgument, 2);
113 auto entryVarConstant = gammaNodeOuter->AddEntryVar(constantNode.output(0));
114
115 // gammaNodeOuter subregion 0
116 auto testNode0 = TestOperation::createNode(
117 gammaNodeOuter->subregion(0),
118 { entryVarConstant.branchArgument[0] },
119 { bit32Type });
120
121 // gammaNodeOuter subregion 1
122 auto controlConstant = &ControlConstantOperation::create(*gammaNodeOuter->subregion(1), 2, 0);
123 auto gammaNodeInner = GammaNode::create(controlConstant, 2);
124 auto entryVariable = gammaNodeInner->AddEntryVar(entryVarConstant.branchArgument[1]);
125 auto exitVariableInner = gammaNodeInner->AddExitVar(
126 { entryVariable.branchArgument[0], entryVariable.branchArgument[1] });
127
128 auto exitVariableOuter =
129 gammaNodeOuter->AddExitVar({ testNode0->output(0), exitVariableInner.output });
130
131 auto testNode1 = TestOperation::createNode(
132 lambdaNode->subregion(),
133 { exitVariableOuter.output },
134 { bit32Type });
135
136 auto lambdaOutput = lambdaNode->finalize({ testNode1->output(0) });
137
138 jlm::rvsdg::GraphExport::Create(*lambdaOutput, "");
139
140 view(rvsdg, stdout);
141
142 // Act
144 ConstantDistribution::CreateAndRun(rvsdgModule, statisticsCollector);
145 view(rvsdg, stdout);
146
147 // Assert
148 EXPECT_EQ(lambdaNode->subregion()->numNodes(), 3u);
149
150 {
151 // check gammaNodeOuter subregion 0
152 EXPECT_EQ(gammaNodeOuter->subregion(0)->numNodes(), 2u);
153 EXPECT_TRUE(IsOwnerNodeOperation<IntegerConstantOperation>(*testNode0->input(0)->origin()));
154 }
155
156 {
157 // check gammaNodeOuter subregion 1
158 // The constantNode was copied into this region (even though it does not have a user), so we
159 // expect one more node than before the transformation.
160 EXPECT_EQ(gammaNodeOuter->subregion(1)->numNodes(), 3u);
161
162 {
163 // check gammaNodeInner subregion 0
164 EXPECT_EQ(gammaNodeInner->subregion(0)->numNodes(), 0u);
165 }
166
167 {
168 // check gammaNodeInner subregion 1
169 EXPECT_EQ(gammaNodeInner->subregion(1)->numNodes(), 0u);
170 }
171 }
172
173 EXPECT_TRUE(TryGetOwnerNode<GammaNode>(*testNode1->input(0)->origin()));
174}
175
176TEST(DistributeConstantsTests, Theta)
177{
178 using namespace jlm::hls;
179 using namespace jlm::llvm;
180 using namespace jlm::rvsdg;
181 using namespace jlm::util;
182
183 // Arrange
184 auto controlType = ControlType::Create(3);
185 auto bit32Type = BitType::Create(32);
186 auto functionType = FunctionType::Create({}, { bit32Type, bit32Type, bit32Type });
187
188 jlm::llvm::LlvmRvsdgModule rvsdgModule(FilePath(""), "", "");
189 auto & rvsdg = rvsdgModule.Rvsdg();
190
191 auto lambdaNode = LambdaNode::Create(
192 rvsdg.GetRootRegion(),
193 LlvmLambdaOperation::Create(functionType, "f", Linkage::externalLinkage));
194
195 auto & constantNode0 = IntegerConstantOperation::Create(*lambdaNode->subregion(), 32, 0);
196 auto & constantNode2 = IntegerConstantOperation::Create(*lambdaNode->subregion(), 32, 2);
197
198 auto thetaNode = ThetaNode::create(lambdaNode->subregion());
199
200 auto loopVar0 = thetaNode->AddLoopVar(constantNode0.output(0));
201 auto loopVar1 = thetaNode->AddLoopVar(constantNode0.output(0));
202 auto loopVar2 = thetaNode->AddLoopVar(constantNode2.output(0));
203
204 auto testNode0 =
205 TestOperation::createNode(thetaNode->subregion(), { loopVar0.pre }, { bit32Type });
206 auto & constantNode1 = IntegerConstantOperation::Create(*thetaNode->subregion(), 32, 1);
207 auto testNode2 =
208 TestOperation::createNode(thetaNode->subregion(), { loopVar2.pre }, { bit32Type });
209
210 loopVar0.post->divert_to(testNode0->output(0));
211 loopVar1.post->divert_to(constantNode1.output(0));
212
213 auto testNode1 =
214 TestOperation::createNode(thetaNode->subregion(), { loopVar0.output }, { bit32Type });
215
216 auto lambdaOutput =
217 lambdaNode->finalize({ testNode1->output(0), loopVar1.output, loopVar2.output });
218
219 jlm::rvsdg::GraphExport::Create(*lambdaOutput, "");
220
221 view(rvsdg, stdout);
222
223 // Act
225 ConstantDistribution::CreateAndRun(rvsdgModule, statisticsCollector);
226 view(rvsdg, stdout);
227
228 // Arrange
229 // We expect constantNode1 to be distributed from the theta subregion to the lambda subregion
230 EXPECT_EQ(lambdaNode->subregion()->numNodes(), 5u);
231
232 // We expect constantNode2 to be distributed from the lambda subregion to the theta subregion
233 EXPECT_EQ(thetaNode->subregion()->numNodes(), 5u);
234
235 {
236 // We expect no changes with loopVar0
237 auto loopVar = thetaNode->MapOutputLoopVar(*thetaNode->output(0));
238 EXPECT_EQ(lambdaNode->subregion()->result(0)->origin(), testNode1->output(0));
239 EXPECT_EQ(loopVar.output, testNode1->input(0)->origin());
240 EXPECT_EQ(loopVar.post->origin(), testNode0->output(0));
241 EXPECT_EQ(testNode0->input(0)->origin(), loopVar.pre);
242 EXPECT_EQ(loopVar.input->origin(), constantNode0.output(0));
243 }
244
245 {
246 // We expect constantNode1 to be distributed from the theta subregion to the lambda subregion,
247 // rendering loopVar1 to be dead
248 auto loopVar = thetaNode->MapOutputLoopVar(*thetaNode->output(1));
249 EXPECT_TRUE(loopVar.output->IsDead());
250 EXPECT_TRUE(loopVar.pre->IsDead());
251
252 auto [constantNode, constantOperation] =
253 TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(
254 *lambdaNode->subregion()->result(1)->origin());
255 EXPECT_TRUE(constantNode && constantOperation);
256 EXPECT_EQ(constantOperation->Representation(), 1u);
257 }
258
259 {
260 // LoopVar2 was a passthrough so we expect it to be redirected to constantNode2
261 auto [constantNode, constantOperation] =
262 TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(
263 *lambdaNode->subregion()->result(2)->origin());
264 EXPECT_TRUE(constantNode && constantOperation);
265 EXPECT_EQ(constantNode, &constantNode2);
266 }
267
268 {
269 // We expect constantNode2 to be distributed t o the theta subregion for testNode2
270 auto [constantNode, constantOperation] =
271 TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(*testNode2->input(0)->origin());
272 EXPECT_TRUE(constantNode && constantOperation);
273 EXPECT_EQ(constantOperation->Representation(), 2u);
274 }
275}
276
277TEST(DistributeConstantsTests, Lambda)
278{
279 using namespace jlm::hls;
280 using namespace jlm::llvm;
281 using namespace jlm::rvsdg;
282 using namespace jlm::util;
283
284 // Arrange
285 auto bit32Type = BitType::Create(32);
286 auto functionType = FunctionType::Create({}, { bit32Type });
287
288 jlm::llvm::LlvmRvsdgModule rvsdgModule(FilePath(""), "", "");
289 auto & rvsdg = rvsdgModule.Rvsdg();
290
291 auto lambdaNode = LambdaNode::Create(
292 rvsdg.GetRootRegion(),
293 LlvmLambdaOperation::Create(functionType, "f", Linkage::externalLinkage));
294
295 auto & constantNode0 = IntegerConstantOperation::Create(*lambdaNode->subregion(), 32, 0);
296
297 auto lambdaOutput = lambdaNode->finalize({ constantNode0.output(0) });
298
299 GraphExport::Create(*lambdaOutput, "");
300
301 view(rvsdg, stdout);
302
303 // Act
305 ConstantDistribution::CreateAndRun(rvsdgModule, statisticsCollector);
306 view(rvsdg, stdout);
307
308 // Arrange
309 // We expect no change at all in the graph
310 EXPECT_EQ(lambdaNode->subregion()->numNodes(), 1u);
311}
static jlm::util::StatisticsCollector statisticsCollector
TEST(DistributeConstantsTests, GammaSubregionUsage)
static GraphExport & Create(Output &origin, std::string name)
Definition graph.cpp:62
Global memory state passed between functions.