40 static std::unique_ptr<Statistics>
43 return std::make_unique<Statistics>(sourceFile);
63 if (jlm::rvsdg::is<rvsdg::BitConstantOperation>(
64 rvsdg::TryGetOwnerNode<rvsdg::SimpleNode>(*output)))
67 auto theta = rvsdg::TryGetRegionParentNode<rvsdg::ThetaNode>(*output);
71 auto loopVar = theta->MapPreLoopVar(*output);
82 auto tmp = rvsdg::TryGetOwnerNode<rvsdg::SimpleNode>(*output);
83 JLM_ASSERT(jlm::rvsdg::is<jlm::rvsdg::BitConstantOperation>(tmp));
87 auto node = tmp->
copy(theta->region(), {});
99 auto node = TryGetOwnerNode<SimpleNode>(*input);
100 JLM_ASSERT(is<bitadd_op>(node) || is<bitsub_op>(node));
102 if (
auto theta = rvsdg::TryGetRegionParentNode<ThetaNode>(*input->
origin()))
104 auto loopvar = theta->MapPreLoopVar(*input->
origin());
105 return rvsdg::TryGetOwnerNode<Node>(*loopvar.post->origin()) == node;
111 std::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));
134 std::unique_ptr<LoopUnrollInfo>
140 if (!is<MatchOperation>(matchNode))
143 auto cmpnode = rvsdg::TryGetOwnerNode<SimpleNode>(*matchNode->input(0)->origin());
144 if (!is<BitCompareOperation>(
cmpnode))
153 auto armnode = rvsdg::TryGetOwnerNode<SimpleNode>(*(
end == o0 ? o1 : o0));
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()));
225 for (
const auto & olv : oldLoopVars)
227 auto nlv = unrolled_theta->AddLoopVar(olv.input->origin());
228 smap.
insert(olv.pre, nlv.pre);
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);
280 olv.output->divert_users(&smap.
lookup(*olv.output));
290 olv.input->divert_to(&smap.
lookup(*olv.output));
308 auto original_theta = ui.
theta();
312 if (
niterations->ule({ nbits, (int64_t)factor }) ==
'1')
319 return remove(original_theta);
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) });
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 pred =
match(1, { { 1, 1 } }, 0, 2,
cmp);
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());
537 statisticsCollector.CollectDemandedStatistics(std::move(statistics));
rvsdg::Output * idv() const noexcept
std::unique_ptr< jlm::rvsdg::BitValueRepresentation > niterations() const noexcept
rvsdg::Output * end() const noexcept
const rvsdg::SimpleOperation & cmpoperation() const noexcept
rvsdg::SimpleNode * armnode() const noexcept
bool is_additive() const noexcept
static std::unique_ptr< LoopUnrollInfo > create(rvsdg::ThetaNode *theta)
LoopUnrollInfo(rvsdg::SimpleNode *cmpnode, rvsdg::SimpleNode *armnode, rvsdg::Output *idv, rvsdg::Output *step, rvsdg::Output *end)
rvsdg::Output * step() const noexcept
const jlm::rvsdg::BitValueRepresentation * end_value() const noexcept
bool is_known() const noexcept
const rvsdg::SimpleOperation & armoperation() const noexcept
rvsdg::ThetaNode * theta() const noexcept
size_t nbits() const noexcept
rvsdg::SimpleNode * cmpnode() const noexcept
jlm::rvsdg::BitValueRepresentation remainder(size_t factor) const noexcept
const jlm::rvsdg::BitValueRepresentation * step_value() const noexcept
const jlm::rvsdg::BitValueRepresentation * init_value() const noexcept
~Statistics() override=default
static std::unique_ptr< Statistics > Create(const util::FilePath &sourceFile)
void end(const rvsdg::Graph &graph) noexcept
Statistics(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
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
NodeInput * input(size_t index) const noexcept
NodeOutput * output(size_t index) const noexcept
static SimpleNode & Create(Region ®ion, std::unique_ptr< Operation > operation, const std::vector< rvsdg::Output * > &operands)
void insert(const Output *original, Output *substitute)
Output & lookup(const Output &original) const
RegionResult * predicate() const noexcept
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)
LoopVar AddLoopVar(rvsdg::Output *origin)
Creates a new loop-carried variable.
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_unrolled_gamma_predicate(const LoopUnrollInfo &ui, size_t factor)
static rvsdg::Output * push_from_theta(jlm::rvsdg::Output *output)
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 jlm::rvsdg::Output * create_residual_gamma_predicate(const rvsdg::SubstitutionMap &smap, const LoopUnrollInfo &ui)
static jlm::rvsdg::Output * create_unrolled_theta_predicate(rvsdg::Region *, const rvsdg::SubstitutionMap &smap, const LoopUnrollInfo &ui, 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)
void unroll(rvsdg::ThetaNode *otheta, size_t factor)
static bool is_theta_invariant(const jlm::rvsdg::Output *output)
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 bool ThetaLoopVarIsInvariant(const ThetaNode::LoopVar &loopVar) noexcept
static void remove(Node *node)
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)
size_t nnodes(const jlm::rvsdg::Region *region) noexcept
rvsdg::Output * output
Variable at loop exit (output of theta).
rvsdg::Input * input
Variable at loop entry (input to theta).
static const char * NumRvsdgNodesBefore
static const char * NumRvsdgNodesAfter
static const char * Timer