Jlm
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 
9 #include <jlm/rvsdg/TestType.hpp>
10 #include <jlm/rvsdg/traverser.hpp>
11 
12 TEST(TopDownTraverserTests, testInitialization)
13 {
14  using namespace jlm::rvsdg;
15 
17 
18  jlm::rvsdg::Graph graph;
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 
48 TEST(TopDownTraverserTests, testBasicTraversal)
49 {
50  using namespace jlm::rvsdg;
51 
52  jlm::rvsdg::Graph graph;
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 
74 TEST(TopDownTraverserTests, testOrderEnforcement)
75 {
76  using namespace jlm::rvsdg;
77 
78  jlm::rvsdg::Graph graph;
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 
101 TEST(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 
176 TEST(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 
214 TEST(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 
253 TEST(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 
304 TEST(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 
329 TEST(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 
353 TEST(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 SimpleNode * createNode(Region *region, const std::vector< Output * > &operands, std::vector< std::shared_ptr< const Type >> resultTypes)
static std::shared_ptr< const TestType > createValueType()
Definition: TestType.cpp:67