Jlm
NodeTests.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 #include <jlm/rvsdg/TestType.hpp>
12 #include <jlm/rvsdg/theta.hpp>
13 #include <jlm/rvsdg/view.hpp>
14 #include <jlm/util/HashSet.hpp>
15 
16 TEST(NodeTests, RemoveOutputs)
17 {
18  using namespace jlm::rvsdg;
19 
20  // Arrange
21  const auto valueType = TestType::createValueType();
22 
23  Graph rvsdg;
24  auto node = TestOperation::createNode(
25  &rvsdg.GetRootRegion(),
26  {},
27  std::vector<std::shared_ptr<const Type>>{ valueType,
28  valueType,
29  valueType,
30  valueType,
31  valueType,
32  valueType,
33  valueType,
34  valueType,
35  valueType,
36  valueType });
37 
38  auto & x1 = GraphExport::Create(*node->output(1), "x1");
39  auto & x2 = GraphExport::Create(*node->output(2), "x2");
40  auto & x3 = GraphExport::Create(*node->output(3), "x3");
41  auto & x4 = GraphExport::Create(*node->output(4), "x4");
42  auto & x5 = GraphExport::Create(*node->output(5), "x5");
43  auto & x6 = GraphExport::Create(*node->output(6), "x6");
44  auto & x7 = GraphExport::Create(*node->output(7), "x7");
45  auto & x9 = GraphExport::Create(*node->output(9), "x9");
46 
47  // Act & Assert
48  // Remove all outputs that have an even index
49  size_t numRemovedOutputs = node->RemoveOutputs({ 0, 2, 4, 6, 8 });
50  // We expect only output0 and output8 to be removed, as output2, output4, and
51  // output6 are not dead
52  EXPECT_EQ(numRemovedOutputs, 2u);
53  EXPECT_EQ(node->noutputs(), 8u);
54  EXPECT_EQ(x1.origin()->index(), 0u);
55  EXPECT_EQ(x2.origin()->index(), 1u);
56  EXPECT_EQ(x3.origin()->index(), 2u);
57  EXPECT_EQ(x4.origin()->index(), 3u);
58  EXPECT_EQ(x5.origin()->index(), 4u);
59  EXPECT_EQ(x6.origin()->index(), 5u);
60  EXPECT_EQ(x7.origin()->index(), 6u);
61  EXPECT_EQ(x9.origin()->index(), 7u);
62 
63  // Remove all users from outputs
64  rvsdg.GetRootRegion().RemoveResults({ 0, 1, 2, 3, 4, 5, 6, 7 });
65 
66  // Remove all outputs that have an even index
67  numRemovedOutputs = node->RemoveOutputs({ 0, 2, 4, 6 });
68  EXPECT_EQ(numRemovedOutputs, 4u);
69  EXPECT_EQ(node->noutputs(), 4u);
70  EXPECT_EQ(node->output(0)->index(), 0u);
71  EXPECT_EQ(node->output(1)->index(), 1u);
72  EXPECT_EQ(node->output(2)->index(), 2u);
73  EXPECT_EQ(node->output(3)->index(), 3u);
74 
75  // Remove no output
76  numRemovedOutputs = node->RemoveOutputs({});
77  EXPECT_EQ(numRemovedOutputs, 0u);
78  EXPECT_EQ(node->noutputs(), 4u);
79  EXPECT_EQ(node->output(0)->index(), 0u);
80  EXPECT_EQ(node->output(1)->index(), 1u);
81  EXPECT_EQ(node->output(2)->index(), 2u);
82  EXPECT_EQ(node->output(3)->index(), 3u);
83 
84  // Remove non-existent output
85  numRemovedOutputs = node->RemoveOutputs({ 15 });
86  EXPECT_EQ(numRemovedOutputs, 0u);
87  EXPECT_EQ(node->noutputs(), 4u);
88 
89  // Remove all remaining outputs
90  numRemovedOutputs = node->RemoveOutputs({ 0, 1, 2, 3 });
91  EXPECT_EQ(numRemovedOutputs, 4u);
92  EXPECT_EQ(node->noutputs(), 0u);
93 }
94 
95 TEST(NodeTests, RemoveInputs)
96 {
97  using namespace jlm::rvsdg;
98 
99  // Arrange
100  Graph rvsdg;
101  const RecordingObserver observer(rvsdg.GetRootRegion());
102  const auto valueType = TestType::createValueType();
103 
104  auto i0 = &GraphImport::Create(rvsdg, valueType, "i0");
105  auto i1 = &GraphImport::Create(rvsdg, valueType, "i1");
106  auto i2 = &GraphImport::Create(rvsdg, valueType, "i2");
107  auto i3 = &GraphImport::Create(rvsdg, valueType, "i3");
108  auto i4 = &GraphImport::Create(rvsdg, valueType, "i4");
109  auto i5 = &GraphImport::Create(rvsdg, valueType, "i5");
110  auto i6 = &GraphImport::Create(rvsdg, valueType, "i6");
111  auto i7 = &GraphImport::Create(rvsdg, valueType, "i7");
112  auto i8 = &GraphImport::Create(rvsdg, valueType, "i8");
113  auto i9 = &GraphImport::Create(rvsdg, valueType, "i9");
114 
115  auto node = TestOperation::createNode(
116  &rvsdg.GetRootRegion(),
117  { i0, i1, i2, i3, i4, i5, i6, i7, i8, i9 },
118  {});
119 
120  // Act & Assert
121  EXPECT_EQ(rvsdg.GetRootRegion().numTopNodes(), 0u);
122 
123  // Remove all inputs that have an even index
124  size_t numRemovedInputs = node->RemoveInputs({ 0, 2, 4, 6, 8 });
125  EXPECT_EQ(numRemovedInputs, 5u);
126  EXPECT_EQ(node->ninputs(), 5u);
127  EXPECT_EQ(node->input(0)->origin(), i1);
128  EXPECT_EQ(node->input(1)->origin(), i3);
129  EXPECT_EQ(node->input(2)->origin(), i5);
130  EXPECT_EQ(node->input(3)->origin(), i7);
131  EXPECT_EQ(node->input(4)->origin(), i9);
132  EXPECT_EQ(i0->nusers(), 0u);
133  EXPECT_EQ(i2->nusers(), 0u);
134  EXPECT_EQ(i4->nusers(), 0u);
135  EXPECT_EQ(i6->nusers(), 0u);
136  EXPECT_EQ(i8->nusers(), 0u);
137  // We specified that the region is notified about the input removal
138  EXPECT_EQ(observer.destroyedInputIndices(), std::vector<size_t>({ 0, 2, 4, 6, 8 }));
139 
140  // Remove no input
141  numRemovedInputs = node->RemoveInputs({});
142  EXPECT_EQ(numRemovedInputs, 0u);
143  EXPECT_EQ(node->ninputs(), 5u);
144  EXPECT_EQ(observer.destroyedInputIndices(), std::vector<size_t>({ 0, 2, 4, 6, 8 }));
145 
146  // Remove non-existent input
147  numRemovedInputs = node->RemoveInputs({ 15 });
148  EXPECT_EQ(numRemovedInputs, 0u);
149  EXPECT_EQ(node->ninputs(), 5u);
150  EXPECT_EQ(observer.destroyedInputIndices(), std::vector<size_t>({ 0, 2, 4, 6, 8 }));
151 
152  // Remove remaining inputs
153  numRemovedInputs = node->RemoveInputs({ 0, 1, 2, 3, 4 });
154  EXPECT_EQ(numRemovedInputs, 5u);
155  EXPECT_EQ(node->ninputs(), 0u);
156  EXPECT_EQ(i1->nusers(), 0u);
157  EXPECT_EQ(i3->nusers(), 0u);
158  EXPECT_EQ(i5->nusers(), 0u);
159  EXPECT_EQ(i7->nusers(), 0u);
160  EXPECT_EQ(i9->nusers(), 0u);
161  // We specified that the region is not notified about the input removal
162  EXPECT_EQ(
163  observer.destroyedInputIndices(),
164  std::vector<size_t>({ 0, 2, 4, 6, 8, 0, 1, 2, 3, 4 }));
165 
166  // Check that node is a top node
167  EXPECT_EQ(rvsdg.GetRootRegion().numTopNodes(), 1u);
168  EXPECT_EQ(&*rvsdg.GetRootRegion().TopNodes().begin(), node);
169 }
170 
171 TEST(NodeTests, NodeInputIteration)
172 {
173  using namespace jlm::rvsdg;
174 
175  // Arrange
176  const auto valueType = TestType::createValueType();
177 
178  Graph rvsdg;
179  auto i = &jlm::rvsdg::GraphImport::Create(rvsdg, valueType, "i");
180 
181  auto & node = CreateOpNode<TestOperation>(
182  { i, i, i, i, i },
183  std::vector<std::shared_ptr<const Type>>(5, valueType),
184  std::vector<std::shared_ptr<const Type>>{ valueType });
185 
186  GraphExport::Create(*node.output(0), "x0");
187 
188  // Act & Assert
189  size_t n = 0;
190  for (auto & input : node.Inputs())
191  {
192  EXPECT_EQ(&input, node.input(n++));
193  }
194  EXPECT_EQ(n, node.ninputs());
195 
196  n = 0;
197  const Node * constNode = &node;
198  for (auto & input : constNode->Inputs())
199  {
200  EXPECT_EQ(&input, node.input(n++));
201  }
202  EXPECT_EQ(n, node.ninputs());
203 }
204 
205 TEST(NodeTests, NodeOutputIteration)
206 {
207  using namespace jlm::rvsdg;
208 
209  // Arrange
210  const auto valueType = TestType::createValueType();
211 
212  Graph rvsdg;
213  auto i = &jlm::rvsdg::GraphImport::Create(rvsdg, valueType, "i");
214 
215  auto & node = CreateOpNode<TestOperation>(
216  { i },
217  std::vector<std::shared_ptr<const Type>>{ valueType },
218  std::vector<std::shared_ptr<const Type>>(5, valueType));
219 
220  GraphExport::Create(*node.output(0), "x0");
221 
222  // Act & Assert
223  size_t n = 0;
224  for (auto & output : node.Outputs())
225  {
226  EXPECT_EQ(&output, node.output(n++));
227  }
228  EXPECT_EQ(n, node.noutputs());
229 
230  n = 0;
231  const Node * constNode = &node;
232  for (auto & output : constNode->Outputs())
233  {
234  EXPECT_EQ(&output, constNode->output(n++));
235  }
236  EXPECT_EQ(n, constNode->noutputs());
237 }
238 
239 TEST(NodeTests, zeroInputOutputIteration)
240 {
241  using namespace jlm::rvsdg;
242 
243  // Arrange
244  Graph rvsdg;
245  auto node = TestOperation::createNode(&rvsdg.GetRootRegion(), {}, {});
246 
247  // Act & Assert
248  bool enteredLoopBody = false;
249  for ([[maybe_unused]] auto & _ : node->Inputs())
250  {
251  enteredLoopBody = true;
252  }
253  for ([[maybe_unused]] auto & _ : node->Outputs())
254  {
255  enteredLoopBody = true;
256  }
257 
258  const Node * constNode = node;
259  for ([[maybe_unused]] auto & _ : constNode->Inputs())
260  {
261  enteredLoopBody = true;
262  }
263  for ([[maybe_unused]] auto & _ : constNode->Outputs())
264  {
265  enteredLoopBody = true;
266  }
267 
268  EXPECT_FALSE(enteredLoopBody);
269 }
270 
271 TEST(NodeTests, NodeId)
272 {
273  using namespace jlm::rvsdg;
274  using namespace jlm::util;
275 
276  // Arrange & Act & Assert
277  Graph rvsdg1;
278  HashSet<Node::Id> NodeIds;
279 
280  auto node0 = TestOperation::createNode(&rvsdg1.GetRootRegion(), {}, {});
281  auto node1 = TestOperation::createNode(&rvsdg1.GetRootRegion(), {}, {});
282  auto node2 = TestOperation::createNode(&rvsdg1.GetRootRegion(), {}, {});
283 
284  NodeIds.insert(node0->GetNodeId());
285  NodeIds.insert(node1->GetNodeId());
286  NodeIds.insert(node2->GetNodeId());
287 
288  // We should have three unique identifiers in the set
289  EXPECT_EQ(NodeIds.Size(), 3u);
290 
291  // The identifiers should be consecutive as no other nodes where created in between those
292  // three nodes
293  EXPECT_EQ(node0->GetNodeId(), 0u);
294  EXPECT_EQ(node1->GetNodeId(), 1u);
295  EXPECT_EQ(node2->GetNodeId(), 2u);
296 
297  // Removing a node should not change the identifiers of the other nodes
298  remove(node1);
299  EXPECT_EQ(node0->GetNodeId(), 0u);
300  EXPECT_EQ(node2->GetNodeId(), 2u);
301 
302  // Adding a new node should give us the next identifier as no other nodes have been created in
303  // between
304  auto node3 = TestOperation::createNode(&rvsdg1.GetRootRegion(), {}, {});
305  EXPECT_EQ(node3->GetNodeId(), 3u);
306 
307  // Identifiers should be only unique for each region
308  Graph rvsdg2;
309  auto node4 = TestOperation::createNode(&rvsdg2.GetRootRegion(), {}, {});
310  EXPECT_EQ(node4->GetNodeId(), 0u);
311 }
TEST(NodeTests, RemoveOutputs)
Definition: NodeTests.cpp:16
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
OutputIteratorRange Outputs() noexcept
Definition: node.hpp:657
InputIteratorRange Inputs() noexcept
Definition: node.hpp:622
NodeOutput * output(size_t index) const noexcept
Definition: node.hpp:650
size_t noutputs() const noexcept
Definition: node.hpp:644
const std::vector< size_t > & destroyedInputIndices() const noexcept
Definition: region.hpp:907
size_t RemoveResults(const util::HashSet< size_t > &indices)
Definition: region.cpp:278
TopNodeRange TopNodes() noexcept
Definition: region.hpp:309
size_t numTopNodes() const noexcept
Definition: region.hpp:490
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
bool insert(ItemType item)
Definition: HashSet.hpp:210
std::size_t Size() const noexcept
Definition: HashSet.hpp:187
static void remove(Node *node)
Definition: region.hpp:978