Jlm
cne.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 <jlm/hls/ir/hls.hpp>
7 #include <jlm/hls/opt/cne.hpp>
10 #include <jlm/rvsdg/gamma.hpp>
11 #include <jlm/rvsdg/MatchType.hpp>
12 #include <jlm/rvsdg/theta.hpp>
13 #include <jlm/rvsdg/traverser.hpp>
14 #include <jlm/util/Statistics.hpp>
15 #include <jlm/util/time.hpp>
16 
17 #include <typeindex>
18 
19 namespace jlm::hls
20 {
21 
22 using namespace jlm::rvsdg;
23 
25 {
26  const char * MarkTimerLabel_ = "MarkTime";
27  const char * DivertTimerLabel_ = "DivertTime";
28 
29 public:
30  ~Statistics() override = default;
31 
32  explicit Statistics(const util::FilePath & sourceFile)
33  : util::Statistics(Id::CommonNodeElimination, sourceFile)
34  {}
35 
36  void
37  start_mark_stat(const Graph & graph) noexcept
38  {
39  AddMeasurement(Label::NumRvsdgNodesBefore, rvsdg::nnodes(&graph.GetRootRegion()));
40  AddMeasurement(Label::NumRvsdgInputsBefore, rvsdg::ninputs(&graph.GetRootRegion()));
41  AddTimer(MarkTimerLabel_).start();
42  }
43 
44  void
45  end_mark_stat() noexcept
46  {
47  GetTimer(MarkTimerLabel_).stop();
48  }
49 
50  void
51  start_divert_stat() noexcept
52  {
53  AddTimer(DivertTimerLabel_).start();
54  }
55 
56  void
57  end_divert_stat(const Graph & graph) noexcept
58  {
59  AddMeasurement(Label::NumRvsdgNodesAfter, rvsdg::nnodes(&graph.GetRootRegion()));
60  AddMeasurement(Label::NumRvsdgInputsAfter, rvsdg::ninputs(&graph.GetRootRegion()));
61  GetTimer(DivertTimerLabel_).stop();
62  }
63 
64  static std::unique_ptr<Statistics>
65  Create(const util::FilePath & sourceFile)
66  {
67  return std::make_unique<Statistics>(sourceFile);
68  }
69 };
70 
71 typedef std::unordered_set<jlm::rvsdg::Output *> congruence_set;
72 
73 class Context final
74 {
75 public:
76  inline void
78  {
79  auto s1 = set(o1);
80  auto s2 = set(o2);
81 
82  if (s1 == s2)
83  return;
84 
85  if (s2->size() < s1->size())
86  {
87  s1 = outputs_[o2];
88  s2 = outputs_[o1];
89  }
90 
91  for (auto & o : *s1)
92  {
93  s2->insert(o);
94  outputs_[o] = s2;
95  }
96  }
97 
98  inline void
99  mark(const Node * n1, const Node * n2)
100  {
101  JLM_ASSERT(n1->noutputs() == n2->noutputs());
102 
103  for (size_t n = 0; n < n1->noutputs(); n++)
104  mark(n1->output(n), n2->output(n));
105  }
106 
107  inline bool
109  {
110  if (o1 == o2)
111  return true;
112 
113  auto it = outputs_.find(o1);
114  if (it == outputs_.end())
115  return false;
116 
117  return it->second->find(o2) != it->second->end();
118  }
119 
120  inline bool
121  congruent(const jlm::rvsdg::Input * i1, const jlm::rvsdg::Input * i2) const noexcept
122  {
123  return congruent(i1->origin(), i2->origin());
124  }
125 
127  set(jlm::rvsdg::Output * output) noexcept
128  {
129  if (outputs_.find(output) == outputs_.end())
130  {
131  std::unique_ptr<congruence_set> set(new congruence_set({ output }));
132  outputs_[output] = set.get();
133  sets_.insert(std::move(set));
134  }
135 
136  return outputs_[output];
137  }
138 
139 private:
140  std::unordered_set<std::unique_ptr<congruence_set>> sets_;
141  std::unordered_map<const jlm::rvsdg::Output *, congruence_set *> outputs_;
142 };
143 
144 class VisitorSet final
145 {
146 public:
147  void
149  {
150  auto it = sets_.find(o1);
151  if (it != sets_.end())
152  sets_[o1].insert(o2);
153  else
154  sets_[o1] = { o2 };
155 
156  it = sets_.find(o2);
157  if (it != sets_.end())
158  sets_[o2].insert(o1);
159  else
160  sets_[o2] = { o1 };
161  }
162 
163  bool
164  visited(const jlm::rvsdg::Output * o1, const jlm::rvsdg::Output * o2) const
165  {
166  auto it = sets_.find(o1);
167  if (it == sets_.end())
168  return false;
169 
170  return it->second.find(o2) != it->second.end();
171  }
172 
173 private:
174  std::unordered_map<const jlm::rvsdg::Output *, std::unordered_set<const jlm::rvsdg::Output *>>
176 };
177 
178 /* mark phase */
179 
180 static bool
181 congruent(Output * o1, Output * o2, VisitorSet & vs, Context & ctx)
182 {
183  if (ctx.congruent(o1, o2) || vs.visited(o1, o2))
184  return true;
185 
186  if (*o1->Type() != *o2->Type())
187  return false;
188 
189  if (auto theta1 = rvsdg::TryGetRegionParentNode<rvsdg::ThetaNode>(*o1))
190  {
191  if (auto theta2 = rvsdg::TryGetRegionParentNode<rvsdg::ThetaNode>(*o2))
192  {
193  JLM_ASSERT(o1->region()->node() == o2->region()->node());
194  auto loopvar1 = theta1->MapPreLoopVar(*o1);
195  auto loopvar2 = theta2->MapPreLoopVar(*o2);
196  vs.insert(o1, o2);
197  auto i1 = loopvar1.input, i2 = loopvar2.input;
198  if (!congruent(loopvar1.input->origin(), loopvar2.input->origin(), vs, ctx))
199  return false;
200 
201  auto output1 = o1->region()->node()->output(i1->index());
202  auto output2 = o2->region()->node()->output(i2->index());
203  return congruent(output1, output2, vs, ctx);
204  }
205  }
206 
207  if (auto theta1 = rvsdg::TryGetOwnerNode<rvsdg::ThetaNode>(*o1))
208  {
209  if (auto theta2 = rvsdg::TryGetOwnerNode<rvsdg::ThetaNode>(*o2))
210  {
211  if (theta1 == theta2)
212  {
213  vs.insert(o1, o2);
214  auto loopvar1 = theta1->MapOutputLoopVar(*o1);
215  auto loopvar2 = theta2->MapOutputLoopVar(*o2);
216  auto r1 = loopvar1.post;
217  auto r2 = loopvar2.post;
218  return congruent(r1->origin(), r2->origin(), vs, ctx);
219  }
220  }
221  }
222 
223  auto n1 = TryGetOwnerNode<Node>(*o1);
224  auto n2 = TryGetOwnerNode<Node>(*o2);
225 
226  auto a1 = dynamic_cast<rvsdg::RegionArgument *>(o1);
227  auto a2 = dynamic_cast<rvsdg::RegionArgument *>(o2);
228  if (a1 && dynamic_cast<const LoopNode *>(a1->region()->node()) && a2
229  && dynamic_cast<const LoopNode *>(a2->region()->node()))
230  {
231  JLM_ASSERT(o1->region()->node() == o2->region()->node());
232  if (a1->input() && a2->input())
233  {
234  // input arguments
235  vs.insert(a1, a2);
236  return congruent(a1->input()->origin(), a2->input()->origin(), vs, ctx);
237  }
238  }
239 
240  if (dynamic_cast<const rvsdg::GammaNode *>(n1) && n1 == n2)
241  {
242  auto so1 = static_cast<StructuralOutput *>(o1);
243  auto so2 = static_cast<StructuralOutput *>(o2);
244  auto r1 = so1->results.begin();
245  auto r2 = so2->results.begin();
246  for (; r1 != so1->results.end(); r1++, r2++)
247  {
248  JLM_ASSERT(r1->region() == r2->region());
249  if (!congruent(r1->origin(), r2->origin(), vs, ctx))
250  return false;
251  }
252  return true;
253  }
254 
255  if (auto g1 = rvsdg::TryGetRegionParentNode<rvsdg::GammaNode>(*o1))
256  {
257  if (auto g2 = rvsdg::TryGetRegionParentNode<rvsdg::GammaNode>(*o2))
258  {
259  JLM_ASSERT(g1 == g2);
260  auto origin1 = std::visit(
261  [](const auto & rolevar) -> rvsdg::Output *
262  {
263  return rolevar.input->origin();
264  },
265  g1->MapBranchArgument(*o1));
266  auto origin2 = std::visit(
267  [](const auto & rolevar) -> rvsdg::Output *
268  {
269  return rolevar.input->origin();
270  },
271  g2->MapBranchArgument(*o2));
272  return congruent(origin1, origin2, vs, ctx);
273  }
274  }
275 
276  if (jlm::rvsdg::is<SimpleOperation>(n1) && jlm::rvsdg::is<SimpleOperation>(n2)
277  && n1->GetOperation() == n2->GetOperation() && n1->ninputs() == n2->ninputs()
278  && o1->index() == o2->index())
279  {
280  for (size_t n = 0; n < n1->ninputs(); n++)
281  {
282  auto origin1 = n1->input(n)->origin();
283  auto origin2 = n2->input(n)->origin();
284  if (!congruent(origin1, origin2, vs, ctx))
285  return false;
286  }
287  return true;
288  }
289 
290  return false;
291 }
292 
293 static bool
295 {
296  VisitorSet vs;
297  return congruent(o1, o2, vs, ctx);
298 }
299 
300 static void
302 {
303  JLM_ASSERT(i1->node() && i1->node() == i2->node());
304  JLM_ASSERT(i1->arguments.size() == i2->arguments.size());
305 
306  auto a1 = i1->arguments.begin();
307  auto a2 = i2->arguments.begin();
308  for (; a1 != i1->arguments.end(); a1++, a2++)
309  {
310  JLM_ASSERT(a1->region() == a2->region());
311  if (congruent(a1.ptr(), a2.ptr(), ctx))
312  ctx.mark(a1.ptr(), a2.ptr());
313  }
314 }
315 
316 static void
317 mark(jlm::rvsdg::Region *, Context &);
318 
319 static void
320 mark_gamma(const rvsdg::GammaNode * node, Context & ctx)
321 {
322  /* mark entry variables */
323  for (size_t i1 = 1; i1 < node->ninputs(); i1++)
324  {
325  for (size_t i2 = i1 + 1; i2 < node->ninputs(); i2++)
326  mark_arguments(node->input(i1), node->input(i2), ctx);
327  }
328 
329  for (size_t n = 0; n < node->nsubregions(); n++)
330  mark(node->subregion(n), ctx);
331 
332  /* mark exit variables */
333  for (size_t o1 = 0; o1 < node->noutputs(); o1++)
334  {
335  for (size_t o2 = o1 + 1; o2 < node->noutputs(); o2++)
336  {
337  if (congruent(node->output(o1), node->output(o2), ctx))
338  ctx.mark(node->output(o1), node->output(o2));
339  }
340  }
341 }
342 
343 static void
344 mark_theta(const rvsdg::ThetaNode * theta, Context & ctx)
345 {
346  /* mark loop variables */
347  for (size_t i1 = 0; i1 < theta->ninputs(); i1++)
348  {
349  for (size_t i2 = i1 + 1; i2 < theta->ninputs(); i2++)
350  {
351  auto input1 = theta->input(i1);
352  auto input2 = theta->input(i2);
353  auto loopvar1 = theta->MapInputLoopVar(*input1);
354  auto loopvar2 = theta->MapInputLoopVar(*input2);
355  if (congruent(loopvar1.pre, loopvar2.pre, ctx))
356  {
357  ctx.mark(loopvar1.pre, loopvar2.pre);
358  ctx.mark(loopvar1.output, loopvar2.output);
359  }
360  }
361  }
362 
363  mark(theta->subregion(), ctx);
364 }
365 
366 static void
367 mark_loop(const LoopNode * loop, Context & ctx)
368 {
369  /* mark loop variables */
370  for (size_t i1 = 0; i1 < loop->ninputs(); i1++)
371  {
372  for (size_t i2 = i1 + 1; i2 < loop->ninputs(); i2++)
373  {
374  auto input1 = loop->input(i1);
375  auto input2 = loop->input(i2);
376  if (congruent(input1->arguments.first(), input2->arguments.first(), ctx))
377  {
378  ctx.mark(input1->arguments.first(), input2->arguments.first());
379  }
380  }
381  }
382  mark(loop->subregion(), ctx);
383 }
384 
385 static void
387 {
388  /* mark dependencies */
389  for (size_t i1 = 0; i1 < node->ninputs(); i1++)
390  {
391  for (size_t i2 = i1 + 1; i2 < node->ninputs(); i2++)
392  {
393  auto input1 = node->input(i1);
394  auto input2 = node->input(i2);
395  if (ctx.congruent(input1, input2))
396  ctx.mark(input1->arguments.first(), input2->arguments.first());
397  }
398  }
399 
400  mark(node->subregion(), ctx);
401 }
402 
403 static void
404 mark_phi(const rvsdg::PhiNode * phi, Context & ctx)
405 {
406  auto ctxvars = phi->GetContextVars();
407 
408  /* mark dependencies */
409  for (size_t i1 = 0; i1 < ctxvars.size(); ++i1)
410  {
411  for (size_t i2 = i1 + 1; i2 < ctxvars.size(); ++i2)
412  {
413  if (ctx.congruent(ctxvars[i1].input, ctxvars[i2].input))
414  {
415  ctx.mark(ctxvars[i1].inner, ctxvars[i2].inner);
416  }
417  }
418  }
419 
420  mark(phi->subregion(), ctx);
421 }
422 
423 static void
424 mark(const rvsdg::StructuralNode * node, Context & ctx)
425 {
427  *node,
428  [&](const GammaNode & node)
429  {
430  mark_gamma(&node, ctx);
431  },
432  [&](const ThetaNode & node)
433  {
434  mark_theta(&node, ctx);
435  },
436  [&](const LoopNode & node)
437  {
438  mark_loop(&node, ctx);
439  },
440  [&](const LambdaNode & node)
441  {
442  mark_lambda(&node, ctx);
443  },
444  [&](const PhiNode & node)
445  {
446  mark_phi(&node, ctx);
447  },
448  [&](const DeltaNode & node) { /* nothing to do */ });
449 }
450 
451 static void
452 mark(const jlm::rvsdg::SimpleNode * node, Context & ctx)
453 {
454  if (node->ninputs() == 0)
455  {
456  for (const auto & other : node->region()->TopNodes())
457  {
458  if (&other != node && node->GetOperation() == other.GetOperation())
459  {
460  ctx.mark(node, &other);
461  break;
462  }
463  }
464  return;
465  }
466 
467  auto set = ctx.set(node->input(0)->origin());
468  for (const auto & origin : *set)
469  {
470  for (const auto & user : origin->Users())
471  {
472  const auto other = TryGetOwnerNode<rvsdg::Node>(user);
473  if (!other || other == node || other->GetOperation() != node->GetOperation()
474  || other->ninputs() != node->ninputs())
475  continue;
476 
477  size_t n = 0;
478  for (n = 0; n < node->ninputs(); n++)
479  {
480  if (!ctx.congruent(node->input(n), other->input(n)))
481  break;
482  }
483  if (n == node->ninputs())
484  ctx.mark(node, other);
485  }
486  }
487 }
488 
489 static void
490 mark(rvsdg::Region * region, Context & ctx)
491 {
492  for (const auto & node : TopDownTraverser(region))
493  {
494  if (auto simple = dynamic_cast<const jlm::rvsdg::SimpleNode *>(node))
495  mark(simple, ctx);
496  else
497  mark(static_cast<const rvsdg::StructuralNode *>(node), ctx);
498  }
499 }
500 
501 /* divert phase */
502 
503 static void
505 {
506  auto set = ctx.set(output);
507  for (auto & other : *set)
508  other->divert_users(output);
509  set->clear();
510 }
511 
512 static void
514 {
515  for (size_t n = 0; n < node->noutputs(); n++)
516  divert_users(node->output(n), ctx);
517 }
518 
519 static void
521 {
522  for (size_t n = 0; n < region->narguments(); n++)
523  divert_users(region->argument(n), ctx);
524 }
525 
526 static void
527 divert(rvsdg::Region *, Context &);
528 
529 static void
531 {
532  for (const auto & ev : gamma->GetEntryVars())
533  {
534  for (auto input : ev.branchArgument)
535  divert_users(input, ctx);
536  }
537 
538  for (auto & subregion : gamma->Subregions())
539  divert(&subregion, ctx);
540 
541  divert_outputs(gamma, ctx);
542 }
543 
544 static void
546 {
547  auto subregion = theta->subregion();
548 
549  for (const auto & lv : theta->GetLoopVars())
550  {
551  JLM_ASSERT(ctx.set(lv.pre)->size() == ctx.set(lv.output)->size());
552  divert_users(lv.pre, ctx);
553  divert_users(lv.output, ctx);
554  }
555 
556  divert(subregion, ctx);
557 }
558 
559 static void
561 {
562  auto subregion = node->subregion();
563  divert(subregion, ctx);
564 }
565 
566 static void
568 {
569  divert_arguments(node->subregion(), ctx);
570  divert(node->subregion(), ctx);
571 }
572 
573 static void
575 {
576  divert_arguments(phi->subregion(), ctx);
577  divert(phi->subregion(), ctx);
578 }
579 
580 static void
582 {
584  *node,
585  [&](rvsdg::GammaNode & node)
586  {
587  divert_gamma(&node, ctx);
588  },
589  [&](rvsdg::ThetaNode & node)
590  {
591  divert_theta(&node, ctx);
592  },
593  [&](LoopNode & node)
594  {
595  divert_loop(&node, ctx);
596  },
597  [&](rvsdg::LambdaNode & node)
598  {
599  divert_lambda(&node, ctx);
600  },
601  [&](rvsdg::PhiNode & node)
602  {
603  divert_phi(&node, ctx);
604  },
605  [&](rvsdg::DeltaNode & node) { /* nothing to do */ });
606 }
607 
608 static void
609 divert(rvsdg::Region * region, Context & ctx)
610 {
611  for (const auto & node : TopDownTraverser(region))
612  {
613  if (auto simple = dynamic_cast<jlm::rvsdg::SimpleNode *>(node))
614  divert_outputs(simple, ctx);
615  else
616  divert(static_cast<rvsdg::StructuralNode *>(node), ctx);
617  }
618 }
619 
621 
622 void
624  rvsdg::RvsdgModule & module,
625  util::StatisticsCollector & statisticsCollector)
626 {
627  const auto & graph = module.Rvsdg();
628 
629  Context ctx;
630  auto statistics = Statistics::Create(module.SourceFilePath().value());
631 
632  statistics->start_mark_stat(graph);
633  mark(&graph.GetRootRegion(), ctx);
634  statistics->end_mark_stat();
635 
636  statistics->start_divert_stat();
637  divert(&graph.GetRootRegion(), ctx);
638  statistics->end_divert_stat(graph);
639 
640  statisticsCollector.CollectDemandedStatistics(std::move(statistics));
641 }
642 
643 }
Statistics(const util::FilePath &sourceFile)
Definition: cne.cpp:32
void start_mark_stat(const Graph &graph) noexcept
Definition: cne.cpp:37
void end_divert_stat(const Graph &graph) noexcept
Definition: cne.cpp:57
static std::unique_ptr< Statistics > Create(const util::FilePath &sourceFile)
Definition: cne.cpp:65
Common Node Elimination This is mainly a copy of the CNE optimization in the LLVM backend with the ad...
Definition: cne.hpp:24
~CommonNodeElimination() noexcept override
std::unordered_set< std::unique_ptr< congruence_set > > sets_
Definition: cne.cpp:140
void mark(const Node *n1, const Node *n2)
Definition: cne.cpp:99
bool congruent(jlm::rvsdg::Output *o1, jlm::rvsdg::Output *o2) const noexcept
Definition: cne.cpp:108
congruence_set * set(jlm::rvsdg::Output *output) noexcept
Definition: cne.cpp:127
std::unordered_map< const jlm::rvsdg::Output *, congruence_set * > outputs_
Definition: cne.cpp:141
void mark(jlm::rvsdg::Output *o1, jlm::rvsdg::Output *o2)
Definition: cne.cpp:77
bool congruent(const jlm::rvsdg::Input *i1, const jlm::rvsdg::Input *i2) const noexcept
Definition: cne.cpp:121
rvsdg::Region * subregion() const noexcept
Definition: hls.hpp:725
std::unordered_map< const jlm::rvsdg::Output *, std::unordered_set< const jlm::rvsdg::Output * > > sets_
Definition: cne.cpp:175
void insert(const jlm::rvsdg::Output *o1, const jlm::rvsdg::Output *o2)
Definition: cne.cpp:148
bool visited(const jlm::rvsdg::Output *o1, const jlm::rvsdg::Output *o2) const
Definition: cne.cpp:164
Delta node.
Definition: delta.hpp:129
Conditional operator / pattern matching.
Definition: gamma.hpp:99
std::vector< EntryVar > GetEntryVars() const
Gets all entry variables for this gamma.
Definition: gamma.cpp:303
Output * origin() const noexcept
Definition: node.hpp:58
Lambda node.
Definition: lambda.hpp:83
rvsdg::Region * subregion() const noexcept
Definition: lambda.hpp:138
rvsdg::Region * region() const noexcept
Definition: node.hpp:761
NodeOutput * output(size_t index) const noexcept
Definition: node.hpp:650
size_t ninputs() const noexcept
Definition: node.hpp:609
size_t noutputs() const noexcept
Definition: node.hpp:644
rvsdg::Region * region() const noexcept
Definition: node.cpp:151
const std::shared_ptr< const rvsdg::Type > & Type() const noexcept
Definition: node.hpp:366
size_t index() const noexcept
Definition: node.hpp:274
A phi node represents the fixpoint of mutually recursive definitions.
Definition: Phi.hpp:46
rvsdg::Region * subregion() const noexcept
Definition: Phi.hpp:320
std::vector< ContextVar > GetContextVars() const noexcept
Gets all bound context variables.
Definition: Phi.cpp:50
Represents the argument of a region.
Definition: region.hpp:41
Represent acyclic RVSDG subgraphs.
Definition: region.hpp:213
rvsdg::StructuralNode * node() const noexcept
Definition: region.hpp:369
TopNodeRange TopNodes() noexcept
Definition: region.hpp:309
RegionArgument * argument(size_t index) const noexcept
Definition: region.hpp:437
size_t narguments() const noexcept
Definition: region.hpp:431
const SimpleOperation & GetOperation() const noexcept override
Definition: simple-node.cpp:48
NodeInput * input(size_t index) const noexcept
Definition: simple-node.hpp:82
StructuralNode * node() const noexcept
SubregionIteratorRange Subregions()
size_t nsubregions() const noexcept
StructuralOutput * output(size_t index) const noexcept
StructuralInput * input(size_t index) const noexcept
rvsdg::Region * subregion(size_t index) const noexcept
std::vector< LoopVar > GetLoopVars() const
Returns all loop variables.
Definition: theta.cpp:176
rvsdg::Region * subregion() const noexcept
Definition: theta.hpp:79
LoopVar MapInputLoopVar(const rvsdg::Input &input) const
Maps variable at entry to full varibale description.
Definition: theta.cpp:130
Iterator end() noexcept
size_type size() const noexcept
Iterator begin() noexcept
Statistics Interface.
Definition: Statistics.hpp:31
#define JLM_ASSERT(x)
Definition: common.hpp:16
static void mark_arguments(StructuralInput *i1, StructuralInput *i2, Context &ctx)
Definition: cne.cpp:301
static void divert_gamma(rvsdg::GammaNode *gamma, Context &ctx)
Definition: cne.cpp:530
static void mark_theta(const rvsdg::ThetaNode *theta, Context &ctx)
Definition: cne.cpp:344
static void mark_gamma(const rvsdg::GammaNode *node, Context &ctx)
Definition: cne.cpp:320
static void divert(rvsdg::Region *, Context &)
Definition: cne.cpp:609
static void divert_theta(rvsdg::ThetaNode *theta, Context &ctx)
Definition: cne.cpp:545
static void divert_arguments(rvsdg::Region *region, Context &ctx)
Definition: cne.cpp:520
std::unordered_set< jlm::rvsdg::Output * > congruence_set
Definition: cne.cpp:71
static void divert_users(jlm::rvsdg::Output *output, Context &ctx)
Definition: cne.cpp:504
static bool congruent(Output *o1, Output *o2, VisitorSet &vs, Context &ctx)
Definition: cne.cpp:181
static void mark_phi(const rvsdg::PhiNode *phi, Context &ctx)
Definition: cne.cpp:404
static void mark_lambda(const rvsdg::LambdaNode *node, Context &ctx)
Definition: cne.cpp:386
static void divert_outputs(Node *node, Context &ctx)
Definition: cne.cpp:513
static void divert_lambda(rvsdg::LambdaNode *node, Context &ctx)
Definition: cne.cpp:567
static void divert_loop(LoopNode *node, Context &ctx)
Definition: cne.cpp:560
static void mark_loop(const LoopNode *loop, Context &ctx)
Definition: cne.cpp:367
static void divert_phi(rvsdg::PhiNode *phi, Context &ctx)
Definition: cne.cpp:574
static void mark(jlm::rvsdg::Region *, Context &)
Definition: cne.cpp:490
void MatchTypeOrFail(T &obj, const Fns &... fns)
Pattern match over subclass type of given object.
size_t nnodes(const jlm::rvsdg::Region *region) noexcept
Definition: region.cpp:629
size_t ninputs(const rvsdg::Region *region) noexcept
Definition: region.cpp:682
detail::TopDownTraverserGeneric< false > TopDownTraverser
Traverser for visiting every node in a region in a top down order.
Definition: traverser.hpp:308