Jlm
Loading...
Searching...
No Matches
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
12#include <jlm/rvsdg/theta.hpp>
13#include <jlm/rvsdg/view.hpp>
14#include <jlm/util/HashSet.hpp>
15
16TEST(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
95TEST(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
171TEST(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
205TEST(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
239TEST(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
271TEST(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 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
NodeOutput * output(size_t index) const noexcept
Definition node.hpp:650
OutputIteratorRange Outputs() noexcept
Definition node.hpp:657
InputIteratorRange Inputs() noexcept
Definition node.hpp:622
size_t noutputs() const noexcept
Definition node.hpp:644
const std::vector< size_t > & destroyedInputIndices() const noexcept
Definition region.hpp:964
size_t RemoveResults(const util::HashSet< size_t > &indices)
Definition region.cpp:281
TopNodeRange TopNodes() noexcept
Definition region.hpp:356
size_t numTopNodes() const noexcept
Definition region.hpp:519
bool insert(ItemType item)
Definition HashSet.hpp:210
std::size_t Size() const noexcept
Definition HashSet.hpp:187