Jlm
Loading...
Searching...
No Matches
TraverserTests.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
11
12TEST(TopDownTraverserTests, testInitialization)
13{
14 using namespace jlm::rvsdg;
15
17
19 auto i = &jlm::rvsdg::GraphImport::Create(graph, vtype, "i");
20
21 auto constant = TestOperation::createNode(&graph.GetRootRegion(), {}, { vtype });
22 auto unary = TestOperation::createNode(&graph.GetRootRegion(), { i }, { vtype });
23 auto binary =
24 TestOperation::createNode(&graph.GetRootRegion(), { i, unary->output(0) }, { vtype });
25
26 jlm::rvsdg::GraphExport::Create(*constant->output(0), "c");
27 jlm::rvsdg::GraphExport::Create(*unary->output(0), "u");
28 jlm::rvsdg::GraphExport::Create(*binary->output(0), "b");
29
30 bool unary_visited = false;
31 bool binary_visited = false;
32 bool constant_visited = false;
33 for (const auto & node : jlm::rvsdg::TopDownTraverser(&graph.GetRootRegion()))
34 {
35 if (node == unary)
36 unary_visited = true;
37 if (node == constant)
38 constant_visited = true;
39 if (node == binary && unary_visited)
40 binary_visited = true;
41 }
42
43 EXPECT_TRUE(unary_visited);
44 EXPECT_TRUE(binary_visited);
45 EXPECT_TRUE(constant_visited);
46}
47
48TEST(TopDownTraverserTests, testBasicTraversal)
49{
50 using namespace jlm::rvsdg;
51
54
55 auto n1 = TestOperation::createNode(&graph.GetRootRegion(), {}, { type, type });
56 auto n2 =
57 TestOperation::createNode(&graph.GetRootRegion(), { n1->output(0), n1->output(1) }, { type });
58
59 jlm::rvsdg::GraphExport::Create(*n2->output(0), "dummy");
60
61 {
62 const jlm::rvsdg::Node * tmp = nullptr;
64
65 tmp = trav.next();
66 EXPECT_EQ(tmp, n1);
67 tmp = trav.next();
68 EXPECT_EQ(tmp, n2);
69 tmp = trav.next();
70 EXPECT_EQ(tmp, nullptr);
71 }
72}
73
74TEST(TopDownTraverserTests, testOrderEnforcement)
75{
76 using namespace jlm::rvsdg;
77
80
81 auto n1 = TestOperation::createNode(&graph.GetRootRegion(), {}, { type, type });
82 auto n2 = TestOperation::createNode(&graph.GetRootRegion(), { n1->output(0) }, { type });
83 auto n3 =
84 TestOperation::createNode(&graph.GetRootRegion(), { n2->output(0), n1->output(1) }, { type });
85
86 {
87 const jlm::rvsdg::Node * tmp = nullptr;
89
90 tmp = trav.next();
91 EXPECT_EQ(tmp, n1);
92 tmp = trav.next();
93 EXPECT_EQ(tmp, n2);
94 tmp = trav.next();
95 EXPECT_EQ(tmp, n3);
96 tmp = trav.next();
97 EXPECT_EQ(tmp, nullptr);
98 }
99}
100
101TEST(TopDownTraverserTests, testInsertion)
102{
135 using namespace jlm::rvsdg;
136
137 jlm::rvsdg::Graph graph;
139
140 auto n1 = TestOperation::createNode(&graph.GetRootRegion(), {}, { type, type });
141 auto n2 =
142 TestOperation::createNode(&graph.GetRootRegion(), { n1->output(0), n1->output(1) }, { type });
143 auto n3 = TestOperation::createNode(&graph.GetRootRegion(), { n2->output(0) }, { type });
144
145 auto & graphExport = jlm::rvsdg::GraphExport::Create(*n3->output(0), "dummy");
146
147 {
148 const jlm::rvsdg::Node * node = nullptr;
150
151 node = trav.next();
152 EXPECT_EQ(node, n1);
153
154 /* At this point, n1 has been visited, make the transformation */
155
156 auto nX = TestOperation::createNode(&graph.GetRootRegion(), { n1->output(0) }, { type });
157 n3->input(0)->divert_to(n1->output(1));
158 auto nY = TestOperation::createNode(&graph.GetRootRegion(), { n3->output(0) }, { type });
159
160 n2->input(0)->divert_to(nX->output(0));
161 n2->input(1)->divert_to(nY->output(0));
162
163 graphExport.divert_to(n2->output(0));
164
165 // The newly created nX and nY should not be visited, but n3 must come before n2
166
167 node = trav.next();
168 EXPECT_EQ(node, n3);
169 node = trav.next();
170 EXPECT_EQ(node, n2);
171 node = trav.next();
172 EXPECT_EQ(node, nullptr);
173 }
174}
175
176TEST(TopDownTraverserTests, testInsertingTopNode)
177{
178 // Starts with a graph like
179 // n1 -> n2 -> GraphExport
180 //
181 // when n1 is visited, the graph is converted into
182 //
183 // n1
184 // nX -> n2 -> GraphExport
185 //
186 // Since nX is created without any unvisited predecessors, it should not be visited.
187 // n2 should be visited, however.
188
189 using namespace jlm::rvsdg;
190
191 jlm::rvsdg::Graph graph;
193
194 auto n1 = TestOperation::createNode(&graph.GetRootRegion(), {}, { type });
195 auto n2 = TestOperation::createNode(&graph.GetRootRegion(), { n1->output(0) }, { type });
196
197 jlm::rvsdg::GraphExport::Create(*n2->output(0), "dummy");
198
199 // Act and assert
201 auto node = trav.next();
202 EXPECT_EQ(node, n1);
203
204 auto nX = TestOperation::createNode(&graph.GetRootRegion(), {}, { type });
205 n1->output(0)->divert_users(nX->output(0));
206
207 node = trav.next();
208 EXPECT_EQ(node, n2);
209
210 node = trav.next();
211 EXPECT_EQ(node, nullptr);
212}
213
214TEST(TopDownTraverserTests, testMutating)
215{
216 using namespace jlm::rvsdg;
217
218 auto test = [](jlm::rvsdg::Graph * graph,
219 jlm::rvsdg::Node * n1,
220 jlm::rvsdg::Node * n2,
221 jlm::rvsdg::Node * n3)
222 {
223 bool seen_n1 = false;
224 bool seen_n2 = false;
225 bool seen_n3 = false;
226
227 for (const auto & tmp : jlm::rvsdg::TopDownTraverser(&graph->GetRootRegion()))
228 {
229 seen_n1 = seen_n1 || (tmp == n1);
230 seen_n2 = seen_n2 || (tmp == n2);
231 seen_n3 = seen_n3 || (tmp == n3);
232 if (n3->input(0)->origin() == n1->output(0))
233 n3->input(0)->divert_to(n2->output(0));
234 else
235 n3->input(0)->divert_to(n1->output(0));
236 }
237
238 EXPECT_TRUE(seen_n1);
239 EXPECT_TRUE(seen_n2);
240 EXPECT_TRUE(seen_n3);
241 };
242
243 jlm::rvsdg::Graph graph;
245 auto n1 = TestOperation::createNode(&graph.GetRootRegion(), {}, { type });
246 auto n2 = TestOperation::createNode(&graph.GetRootRegion(), {}, { type });
247 auto n3 = TestOperation::createNode(&graph.GetRootRegion(), { n1->output(0) }, {});
248
249 test(&graph, n1, n2, n3);
250 test(&graph, n1, n2, n3);
251}
252
253TEST(TopDownTraverserTests, testReplacement)
254{
255 // Starts with a graph like
256 // n1 -> n2 -> n3 -> n4 -> GraphExport
257 // \-> n5 -> GraphExport
258 //
259 // when n2 is visited, the graph is converted into
260 //
261 // n1 -> n2 -> n3
262 // \-> nX -> nY -> n4 -> GraphExport
263 // \-> n5 -> GraphExport
264 //
265 // Since nX and nY are new, they are not visited.
266 // n3, n4 and n5 should be visited, however.
267
268 using namespace jlm::rvsdg;
269
270 jlm::rvsdg::Graph graph;
272
273 auto n1 = TestOperation::createNode(&graph.GetRootRegion(), {}, { type });
274 auto n2 = TestOperation::createNode(&graph.GetRootRegion(), { n1->output(0) }, { type });
275 auto n3 = TestOperation::createNode(&graph.GetRootRegion(), { n2->output(0) }, { type });
276 auto n4 = TestOperation::createNode(&graph.GetRootRegion(), { n3->output(0) }, { type });
277 auto n5 = TestOperation::createNode(&graph.GetRootRegion(), { n2->output(0) }, { type });
278
279 jlm::rvsdg::GraphExport::Create(*n4->output(0), "dummy");
280
281 // Act and assert
283 auto node = trav.next();
284 EXPECT_EQ(node, n1);
285
286 node = trav.next();
287 EXPECT_EQ(node, n2);
288 auto nX = TestOperation::createNode(&graph.GetRootRegion(), { n1->output(0) }, { type });
289 auto nY = TestOperation::createNode(&graph.GetRootRegion(), { nX->output(0) }, { type });
290 n3->output(0)->divert_users(nY->output(0));
291 n5->input(0)->divert_to(nX->output(0));
292
293 auto next1 = trav.next();
294 auto next2 = trav.next();
295 auto next3 = trav.next();
296 EXPECT_TRUE(n3 == next1 || n3 == next2 || n3 == next3);
297 EXPECT_TRUE(n4 == next1 || n4 == next2 || n4 == next3);
298 EXPECT_TRUE(n5 == next1 || n5 == next2 || n5 == next3);
299
300 auto next4 = trav.next();
301 EXPECT_EQ(next4, nullptr);
302}
303
304TEST(BottomUpTraverserTests, testInitialization)
305{
306 using namespace jlm::rvsdg;
307
308 jlm::rvsdg::Graph graph;
310 auto n1 = TestOperation::createNode(&graph.GetRootRegion(), {}, {});
311 auto n2 = TestOperation::createNode(&graph.GetRootRegion(), {}, { vtype });
312
313 jlm::rvsdg::GraphExport::Create(*n2->output(0), "dummy");
314
315 bool n1_visited = false;
316 bool n2_visited = false;
317 for (const auto & node : jlm::rvsdg::BottomUpTraverser(&graph.GetRootRegion()))
318 {
319 if (node == n1)
320 n1_visited = true;
321 if (node == n2)
322 n2_visited = true;
323 }
324
325 EXPECT_TRUE(n1_visited);
326 EXPECT_TRUE(n2_visited);
327}
328
329TEST(BottomUpTraverserTests, testBasicTraversal)
330{
331 using namespace jlm::rvsdg;
332
333 jlm::rvsdg::Graph graph;
335 auto n1 = TestOperation::createNode(&graph.GetRootRegion(), {}, { type, type });
336 auto n2 =
337 TestOperation::createNode(&graph.GetRootRegion(), { n1->output(0), n1->output(1) }, { type });
338
339 jlm::rvsdg::GraphExport::Create(*n2->output(0), "dummy");
340
341 {
342 const jlm::rvsdg::Node * tmp = nullptr;
344 tmp = trav.next();
345 EXPECT_EQ(tmp, n2);
346 tmp = trav.next();
347 EXPECT_EQ(tmp, n1);
348 tmp = trav.next();
349 EXPECT_EQ(tmp, nullptr);
350 }
351}
352
353TEST(BottomUpTraverserTests, testOrderEnforcement)
354{
355 using namespace jlm::rvsdg;
356
357 jlm::rvsdg::Graph graph;
359 auto n1 = TestOperation::createNode(&graph.GetRootRegion(), {}, { type, type });
360 auto n2 = TestOperation::createNode(&graph.GetRootRegion(), { n1->output(0) }, { type });
361 auto n3 =
362 TestOperation::createNode(&graph.GetRootRegion(), { n2->output(0), n1->output(1) }, { type });
363
364 {
365 const jlm::rvsdg::Node * tmp = nullptr;
367
368 tmp = trav.next();
369 EXPECT_EQ(tmp, n3);
370 tmp = trav.next();
371 EXPECT_EQ(tmp, n2);
372 tmp = trav.next();
373 EXPECT_EQ(tmp, n1);
374 tmp = trav.next();
375 EXPECT_EQ(tmp, nullptr);
376 }
377}
TEST(TopDownTraverserTests, testInitialization)
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 std::shared_ptr< const TestType > createValueType()
Definition TestType.cpp:67
detail::BottomUpTraverserGeneric< false > BottomUpTraverser
Traverser for visiting every node in a region in a bottom up order.
detail::TopDownTraverserGeneric< false > TopDownTraverser
Traverser for visiting every node in a region in a top down order.