Jlm
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 
8 #include <jlm/rvsdg/control.hpp>
9 #include <jlm/rvsdg/delta.hpp>
10 #include <jlm/rvsdg/gamma.hpp>
11 #include <jlm/rvsdg/lambda.hpp>
12 #include <jlm/rvsdg/Phi.hpp>
14 #include <jlm/rvsdg/TestType.hpp>
15 #include <jlm/rvsdg/theta.hpp>
16 
17 TEST(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 
78 TEST(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 
101 TEST(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 
122 TEST(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 
145 TEST(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 
168 TEST(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 
191 TEST(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 
223 TEST(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 
244 TEST(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)
Definition: OutputTests.cpp:17
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 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 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
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:140
PhiNode * end()
Definition: Phi.cpp:270
void begin(rvsdg::Region *parent)
Definition: Phi.hpp:355
static std::shared_ptr< const TestType > createValueType()
Definition: TestType.cpp:67
static ThetaNode * create(rvsdg::Region *parent)
Definition: theta.hpp:73
Output & RouteToRegion(Output &output, Region &region)
Definition: node.cpp:381