Jlm
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 
13 namespace jlm::llvm
14 {
15 
16 AggregationNode::~AggregationNode() noexcept = default;
17 
18 void
19 AggregationNode::normalize(AggregationNode & node)
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 
60 EntryAggregationNode::constiterator
61 EntryAggregationNode::begin() const
62 {
63  return constiterator(arguments_.begin());
64 }
65 
68 {
69  return constiterator(arguments_.end());
70 }
71 
72 std::string
74 {
75  return "entry";
76 }
77 
79 
80 std::string
81 ExitAggregationNode::debug_string() const
82 {
83  return "exit";
84 }
85 
87 
88 std::string
89 BasicBlockAggregationNode::debug_string() const
90 {
91  return "block";
92 }
93 
95 
96 std::string
97 LinearAggregationNode::debug_string() const
98 {
99  return "linear";
100 }
101 
103 
104 std::string
105 BranchAggregationNode::debug_string() const
106 {
107  return "branch";
108 }
109 
110 LoopAggregationNode::~LoopAggregationNode() noexcept = default;
111 
112 std::string
113 LoopAggregationNode::debug_string() const
114 {
115  return "loop";
116 }
117 
122 class AggregationMap final
123 {
124 public:
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 
169 private:
170  std::unordered_map<ControlFlowGraphNode *, std::unique_ptr<AggregationNode>> map_;
171 };
172 
173 static bool
175 {
176  return node->NumInEdges() == 1 && node->NumOutEdges() == 1;
177 }
178 
179 static bool
180 is_branch_split(const ControlFlowGraphNode * node) noexcept
181 {
182  return node->NumOutEdges() > 1;
183 }
184 
185 static bool
186 is_branch_join(const ControlFlowGraphNode * node) noexcept
187 {
188  return node->NumInEdges() > 1;
189 }
190 
191 static bool
192 is_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 
214 static bool
215 is_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 
227 static ControlFlowGraphNode *
228 aggregate(ControlFlowGraphNode *, ControlFlowGraphNode *, AggregationMap &);
229 
234 static void
236 {
237  JLM_ASSERT(sccstruct.IsTailControlledLoop());
238 
239  auto exit = (*sccstruct.ExitEdges().begin())->source();
240  auto entry = *sccstruct.EntryNodes().begin();
241 
242  auto redge = *sccstruct.RepetitionEdges().begin();
243  redge->source()->remove_outedge(redge->index());
244 
245  auto sese = aggregate(entry, exit, map);
246  auto loop = LoopAggregationNode::create(std::move(map.lookup(sese)));
247  map.insert(sese, std::move(loop));
248 }
249 
277 static ControlFlowGraphNode *
279 {
280  /* sanity checks */
281  JLM_ASSERT(split->NumOutEdges() > 1);
282  JLM_ASSERT(split->OutEdge(0)->sink()->NumOutEdges() == 1);
283  JLM_ASSERT(map.contains(split));
284 
285  auto join = split->OutEdge(0)->sink()->OutEdge(0)->sink();
286  for (auto & edge : split->OutEdges())
287  {
288  JLM_ASSERT(edge.sink()->NumInEdges() == 1);
289  JLM_ASSERT(map.contains(edge.sink()));
290  JLM_ASSERT(edge.sink()->NumOutEdges() == 1);
291  JLM_ASSERT(edge.sink()->OutEdge(0)->sink() == join);
292  }
293 
294  /* perform reduction */
295  auto sese = BasicBlock::create(split->cfg());
296  split->divert_inedges(sese);
297  sese->add_outedge(join);
298 
299  auto branch = BranchAggregationNode::create();
300  for (auto & edge : split->OutEdges())
301  {
302  edge.sink()->remove_outedge(0);
303  branch->add_child(std::move(map.lookup(edge.sink())));
304  map.remove(edge.sink());
305  }
306 
307  auto & child = map.lookup(split);
308  map.insert(sese, LinearAggregationNode::create(std::move(child), std::move(branch)));
309  map.remove(split);
310 
311  /*
312  We need to adjust the SEE subgraphs' entry, in case it was the same as the split and we just
313  reduced it. We do not have to adjust the SESE subgraphs' exit node, as the branch join is not
314  reduced in this function.
315  */
316  *entry = split == *entry ? sese : *entry;
317  return sese;
318 }
319 
337 static ControlFlowGraphNode *
339  ControlFlowGraphNode * source,
340  ControlFlowGraphNode ** entry,
341  ControlFlowGraphNode ** exit,
342  AggregationMap & map)
343 {
344  JLM_ASSERT(is_linear(source));
345  auto sink = source->OutEdge(0)->sink();
346 
347  auto sese = BasicBlock::create(source->cfg());
348  source->divert_inedges(sese);
349  for (auto & edge : sink->OutEdges())
350  sese->add_outedge(edge.sink());
351  sink->remove_outedges();
352 
353  auto child0 = std::move(map.lookup(source));
354  auto child1 = std::move(map.lookup(sink));
355  map.insert(sese, LinearAggregationNode::create(std::move(child0), std::move(child1)));
356  map.remove(source);
357  map.remove(sink);
358 
359  /*
360  We need to adjust the SESE subgraphs' entry and exit, in case we have just reduced either of
361  them.
362  */
363  *entry = source == *entry ? sese : *entry;
364  *exit = sink == *exit ? sese : *exit;
365 
366  return sese;
367 }
368 
372 static void
374 {
375  auto sccs = find_sccs(entry, exit);
376  for (auto scc : sccs)
377  {
378  auto sccStructure = StronglyConnectedComponentStructure::Create(scc);
379 
380  if (sccStructure->IsTailControlledLoop())
381  {
382  reduce_loop(*sccStructure, map);
383  continue;
384  }
385 
386  JLM_UNREACHABLE("We should have never reached this point!");
387  }
388 }
389 
390 static void
392  ControlFlowGraphNode * node,
393  ControlFlowGraphNode ** entry,
394  ControlFlowGraphNode ** exit,
395  AggregationMap & map)
396 {
397  /*
398  We reduced the entire subgraph to a single node. We are done here.
399  */
400  if (*entry == *exit)
401  {
402  JLM_ASSERT(node == *entry);
403  return;
404  }
405 
406  /*
407  We traversed the entire subgraph until the end. Turn around.
408  */
409  if (node == *exit)
410  return;
411 
412  /*
413  Reduce linear subgraph
414  */
415  if (is_linear(node))
416  {
417  auto sese = reduce_linear(node, entry, exit, map);
418  aggregate_acyclic_sese(sese, entry, exit, map);
419  return;
420  }
421 
422  /*
423  Reduce branch subgraph
424  */
425  if (is_branch_split(node))
426  {
427  /*
428  First, greedily reduce all branches of the branch subgraph...
429  */
430  for (auto & edge : node->OutEdges())
431  aggregate_acyclic_sese(edge.sink(), entry, exit, map);
432 
433  /*
434  ..., then try to reduce the branch subgraph itself.
435  */
436  if (is_branch(node))
437  {
438  auto sese = reduce_branch(node, entry, map);
439  aggregate_acyclic_sese(sese, entry, exit, map);
440  return;
441  }
442 
443  JLM_UNREACHABLE("We should have never reached this point!");
444  }
445 
446  /*
447  It is only a single basic block with one incoming and outgoing edge, simply step over it.
448  */
449  if (is_sese_basic_block(node))
450  {
451  aggregate_acyclic_sese(node->OutEdge(0)->sink(), entry, exit, map);
452  return;
453  }
454 
455  /*
456  It is a branch join, turn around to the branch split such that we can reduce it.
457  */
458  if (is_branch_join(node))
459  return;
460 
461  JLM_UNREACHABLE("We should have never reached this point!");
462 }
463 
478 static ControlFlowGraphNode *
480 {
481  aggregate_loops(entry, exit, map);
482  aggregate_acyclic_sese(entry, &entry, &exit, map);
483  JLM_ASSERT(entry == exit);
484 
485  return entry;
486 }
487 
488 std::unique_ptr<AggregationNode>
490 {
492 
493  auto map = AggregationMap::create(cfg);
494  auto root = aggregate(cfg.entry(), cfg.exit(), *map);
495 
496  return std::move(map->lookup(root));
497 }
498 
499 size_t
500 ntacs(const AggregationNode & root)
501 {
502  size_t n = 0;
503  for (auto & child : root)
504  n += ntacs(child);
505 
506  if (auto bb = dynamic_cast<const BasicBlockAggregationNode *>(&root))
507  n += bb->tacs().ntacs();
508 
509  return n;
510 }
511 
512 }
static std::unique_ptr< AggregationMap > create(ControlFlowGraph &cfg)
void remove(ControlFlowGraphNode *node)
std::unique_ptr< AggregationNode > & lookup(ControlFlowGraphNode *node)
void insert(ControlFlowGraphNode *node, std::unique_ptr< AggregationNode > anode)
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)
Definition: basic-block.cpp:37
static std::unique_ptr< AggregationNode > create()
~BranchAggregationNode() noexcept override
ControlFlowGraphNode * sink() const noexcept
Definition: cfg-node.hpp:57
ControlFlowGraphEdge * OutEdge(size_t n) const
Definition: cfg-node.hpp:115
ControlFlowGraph & cfg() const noexcept
Definition: cfg-node.hpp:106
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
EntryNode * entry() const noexcept
Definition: cfg.hpp:205
ExitNode * exit() const noexcept
Definition: cfg.hpp:211
std::vector< llvm::Argument * > arguments_
constiterator end() const
Definition: aggregation.cpp:67
std::string debug_string() const override
Definition: aggregation.cpp:73
util::PtrIterator< const llvm::Argument, std::vector< llvm::Argument * >::const_iterator > constiterator
static std::unique_ptr< AggregationNode > create(const std::vector< llvm::Argument * > &arguments)
~EntryAggregationNode() noexcept override
static std::unique_ptr< AggregationNode > create(const std::vector< const Variable * > &results)
~ExitAggregationNode() noexcept override
~LinearAggregationNode() noexcept override
static std::unique_ptr< AggregationNode > create(std::unique_ptr< AggregationNode > n1, std::unique_ptr< AggregationNode > n2)
~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 void reduce_loop(const StronglyConnectedComponentStructure &sccstruct, AggregationMap &map)
static bool is_branch_join(const ControlFlowGraphNode *node) noexcept
static bool is_linear(const ControlFlowGraphNode *node) noexcept
static bool reduce(const ControlFlowGraph &cfg, const std::function< bool(llvm::ControlFlowGraphNode *, std::unordered_set< llvm::ControlFlowGraphNode * > &)> &f)
static ControlFlowGraphNode * reduce_branch(ControlFlowGraphNode *split, ControlFlowGraphNode **entry, AggregationMap &map)
static bool is_branch_split(const ControlFlowGraphNode *node) noexcept
static bool is_branch(const ControlFlowGraphNode *split) noexcept
static void aggregate_acyclic_sese(ControlFlowGraphNode *node, ControlFlowGraphNode **entry, ControlFlowGraphNode **exit, AggregationMap &map)
static ControlFlowGraphNode * reduce_linear(ControlFlowGraphNode *source, 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