Jlm
Loading...
Searching...
No Matches
OutputTests.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
9#include <jlm/rvsdg/delta.hpp>
10#include <jlm/rvsdg/gamma.hpp>
11#include <jlm/rvsdg/lambda.hpp>
12#include <jlm/rvsdg/Phi.hpp>
15#include <jlm/rvsdg/theta.hpp>
16
17TEST(OutputTests, TestOutputIterator)
18{
19 using namespace jlm::rvsdg;
20
21 // Arrange
22 auto valueType = TestType::createValueType();
23
24 Graph rvsdg;
25 auto & rootRegion = rvsdg.GetRootRegion();
26 auto i0 = &GraphImport::Create(rvsdg, valueType, "i");
27 auto i1 = &GraphImport::Create(rvsdg, valueType, "i");
28 auto i2 = &GraphImport::Create(rvsdg, valueType, "i");
29
30 auto & node = CreateOpNode<TestOperation>(
31 rootRegion,
32 std::vector<std::shared_ptr<const Type>>(),
33 std::vector<std::shared_ptr<const Type>>(5, valueType));
34
35 GraphExport::Create(*node.output(0), "x0");
36
37 // Act & Assert
38 auto nodeIt = Output::Iterator(node.output(0));
39 EXPECT_EQ(nodeIt.GetOutput(), node.output(0));
40 EXPECT_EQ(nodeIt->index(), node.output(0)->index());
41 EXPECT_EQ((*nodeIt).index(), node.output(0)->index());
42 EXPECT_EQ(nodeIt, Output::Iterator(node.output(0)));
43 EXPECT_NE(nodeIt, Output::Iterator(node.output(1)));
44
45 nodeIt++;
46 EXPECT_EQ(nodeIt.GetOutput(), node.output(1));
47
48 ++nodeIt;
49 EXPECT_EQ(nodeIt.GetOutput(), node.output(2));
50
51 ++nodeIt;
52 ++nodeIt;
53 EXPECT_EQ(nodeIt.GetOutput(), node.output(4));
54
55 ++nodeIt;
56 EXPECT_EQ(nodeIt.GetOutput(), nullptr);
57
58 auto regionIt = Output::Iterator(rootRegion.argument(0));
59 EXPECT_EQ(regionIt.GetOutput(), i0);
60 EXPECT_EQ(regionIt->index(), i0->index());
61 EXPECT_EQ((*regionIt).index(), i0->index());
62 EXPECT_EQ(regionIt, Output::Iterator(i0));
63 EXPECT_NE(regionIt, Output::Iterator(i1));
64
65 regionIt++;
66 regionIt++;
67 EXPECT_EQ(regionIt.GetOutput(), i2);
68
69 regionIt++;
70 EXPECT_EQ(regionIt.GetOutput(), nullptr);
71
72 auto it = Input::Iterator(nullptr);
73 it++;
74 ++it;
75 EXPECT_EQ(it.GetInput(), nullptr);
76}
77
78TEST(OutputTests, RouteToRegion_Gamma)
79{
80 using namespace jlm::rvsdg;
81
82 // Arrange
83 const auto controlType = ControlType::Create(2);
84 const auto valueType = TestType::createValueType();
85
86 Graph rvsdg;
87 auto & i0 = GraphImport::Create(rvsdg, valueType, "i0");
88 auto & i1 = GraphImport::Create(rvsdg, controlType, "i1");
89
90 const auto gammaNode = GammaNode::create(&i1, 2);
91
92 // Act
93 const auto & output = RouteToRegion(i0, *gammaNode->subregion(1));
94
95 // Assert
96 EXPECT_EQ(output.region(), gammaNode->subregion(1));
97 EXPECT_EQ(gammaNode->GetEntryVars().size(), 1u);
98 EXPECT_EQ(gammaNode->GetExitVars().size(), 0u);
99}
100
101TEST(OutputTests, RouteToRegion_Theta)
102{
103 using namespace jlm::rvsdg;
104
105 // Arrange
106 const auto valueType = TestType::createValueType();
107
108 Graph rvsdg;
109 auto & i0 = GraphImport::Create(rvsdg, valueType, "i0");
110
111 const auto thetaNode = ThetaNode::create(&rvsdg.GetRootRegion());
112
113 // Act
114 const auto & output = RouteToRegion(i0, *thetaNode->subregion());
115
116 // Assert
117 EXPECT_EQ(output.region(), thetaNode->subregion());
118 EXPECT_EQ(thetaNode->GetLoopVars().size(), 1u);
119 EXPECT_EQ(&output, thetaNode->GetLoopVars()[0].pre);
120}
121
122TEST(OutputTests, RouteToRegion_Lambda)
123{
124 using namespace jlm::rvsdg;
125
126 // Arrange
127 auto valueType = TestType::createValueType();
128 auto functionType = FunctionType::Create({ valueType }, { valueType });
129
130 Graph rvsdg;
131 auto & i0 = GraphImport::Create(rvsdg, valueType, "i0");
132
133 const auto lambdaNode =
134 LambdaNode::Create(rvsdg.GetRootRegion(), std::make_unique<LambdaOperation>(functionType));
135
136 // Act
137 const auto & output = RouteToRegion(i0, *lambdaNode->subregion());
138
139 // Assert
140 EXPECT_EQ(output.region(), lambdaNode->subregion());
141 EXPECT_EQ(lambdaNode->GetContextVars().size(), 1u);
142 EXPECT_EQ(&output, lambdaNode->GetContextVars()[0].inner);
143}
144
145TEST(OutputTests, RouteToRegion_Phi)
146{
147 using namespace jlm::rvsdg;
148
149 // Arrange
150 auto valueType = TestType::createValueType();
151
152 Graph rvsdg;
153 auto & i0 = GraphImport::Create(rvsdg, valueType, "i0");
154
155 PhiBuilder phiBuilder;
156 phiBuilder.begin(&rvsdg.GetRootRegion());
157 auto phiNode = phiBuilder.end();
158
159 // Act
160 const auto & output = RouteToRegion(i0, *phiNode->subregion());
161
162 // Assert
163 EXPECT_EQ(output.region(), phiNode->subregion());
164 EXPECT_EQ(phiNode->GetContextVars().size(), 1u);
165 EXPECT_EQ(&output, phiNode->GetContextVars()[0].inner);
166}
167
168TEST(OutputTests, RouteToRegion_Delta)
169{
170 using namespace jlm::rvsdg;
171
172 // Arrange
173 auto valueType = TestType::createValueType();
174
175 Graph rvsdg;
176 auto & i0 = GraphImport::Create(rvsdg, valueType, "i0");
177
178 auto deltaNode = DeltaNode::Create(
179 &rvsdg.GetRootRegion(),
180 std::make_unique<DeltaOperation>(valueType, true, valueType));
181
182 // Act
183 const auto & output = RouteToRegion(i0, *deltaNode->subregion());
184
185 // Assert
186 EXPECT_EQ(output.region(), deltaNode->subregion());
187 EXPECT_EQ(deltaNode->GetContextVars().size(), 1u);
188 EXPECT_EQ(&output, deltaNode->GetContextVars()[0].inner);
189}
190
191TEST(OutputTests, RouteToRegion_Nesting)
192{
193 using namespace jlm::rvsdg;
194
195 // Arrange
196 const auto controlType = ControlType::Create(2);
197 auto valueType = TestType::createValueType();
198 auto functionType = FunctionType::Create({ valueType }, { valueType });
199
200 Graph rvsdg;
201 auto & i0 = GraphImport::Create(rvsdg, valueType, "i0");
202
203 const auto lambdaNode =
204 LambdaNode::Create(rvsdg.GetRootRegion(), std::make_unique<LambdaOperation>(functionType));
205
206 const auto controlConstant = &ControlConstantOperation::create(*lambdaNode->subregion(), 2, 0);
207 const auto gammaNode = GammaNode::create(controlConstant, 2);
208
209 // Act
210 const auto & output = RouteToRegion(i0, *gammaNode->subregion(0));
211
212 // Assert
213 EXPECT_EQ(output.region(), gammaNode->subregion(0));
214 EXPECT_EQ(gammaNode->GetEntryVars().size(), 1u);
215 EXPECT_EQ(gammaNode->GetExitVars().size(), 0u);
216 EXPECT_EQ(&output, gammaNode->GetEntryVars()[0].branchArgument[0]);
217
218 auto origin = gammaNode->GetEntryVars()[0].input->origin();
219 EXPECT_EQ(lambdaNode->GetContextVars().size(), 1u);
220 EXPECT_EQ(origin, lambdaNode->GetContextVars()[0].inner);
221}
222
223TEST(OutputTests, RouteToRegion_Failure)
224{
225 using namespace jlm::rvsdg;
226
227 // Arrange
228 const auto controlType = ControlType::Create(2);
229 const auto valueType = TestType::createValueType();
230
231 Graph rvsdg;
232 auto & i0 = GraphImport::Create(rvsdg, valueType, "i0");
233 auto & i1 = GraphImport::Create(rvsdg, controlType, "i1");
234
235 const auto gammaNode = GammaNode::create(&i1, 2);
236 auto entryVar = gammaNode->AddEntryVar(&i0);
237
238 // Act & Assert
239 EXPECT_THROW(
240 RouteToRegion(*entryVar.branchArgument[0], *gammaNode->subregion(1)),
241 std::logic_error);
242}
243
244TEST(OutputTests, DivertUsersWhere)
245{
246 using namespace jlm::rvsdg;
247
248 // Assert
249 const auto valueType = TestType::createValueType();
250
251 Graph rvsdg;
252 auto & i0 = GraphImport::Create(rvsdg, valueType, "i0");
253 auto & i1 = GraphImport::Create(rvsdg, valueType, "i1");
254
255 auto & x0 = GraphExport::Create(i0, "x0");
256 auto & x1 = GraphExport::Create(i0, "x1");
257 auto & x2 = GraphExport::Create(i0, "x2");
258 auto & x3 = GraphExport::Create(i0, "x3");
259
260 // Act & Assert
261
262 // The new origin is the same as the old origin. Nothing should happen.
263 auto numDivertedUsers = i0.divertUsersWhere(
264 i0,
265 [](const Input &)
266 {
267 return true;
268 });
269 EXPECT_EQ(numDivertedUsers, 0u);
270 EXPECT_EQ(i0.nusers(), 4u);
271
272 // Divert user x0 to new origin i0
273 numDivertedUsers = i0.divertUsersWhere(
274 i1,
275 [&x0](const Input & user)
276 {
277 return &user == &x0;
278 });
279 EXPECT_EQ(numDivertedUsers, 1u);
280 EXPECT_EQ(i0.nusers(), 3u);
281 EXPECT_EQ(x0.origin(), &i1);
282
283 // Nothing should happen as x0 is no longer a user of i0
284 numDivertedUsers = i0.divertUsersWhere(
285 i1,
286 [&x0](const Input & user)
287 {
288 return &user == &x0;
289 });
290 EXPECT_EQ(numDivertedUsers, 0u);
291 EXPECT_EQ(i0.nusers(), 3u);
292
293 // Divert users x1 and x2 to i1
294 numDivertedUsers = i0.divertUsersWhere(
295 i1,
296 [&x1, &x2](const Input & user)
297 {
298 return &user == &x1 || &user == &x2;
299 });
300 EXPECT_EQ(numDivertedUsers, 2u);
301 EXPECT_EQ(i0.nusers(), 1u);
302 EXPECT_EQ(x1.origin(), &i1);
303 EXPECT_EQ(x2.origin(), &i1);
304
305 // Finally, divert user x3 to i1
306 numDivertedUsers = i0.divertUsersWhere(
307 i1,
308 [&x3](const Input & user)
309 {
310 return &user == &x3;
311 });
312 EXPECT_EQ(numDivertedUsers, 1u);
313 EXPECT_EQ(i0.nusers(), 0u);
314 EXPECT_EQ(x3.origin(), &i1);
315}
TEST(OutputTests, TestOutputIterator)
Region & GetRootRegion() const noexcept
Definition graph.hpp:99
PhiNode * end()
Definition Phi.cpp:270
void begin(rvsdg::Region *parent)
Definition Phi.hpp:355