Jlm
Loading...
Searching...
No Matches
gamma.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2010 2011 2012 2013 2014 Helge Bahmann <hcb@chaoticmind.net>
3 * Copyright 2013 2014 2015 2016 Nico Reißmann <nico.reissmann@gmail.com>
4 * See COPYING for terms of redistribution.
5 */
6
7#include <algorithm>
8
10#include <jlm/rvsdg/gamma.hpp>
13
14namespace jlm::rvsdg
15{
16
17/* gamma normal form */
18
19static bool
21{
22 auto constant = rvsdg::TryGetOwnerNode<SimpleNode>(*gamma->predicate()->origin());
23 return constant && is<ControlConstantOperation>(constant->GetOperation());
24}
25
26static void
28{
29 auto origin = gamma->predicate()->origin();
30 auto & constant = AssertGetOwnerNode<SimpleNode>(*origin);
31 auto cop = static_cast<const ControlConstantOperation *>(&constant.GetOperation());
32 auto alternative = cop->value().alternative();
33
35 for (const auto & ev : gamma->GetEntryVars())
36 smap.insert(ev.branchArgument[alternative], ev.input->origin());
37
38 gamma->subregion(alternative)->copy(gamma->region(), smap);
39
40 for (auto exitvar : gamma->GetExitVars())
41 exitvar.output->divert_users(&smap.lookup(*exitvar.branchResult[alternative]->origin()));
42
43 remove(gamma);
44}
45
46static bool
48{
49 bool was_normalized = true;
50 for (auto exitvar : gamma->GetExitVars())
51 {
52 auto argument = dynamic_cast<const rvsdg::RegionArgument *>(exitvar.branchResult[0]->origin());
53 if (!argument)
54 continue;
55
56 size_t n = 0;
57 auto input = argument->input();
58 for (n = 1; n < exitvar.branchResult.size(); n++)
59 {
60 auto argument =
61 dynamic_cast<const rvsdg::RegionArgument *>(exitvar.branchResult[n]->origin());
62 if (!argument && argument->input() != input)
63 break;
64 }
65
66 if (n == exitvar.branchResult.size())
67 {
68 exitvar.output->divert_users(argument->input()->origin());
69 was_normalized = false;
70 }
71 }
72
73 return was_normalized;
74}
75
76static std::unordered_set<jlm::rvsdg::Output *>
78{
79 // check gamma predicate
81 if (!match || !is<MatchOperation>(match->GetOperation()))
82 return {};
83
84 /* check number of alternatives */
85 auto match_op = static_cast<const MatchOperation *>(&match->GetOperation());
86 std::unordered_set<uint64_t> set({ match_op->default_alternative() });
87 for (const auto & pair : *match_op)
88 set.insert(pair.second);
89
90 if (set.size() != gamma->nsubregions())
91 return {};
92
93 /* check for constants */
94 std::unordered_set<jlm::rvsdg::Output *> outputs;
95 for (const auto & exitvar : gamma->GetExitVars())
96 {
97 if (!is<ControlType>(*exitvar.output->Type()))
98 continue;
99
100 size_t n = 0;
101 for (n = 0; n < exitvar.branchResult.size(); n++)
102 {
103 auto node = rvsdg::TryGetOwnerNode<SimpleNode>(*exitvar.branchResult[n]->origin());
104 if (!node || !is<ControlConstantOperation>(node->GetOperation()))
105 break;
106
107 auto op = static_cast<const ControlConstantOperation *>(&node->GetOperation());
108 if (op->value().nalternatives() != 2)
109 break;
110 }
111 if (n == exitvar.branchResult.size())
112 outputs.insert(exitvar.output);
113 }
114
115 return outputs;
116}
117
118static void
119perform_control_constant_reduction(std::unordered_set<jlm::rvsdg::Output *> & outputs)
120{
121 auto & gamma = rvsdg::AssertGetOwnerNode<GammaNode>(**outputs.begin());
122 auto origin = gamma.predicate()->origin();
124 JLM_ASSERT(matchNode && matchOperation);
125
126 std::unordered_map<uint64_t, uint64_t> map;
127 for (const auto & pair : *matchOperation)
128 map[pair.second] = pair.first;
129
130 for (const auto & xv : gamma.GetExitVars())
131 {
132 if (outputs.find(xv.output) == outputs.end())
133 continue;
134
135 size_t defalt = 0;
136 size_t nalternatives = 0;
137 std::unordered_map<uint64_t, uint64_t> new_mapping;
138 for (size_t n = 0; n < xv.branchResult.size(); n++)
139 {
140 auto origin = xv.branchResult[n]->origin();
143 auto & value = ctlConstantOperation->value();
144 nalternatives = value.nalternatives();
145 if (map.find(n) != map.end())
146 new_mapping[map[n]] = value.alternative();
147 else
148 defalt = value.alternative();
149 }
150
151 auto origin = matchNode->input(0)->origin();
152 auto & matchNode = MatchOperation::CreateNode(*origin, new_mapping, defalt, nalternatives);
153 xv.output->divert_users(matchNode.output(0));
154 }
155}
156
157bool
159{
160 auto gammaNode = dynamic_cast<GammaNode *>(&node);
161 if (gammaNode && is_predicate_reducible(gammaNode))
162 {
164 return true;
165 }
166
167 return false;
168}
169
170bool
172{
173 auto gammaNode = dynamic_cast<GammaNode *>(&node);
174 if (gammaNode == nullptr)
175 return false;
176
177 auto outputs = is_control_constant_reducible(gammaNode);
178 if (outputs.empty())
179 return false;
180
182 return true;
183}
184
185bool
187{
188 const auto gammaNode = dynamic_cast<GammaNode *>(&node);
189 if (gammaNode == nullptr)
190 return false;
191
192 return !perform_invariant_reduction(gammaNode);
193}
194
197
198std::string
200{
201 return "GAMMA";
202}
203
204std::unique_ptr<Operation>
206{
207 return std::make_unique<GammaOperation>(*this);
208}
209
210bool
212{
213 auto op = dynamic_cast<const GammaOperation *>(&other);
214 return op && op->numAlternatives_ == numAlternatives_;
215}
216
217std::shared_ptr<const Type>
218GammaOperation::GetMatchContentType(std::size_t alternative) const
219{
220 return alternative < MatchContentTypes_.size() ? MatchContentTypes_[alternative]
222}
223
224/* gamma node */
225
227
229 : StructuralNode(predicate.region(), op->nalternatives()),
230 Operation_(std::move(op))
231{
232 addInput(
233 std::make_unique<StructuralInput>(
234 this,
235 &predicate,
236 ControlType::Create(Operation_->nalternatives())),
237 false);
238 for (std::size_t n = 0; n < Operation_->nalternatives(); ++n)
239 {
240 RegionArgument::Create(*subregion(n), nullptr, Operation_->GetMatchContentType(n));
241 }
242}
243
245 rvsdg::Output & predicate,
246 size_t nalternatives,
247 std::vector<std::shared_ptr<const Type>> match_content_types)
248 : GammaNode(
249 predicate,
250 std::make_unique<GammaOperation>(nalternatives, std::move(match_content_types)))
251{}
252
253[[nodiscard]] const GammaOperation &
258
261{
262 auto gammaInput = new StructuralInput(this, origin, origin->Type());
263 addInput(std::unique_ptr<StructuralInput>(gammaInput), true);
264
265 EntryVar ev;
267
268 for (size_t n = 0; n < nsubregions(); n++)
269 {
270 ev.branchArgument.push_back(
272 }
273
274 return ev;
275}
276
278GammaNode::GetEntryVar(std::size_t index) const
279{
280 JLM_ASSERT(index <= ninputs() - 1);
281 EntryVar ev;
282 ev.input = input(index + 1);
283 ev.branchArgument.resize(nsubregions());
284 for (size_t n = 0; n < nsubregions(); ++n)
285 {
286 ev.branchArgument[n] = subregion(n)->argument(index + 1);
287 }
288 return ev;
289}
290
293{
294 MatchVar mv;
295 mv.input = input(0);
296 mv.matchContent.resize(nsubregions());
297 for (size_t n = 0; n < nsubregions(); ++n)
298 {
299 mv.matchContent[n] = subregion(n)->argument(0);
300 }
301 return mv;
302}
303
304std::vector<GammaNode::EntryVar>
306{
307 std::vector<GammaNode::EntryVar> vars(ninputs() - 1);
308 for (size_t n = 0; n < vars.size(); ++n)
309 {
310 vars[n] = GetEntryVar(n);
311 }
312 return vars;
313}
314
315std::variant<GammaNode::MatchVar, GammaNode::EntryVar>
317{
319 if (input.index() == 0)
320 {
321 return GetMatchVar();
322 }
323 else
324 {
325 return GetEntryVar(input.index() - 1);
326 }
327}
328
329std::variant<GammaNode::MatchVar, GammaNode::EntryVar>
331{
333 if (output.index() == 0)
334 {
335 return GetMatchVar();
336 }
337 else
338 {
339 return GetEntryVar(output.index() - 1);
340 }
341}
342
343const rvsdg::Input &
345{
347 auto & in = *input(output.index());
348 JLM_ASSERT(*in.Type() == *output.Type());
349 return in;
350}
351
352Input &
354{
356 auto & in = *input(output.index());
357 JLM_ASSERT(*in.Type() == *output.Type());
358 return in;
359}
360
362GammaNode::AddExitVar(const std::vector<jlm::rvsdg::Output *> & values)
363{
364 if (values.size() != nsubregions())
365 throw util::Error("Incorrect number of values.");
366
367 const auto & type = values[0]->Type();
368 auto output = addOutput(std::make_unique<StructuralOutput>(this, type));
369
370 std::vector<rvsdg::Input *> branchResults;
371 for (size_t n = 0; n < nsubregions(); n++)
372 {
373 branchResults.push_back(
375 }
376
377 return ExitVar{ std::move(branchResults), std::move(output) };
378}
379
380std::vector<GammaNode::ExitVar>
382{
383 std::vector<GammaNode::ExitVar> vars;
384 for (size_t n = 0; n < noutputs(); ++n)
385 {
386 std::vector<rvsdg::Input *> branchResults;
387 for (size_t k = 0; k < nsubregions(); ++k)
388 {
389 branchResults.push_back(subregion(k)->result(n));
390 }
391 vars.push_back(ExitVar{ std::move(branchResults), output(n) });
392 }
393 return vars;
394}
395
398{
400 std::vector<rvsdg::Input *> branchResults;
401 for (size_t k = 0; k < nsubregions(); ++k)
402 {
403 branchResults.push_back(subregion(k)->result(output.index()));
404 }
405 return ExitVar{ std::move(branchResults), Node::output(output.index()) };
406}
407
410{
412 std::vector<rvsdg::Input *> branchResults;
413 for (size_t k = 0; k < nsubregions(); ++k)
414 {
415 branchResults.push_back(subregion(k)->result(input.index()));
416 }
417 return ExitVar{ std::move(branchResults), Node::output(input.index()) };
418}
419
420const Output &
422{
424 auto & out = *output(input.index());
425 JLM_ASSERT(*out.Type() == *input.Type());
426 return out;
427}
428
429Output &
431{
433 auto & out = *output(input.index());
434 JLM_ASSERT(*out.Type() == *input.Type());
435 return out;
436}
437
438void
439GammaNode::RemoveExitVars(const std::vector<Output *> & gammaOutputs)
440{
441 util::HashSet<size_t> indices;
442 for (const auto output : gammaOutputs)
443 {
446 indices.insert(output->index());
447 }
448
449 for (auto & subregion : Subregions())
450 {
451 [[maybe_unused]] const auto numRemovedResults = subregion.RemoveResults(indices);
452 JLM_ASSERT(numRemovedResults == indices.Size());
453 }
454 [[maybe_unused]] const auto numRemovedOutputs = RemoveOutputs(indices);
455 JLM_ASSERT(numRemovedOutputs == indices.Size());
456}
457
458void
459GammaNode::RemoveEntryVars(const std::vector<EntryVar> & entryVars)
460{
461 util::HashSet<size_t> indices;
462 for (const auto & [input, _] : entryVars)
463 {
465 indices.insert(input->index());
466 }
467
468 for (auto & subregion : Subregions())
469 {
471 JLM_ASSERT(numRemovedArguments == indices.Size());
472 }
473 [[maybe_unused]] const auto numRemovedInputs = RemoveInputs(indices);
474 JLM_ASSERT(numRemovedInputs == indices.Size());
475}
476
477GammaNode *
479{
480 auto gamma = create(&smap.lookup(*predicate()->origin()), nsubregions());
481
482 /* add entry variables to new gamma */
483 std::vector<SubstitutionMap> rmap(nsubregions());
484 for (const auto & oev : GetEntryVars())
485 {
486 auto nev = gamma->AddEntryVar(&smap.lookup(*oev.input->origin()));
487 for (size_t n = 0; n < nsubregions(); n++)
488 rmap[n].insert(oev.branchArgument[n], nev.branchArgument[n]);
489 }
490
491 /* copy subregions */
492 for (size_t r = 0; r < nsubregions(); r++)
493 subregion(r)->copy(gamma->subregion(r), rmap[r]);
494
495 /* add exit variables to new gamma */
496 for (const auto & oex : GetExitVars())
497 {
498 std::vector<jlm::rvsdg::Output *> operands;
499 for (size_t n = 0; n < oex.branchResult.size(); n++)
500 operands.push_back(&rmap[n].lookup(*oex.branchResult[n]->origin()));
501 auto nex = gamma->AddExitVar(std::move(operands));
502 smap.insert(oex.output, nex.output);
503 }
504
505 return gamma;
506}
507
508std::optional<rvsdg::Output *>
510{
511 // For any region result, check if it directly maps to a
512 // gamma entry variable, and returns the origin of its
513 // corresponding value (the def site preceding the gamma node).
514 auto GetExternalOriginOf = [&gamma](rvsdg::Input * use) -> std::optional<rvsdg::Output *>
515 {
516 // Test whether origin of this is a region entry argument of
517 // this gamma node.
518 auto def = use->origin();
520 {
521 return std::nullopt;
522 }
523 auto rolevar = gamma.MapBranchArgument(*def);
524 if (auto entryvar = std::get_if<GammaNode::EntryVar>(&rolevar))
525 {
526 return entryvar->input->origin();
527 }
528 else
529 {
530 return std::nullopt;
531 }
532 };
533
534 auto firstOrigin = GetExternalOriginOf(exitvar.branchResult[0]);
535 if (!firstOrigin)
536 {
537 return std::nullopt;
538 }
539
540 for (size_t n = 1; n < exitvar.branchResult.size(); ++n)
541 {
542 auto currentOrigin = GetExternalOriginOf(exitvar.branchResult[n]);
544 {
545 return std::nullopt;
546 }
547 }
548
549 return firstOrigin;
550}
551
552}
const ControlValueRepresentation & value() const noexcept
Definition control.hpp:116
static std::shared_ptr< const ControlType > Create(std::size_t nalternatives)
Instantiates control type.
Definition control.cpp:50
size_t alternative() const noexcept
Definition control.hpp:83
Conditional operator / pattern matching.
Definition gamma.hpp:99
void RemoveEntryVars(const std::vector< EntryVar > &entryVars)
Removes the given entry variables.
Definition gamma.cpp:459
const GammaOperation & GetOperation() const noexcept override
Definition gamma.cpp:254
ExitVar MapOutputExitVar(const rvsdg::Output &output) const
Maps gamma output to exit variable description.
Definition gamma.cpp:397
const rvsdg::Input & mapBranchArgumentToInput(const rvsdg::Output &output) const
Maps branch subregion entry argument to its corresponding gamma input.
Definition gamma.cpp:344
std::unique_ptr< GammaOperation > Operation_
Definition gamma.hpp:459
std::variant< MatchVar, EntryVar > MapInput(const rvsdg::Input &input) const
Maps gamma input to its role (match variable or entry variable).
Definition gamma.cpp:316
GammaNode * copy(jlm::rvsdg::Region *region, SubstitutionMap &smap) const override
Copy a node with substitutions.
Definition gamma.cpp:478
EntryVar AddEntryVar(rvsdg::Output *origin)
Routes a variable into the gamma branches.
Definition gamma.cpp:260
EntryVar GetEntryVar(std::size_t index) const
Gets entry variable by index.
Definition gamma.cpp:278
static GammaNode * create(jlm::rvsdg::Output *predicate, size_t nalternatives)
Definition gamma.hpp:161
GammaNode(rvsdg::Output &predicate, std::unique_ptr< GammaOperation > op)
Definition gamma.cpp:228
std::variant< MatchVar, EntryVar > MapBranchArgument(const rvsdg::Output &output) const
Maps branch subregion entry argument to its role (pattern match or entry variable).
Definition gamma.cpp:330
std::vector< ExitVar > GetExitVars() const
Gets all exit variables for this gamma.
Definition gamma.cpp:381
const Output & mapBranchResultToOutput(const Input &input) const
Maps branch subregion exit result to its corresponding gamma output.
Definition gamma.cpp:421
std::vector< EntryVar > GetEntryVars() const
Gets all entry variables for this gamma.
Definition gamma.cpp:305
void RemoveExitVars(const std::vector< Output * > &gammaOutputs)
Removes the exit variables corresponding to the given gammaOutputs.
Definition gamma.cpp:439
ExitVar MapBranchResultExitVar(const rvsdg::Input &input) const
Maps gamma region exit result to exit variable description.
Definition gamma.cpp:409
rvsdg::Input * predicate() const noexcept
Definition gamma.hpp:487
~GammaNode() noexcept override
ExitVar AddExitVar(const std::vector< rvsdg::Output * > &values)
Routes per-branch result of gamma to output.
Definition gamma.cpp:362
MatchVar GetMatchVar() const
Definition gamma.cpp:292
std::shared_ptr< const Type > GetMatchContentType(std::size_t alternative) const
Returns the type of pattern matching content produced in a branch.
Definition gamma.cpp:218
std::unique_ptr< Operation > copy() const override
Definition gamma.cpp:205
bool operator==(const Operation &other) const noexcept override
Definition gamma.cpp:211
std::vector< std::shared_ptr< const Type > > MatchContentTypes_
Definition gamma.hpp:61
std::string debug_string() const override
Definition gamma.cpp:199
~GammaOperation() noexcept override
Definition gamma.cpp:195
size_t index() const noexcept
Definition node.hpp:52
Output * origin() const noexcept
Definition node.hpp:58
const std::shared_ptr< const rvsdg::Type > & Type() const noexcept
Definition node.hpp:67
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
size_t RemoveInputs(const util::HashSet< size_t > &indices)
Definition node.cpp:306
rvsdg::Region * region() const noexcept
Definition node.hpp:761
size_t ninputs() const noexcept
Definition node.hpp:609
size_t noutputs() const noexcept
Definition node.hpp:644
size_t RemoveOutputs(const util::HashSet< size_t > &indices)
Definition node.cpp:342
size_t index() const noexcept
Definition node.hpp:274
void divert_users(jlm::rvsdg::Output *new_origin)
Definition node.hpp:301
bool IsDead() const noexcept
Definition node.hpp:295
const std::shared_ptr< const rvsdg::Type > & Type() const noexcept
Definition node.hpp:366
Represents the argument of a region.
Definition region.hpp:41
static RegionArgument & Create(rvsdg::Region &region, StructuralInput *input, std::shared_ptr< const rvsdg::Type > type)
Creates region entry argument.
Definition region.cpp:63
StructuralInput * input() const noexcept
Definition region.hpp:69
static RegionResult & Create(rvsdg::Region &region, rvsdg::Output &origin, StructuralOutput *output, std::shared_ptr< const rvsdg::Type > type)
Create region exit result.
Definition region.cpp:112
Represent acyclic RVSDG subgraphs.
Definition region.hpp:213
size_t RemoveResults(const util::HashSet< size_t > &indices)
Definition region.cpp:281
RegionArgument * argument(size_t index) const noexcept
Definition region.hpp:466
void copy(Region *target, SubstitutionMap &smap) const
Copy a region with substitutions.
Definition region.cpp:317
RegionResult * result(size_t index) const noexcept
Definition region.hpp:500
size_t RemoveArguments(const util::HashSet< size_t > &indices)
Definition region.cpp:213
StructuralInput * addInput(std::unique_ptr< StructuralInput > input, bool notifyRegion)
StructuralOutput * addOutput(std::unique_ptr< StructuralOutput > input)
SubregionIteratorRange Subregions()
rvsdg::Region * subregion(size_t index) const noexcept
size_t nsubregions() const noexcept
StructuralOutput * output(size_t index) const noexcept
StructuralInput * input(size_t index) const noexcept
void insert(const Output *original, Output *substitute)
static std::shared_ptr< const UnitType > Create()
Definition UnitType.cpp:33
bool insert(ItemType item)
Definition HashSet.hpp:210
std::size_t Size() const noexcept
Definition HashSet.hpp:187
#define JLM_ASSERT(x)
Definition common.hpp:16
static bool perform_invariant_reduction(GammaNode *gamma)
Definition gamma.cpp:47
bool ReduceGammaControlConstant(Node &node)
Definition gamma.cpp:171
static void perform_predicate_reduction(GammaNode *gamma)
Definition gamma.cpp:27
bool ReduceGammaWithStaticallyKnownPredicate(Node &node)
Definition gamma.cpp:158
static bool is_predicate_reducible(const GammaNode *gamma)
Definition gamma.cpp:20
static void remove(Node *node)
Definition region.hpp:1035
static void perform_control_constant_reduction(std::unordered_set< jlm::rvsdg::Output * > &outputs)
Definition gamma.cpp:119
static std::vector< jlm::rvsdg::Output * > operands(const Node *node)
Definition node.hpp:1049
static std::vector< jlm::rvsdg::Output * > outputs(const Node *node)
Definition node.hpp:1058
NodeType * TryGetOwnerNode(const rvsdg::Input &input) noexcept
Checks if this is an input to a node of specified type.
Definition node.hpp:872
std::optional< rvsdg::Output * > GetGammaInvariantOrigin(const GammaNode &gamma, const GammaNode::ExitVar &exitvar)
Determines whether a gamma exit var is path-invariant.
Definition gamma.cpp:509
static std::unordered_set< jlm::rvsdg::Output * > is_control_constant_reducible(GammaNode *gamma)
Definition gamma.cpp:77
bool ReduceGammaInvariantVariables(Node &node)
Definition gamma.cpp:186
A variable routed into all gamma regions.
Definition gamma.hpp:131
rvsdg::Input * input
Variable at entry point (input to gamma node).
Definition gamma.hpp:135
A variable routed out of all gamma regions as result.
Definition gamma.hpp:146
The match/discriminator variable of this gamma node.
Definition gamma.hpp:116
rvsdg::Input * input
The variable matched over (i.e. the "selector" of the gamma branch).
Definition gamma.hpp:120