Jlm
Loading...
Searching...
No Matches
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
8#include <jlm/rvsdg/gamma.hpp>
12#include <jlm/util/time.hpp>
13
14namespace jlm::llvm
15{
16
18{
19public:
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 {
29 AddMeasurement(Label::NumRvsdgNodesBefore, rvsdg::nnodes(&graph.GetRootRegion()));
30 AddTimer(Label::Timer).start();
31 }
32
33 void
34 end(const rvsdg::Graph & graph) noexcept
35 {
36 AddMeasurement(Label::NumRvsdgNodesAfter, rvsdg::nnodes(&graph.GetRootRegion()));
37 GetTimer(Label::Timer).stop();
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
49static 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
58static bool
60{
61 JLM_ASSERT(dynamic_cast<const rvsdg::ThetaNode *>(output->region()->node()));
62
65 return true;
66
68 if (!theta)
69 return false;
70
71 auto loopVar = theta->MapPreLoopVar(*output);
72 return ThetaLoopVarIsInvariant(loopVar);
73}
74
75static rvsdg::Output *
77{
78 auto argument = dynamic_cast<rvsdg::RegionArgument *>(output);
79 if (argument)
80 return argument;
81
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
94static 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
111std::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
134std::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();
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
178static void
180 const rvsdg::ThetaNode * theta,
181 rvsdg::Region * target,
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*/
201static void
202copy_body_and_unroll(const rvsdg::ThetaNode * theta, size_t factor)
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*/
217static void
218unroll_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*/
267static void
268add_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 */
298 copy_body_and_unroll(theta, 1);
299 remove(theta);
300 }
301}
302
303static void
304unroll_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
336static 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) });
345 auto mul = jlm::rvsdg::bitmul_op::create(nbits, step, uf);
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 & predNode = rvsdg::MatchOperation::CreateNode(*cmp, { { 1, 1 } }, 0, 2);
351
352 return predNode.output(0);
353}
354
355static jlm::rvsdg::Output *
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 & predNode = MatchOperation::CreateNode(*cmp, { { 1, 1 } }, 0, 2);
383
384 return predNode.output(0);
385}
386
387static 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 & predNode = rvsdg::MatchOperation::CreateNode(*cmp, { { 1, 1 } }, 0, 2);
397
398 return predNode.output(0);
399}
400
401static void
402unroll_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
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
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
481void
482unroll(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
497static bool
498unroll(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
522LoopUnrolling::~LoopUnrolling() noexcept = default;
523
524void
525LoopUnrolling::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}
static jlm::util::StatisticsCollector statisticsCollector
std::unique_ptr< jlm::rvsdg::BitValueRepresentation > niterations() const noexcept
Definition unroll.cpp:112
const rvsdg::SimpleOperation & cmpoperation() const noexcept
Definition unroll.hpp:121
const jlm::rvsdg::BitValueRepresentation * end_value() const noexcept
Definition unroll.hpp:175
bool is_additive() const noexcept
Definition unroll.hpp:181
rvsdg::Output * step() const noexcept
Definition unroll.hpp:157
rvsdg::SimpleNode * cmpnode() const noexcept
Definition unroll.hpp:115
static std::unique_ptr< LoopUnrollInfo > create(rvsdg::ThetaNode *theta)
Definition unroll.cpp:135
bool is_known() const noexcept
Definition unroll.hpp:106
rvsdg::ThetaNode * theta() const noexcept
Definition unroll.hpp:81
rvsdg::SimpleNode * armnode() const noexcept
Definition unroll.hpp:127
size_t nbits() const noexcept
Definition unroll.hpp:193
rvsdg::Output * idv() const noexcept
Definition unroll.hpp:139
jlm::rvsdg::BitValueRepresentation remainder(size_t factor) const noexcept
Definition unroll.hpp:202
const jlm::rvsdg::BitValueRepresentation * init_value() const noexcept
Definition unroll.hpp:151
const jlm::rvsdg::BitValueRepresentation * step_value() const noexcept
Definition unroll.hpp:163
rvsdg::Output * end() const noexcept
Definition unroll.hpp:169
const rvsdg::SimpleOperation & armoperation() const noexcept
Definition unroll.hpp:133
void end(const rvsdg::Graph &graph) noexcept
Definition unroll.cpp:34
Statistics(const util::FilePath &sourceFile)
Definition unroll.cpp:22
static std::unique_ptr< Statistics > Create(const util::FilePath &sourceFile)
Definition unroll.cpp:41
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
static Node & CreateNode(Output &predicate, const std::unordered_map< uint64_t, uint64_t > &mapping, const uint64_t defaultAlternative, const size_t numAlternatives)
Definition control.hpp:220
NodeOutput * output(size_t index) const noexcept
Definition node.hpp:650
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:317
rvsdg::StructuralNode * node() const noexcept
Definition region.hpp:301
static SimpleNode & Create(Region &region, std::unique_ptr< Operation > operation, const std::vector< rvsdg::Output * > &operands)
NodeInput * input(size_t index) const noexcept
NodeOutput * output(size_t index) const noexcept
void insert(const Output *original, Output *substitute)
Output & lookup(const Output &original) const
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
RegionResult * predicate() const noexcept
Definition theta.hpp:85
LoopVar AddLoopVar(rvsdg::Output *origin)
Creates a new loop-carried variable.
Definition theta.cpp:49
void CollectDemandedStatistics(std::unique_ptr< Statistics > statistics)
Statistics Interface.
util::Timer & GetTimer(const std::string &name)
util::Timer & AddTimer(std::string name)
void AddMeasurement(std::string name, T value)
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_residual_gamma_predicate(const rvsdg::SubstitutionMap &smap, const LoopUnrollInfo &ui)
Definition unroll.cpp:388
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 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
static rvsdg::Output * push_from_theta(jlm::rvsdg::Output *output)
Definition unroll.cpp:76
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 jlm::rvsdg::Output * create_unrolled_gamma_predicate(const LoopUnrollInfo &ui, size_t factor)
Definition unroll.cpp:337
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 jlm::rvsdg::Output * create_unrolled_theta_predicate(rvsdg::Region *, const rvsdg::SubstitutionMap &smap, const LoopUnrollInfo &ui, size_t factor)
Definition unroll.cpp:356
size_t nnodes(const jlm::rvsdg::Region *region) noexcept
Definition region.cpp:808
NodeType * TryGetOwnerNode(const rvsdg::Input &input) noexcept
Checks if this is an input to a node of specified type.
Definition node.hpp:872
detail::TopDownTraverserGeneric< false > TopDownTraverser
Traverser for visiting every node in a region in a top down order.
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