40 static std::unique_ptr<Statistics>
43 return std::make_unique<Statistics>(sourceFile);
71 auto loopVar = theta->MapPreLoopVar(*output);
72 return ThetaLoopVarIsInvariant(loopVar);
87 auto node = tmp->
copy(theta->region(), {});
99 auto node = TryGetOwnerNode<SimpleNode>(*input);
100 JLM_ASSERT(is<bitadd_op>(node) || is<bitsub_op>(node));
104 auto loopvar = theta->MapPreLoopVar(*input->
origin());
111std::unique_ptr<jlm::rvsdg::BitValueRepresentation>
124 auto range =
end.sub(start);
125 if (range.is_negative())
128 if (range.umod(
step) != 0)
131 return std::make_unique<jlm::rvsdg::BitValueRepresentation>(range.udiv(
step));
134std::unique_ptr<LoopUnrollInfo>
140 if (!is<MatchOperation>(matchNode))
144 if (!is<BitCompareOperation>(
cmpnode))
166 auto step =
idv == i0->origin() ? i1->origin() : i0->origin();
172 return std::unique_ptr<LoopUnrollInfo>(
185 for (
size_t n = 0; n < factor - 1; n++)
190 tmap.
insert(olv.pre, &smap.
lookup(*olv.post->origin()));
206 smap.
insert(olv.pre, olv.input->origin());
211 olv.output->divert_users(&smap.
lookup(*olv.post->origin()));
220 auto theta = ui.
theta();
224 auto oldLoopVars = theta->GetLoopVars();
225 for (
const auto & olv : oldLoopVars)
227 auto nlv = unrolled_theta->AddLoopVar(olv.input->origin());
228 smap.
insert(olv.pre, nlv.pre);
231 unroll_body(theta, unrolled_theta->subregion(), smap, factor);
232 unrolled_theta->set_predicate(&smap.
lookup(*theta->predicate()->origin()));
234 auto newLoopVars = unrolled_theta->GetLoopVars();
235 for (
size_t i = 0; i < oldLoopVars.size(); ++i)
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);
252 auto input = cmp->input(0)->origin() == &smap.
lookup(*ui.
end()) ? cmp->input(0) : cmp->input(1);
256 auto end = remainder.
mul(sv);
270 auto theta = ui.
theta();
279 for (
const auto & olv : theta->GetLoopVars())
280 olv.output->divert_users(&smap.
lookup(*olv.output));
281 return remove(theta);
289 for (
const auto & olv : theta->GetLoopVars())
290 olv.input->divert_to(&smap.
lookup(*olv.output));
308 auto original_theta = ui.
theta();
309 auto nbits = ui.
nbits();
312 if (niterations->ule({ nbits, (int64_t)factor }) ==
'1')
319 return remove(original_theta);
322 JLM_ASSERT(niterations->ugt({ nbits, (int64_t)factor }) ==
'1');
340 auto nbits = ui.
nbits();
352 return predNode.
output(0);
368 auto nbits = ui.
nbits();
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;
375 auto uf = &BitConstantOperation::create(*region, { nbits,
static_cast<int64_t
>(factor) });
376 auto mul = bitmul_op::create(nbits, step, uf);
378 SimpleNode::Create(*region, ui.
armoperation().
copy(), { idv->origin(), mul }).output(0);
381 SimpleNode::Create(*region, ui.
cmpoperation().
copy(), { arm, iend->origin() }).output(0);
382 auto & predNode = MatchOperation::CreateNode(*cmp, { { 1, 1 } }, 0, 2);
384 return predNode.output(0);
398 return predNode.
output(0);
404 auto otheta = ui.
theta();
414 for (
const auto & olv : otheta->GetLoopVars())
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);
422 unroll_body(otheta, ntheta->subregion(), rmap[1], factor);
424 ntheta->set_predicate(pred);
426 auto oldLoopVars = otheta->GetLoopVars();
427 auto newLoopVars = ntheta->GetLoopVars();
428 for (std::size_t n = 0; n < oldLoopVars.size(); ++n)
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);
437 for (
const auto & olv : oldLoopVars)
440 ngamma->AddExitVar({ &rmap[0].
lookup(*olv.output), &rmap[1].
lookup(*olv.output) }).output;
441 smap.
insert(olv.output, xv);
452 auto oldLoopVars = otheta->GetLoopVars();
453 for (
const auto & olv : oldLoopVars)
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);
461 otheta->subregion()->copy(ntheta->subregion(), rmap[1]);
462 ntheta->set_predicate(&rmap[1].lookup(*otheta->predicate()->origin()));
464 auto newLoopVars = ntheta->GetLoopVars();
466 for (std::size_t n = 0; n < oldLoopVars.size(); ++n)
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);
476 for (
const auto & olv : otheta->GetLoopVars())
477 olv.output->divert_users(&smap.
lookup(*olv.output));
491 if (ui->is_known() && ui->niterations())
500 bool unrolled =
false;
505 for (
size_t n = 0; n < structnode->nsubregions(); n++)
506 unrolled =
unroll(structnode->subregion(n), factor);
530 auto & graph =
module.Rvsdg();
531 auto statistics = Statistics::Create(module.SourceFilePath().value());
533 statistics->start(module.Rvsdg());
534 unroll(&graph.GetRootRegion(), factor_);
535 statistics->end(module.Rvsdg());
static jlm::util::StatisticsCollector statisticsCollector
std::unique_ptr< jlm::rvsdg::BitValueRepresentation > niterations() const noexcept
const rvsdg::SimpleOperation & cmpoperation() const noexcept
const jlm::rvsdg::BitValueRepresentation * end_value() const noexcept
bool is_additive() const noexcept
rvsdg::Output * step() const noexcept
rvsdg::SimpleNode * cmpnode() const noexcept
static std::unique_ptr< LoopUnrollInfo > create(rvsdg::ThetaNode *theta)
bool is_known() const noexcept
rvsdg::ThetaNode * theta() const noexcept
rvsdg::SimpleNode * armnode() const noexcept
size_t nbits() const noexcept
rvsdg::Output * idv() const noexcept
jlm::rvsdg::BitValueRepresentation remainder(size_t factor) const noexcept
const jlm::rvsdg::BitValueRepresentation * init_value() const noexcept
const jlm::rvsdg::BitValueRepresentation * step_value() const noexcept
rvsdg::Output * end() const noexcept
const rvsdg::SimpleOperation & armoperation() const noexcept
~Statistics() override=default
void end(const rvsdg::Graph &graph) noexcept
Statistics(const util::FilePath &sourceFile)
static std::unique_ptr< Statistics > Create(const util::FilePath &sourceFile)
void start(const rvsdg::Graph &graph) noexcept
Optimization that attempts to unroll loops (thetas).
~LoopUnrolling() noexcept override
static Output & create(Region ®ion, BitValueRepresentation value)
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)
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)
NodeOutput * output(size_t index) const noexcept
rvsdg::Region * region() const noexcept
size_t ninputs() const noexcept
virtual std::unique_ptr< Operation > copy() const =0
rvsdg::Region * region() const noexcept
void divert_users(jlm::rvsdg::Output *new_origin)
Represents the argument of a region.
Represent acyclic RVSDG subgraphs.
void copy(Region *target, SubstitutionMap &smap) const
Copy a region with substitutions.
rvsdg::StructuralNode * node() const noexcept
static SimpleNode & Create(Region ®ion, 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.
std::vector< LoopVar > GetLoopVars() const
Returns all loop variables.
ThetaNode * copy(rvsdg::Region *region, rvsdg::SubstitutionMap &smap) const override
Copy a node with substitutions.
rvsdg::Region * subregion() const noexcept
static ThetaNode * create(rvsdg::Region *parent)
RegionResult * predicate() const noexcept
LoopVar AddLoopVar(rvsdg::Output *origin)
Creates a new loop-carried variable.
void CollectDemandedStatistics(std::unique_ptr< Statistics > statistics)
util::Timer & GetTimer(const std::string &name)
util::Timer & AddTimer(std::string name)
void AddMeasurement(std::string name, T value)
Global memory state passed between functions.
static jlm::rvsdg::Output * create_residual_gamma_predicate(const rvsdg::SubstitutionMap &smap, const LoopUnrollInfo &ui)
static bool is_eqcmp(const rvsdg::Operation &op)
static void unroll_body(const rvsdg::ThetaNode *theta, rvsdg::Region *target, rvsdg::SubstitutionMap &smap, size_t factor)
static void unroll_theta(const LoopUnrollInfo &ui, rvsdg::SubstitutionMap &smap, size_t factor)
static bool is_idv(jlm::rvsdg::Input *input)
static void unroll_unknown_theta(const LoopUnrollInfo &ui, size_t factor)
static void add_remainder(const LoopUnrollInfo &ui, rvsdg::SubstitutionMap &smap, size_t factor)
static rvsdg::Output * push_from_theta(jlm::rvsdg::Output *output)
void unroll(rvsdg::ThetaNode *otheta, size_t factor)
static bool is_theta_invariant(const jlm::rvsdg::Output *output)
static jlm::rvsdg::Output * create_unrolled_gamma_predicate(const LoopUnrollInfo &ui, size_t factor)
static void copy_body_and_unroll(const rvsdg::ThetaNode *theta, size_t factor)
static void unroll_known_theta(const LoopUnrollInfo &ui, size_t factor)
static jlm::rvsdg::Output * create_unrolled_theta_predicate(rvsdg::Region *, const rvsdg::SubstitutionMap &smap, const LoopUnrollInfo &ui, size_t factor)
size_t nnodes(const jlm::rvsdg::Region *region) noexcept
NodeType * TryGetOwnerNode(const rvsdg::Input &input) noexcept
Checks if this is an input to a node of specified type.
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).
rvsdg::Input * input
Variable at loop entry (input to theta).