Jlm
Loading...
Searching...
No Matches
node.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2010 2011 2012 2014 2015 Helge Bahmann <hcb@chaoticmind.net>
3 * Copyright 2012 2013 2014 2015 2016 Nico Reißmann <nico.reissmann@gmail.com>
4 * See COPYING for terms of redistribution.
5 */
6
7#include <jlm/rvsdg/delta.hpp>
8#include <jlm/rvsdg/gamma.hpp>
11#include <jlm/rvsdg/Phi.hpp>
12#include <jlm/rvsdg/region.hpp>
14#include <jlm/rvsdg/theta.hpp>
15
16namespace jlm::rvsdg
17{
18
23
24void
26 const Region & region,
27 const Output & origin,
28 const std::shared_ptr<const rvsdg::Type> & type)
29{
30 if (&region != origin.region())
31 throw util::Error("Invalid operand region.");
32
33 if (*type != *origin.Type())
34 throw util::TypeError(type->debug_string(), origin.Type()->debug_string());
35}
36
37Input::Input(rvsdg::Node & owner, rvsdg::Output & origin, std::shared_ptr<const rvsdg::Type> type)
38 : index_(0),
39 Owner_(&owner),
40 Type_(std::move(type)),
41 UsersList_()
42{
43 CheckTypes(*owner.region(), origin, Type_);
44 origin.add_user(this);
45}
46
47Input::Input(rvsdg::Region & owner, rvsdg::Output & origin, std::shared_ptr<const rvsdg::Type> type)
48 : index_(0),
49 Owner_(&owner),
50 Type_(std::move(type)),
51 UsersList_()
52{
54 origin.add_user(this);
55}
56
57std::string
59{
60 return jlm::util::strfmt("i", index());
61}
62
63void
65{
66 if (origin() == new_origin)
67 return;
68
69 if (*Type() != *new_origin->Type())
70 throw jlm::util::TypeError(Type()->debug_string(), new_origin->Type()->debug_string());
71
72 if (region() != new_origin->region())
73 throw util::Error("Invalid operand region.");
74
75 auto old_origin = origin();
76 old_origin->remove_user(this);
77 new_origin->add_user(this);
78
80}
81
84{
85 if (auto node = std::get_if<Node *>(&Owner_))
86 {
87 return (*node)->region();
88 }
89 else if (auto region = std::get_if<Region *>(&Owner_))
90 {
91 return *region;
92 }
93 else
94 {
95 JLM_UNREACHABLE("Unhandled owner case.");
96 }
97}
98
99static Input *
101{
102 if (input == nullptr)
103 return nullptr;
104
105 const auto index = input->index();
106 auto owner = input->GetOwner();
107
108 if (auto node = std::get_if<Node *>(&owner))
109 {
110 return index + 1 < (*node)->ninputs() ? (*node)->input(index + 1) : nullptr;
111 }
112
113 if (auto region = std::get_if<Region *>(&owner))
114 {
115 return index + 1 < (*region)->nresults() ? (*region)->result(index + 1) : nullptr;
116 }
117
118 JLM_UNREACHABLE("Unhandled owner case.");
119}
120
121Input *
126
127Input *
129{
130 return ComputeNextInput(Input_);
131}
132
134{
135 JLM_ASSERT(NumUsers_ == 0);
136}
137
138Output::Output(Node & owner, std::shared_ptr<const rvsdg::Type> type)
139 : index_(0),
140 Owner_(&owner),
141 Type_(std::move(type))
142{}
143
144Output::Output(rvsdg::Region * owner, std::shared_ptr<const rvsdg::Type> type)
145 : index_(0),
146 Owner_(owner),
147 Type_(std::move(type))
148{}
149
152{
153 if (auto node = std::get_if<Node *>(&Owner_))
154 {
155 return (*node)->region();
156 }
157 else if (auto region = std::get_if<Region *>(&Owner_))
158 {
159 return *region;
160 }
161 else
162 {
163 JLM_UNREACHABLE("Unhandled owner case.");
164 }
165}
166
167std::string
169{
170 return jlm::util::strfmt("o", index());
171}
172
173void
175{
176 JLM_ASSERT(user->origin_ == this);
177 user->origin_ = nullptr;
178
180 NumUsers_ -= 1;
181
182 if (auto node = TryGetOwnerNode<Node>(*this))
183 {
184 node->numSuccessors_ -= 1;
185 if (node->IsDead())
186 {
187 region()->onBottomNodeAdded(*node);
188 }
189 }
190}
191
192void
194{
195 JLM_ASSERT(user->origin_ == nullptr);
196 user->origin_ = this;
197
198 if (auto node = TryGetOwnerNode<Node>(*this))
199 {
200 if (node->IsDead())
201 {
202 region()->onBottomNodeRemoved(*node);
203 }
204 node->numSuccessors_ += 1;
205 }
206
208 NumUsers_ += 1;
209}
210
211static Output *
213{
214 if (output == nullptr)
215 return nullptr;
216
217 const auto index = output->index();
218 const auto owner = output->GetOwner();
219
220 if (const auto node = std::get_if<Node *>(&owner))
221 {
222 return index + 1 < (*node)->noutputs() ? (*node)->output(index + 1) : nullptr;
223 }
224
225 if (const auto region = std::get_if<Region *>(&owner))
226 {
227 return index + 1 < (*region)->narguments() ? (*region)->argument(index + 1) : nullptr;
228 }
229
230 JLM_UNREACHABLE("Unhandled owner case.");
231}
232
233Output *
238
239Output *
241{
242 return ComputeNextOutput(Output_);
243}
244
246 jlm::rvsdg::Output * origin,
247 Node * node,
248 std::shared_ptr<const rvsdg::Type> type)
249 : jlm::rvsdg::Input(*node, *origin, std::move(type))
250{}
251
252NodeOutput::NodeOutput(Node * node, std::shared_ptr<const rvsdg::Type> type)
253 : Output(*node, std::move(type))
254{}
255
257 : Id_(region->generateNodeId()),
258 region_(region)
259{
261 region->onTopNodeAdded(*this);
262 region->onNodeAdded(*this);
263}
264
266{
267 // Nodes should always be dead before they are removed
269 outputs_.clear();
270 region()->onBottomNodeRemoved(*this);
271
272 if (ninputs() == 0)
273 {
274 region()->onTopNodeRemoved(*this);
275 }
276 inputs_.clear();
277
278 region()->onNodeRemoved(*this);
279}
280
281Graph *
283{
284 return region_->graph();
285}
286
287NodeInput *
288Node::addInput(std::unique_ptr<NodeInput> input, bool notifyRegion)
289{
290 // If we used to be a top node, we no longer are
291 if (ninputs() == 0)
292 {
293 region()->onTopNodeRemoved(*this);
294 }
295
296 input->index_ = ninputs();
297 inputs_.push_back(std::move(input));
298 const auto inputPtr = inputs_.back().get();
299 if (notifyRegion)
301
302 return inputPtr;
303}
304
305size_t
307{
308 if (indices.IsEmpty())
309 {
310 return 0;
311 }
312
313 size_t numLiveInputs = 0;
314 size_t numRemovedInputs = 0;
315 for (size_t n = 0; n < ninputs(); n++)
316 {
317 auto & input = inputs_[n];
318 if (indices.Contains(input->index()))
319 {
321 input.reset();
323 }
324 else
325 {
327 inputs_[numLiveInputs++] = std::move(input);
328 }
329 }
330 inputs_.resize(numLiveInputs);
331
332 // If we no longer have any inputs we are now a top node
333 if (numLiveInputs == 0)
334 {
335 region()->onTopNodeAdded(*this);
336 }
337
338 return numRemovedInputs;
339}
340
341size_t
343{
344 if (indices.IsEmpty())
345 return 0;
346
347 size_t numLiveOutputs = 0;
348 size_t numRemovedOutputs = 0;
349 for (size_t n = 0; n < noutputs(); n++)
350 {
351 auto & output = outputs_[n];
352 if (output->IsDead() && indices.Contains(output->index()))
353 {
354 output.reset();
356 }
357 else
358 {
360 outputs_[numLiveOutputs++] = std::move(output);
361 }
362 }
363 outputs_.resize(numLiveOutputs);
364
365 return numRemovedOutputs;
366}
367
368Node *
369Node::copy(rvsdg::Region * region, const std::vector<jlm::rvsdg::Output *> & operands) const
370{
372
373 size_t noperands = std::min(operands.size(), ninputs());
374 for (size_t n = 0; n < noperands; n++)
375 smap.insert(input(n)->origin(), operands[n]);
376
377 return copy(region, smap);
378}
379
380Output &
381RouteToRegion(Output & output, Region & region)
382{
383 if (&region == output.region())
384 return output;
385
386 if (&region == &region.graph()->GetRootRegion())
387 {
388 // We reached the root region and have not found the outputs' region yet.
389 // This means that the output comes from a region in the region tree that
390 // is not an ancestor of "region".
391 throw std::logic_error("Output is not in an ancestor of region.");
392 }
393
394 auto & origin = RouteToRegion(output, *region.node()->region());
395
396 const auto newOrigin = MatchTypeOrFail(
397 *region.node(),
398 [&origin, &region](GammaNode & gammaNode)
399 {
400 auto [input, branchArgument] = gammaNode.AddEntryVar(&origin);
401 return branchArgument[region.index()];
402 },
403 [&origin](ThetaNode & thetaNode)
404 {
405 return thetaNode.AddLoopVar(&origin).pre;
406 },
407 [&origin](LambdaNode & lambdaNode)
408 {
409 return lambdaNode.AddContextVar(origin).inner;
410 },
411 [&origin](PhiNode & phiNode)
412 {
413 return phiNode.AddContextVar(origin).inner;
414 },
415 [&origin](DeltaNode & deltaNode)
416 {
417 return deltaNode.AddContextVar(origin).inner;
418 });
419
420 return *newOrigin;
421}
422
490}
Conditional operator / pattern matching.
Definition gamma.hpp:99
Region & GetRootRegion() const noexcept
Definition graph.hpp:99
Input * ComputeNext() const
Definition node.cpp:128
Input * ComputeNext() const
Definition node.cpp:122
std::variant< Node *, Region * > Owner_
Definition node.hpp:225
void divert_to(Output *new_origin)
Definition node.cpp:64
std::shared_ptr< const rvsdg::Type > Type_
Definition node.hpp:226
size_t index() const noexcept
Definition node.hpp:52
Input(Node &owner, Output &origin, std::shared_ptr< const rvsdg::Type > type)
Definition node.cpp:37
virtual std::string debug_string() const
Definition node.cpp:58
std::variant< Node *, Region * > GetOwner() const noexcept
Definition node.hpp:79
Output * origin() const noexcept
Definition node.hpp:58
const std::shared_ptr< const rvsdg::Type > & Type() const noexcept
Definition node.hpp:67
Region * region() const noexcept
Definition node.cpp:83
virtual ~Input() noexcept
Definition node.cpp:19
static void CheckTypes(const Region &region, const Output &origin, const std::shared_ptr< const rvsdg::Type > &type)
Definition node.cpp:25
NodeInput(Output *origin, Node *node, std::shared_ptr< const rvsdg::Type > type)
Definition node.cpp:245
NodeOutput(Node *node, std::shared_ptr< const rvsdg::Type > type)
Definition node.cpp:252
Graph * graph() const noexcept
Definition node.cpp:282
Node(Region *region)
Definition node.cpp:256
NodeInput * input(size_t index) const noexcept
Definition node.hpp:615
NodeOutput * output(size_t index) const noexcept
Definition node.hpp:650
Region * region_
Definition node.hpp:807
virtual ~Node()
Definition node.cpp:265
bool IsDead() const noexcept
Determines whether the node is dead.
Definition node.hpp:688
std::vector< std::unique_ptr< NodeInput > > inputs_
Definition node.hpp:808
std::vector< std::unique_ptr< NodeOutput > > outputs_
Definition node.hpp:809
size_t RemoveInputs(const util::HashSet< size_t > &indices)
Definition node.cpp:306
rvsdg::Region * region() const noexcept
Definition node.hpp:761
size_t ninputs() const noexcept
Definition node.hpp:609
size_t noutputs() const noexcept
Definition node.hpp:644
NodeInput * addInput(std::unique_ptr< NodeInput > input, bool notifyRegion)
Definition node.cpp:288
size_t RemoveOutputs(const util::HashSet< size_t > &indices)
Definition node.cpp:342
virtual Node * copy(rvsdg::Region *region, const std::vector< jlm::rvsdg::Output * > &operands) const
Definition node.cpp:369
Output * ComputeNext() const
Definition node.cpp:240
Output * ComputeNext() const
Definition node.cpp:234
std::size_t NumUsers_
Definition node.hpp:526
void add_user(jlm::rvsdg::Input *user)
Definition node.cpp:193
rvsdg::Region * region() const noexcept
Definition node.cpp:151
virtual ~Output() noexcept
Definition node.cpp:133
virtual std::string debug_string() const
Definition node.cpp:168
size_t index() const noexcept
Definition node.hpp:274
void remove_user(jlm::rvsdg::Input *user)
Definition node.cpp:174
std::variant< Node *, Region * > Owner_
Definition node.hpp:523
std::variant< Node *, Region * > GetOwner() const noexcept
Definition node.hpp:378
UsersList Users_
Definition node.hpp:525
bool IsDead() const noexcept
Definition node.hpp:295
const std::shared_ptr< const rvsdg::Type > & Type() const noexcept
Definition node.hpp:366
Output(Node &owner, std::shared_ptr< const rvsdg::Type > type)
Definition node.cpp:138
A phi node represents the fixpoint of mutually recursive definitions.
Definition Phi.hpp:46
Represent acyclic RVSDG subgraphs.
Definition region.hpp:213
Graph * graph() const noexcept
Definition region.hpp:267
void onNodeRemoved(Node &node)
Definition region.cpp:403
void onNodeAdded(Node &node)
Adds node to the list of nodes in the region.
Definition region.cpp:395
void notifyInputChange(Input *input, Output *old_origin, Output *new_origin)
Definition region.cpp:438
void onBottomNodeRemoved(Node &node)
Definition region.cpp:387
void onTopNodeRemoved(Node &node)
Definition region.cpp:370
rvsdg::StructuralNode * node() const noexcept
Definition region.hpp:301
void onTopNodeAdded(Node &node)
Adds node to the top nodes of the region.
Definition region.cpp:361
void notifyInputDestroy(Input *input)
Definition region.cpp:447
void notifyInputCreate(Input *input)
Definition region.cpp:429
void onBottomNodeAdded(Node &node)
Adds node to the set of bottom nodes in the region.
Definition region.cpp:378
bool Contains(const ItemType &item) const noexcept
Definition HashSet.hpp:150
bool IsEmpty() const noexcept
Definition HashSet.hpp:198
void erase(ElementType *element) noexcept
void push_back(ElementType *element) noexcept
#define JLM_ASSERT(x)
Definition common.hpp:16
#define JLM_UNREACHABLE(msg)
Definition common.hpp:43
static Output * ComputeNextOutput(const Output *output)
Definition node.cpp:212
void MatchTypeOrFail(T &obj, const Fns &... fns)
Pattern match over subclass type of given object.
static std::vector< jlm::rvsdg::Output * > operands(const Node *node)
Definition node.hpp:1049
Output & RouteToRegion(Output &output, Region &region)
Definition node.cpp:381
static Input * ComputeNextInput(const Input *input)
Definition node.cpp:100
NodeType * TryGetOwnerNode(const rvsdg::Input &input) noexcept
Checks if this is an input to a node of specified type.
Definition node.hpp:872
static std::string strfmt(Args... args)
Definition strfmt.hpp:35