Jlm
Loading...
Searching...
No Matches
aggregation.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
9#include <deque>
10#include <functional>
11#include <unordered_map>
12
13namespace jlm::llvm
14{
15
16AggregationNode::~AggregationNode() noexcept = default;
17
18void
20{
21 std::function<std::vector<std::unique_ptr<AggregationNode>>(AggregationNode &)> reduce =
22 [&](AggregationNode & node)
23 {
24 JLM_ASSERT(is<LinearAggregationNode>(&node));
25
26 std::vector<std::unique_ptr<AggregationNode>> children;
27 for (size_t n = 0; n < node.children_.size(); n++)
28 {
29 auto & child = node.children_[n];
30
31 if (is<LinearAggregationNode>(child.get()))
32 {
33 auto tmp = reduce(*child);
34 std::move(tmp.begin(), tmp.end(), std::back_inserter(children));
35 }
36 else
37 {
38 children.push_back(std::move(child));
39 }
40 }
41
42 return children;
43 };
44
45 if (is<LinearAggregationNode>(&node))
46 {
47 auto children = reduce(node);
48
49 node.remove_children();
50 for (auto & child : children)
51 node.add_child(std::move(child));
52 }
53
54 for (auto & child : node)
55 normalize(child);
56}
57
59
60EntryAggregationNode::constiterator
62{
63 return constiterator(arguments_.begin());
64}
65
68{
69 return constiterator(arguments_.end());
70}
71
72std::string
74{
75 return "entry";
76}
77
79
80std::string
81ExitAggregationNode::debug_string() const
82{
83 return "exit";
84}
85
87
88std::string
89BasicBlockAggregationNode::debug_string() const
90{
91 return "block";
92}
93
95
96std::string
97LinearAggregationNode::debug_string() const
98{
99 return "linear";
100}
101
103
104std::string
105BranchAggregationNode::debug_string() const
106{
107 return "branch";
108}
109
111
112std::string
113LoopAggregationNode::debug_string() const
114{
115 return "loop";
116}
117
122class AggregationMap final
123{
124public:
125 bool
127 {
128 return map_.find(node) != map_.end();
129 }
130
131 std::unique_ptr<AggregationNode> &
133 {
134 JLM_ASSERT(contains(node));
135
136 return map_.at(node);
137 }
138
139 void
140 insert(ControlFlowGraphNode * node, std::unique_ptr<AggregationNode> anode)
141 {
142 map_[node] = std::move(anode);
143 }
144
145 void
147 {
148 map_.erase(node);
149 }
150
151 static std::unique_ptr<AggregationMap>
153 {
154 auto exit = cfg.exit();
155 auto entry = cfg.entry();
156 auto map = std::make_unique<AggregationMap>();
157
158 map->map_[entry] = EntryAggregationNode::create(entry->arguments());
159 map->map_[exit] = ExitAggregationNode::create(exit->results());
160 for (auto & node : cfg)
161 {
162 auto bb = static_cast<BasicBlock *>(&node);
163 map->map_[&node] = BasicBlockAggregationNode::create(std::move(bb->tacs()));
164 }
165
166 return map;
167 }
168
169private:
170 std::unordered_map<ControlFlowGraphNode *, std::unique_ptr<AggregationNode>> map_;
171};
172
173static bool
175{
176 return node->NumInEdges() == 1 && node->NumOutEdges() == 1;
177}
178
179static bool
181{
182 return node->NumOutEdges() > 1;
183}
184
185static bool
187{
188 return node->NumInEdges() > 1;
189}
190
191static bool
192is_branch(const ControlFlowGraphNode * split) noexcept
193{
194 if (split->NumOutEdges() < 2)
195 return false;
196
197 if (split->OutEdge(0)->sink()->NumOutEdges() != 1)
198 return false;
199
200 auto join = split->OutEdge(0)->sink()->OutEdge(0)->sink();
201 for (auto & edge : split->OutEdges())
202 {
203 if (edge.sink()->NumInEdges() != 1)
204 return false;
205 if (edge.sink()->NumOutEdges() != 1)
206 return false;
207 if (edge.sink()->OutEdge(0)->sink() != join)
208 return false;
209 }
210
211 return true;
212}
213
214static bool
215is_linear(const ControlFlowGraphNode * node) noexcept
216{
217 if (node->NumOutEdges() != 1)
218 return false;
219
220 auto exit = node->OutEdge(0)->sink();
221 if (exit->NumInEdges() != 1)
222 return false;
223
224 return true;
225}
226
227static ControlFlowGraphNode *
228aggregate(ControlFlowGraphNode *, ControlFlowGraphNode *, AggregationMap &);
229
234static void
236{
237 JLM_ASSERT(sccStruct.IsTailControlledLoop());
238
239 const auto entryNode = *sccStruct.EntryNodes().begin();
240 const auto exitNode = (*sccStruct.ExitEdges().begin())->source();
241
242 const auto repetitionEdge = *sccStruct.RepetitionEdges().begin();
243 // The RVSDG theta node always expects that the repetition of its body happens on control value 1.
244 JLM_ASSERT(repetitionEdge->index() == 1);
245 repetitionEdge->source()->remove_outedge(repetitionEdge->index());
246
247 const auto seseNode = aggregate(entryNode, exitNode, map);
248 auto loop = LoopAggregationNode::create(std::move(map.lookup(seseNode)));
249 map.insert(seseNode, std::move(loop));
250}
251
279static ControlFlowGraphNode *
281{
282 /* sanity checks */
283 JLM_ASSERT(split->NumOutEdges() > 1);
284 JLM_ASSERT(split->OutEdge(0)->sink()->NumOutEdges() == 1);
285 JLM_ASSERT(map.contains(split));
286
287 auto join = split->OutEdge(0)->sink()->OutEdge(0)->sink();
288 for (auto & edge : split->OutEdges())
289 {
290 JLM_ASSERT(edge.sink()->NumInEdges() == 1);
291 JLM_ASSERT(map.contains(edge.sink()));
292 JLM_ASSERT(edge.sink()->NumOutEdges() == 1);
293 JLM_ASSERT(edge.sink()->OutEdge(0)->sink() == join);
294 }
295
296 /* perform reduction */
297 auto sese = BasicBlock::create(split->cfg());
298 split->divert_inedges(sese);
299 sese->add_outedge(join);
300
301 auto branch = BranchAggregationNode::create();
302 for (auto & edge : split->OutEdges())
303 {
304 edge.sink()->remove_outedge(0);
305 branch->add_child(std::move(map.lookup(edge.sink())));
306 map.remove(edge.sink());
307 }
308
309 auto & child = map.lookup(split);
310 map.insert(sese, LinearAggregationNode::create(std::move(child), std::move(branch)));
311 map.remove(split);
312
313 /*
314 We need to adjust the SEE subgraphs' entry, in case it was the same as the split and we just
315 reduced it. We do not have to adjust the SESE subgraphs' exit node, as the branch join is not
316 reduced in this function.
317 */
318 *entry = split == *entry ? sese : *entry;
319 return sese;
320}
321
339static ControlFlowGraphNode *
341 ControlFlowGraphNode * source,
342 ControlFlowGraphNode ** entry,
343 ControlFlowGraphNode ** exit,
344 AggregationMap & map)
345{
346 JLM_ASSERT(is_linear(source));
347 auto sink = source->OutEdge(0)->sink();
348
349 auto sese = BasicBlock::create(source->cfg());
350 source->divert_inedges(sese);
351 for (auto & edge : sink->OutEdges())
352 sese->add_outedge(edge.sink());
353 sink->remove_outedges();
354
355 auto child0 = std::move(map.lookup(source));
356 auto child1 = std::move(map.lookup(sink));
357 map.insert(sese, LinearAggregationNode::create(std::move(child0), std::move(child1)));
358 map.remove(source);
359 map.remove(sink);
360
361 /*
362 We need to adjust the SESE subgraphs' entry and exit, in case we have just reduced either of
363 them.
364 */
365 *entry = source == *entry ? sese : *entry;
366 *exit = sink == *exit ? sese : *exit;
367
368 return sese;
369}
370
374static void
376{
377 auto sccs = find_sccs(entry, exit);
378 for (auto scc : sccs)
379 {
380 auto sccStructure = StronglyConnectedComponentStructure::Create(scc);
381
382 if (sccStructure->IsTailControlledLoop())
383 {
384 reduceLoop(*sccStructure, map);
385 continue;
386 }
387
388 JLM_UNREACHABLE("We should have never reached this point!");
389 }
390}
391
392static void
395 ControlFlowGraphNode ** entry,
396 ControlFlowGraphNode ** exit,
397 AggregationMap & map)
398{
399 /*
400 We reduced the entire subgraph to a single node. We are done here.
401 */
402 if (*entry == *exit)
403 {
404 JLM_ASSERT(node == *entry);
405 return;
406 }
407
408 /*
409 We traversed the entire subgraph until the end. Turn around.
410 */
411 if (node == *exit)
412 return;
413
414 /*
415 Reduce linear subgraph
416 */
417 if (is_linear(node))
418 {
419 auto sese = reduce_linear(node, entry, exit, map);
420 aggregate_acyclic_sese(sese, entry, exit, map);
421 return;
422 }
423
424 /*
425 Reduce branch subgraph
426 */
427 if (is_branch_split(node))
428 {
429 /*
430 First, greedily reduce all branches of the branch subgraph...
431 */
432 for (auto & edge : node->OutEdges())
433 aggregate_acyclic_sese(edge.sink(), entry, exit, map);
434
435 /*
436 ..., then try to reduce the branch subgraph itself.
437 */
438 if (is_branch(node))
439 {
440 auto sese = reduce_branch(node, entry, map);
441 aggregate_acyclic_sese(sese, entry, exit, map);
442 return;
443 }
444
445 JLM_UNREACHABLE("We should have never reached this point!");
446 }
447
448 /*
449 It is only a single basic block with one incoming and outgoing edge, simply step over it.
450 */
451 if (is_sese_basic_block(node))
452 {
453 aggregate_acyclic_sese(node->OutEdge(0)->sink(), entry, exit, map);
454 return;
455 }
456
457 /*
458 It is a branch join, turn around to the branch split such that we can reduce it.
459 */
460 if (is_branch_join(node))
461 return;
462
463 JLM_UNREACHABLE("We should have never reached this point!");
464}
465
480static ControlFlowGraphNode *
482{
483 aggregate_loops(entry, exit, map);
484 aggregate_acyclic_sese(entry, &entry, &exit, map);
485 JLM_ASSERT(entry == exit);
486
487 return entry;
488}
489
490std::unique_ptr<AggregationNode>
492{
494
495 auto map = AggregationMap::create(cfg);
496 auto root = aggregate(cfg.entry(), cfg.exit(), *map);
497
498 return std::move(map->lookup(root));
499}
500
501size_t
503{
504 size_t n = 0;
505 for (auto & child : root)
506 n += ntacs(child);
507
508 if (auto bb = dynamic_cast<const BasicBlockAggregationNode *>(&root))
509 n += bb->tacs().ntacs();
510
511 return n;
512}
513
514}
void remove(ControlFlowGraphNode *node)
void insert(ControlFlowGraphNode *node, std::unique_ptr< AggregationNode > anode)
std::unique_ptr< AggregationNode > & lookup(ControlFlowGraphNode *node)
static std::unique_ptr< AggregationMap > create(ControlFlowGraph &cfg)
bool contains(ControlFlowGraphNode *node) const
std::unordered_map< ControlFlowGraphNode *, std::unique_ptr< AggregationNode > > map_
virtual ~AggregationNode() noexcept
std::vector< std::unique_ptr< AggregationNode > > children_
static std::unique_ptr< AggregationNode > create()
~BasicBlockAggregationNode() noexcept override
static BasicBlock * create(ControlFlowGraph &cfg)
static std::unique_ptr< AggregationNode > create()
~BranchAggregationNode() noexcept override
ControlFlowGraphNode * sink() const noexcept
Definition cfg-node.hpp:57
ControlFlowGraph & cfg() const noexcept
Definition cfg-node.hpp:106
ControlFlowGraphEdge * OutEdge(size_t n) const
Definition cfg-node.hpp:115
outedge_iterator_range OutEdges() const
Definition cfg-node.hpp:122
size_t NumOutEdges() const noexcept
Definition cfg-node.cpp:46
void divert_inedges(llvm::ControlFlowGraphNode *new_successor)
Definition cfg-node.hpp:171
ExitNode * exit() const noexcept
Definition cfg.hpp:212
EntryNode * entry() const noexcept
Definition cfg.hpp:206
std::vector< llvm::Argument * > arguments_
constiterator end() const
static std::unique_ptr< AggregationNode > create(const std::vector< llvm::Argument * > &arguments)
std::string debug_string() const override
util::PtrIterator< const llvm::Argument, std::vector< llvm::Argument * >::const_iterator > constiterator
~EntryAggregationNode() noexcept override
static std::unique_ptr< AggregationNode > create(const std::vector< const Variable * > &results)
~ExitAggregationNode() noexcept override
static std::unique_ptr< AggregationNode > create(std::unique_ptr< AggregationNode > n1, std::unique_ptr< AggregationNode > n2)
~LinearAggregationNode() noexcept override
~LoopAggregationNode() noexcept override
static std::unique_ptr< AggregationNode > create(std::unique_ptr< AggregationNode > body)
Strongly Connected Component Structure.
static std::unique_ptr< StronglyConnectedComponentStructure > Create(const StronglyConnectedComponent &scc)
#define JLM_ASSERT(x)
Definition common.hpp:16
#define JLM_UNREACHABLE(msg)
Definition common.hpp:43
Global memory state passed between functions.
static void aggregate_loops(ControlFlowGraphNode *entry, ControlFlowGraphNode *exit, AggregationMap &map)
std::vector< StronglyConnectedComponent > find_sccs(const ControlFlowGraph &cfg)
static ControlFlowGraphNode * aggregate(ControlFlowGraphNode *, ControlFlowGraphNode *, AggregationMap &)
static bool is_branch_join(const ControlFlowGraphNode *node) noexcept
static ControlFlowGraphNode * reduce_branch(ControlFlowGraphNode *split, ControlFlowGraphNode **entry, AggregationMap &map)
static bool is_linear(const ControlFlowGraphNode *node) noexcept
static ControlFlowGraphNode * reduce_linear(ControlFlowGraphNode *source, ControlFlowGraphNode **entry, ControlFlowGraphNode **exit, AggregationMap &map)
static bool reduce(const ControlFlowGraph &cfg, const std::function< bool(llvm::ControlFlowGraphNode *, std::unordered_set< llvm::ControlFlowGraphNode * > &)> &f)
static bool is_branch_split(const ControlFlowGraphNode *node) noexcept
static void reduceLoop(const StronglyConnectedComponentStructure &sccStruct, AggregationMap &map)
static bool is_branch(const ControlFlowGraphNode *split) noexcept
static void aggregate_acyclic_sese(ControlFlowGraphNode *node, ControlFlowGraphNode **entry, ControlFlowGraphNode **exit, AggregationMap &map)
bool is_proper_structured(const ControlFlowGraph &cfg)
size_t ntacs(const AggregationNode &root)
static bool is_sese_basic_block(const ControlFlowGraphNode *node) noexcept