Jlm
unroll.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 
9 #include <jlm/rvsdg/gamma.hpp>
10 #include <jlm/rvsdg/traverser.hpp>
11 #include <jlm/util/Statistics.hpp>
12 #include <jlm/util/time.hpp>
13 
14 namespace jlm::llvm
15 {
16 
18 {
19 public:
20  ~Statistics() override = default;
21 
22  explicit Statistics(const util::FilePath & sourceFile)
23  : util::Statistics(Statistics::Id::LoopUnrolling, sourceFile)
24  {}
25 
26  void
27  start(const rvsdg::Graph & graph) noexcept
28  {
31  }
32 
33  void
34  end(const rvsdg::Graph & graph) noexcept
35  {
36  AddMeasurement(Label::NumRvsdgNodesAfter, rvsdg::nnodes(&graph.GetRootRegion()));
38  }
39 
40  static std::unique_ptr<Statistics>
41  Create(const util::FilePath & sourceFile)
42  {
43  return std::make_unique<Statistics>(sourceFile);
44  }
45 };
46 
47 /* helper functions */
48 
49 static bool
51 {
52  return dynamic_cast<const jlm::rvsdg::bituge_op *>(&op)
53  || dynamic_cast<const jlm::rvsdg::bitsge_op *>(&op)
54  || dynamic_cast<const jlm::rvsdg::bitule_op *>(&op)
55  || dynamic_cast<const jlm::rvsdg::bitsle_op *>(&op);
56 }
57 
58 static bool
60 {
61  JLM_ASSERT(dynamic_cast<const rvsdg::ThetaNode *>(output->region()->node()));
62 
63  if (jlm::rvsdg::is<rvsdg::BitConstantOperation>(
64  rvsdg::TryGetOwnerNode<rvsdg::SimpleNode>(*output)))
65  return true;
66 
67  auto theta = rvsdg::TryGetRegionParentNode<rvsdg::ThetaNode>(*output);
68  if (!theta)
69  return false;
70 
71  auto loopVar = theta->MapPreLoopVar(*output);
72  return ThetaLoopVarIsInvariant(loopVar);
73 }
74 
75 static rvsdg::Output *
77 {
78  auto argument = dynamic_cast<rvsdg::RegionArgument *>(output);
79  if (argument)
80  return argument;
81 
82  auto tmp = rvsdg::TryGetOwnerNode<rvsdg::SimpleNode>(*output);
83  JLM_ASSERT(jlm::rvsdg::is<jlm::rvsdg::BitConstantOperation>(tmp));
84  JLM_ASSERT(dynamic_cast<const rvsdg::ThetaNode *>(tmp->region()->node()));
85  auto theta = static_cast<rvsdg::ThetaNode *>(tmp->region()->node());
86 
87  auto node = tmp->copy(theta->region(), {});
88  auto lv = theta->AddLoopVar(node->output(0));
89  output->divert_users(lv.pre);
90 
91  return lv.pre;
92 }
93 
94 static bool
96 {
97  using namespace jlm::rvsdg;
98 
99  auto node = TryGetOwnerNode<SimpleNode>(*input);
100  JLM_ASSERT(is<bitadd_op>(node) || is<bitsub_op>(node));
101 
102  if (auto theta = rvsdg::TryGetRegionParentNode<ThetaNode>(*input->origin()))
103  {
104  auto loopvar = theta->MapPreLoopVar(*input->origin());
105  return rvsdg::TryGetOwnerNode<Node>(*loopvar.post->origin()) == node;
106  }
107 
108  return false;
109 }
110 
111 std::unique_ptr<jlm::rvsdg::BitValueRepresentation>
113 {
114  if (!is_known() || step_value() == 0)
115  return nullptr;
116 
117  auto start = is_additive() ? *init_value() : *end_value();
118  auto step = is_additive() ? *step_value() : step_value()->neg();
119  auto end = is_additive() ? *end_value() : *init_value();
120 
121  if (is_eqcmp(cmpnode()->GetOperation()))
122  end = end.add({ nbits(), 1 });
123 
124  auto range = end.sub(start);
125  if (range.is_negative())
126  return nullptr;
127 
128  if (range.umod(step) != 0)
129  return nullptr;
130 
131  return std::make_unique<jlm::rvsdg::BitValueRepresentation>(range.udiv(step));
132 }
133 
134 std::unique_ptr<LoopUnrollInfo>
136 {
137  using namespace jlm::rvsdg;
138 
139  const auto matchNode = rvsdg::TryGetOwnerNode<SimpleNode>(*theta->predicate()->origin());
140  if (!is<MatchOperation>(matchNode))
141  return nullptr;
142 
143  auto cmpnode = rvsdg::TryGetOwnerNode<SimpleNode>(*matchNode->input(0)->origin());
144  if (!is<BitCompareOperation>(cmpnode))
145  return nullptr;
146 
147  auto o0 = cmpnode->input(0)->origin();
148  auto o1 = cmpnode->input(1)->origin();
149  auto end = is_theta_invariant(o0) ? o0 : (is_theta_invariant(o1) ? o1 : nullptr);
150  if (!end)
151  return nullptr;
152 
153  auto armnode = rvsdg::TryGetOwnerNode<SimpleNode>(*(end == o0 ? o1 : o0));
154  if (!is<bitadd_op>(armnode) && !is<bitsub_op>(armnode))
155  return nullptr;
156  if (armnode->ninputs() != 2)
157  return nullptr;
158 
159  auto i0 = armnode->input(0);
160  auto i1 = armnode->input(1);
161  if (!is_idv(i0) && !is_idv(i1))
162  return nullptr;
163 
164  auto idv = static_cast<rvsdg::RegionArgument *>(is_idv(i0) ? i0->origin() : i1->origin());
165 
166  auto step = idv == i0->origin() ? i1->origin() : i0->origin();
167  if (!is_theta_invariant(step))
168  return nullptr;
169 
170  auto endarg = push_from_theta(end);
171  auto steparg = push_from_theta(step);
172  return std::unique_ptr<LoopUnrollInfo>(
173  new LoopUnrollInfo(cmpnode, armnode, idv, steparg, endarg));
174 }
175 
176 /* loop unrolling */
177 
178 static void
180  const rvsdg::ThetaNode * theta,
181  rvsdg::Region * target,
182  rvsdg::SubstitutionMap & smap,
183  size_t factor)
184 {
185  for (size_t n = 0; n < factor - 1; n++)
186  {
187  theta->subregion()->copy(target, smap);
189  for (const auto & olv : theta->GetLoopVars())
190  tmap.insert(olv.pre, &smap.lookup(*olv.post->origin()));
191  smap = tmap;
192  }
193  theta->subregion()->copy(target, smap);
194 }
195 
196 /*
197  Copy the body of the theta and unroll it factor number of times.
198  The unrolled body has the same inputs and outputs as the theta.
199  The theta itself is not deleted.
200 */
201 static void
203 {
205  for (const auto & olv : theta->GetLoopVars())
206  smap.insert(olv.pre, olv.input->origin());
207 
208  unroll_body(theta, theta->region(), smap, factor);
209 
210  for (const auto & olv : theta->GetLoopVars())
211  olv.output->divert_users(&smap.lookup(*olv.post->origin()));
212 }
213 
214 /*
215  Unroll theta node by given factor.
216 */
217 static void
218 unroll_theta(const LoopUnrollInfo & ui, rvsdg::SubstitutionMap & smap, size_t factor)
219 {
220  auto theta = ui.theta();
221  auto remainder = ui.remainder(factor);
222  auto unrolled_theta = rvsdg::ThetaNode::create(theta->region());
223 
224  auto oldLoopVars = theta->GetLoopVars();
225  for (const auto & olv : oldLoopVars)
226  {
227  auto nlv = unrolled_theta->AddLoopVar(olv.input->origin());
228  smap.insert(olv.pre, nlv.pre);
229  }
230 
231  unroll_body(theta, unrolled_theta->subregion(), smap, factor);
232  unrolled_theta->set_predicate(&smap.lookup(*theta->predicate()->origin()));
233 
234  auto newLoopVars = unrolled_theta->GetLoopVars();
235  for (size_t i = 0; i < oldLoopVars.size(); ++i)
236  {
237  const auto & olv = oldLoopVars[i];
238  const auto & nlv = newLoopVars[i];
239  auto origin = &smap.lookup(*olv.post->origin());
240  nlv.post->divert_to(origin);
241  smap.insert(olv.output, nlv.output);
242  }
243 
244  if (remainder != 0)
245  {
246  /*
247  We have residual iterations. Adjust the end value of the unrolled loop
248  to a multiple of the step value.
249  */
250  auto cmpnode = ui.cmpnode();
251  auto cmp = rvsdg::TryGetOwnerNode<rvsdg::Node>(smap.lookup(*cmpnode->output(0)));
252  auto input = cmp->input(0)->origin() == &smap.lookup(*ui.end()) ? cmp->input(0) : cmp->input(1);
253  JLM_ASSERT(input->origin() == &smap.lookup(*ui.end()));
254 
255  auto sv = ui.is_additive() ? *ui.step_value() : ui.step_value()->neg();
256  auto end = remainder.mul(sv);
257  auto ev = ui.is_additive() ? ui.end_value()->sub(end) : ui.end_value()->add(end);
258 
259  auto c = &rvsdg::BitConstantOperation::create(*unrolled_theta->subregion(), ev);
260  input->divert_to(c);
261  }
262 }
263 
264 /*
265  Adde the reminder for the lopp if any
266 */
267 static void
268 add_remainder(const LoopUnrollInfo & ui, rvsdg::SubstitutionMap & smap, size_t factor)
269 {
270  auto theta = ui.theta();
271  auto remainder = ui.remainder(factor);
272 
273  if (remainder == 0)
274  {
275  /*
276  We only need to redirect the users of the outputs of the old theta node
277  to the outputs of the new theta node, as there are no residual iterations.
278  */
279  for (const auto & olv : theta->GetLoopVars())
280  olv.output->divert_users(&smap.lookup(*olv.output));
281  return remove(theta);
282  }
283 
284  /*
285  Add the old theta node as epilogue after the unrolled loop by simply
286  redirecting the inputs of the old theta to the outputs of the unrolled
287  theta.
288  */
289  for (const auto & olv : theta->GetLoopVars())
290  olv.input->divert_to(&smap.lookup(*olv.output));
291 
292  if (remainder == 1)
293  {
294  /*
295  There is only one loop iteration remaining.
296  Simply copy the body of the theta to replace it.
297  */
299  remove(theta);
300  }
301 }
302 
303 static void
304 unroll_known_theta(const LoopUnrollInfo & ui, size_t factor)
305 {
306  JLM_ASSERT(ui.is_known() && ui.niterations());
307  auto niterations = ui.niterations();
308  auto original_theta = ui.theta();
309  auto nbits = ui.nbits();
310 
311  JLM_ASSERT(niterations != 0);
312  if (niterations->ule({ nbits, (int64_t)factor }) == '1')
313  {
314  /*
315  Completely unroll the loop body and then remove the theta node,
316  as the number of iterations is smaller than the unroll factor.
317  */
318  copy_body_and_unroll(original_theta, niterations->to_uint());
319  return remove(original_theta);
320  }
321 
322  JLM_ASSERT(niterations->ugt({ nbits, (int64_t)factor }) == '1');
323 
324  /*
325  Unroll the theta
326  */
328  unroll_theta(ui, smap, factor);
329 
330  /*
331  Add code for any potential iterations that remains
332  */
333  add_remainder(ui, smap, factor);
334 }
335 
336 static jlm::rvsdg::Output *
338 {
339  auto region = ui.theta()->region();
340  auto nbits = ui.nbits();
341  auto step = ui.theta()->MapPreLoopVar(*ui.step()).input->origin();
342  auto end = ui.theta()->MapPreLoopVar(*ui.end()).input->origin();
343 
344  auto uf = &rvsdg::BitConstantOperation::create(*region, { nbits, static_cast<int64_t>(factor) });
346  auto arm =
347  rvsdg::SimpleNode::Create(*region, ui.armoperation().copy(), { ui.init(), mul }).output(0);
348  /* FIXME: order of operands */
349  auto cmp = rvsdg::SimpleNode::Create(*region, ui.cmpoperation().copy(), { arm, end }).output(0);
350  auto pred = jlm::rvsdg::match(1, { { 1, 1 } }, 0, 2, cmp);
351 
352  return pred;
353 }
354 
355 static jlm::rvsdg::Output *
357  rvsdg::Region *,
358  const rvsdg::SubstitutionMap & smap,
359  const LoopUnrollInfo & ui,
360  size_t factor)
361 {
362  using namespace jlm::rvsdg;
363 
364  auto region = smap.lookup(*ui.cmpnode()->output(0)).region();
365  auto cmpnode = rvsdg::TryGetOwnerNode<Node>(smap.lookup(*ui.cmpnode()->output(0)));
366  auto step = &smap.lookup(*ui.step());
367  auto end = &smap.lookup(*ui.end());
368  auto nbits = ui.nbits();
369 
370  auto i0 = cmpnode->input(0);
371  auto i1 = cmpnode->input(1);
372  auto iend = i0->origin() == end ? i0 : i1;
373  auto idv = i0->origin() == end ? i1 : i0;
374 
375  auto uf = &BitConstantOperation::create(*region, { nbits, static_cast<int64_t>(factor) });
376  auto mul = bitmul_op::create(nbits, step, uf);
377  auto arm =
378  SimpleNode::Create(*region, ui.armoperation().copy(), { idv->origin(), mul }).output(0);
379  /* FIXME: order of operands */
380  auto cmp =
381  SimpleNode::Create(*region, ui.cmpoperation().copy(), { arm, iend->origin() }).output(0);
382  auto pred = match(1, { { 1, 1 } }, 0, 2, cmp);
383 
384  return pred;
385 }
386 
387 static jlm::rvsdg::Output *
389 {
390  auto region = ui.theta()->region();
391  auto idv = &smap.lookup(*ui.theta()->MapPreLoopVar(*ui.idv()).output);
392  auto end = ui.theta()->MapPreLoopVar(*ui.end()).input->origin();
393 
394  /* FIXME: order of operands */
395  auto cmp = rvsdg::SimpleNode::Create(*region, ui.cmpoperation().copy(), { idv, end }).output(0);
396  auto pred = jlm::rvsdg::match(1, { { 1, 1 } }, 0, 2, cmp);
397 
398  return pred;
399 }
400 
401 static void
402 unroll_unknown_theta(const LoopUnrollInfo & ui, size_t factor)
403 {
404  auto otheta = ui.theta();
405 
406  /* handle gamma with unrolled loop */
408  {
409  auto pred = create_unrolled_gamma_predicate(ui, factor);
410  auto ngamma = rvsdg::GammaNode::create(pred, 2);
411  auto ntheta = rvsdg::ThetaNode::create(ngamma->subregion(1));
412 
413  rvsdg::SubstitutionMap rmap[2];
414  for (const auto & olv : otheta->GetLoopVars())
415  {
416  auto ev = ngamma->AddEntryVar(olv.input->origin());
417  auto nlv = ntheta->AddLoopVar(ev.branchArgument[1]);
418  rmap[0].insert(olv.output, ev.branchArgument[0]);
419  rmap[1].insert(olv.pre, nlv.pre);
420  }
421 
422  unroll_body(otheta, ntheta->subregion(), rmap[1], factor);
423  pred = create_unrolled_theta_predicate(ntheta->subregion(), rmap[1], ui, factor);
424  ntheta->set_predicate(pred);
425 
426  auto oldLoopVars = otheta->GetLoopVars();
427  auto newLoopVars = ntheta->GetLoopVars();
428  for (std::size_t n = 0; n < oldLoopVars.size(); ++n)
429  {
430  auto & olv = oldLoopVars[n];
431  auto & nlv = newLoopVars[n];
432  auto origin = &rmap[1].lookup(*olv.post->origin());
433  nlv.post->divert_to(origin);
434  rmap[1].insert(olv.output, nlv.output);
435  }
436 
437  for (const auto & olv : oldLoopVars)
438  {
439  auto xv =
440  ngamma->AddExitVar({ &rmap[0].lookup(*olv.output), &rmap[1].lookup(*olv.output) }).output;
441  smap.insert(olv.output, xv);
442  }
443  }
444 
445  /* handle gamma for residual iterations */
446  {
447  auto pred = create_residual_gamma_predicate(smap, ui);
448  auto ngamma = rvsdg::GammaNode::create(pred, 2);
449  auto ntheta = rvsdg::ThetaNode::create(ngamma->subregion(1));
450 
451  rvsdg::SubstitutionMap rmap[2];
452  auto oldLoopVars = otheta->GetLoopVars();
453  for (const auto & olv : oldLoopVars)
454  {
455  auto ev = ngamma->AddEntryVar(&smap.lookup(*olv.output));
456  auto nlv = ntheta->AddLoopVar(ev.branchArgument[1]);
457  rmap[0].insert(olv.output, ev.branchArgument[0]);
458  rmap[1].insert(olv.pre, nlv.pre);
459  }
460 
461  otheta->subregion()->copy(ntheta->subregion(), rmap[1]);
462  ntheta->set_predicate(&rmap[1].lookup(*otheta->predicate()->origin()));
463 
464  auto newLoopVars = ntheta->GetLoopVars();
465 
466  for (std::size_t n = 0; n < oldLoopVars.size(); ++n)
467  {
468  auto & olv = oldLoopVars[n];
469  auto & nlv = newLoopVars[n];
470  auto origin = &rmap[1].lookup(*olv.post->origin());
471  nlv.post->divert_to(origin);
472  auto xv = ngamma->AddExitVar({ &rmap[0].lookup(*olv.output), nlv.output }).output;
473  smap.insert(olv.output, xv);
474  }
475  }
476  for (const auto & olv : otheta->GetLoopVars())
477  olv.output->divert_users(&smap.lookup(*olv.output));
478  remove(otheta);
479 }
480 
481 void
482 unroll(rvsdg::ThetaNode * otheta, size_t factor)
483 {
484  if (factor < 2)
485  return;
486 
487  auto ui = LoopUnrollInfo::create(otheta);
488  if (!ui)
489  return;
490 
491  if (ui->is_known() && ui->niterations())
492  unroll_known_theta(*ui, factor);
493  else
494  unroll_unknown_theta(*ui, factor);
495 }
496 
497 static bool
498 unroll(rvsdg::Region * region, size_t factor)
499 {
500  bool unrolled = false;
501  for (auto & node : rvsdg::TopDownTraverser(region))
502  {
503  if (auto structnode = dynamic_cast<rvsdg::StructuralNode *>(node))
504  {
505  for (size_t n = 0; n < structnode->nsubregions(); n++)
506  unrolled = unroll(structnode->subregion(n), factor);
507 
508  /* Try to unroll if an inner loop hasn't already been found */
509  if (!unrolled)
510  {
511  if (auto theta = dynamic_cast<rvsdg::ThetaNode *>(node))
512  {
513  unroll(theta, factor);
514  unrolled = true;
515  }
516  }
517  }
518  }
519  return unrolled;
520 }
521 
522 LoopUnrolling::~LoopUnrolling() noexcept = default;
523 
524 void
525 LoopUnrolling::Run(rvsdg::RvsdgModule & module, util::StatisticsCollector & statisticsCollector)
526 {
527  if (factor_ < 2)
528  return;
529 
530  auto & graph = module.Rvsdg();
531  auto statistics = Statistics::Create(module.SourceFilePath().value());
532 
533  statistics->start(module.Rvsdg());
534  unroll(&graph.GetRootRegion(), factor_);
535  statistics->end(module.Rvsdg());
536 
537  statisticsCollector.CollectDemandedStatistics(std::move(statistics));
538 }
539 
540 }
rvsdg::Output * idv() const noexcept
Definition: unroll.hpp:139
std::unique_ptr< jlm::rvsdg::BitValueRepresentation > niterations() const noexcept
Definition: unroll.cpp:112
rvsdg::Output * end() const noexcept
Definition: unroll.hpp:169
const rvsdg::SimpleOperation & cmpoperation() const noexcept
Definition: unroll.hpp:121
rvsdg::SimpleNode * armnode() const noexcept
Definition: unroll.hpp:127
bool is_additive() const noexcept
Definition: unroll.hpp:181
static std::unique_ptr< LoopUnrollInfo > create(rvsdg::ThetaNode *theta)
Definition: unroll.cpp:135
LoopUnrollInfo(rvsdg::SimpleNode *cmpnode, rvsdg::SimpleNode *armnode, rvsdg::Output *idv, rvsdg::Output *step, rvsdg::Output *end)
Definition: unroll.hpp:56
rvsdg::Output * step() const noexcept
Definition: unroll.hpp:157
const jlm::rvsdg::BitValueRepresentation * end_value() const noexcept
Definition: unroll.hpp:175
bool is_known() const noexcept
Definition: unroll.hpp:106
const rvsdg::SimpleOperation & armoperation() const noexcept
Definition: unroll.hpp:133
rvsdg::ThetaNode * theta() const noexcept
Definition: unroll.hpp:81
size_t nbits() const noexcept
Definition: unroll.hpp:193
rvsdg::SimpleNode * cmpnode() const noexcept
Definition: unroll.hpp:115
jlm::rvsdg::BitValueRepresentation remainder(size_t factor) const noexcept
Definition: unroll.hpp:202
const jlm::rvsdg::BitValueRepresentation * step_value() const noexcept
Definition: unroll.hpp:163
const jlm::rvsdg::BitValueRepresentation * init_value() const noexcept
Definition: unroll.hpp:151
static std::unique_ptr< Statistics > Create(const util::FilePath &sourceFile)
Definition: unroll.cpp:41
void end(const rvsdg::Graph &graph) noexcept
Definition: unroll.cpp:34
Statistics(const util::FilePath &sourceFile)
Definition: unroll.cpp:22
void start(const rvsdg::Graph &graph) noexcept
Definition: unroll.cpp:27
Optimization that attempts to unroll loops (thetas).
Definition: unroll.hpp:24
~LoopUnrolling() noexcept override
static Output & create(Region &region, BitValueRepresentation value)
Definition: constant.hpp:44
void mul(const BitValueRepresentation &factor1, const BitValueRepresentation &factor2, BitValueRepresentation &product) const
BitValueRepresentation neg() const
BitValueRepresentation sub(const BitValueRepresentation &other) const
char add(char a, char b, char c) const noexcept
static GammaNode * create(jlm::rvsdg::Output *predicate, size_t nalternatives)
Definition: gamma.hpp:161
Output * origin() const noexcept
Definition: node.hpp:58
std::unique_ptr< BitBinaryOperation > create(size_t nbits) const override
rvsdg::Region * region() const noexcept
Definition: node.hpp:761
size_t ninputs() const noexcept
Definition: node.hpp:609
virtual std::unique_ptr< Operation > copy() const =0
rvsdg::Region * region() const noexcept
Definition: node.cpp:151
void divert_users(jlm::rvsdg::Output *new_origin)
Definition: node.hpp:301
Represents the argument of a region.
Definition: region.hpp:41
Represent acyclic RVSDG subgraphs.
Definition: region.hpp:213
void copy(Region *target, SubstitutionMap &smap) const
Copy a region with substitutions.
Definition: region.cpp:314
rvsdg::StructuralNode * node() const noexcept
Definition: region.hpp:369
NodeInput * input(size_t index) const noexcept
Definition: simple-node.hpp:82
NodeOutput * output(size_t index) const noexcept
Definition: simple-node.hpp:88
static SimpleNode & Create(Region &region, std::unique_ptr< Operation > operation, const std::vector< rvsdg::Output * > &operands)
Definition: simple-node.hpp:49
void insert(const Output *original, Output *substitute)
Output & lookup(const Output &original) const
RegionResult * predicate() const noexcept
Definition: theta.hpp:85
LoopVar MapPreLoopVar(const rvsdg::Output &argument) const
Maps variable at start of loop iteration to full varibale description.
Definition: theta.cpp:140
std::vector< LoopVar > GetLoopVars() const
Returns all loop variables.
Definition: theta.cpp:176
ThetaNode * copy(rvsdg::Region *region, rvsdg::SubstitutionMap &smap) const override
Copy a node with substitutions.
Definition: theta.cpp:100
rvsdg::Region * subregion() const noexcept
Definition: theta.hpp:79
static ThetaNode * create(rvsdg::Region *parent)
Definition: theta.hpp:73
LoopVar AddLoopVar(rvsdg::Output *origin)
Creates a new loop-carried variable.
Definition: theta.cpp:49
Statistics Interface.
Definition: Statistics.hpp:31
util::Timer & GetTimer(const std::string &name)
Definition: Statistics.cpp:134
util::Timer & AddTimer(std::string name)
Definition: Statistics.cpp:155
void AddMeasurement(std::string name, T value)
Definition: Statistics.hpp:174
void start() noexcept
Definition: time.hpp:54
void stop() noexcept
Definition: time.hpp:67
#define JLM_ASSERT(x)
Definition: common.hpp:16
Global memory state passed between functions.
static jlm::rvsdg::Output * create_unrolled_gamma_predicate(const LoopUnrollInfo &ui, size_t factor)
Definition: unroll.cpp:337
static rvsdg::Output * push_from_theta(jlm::rvsdg::Output *output)
Definition: unroll.cpp:76
static bool is_eqcmp(const rvsdg::Operation &op)
Definition: unroll.cpp:50
static void unroll_body(const rvsdg::ThetaNode *theta, rvsdg::Region *target, rvsdg::SubstitutionMap &smap, size_t factor)
Definition: unroll.cpp:179
static void unroll_theta(const LoopUnrollInfo &ui, rvsdg::SubstitutionMap &smap, size_t factor)
Definition: unroll.cpp:218
static jlm::rvsdg::Output * create_residual_gamma_predicate(const rvsdg::SubstitutionMap &smap, const LoopUnrollInfo &ui)
Definition: unroll.cpp:388
static jlm::rvsdg::Output * create_unrolled_theta_predicate(rvsdg::Region *, const rvsdg::SubstitutionMap &smap, const LoopUnrollInfo &ui, size_t factor)
Definition: unroll.cpp:356
static bool is_idv(jlm::rvsdg::Input *input)
Definition: unroll.cpp:95
static void unroll_unknown_theta(const LoopUnrollInfo &ui, size_t factor)
Definition: unroll.cpp:402
static void add_remainder(const LoopUnrollInfo &ui, rvsdg::SubstitutionMap &smap, size_t factor)
Definition: unroll.cpp:268
void unroll(rvsdg::ThetaNode *otheta, size_t factor)
Definition: unroll.cpp:482
static bool is_theta_invariant(const jlm::rvsdg::Output *output)
Definition: unroll.cpp:59
static void copy_body_and_unroll(const rvsdg::ThetaNode *theta, size_t factor)
Definition: unroll.cpp:202
static void unroll_known_theta(const LoopUnrollInfo &ui, size_t factor)
Definition: unroll.cpp:304
static bool ThetaLoopVarIsInvariant(const ThetaNode::LoopVar &loopVar) noexcept
Definition: theta.hpp:227
static void remove(Node *node)
Definition: region.hpp:932
jlm::rvsdg::Output * match(size_t nbits, const std::unordered_map< uint64_t, uint64_t > &mapping, uint64_t default_alternative, size_t nalternatives, jlm::rvsdg::Output *operand)
Definition: control.cpp:179
size_t nnodes(const jlm::rvsdg::Region *region) noexcept
Definition: region.cpp:629
rvsdg::Output * output
Variable at loop exit (output of theta).
Definition: theta.hpp:66
rvsdg::Input * input
Variable at loop entry (input to theta).
Definition: theta.hpp:54
static const char * NumRvsdgNodesBefore
Definition: Statistics.hpp:211
static const char * NumRvsdgNodesAfter
Definition: Statistics.hpp:212
static const char * Timer
Definition: Statistics.hpp:240