Jlm
ControlFlowRestructuring.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2015 Nico Reißmann <nico.reissmann@gmail.com>
3  * See COPYING for terms of redistribution.
4  */
5 
9 
10 #include <deque>
11 #include <unordered_map>
12 
13 namespace jlm::llvm
14 {
15 
17 {
19  : ne(entry),
20  insert(i),
21  replacement(r)
22  {}
23 
27 };
28 
29 static TailControlledLoop
31 {
32  JLM_ASSERT(loopExit.NumOutEdges() == 2);
33  auto & cfg = loopEntry.cfg();
34 
35  auto er = loopExit.OutEdge(0);
36  auto ex = loopExit.OutEdge(1);
37  if (er->sink() != &loopEntry)
38  {
39  er = loopExit.OutEdge(1);
40  ex = loopExit.OutEdge(0);
41  }
42  JLM_ASSERT(er->sink() == &loopEntry);
43 
44  auto exsink = BasicBlock::create(cfg);
45  auto replacement = BasicBlock::create(cfg);
46  loopEntry.divert_inedges(replacement);
47  replacement->add_outedge(ex->sink());
48  ex->divert(exsink);
49  er->divert(&loopEntry);
50 
51  return TailControlledLoop(&loopEntry, exsink, replacement);
52 }
53 
54 static void
56 {
57  JLM_ASSERT(loop.insert->NumInEdges() == 1);
58  JLM_ASSERT(loop.replacement->NumOutEdges() == 1);
59  auto & cfg = loop.ne->cfg();
60 
61  loop.replacement->divert_inedges(loop.ne);
62  loop.insert->divert_inedges(loop.replacement->OutEdge(0)->sink());
63 
64  cfg.remove_node(loop.insert);
65  cfg.remove_node(loop.replacement);
66 }
67 
68 static const ThreeAddressCodeVariable *
69 CreateContinuationVariable(BasicBlock & bb, std::shared_ptr<const rvsdg::ControlType> type)
70 {
71  static size_t c = 0;
72  const auto name = util::strfmt("#p", c++, "#");
73  return bb.insert_before_branch(UndefValueOperation::Create(std::move(type), name))->result(0);
74 }
75 
76 static const ThreeAddressCodeVariable &
77 CreateLoopExitVariable(BasicBlock & bb, std::shared_ptr<const rvsdg::ControlType> type)
78 {
79  static size_t c = 0;
80  const auto name = util::strfmt("#q", c++, "#");
81 
82  auto exitVariable = UndefValueOperation::Create(std::move(type), name);
83  return *bb.append_last(std::move(exitVariable))->result(0);
84 }
85 
86 static const ThreeAddressCodeVariable &
87 CreateLoopEntryVariable(BasicBlock & bb, std::shared_ptr<const rvsdg::ControlType> type)
88 {
89  static size_t c = 0;
90  const auto name = util::strfmt("#q", c++, "#");
91 
92  auto entryVariable = UndefValueOperation::Create(std::move(type), name);
93  return *bb.insert_before_branch(std::move(entryVariable))->result(0);
94 }
95 
96 static const ThreeAddressCodeVariable &
98 {
99  static size_t c = 0;
100  const auto name = util::strfmt("#r", c++, "#");
101 
102  auto repetitionVariable = UndefValueOperation::Create(rvsdg::ControlType::Create(2), name);
103  return *basicBlock.append_last(std::move(repetitionVariable))->result(0);
104 }
105 
106 static void
107 AppendBranch(BasicBlock & basicBlock, const Variable * operand)
108 {
109  const auto numAlternatives =
110  util::assertedCast<const rvsdg::ControlType>(&operand->type())->nalternatives();
111  basicBlock.append_last(BranchOperation::create(numAlternatives, operand));
112 }
113 
114 static void
116  BasicBlock & basicBlock,
117  const ThreeAddressCodeVariable & variable,
118  const size_t value)
119 {
120  const auto numAlternatives =
121  util::assertedCast<const rvsdg::ControlType>(&variable.type())->nalternatives();
122 
123  auto op = std::make_unique<rvsdg::ControlConstantOperation>(
124  rvsdg::ControlValueRepresentation(value, numAlternatives));
125  basicBlock.append_last(ThreeAddressCode::create(std::move(op), {}));
126  basicBlock.append_last(AssignmentOperation::create(basicBlock.last()->result(0), &variable));
127 }
128 
129 static void
131  const StronglyConnectedComponentStructure & sccStructure,
132  BasicBlock * newEntryNode,
133  const ThreeAddressCodeVariable * entryVariable)
134 {
135  size_t n = 0;
136  std::unordered_map<ControlFlowGraphNode *, size_t> indices;
137  for (auto & node : sccStructure.EntryNodes())
138  {
139  newEntryNode->add_outedge(node);
140  indices[node] = n++;
141  }
142 
143  if (entryVariable)
144  AppendBranch(*newEntryNode, entryVariable);
145 
146  for (auto & edge : sccStructure.EntryEdges())
147  {
148  auto os = edge->sink();
149  edge->divert(newEntryNode);
150  if (entryVariable)
151  AppendConstantAssignment(*edge->split(), *entryVariable, indices[os]);
152  }
153 }
154 
155 static void
157  const StronglyConnectedComponentStructure & sccStructure,
158  BasicBlock & newRepetitionNode,
159  BasicBlock & newExitNode,
160  ControlFlowGraphNode & regionExit,
161  const ThreeAddressCodeVariable & repetitionVariable,
162  const ThreeAddressCodeVariable * exitVariable)
163 {
164  // It could be that an SCC has no exit edge. This can arise when the input CFG contains a
165  // statically detectable endless loop, e.g., entry -> basic block exit. Note the missing
166  // ^_________|
167  // edge to the exit node.
168  //
169  // Such CFGs do not play well with our restructuring algorithm, as the exit node does not
170  // post-dominate the basic block. We circumvent this problem by inserting an additional
171  // edge from the newly created exit basic block of the loop to the exit of the SESE region.
172  // This edge is never taken at runtime, but fixes the CFGs structure at compile-time such
173  // that we can create an RVSDG.
174  if (sccStructure.NumExitEdges() == 0)
175  {
176  newExitNode.add_outedge(&regionExit);
177  return;
178  }
179 
180  size_t n = 0;
181  std::unordered_map<ControlFlowGraphNode *, size_t> indices;
182  for (auto & node : sccStructure.ExitNodes())
183  {
184  newExitNode.add_outedge(node);
185  indices[node] = n++;
186  }
187 
188  if (exitVariable)
189  AppendBranch(newExitNode, exitVariable);
190 
191  for (auto & edge : sccStructure.ExitEdges())
192  {
193  auto os = edge->sink();
194  edge->divert(&newRepetitionNode);
195  auto bb = edge->split();
196  if (exitVariable)
197  AppendConstantAssignment(*bb, *exitVariable, indices[os]);
198  AppendConstantAssignment(*bb, repetitionVariable, 0);
199  }
200 }
201 
202 static void
204  const StronglyConnectedComponentStructure & sccStructure,
205  ControlFlowGraphNode & newRepetitionNode,
206  const ThreeAddressCodeVariable * entryVariable,
207  const ThreeAddressCodeVariable & repetitionVariable)
208 {
209  size_t n = 0;
210  std::unordered_map<ControlFlowGraphNode *, size_t> indices;
211  for (auto & node : sccStructure.EntryNodes())
212  indices[node] = n++;
213 
214  for (auto & edge : sccStructure.RepetitionEdges())
215  {
216  auto os = edge->sink();
217  edge->divert(&newRepetitionNode);
218  auto basicBlock = edge->split();
219  if (entryVariable)
220  AppendConstantAssignment(*basicBlock, *entryVariable, indices[os]);
221  AppendConstantAssignment(*basicBlock, repetitionVariable, 1);
222  }
223 }
224 
225 static BasicBlock *
227 {
228  if (auto basicBlock = dynamic_cast<BasicBlock *>(node))
229  return basicBlock;
230 
231  auto sink = node->OutEdge(0)->sink();
232  JLM_ASSERT(is<BasicBlock>(sink));
233 
234  return static_cast<BasicBlock *>(sink);
235 }
236 
237 static void
239  ControlFlowGraphNode &,
240  ControlFlowGraphNode &,
241  std::vector<TailControlledLoop> &);
242 
243 static void
245  ControlFlowGraphNode & regionEntry,
246  ControlFlowGraphNode & regionExit,
247  std::vector<TailControlledLoop> & loops)
248 {
249  if (&regionEntry == &regionExit)
250  return;
251 
252  auto & cfg = regionEntry.cfg();
253 
254  const auto stronglyConnectedComponents = find_sccs(&regionEntry, &regionExit);
255  for (auto & scc : stronglyConnectedComponents)
256  {
257  auto sccStructure = StronglyConnectedComponentStructure::Create(scc);
258 
259  if (sccStructure->IsTailControlledLoop())
260  {
261  auto loopEntry = *sccStructure->EntryNodes().begin();
262  auto loopExit = (*sccStructure->ExitEdges().begin())->source();
263  RestructureControlFlow(*loopEntry, *loopExit, loops);
264  loops.push_back(ExtractLoop(*loopEntry, *loopExit));
265  continue;
266  }
267 
268  auto & newEntryNode = *BasicBlock::create(cfg);
269  auto & newRepetitionNode = *BasicBlock::create(cfg);
270  auto & newExitNode = *BasicBlock::create(cfg);
271  newRepetitionNode.add_outedge(&newExitNode);
272  newRepetitionNode.add_outedge(&newEntryNode);
273 
274  const ThreeAddressCodeVariable * entryVariable = nullptr;
275  if (sccStructure->NumEntryNodes() > 1)
276  {
277  auto bb = GetEntryVariableBlock(&regionEntry);
278  entryVariable =
279  &CreateLoopEntryVariable(*bb, rvsdg::ControlType::Create(sccStructure->NumEntryNodes()));
280  }
281 
282  auto & repetitionVariable = CreateLoopRepetitionVariable(newEntryNode);
283 
284  const ThreeAddressCodeVariable * exitVariable = nullptr;
285  if (sccStructure->NumExitNodes() > 1)
286  exitVariable = &CreateLoopExitVariable(
287  newEntryNode,
288  rvsdg::ControlType::Create(sccStructure->NumExitNodes()));
289 
290  AppendBranch(newRepetitionNode, &repetitionVariable);
291 
292  RestructureLoopEntry(*sccStructure, &newEntryNode, entryVariable);
294  *sccStructure,
295  newRepetitionNode,
296  newExitNode,
297  regionExit,
298  repetitionVariable,
299  exitVariable);
300  RestructureLoopRepetition(*sccStructure, newRepetitionNode, entryVariable, repetitionVariable);
301 
302  RestructureControlFlow(newEntryNode, newRepetitionNode, loops);
303  loops.push_back(ExtractLoop(newEntryNode, newRepetitionNode));
304  }
305 }
306 
307 static ControlFlowGraphNode &
309 {
310  ControlFlowGraphNode * headBranch = &start;
311  do
312  {
313  if (headBranch->is_branch() || headBranch == &end)
314  break;
315 
316  headBranch = headBranch->OutEdge(0)->sink();
317  } while (true);
318 
319  return *headBranch;
320 }
321 
324 {
326  util::HashSet edges({ edge });
327 
328  std::deque toVisit(1, edge->sink());
329  while (toVisit.size() != 0)
330  {
331  ControlFlowGraphNode * node = toVisit.front();
332  toVisit.pop_front();
333  if (nodes.Contains(node))
334  continue;
335 
336  bool accept = true;
337  for (auto & inedge : node->InEdges())
338  {
339  if (!edges.Contains(&inedge))
340  {
341  accept = false;
342  break;
343  }
344  }
345 
346  if (accept)
347  {
348  nodes.insert(node);
349  for (auto & outedge : node->OutEdges())
350  {
351  edges.insert(&outedge);
352  toVisit.push_back(outedge.sink());
353  }
354  }
355  }
356 
357  return nodes;
358 }
359 
361 {
363  std::unordered_map<ControlFlowGraphEdge *, util::HashSet<ControlFlowGraphEdge *>> edges;
364 };
365 
366 static Continuation
368 {
369  JLM_ASSERT(headBranch.NumOutEdges() > 1);
370 
371  std::unordered_map<ControlFlowGraphEdge *, util::HashSet<ControlFlowGraphNode *>> dominatorGraphs;
372  for (auto & outedge : headBranch.OutEdges())
373  dominatorGraphs[&outedge] = ComputeDominatorGraph(&outedge);
374 
375  Continuation c;
376  for (auto & outedge : headBranch.OutEdges())
377  {
378  auto & dominatorGraph = dominatorGraphs[&outedge];
379  if (dominatorGraph.IsEmpty())
380  {
381  c.edges[&outedge].insert(&outedge);
382  c.points.insert(outedge.sink());
383  continue;
384  }
385 
386  for (const auto & node : dominatorGraph.Items())
387  {
388  for (auto & outedge2 : node->OutEdges())
389  {
390  if (!dominatorGraph.Contains(outedge2.sink()))
391  {
392  c.edges[&outedge].insert(&outedge2);
393  c.points.insert(outedge2.sink());
394  }
395  }
396  }
397  }
398 
399  return c;
400 }
401 
402 static void
404 {
405  auto & cfg = entry.cfg();
406 
407  auto & headBranch = ComputeHeadBranch(entry, exit);
408  if (&headBranch == &exit)
409  return;
410 
411  JLM_ASSERT(is<BasicBlock>(&headBranch));
412  auto & hbb = *static_cast<BasicBlock *>(&headBranch);
413 
414  auto [continuationPoints, continuationEdgesDict] = ComputeContinuation(headBranch);
415  JLM_ASSERT(!continuationPoints.IsEmpty());
416 
417  if (continuationPoints.Size() == 1)
418  {
419  const auto continuationPoint = *continuationPoints.Items().begin();
420  for (auto & outedge : headBranch.OutEdges())
421  {
422  auto continuationEdges = continuationEdgesDict[&outedge];
423 
424  // Empty branch subgraph
425  if (outedge.sink() == continuationPoint)
426  {
427  outedge.split();
428  continue;
429  }
430 
431  // only one continuation edge
432  if (continuationEdges.Size() == 1)
433  {
434  const auto continuationEdge = *continuationEdges.Items().begin();
435  JLM_ASSERT(continuationEdge != &outedge);
436  RestructureBranches(*outedge.sink(), *continuationEdge->source());
437  continue;
438  }
439 
440  // more than one continuation edge
441  auto nullNode = BasicBlock::create(cfg);
442  nullNode->add_outedge(continuationPoint);
443  for (const auto & e : continuationEdges.Items())
444  e->divert(nullNode);
445  RestructureBranches(*outedge.sink(), *nullNode);
446  }
447 
448  // Restructure tail subgraph
449  RestructureBranches(*continuationPoint, exit);
450  return;
451  }
452 
453  // insert new continuation point
454  auto p = CreateContinuationVariable(hbb, rvsdg::ControlType::Create(continuationPoints.Size()));
455  auto continuationNode = BasicBlock::create(cfg);
456  AppendBranch(*continuationNode, p);
457  std::unordered_map<ControlFlowGraphNode *, size_t> indices;
458  for (const auto & cp : continuationPoints.Items())
459  {
460  continuationNode->add_outedge(cp);
461  indices.insert({ cp, indices.size() });
462  }
463 
464  // Restructure branch subgraphs
465  for (auto & outedge : headBranch.OutEdges())
466  {
467  auto continuationEdges = continuationEdgesDict[&outedge];
468 
469  auto nullNode = BasicBlock::create(cfg);
470  nullNode->add_outedge(continuationNode);
471  for (const auto & e : continuationEdges.Items())
472  {
473  auto bb = BasicBlock::create(cfg);
474  AppendConstantAssignment(*bb, *p, indices[e->sink()]);
475  bb->add_outedge(nullNode);
476  e->divert(bb);
477  }
478 
479  RestructureBranches(*outedge.sink(), *nullNode);
480  }
481 
482  // Restructure tail subgraph
483  RestructureBranches(*continuationNode, exit);
484 }
485 
486 void
488 {
489  JLM_ASSERT(is_closed(cfg));
490 
491  std::vector<TailControlledLoop> loops;
492  RestructureLoops(*cfg.entry(), *cfg.exit(), loops);
493 
494  for (const auto & loop : loops)
495  ReinsertLoop(loop);
496 }
497 
498 void
500 {
501  JLM_ASSERT(is_acyclic(cfg));
502  RestructureBranches(*cfg.entry(), *cfg.exit());
504 }
505 
506 static void
508  ControlFlowGraphNode & entry,
509  ControlFlowGraphNode & exit,
510  std::vector<TailControlledLoop> & tailControlledLoops)
511 {
512  RestructureLoops(entry, exit, tailControlledLoops);
513  RestructureBranches(entry, exit);
514 }
515 
516 void
518 {
519  JLM_ASSERT(is_closed(cfg));
520 
521  std::vector<TailControlledLoop> loops;
522  RestructureControlFlow(*cfg.entry(), *cfg.exit(), loops);
523 
524  for (const auto & loop : loops)
525  ReinsertLoop(loop);
526 
528 }
529 
530 }
static std::unique_ptr< llvm::ThreeAddressCode > create(const Variable *rhs, const Variable *lhs)
Definition: operators.hpp:117
ThreeAddressCode * last() const noexcept
Definition: basic-block.hpp:86
llvm::ThreeAddressCode * insert_before_branch(std::unique_ptr< llvm::ThreeAddressCode > tac)
Definition: basic-block.cpp:23
static BasicBlock * create(ControlFlowGraph &cfg)
Definition: basic-block.cpp:37
llvm::ThreeAddressCode * append_last(std::unique_ptr< llvm::ThreeAddressCode > tac)
static std::unique_ptr< llvm::ThreeAddressCode > create(size_t nalternatives, const Variable *operand)
Definition: operators.hpp:418
ControlFlowGraphNode * sink() const noexcept
Definition: cfg-node.hpp:57
bool is_branch() const noexcept
Definition: cfg-node.hpp:196
ControlFlowGraphEdge * add_outedge(ControlFlowGraphNode *sink)
Definition: cfg-node.hpp:130
inedge_iterator_range InEdges() const
Definition: cfg-node.hpp:163
ControlFlowGraphEdge * OutEdge(size_t n) const
Definition: cfg-node.hpp:115
size_t NumInEdges() const noexcept
Definition: cfg-node.cpp:63
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
Strongly Connected Component Structure.
static std::unique_ptr< StronglyConnectedComponentStructure > Create(const StronglyConnectedComponent &scc)
const ThreeAddressCodeVariable * result(size_t index) const noexcept
Definition: tac.hpp:109
static std::unique_ptr< llvm::ThreeAddressCode > create(std::unique_ptr< rvsdg::SimpleOperation > operation, const std::vector< const Variable * > &operands)
Definition: tac.hpp:135
static jlm::rvsdg::Output * Create(rvsdg::Region &region, std::shared_ptr< const jlm::rvsdg::Type > type)
Definition: operators.hpp:1024
const jlm::rvsdg::Type & type() const noexcept
Definition: variable.hpp:56
static std::shared_ptr< const ControlType > Create(std::size_t nalternatives)
Instantiates control type.
Definition: control.cpp:50
bool insert(ItemType item)
Definition: HashSet.hpp:210
bool Contains(const ItemType &item) const noexcept
Definition: HashSet.hpp:150
#define JLM_ASSERT(x)
Definition: common.hpp:16
Global memory state passed between functions.
static void RestructureLoopRepetition(const StronglyConnectedComponentStructure &sccStructure, ControlFlowGraphNode &newRepetitionNode, const ThreeAddressCodeVariable *entryVariable, const ThreeAddressCodeVariable &repetitionVariable)
std::vector< StronglyConnectedComponent > find_sccs(const ControlFlowGraph &cfg)
static void RestructureBranches(ControlFlowGraphNode &entry, ControlFlowGraphNode &exit)
static void AppendBranch(BasicBlock &basicBlock, const Variable *operand)
static Continuation ComputeContinuation(const ControlFlowGraphNode &headBranch)
static void RestructureControlFlow(ControlFlowGraphNode &, ControlFlowGraphNode &, std::vector< TailControlledLoop > &)
static void RestructureLoopExit(const StronglyConnectedComponentStructure &sccStructure, BasicBlock &newRepetitionNode, BasicBlock &newExitNode, ControlFlowGraphNode &regionExit, const ThreeAddressCodeVariable &repetitionVariable, const ThreeAddressCodeVariable *exitVariable)
static void RestructureLoops(ControlFlowGraphNode &regionEntry, ControlFlowGraphNode &regionExit, std::vector< TailControlledLoop > &loops)
static void AppendConstantAssignment(BasicBlock &basicBlock, const ThreeAddressCodeVariable &variable, const size_t value)
static void ReinsertLoop(const TailControlledLoop &loop)
static BasicBlock * GetEntryVariableBlock(ControlFlowGraphNode *node)
static const ThreeAddressCodeVariable & CreateLoopExitVariable(BasicBlock &bb, std::shared_ptr< const rvsdg::ControlType > type)
static ControlFlowGraphNode & ComputeHeadBranch(ControlFlowGraphNode &start, ControlFlowGraphNode &end)
static TailControlledLoop ExtractLoop(ControlFlowGraphNode &loopEntry, ControlFlowGraphNode &loopExit)
bool is_proper_structured(const ControlFlowGraph &cfg)
static const ThreeAddressCodeVariable * CreateContinuationVariable(BasicBlock &bb, std::shared_ptr< const rvsdg::ControlType > type)
static const ThreeAddressCodeVariable & CreateLoopEntryVariable(BasicBlock &bb, std::shared_ptr< const rvsdg::ControlType > type)
static util::HashSet< ControlFlowGraphNode * > ComputeDominatorGraph(const ControlFlowGraphEdge *edge)
static const ThreeAddressCodeVariable & CreateLoopRepetitionVariable(BasicBlock &basicBlock)
bool is_closed(const ControlFlowGraph &cfg)
static bool is_acyclic(const ControlFlowGraph &cfg)
static void RestructureLoopEntry(const StronglyConnectedComponentStructure &sccStructure, BasicBlock *newEntryNode, const ThreeAddressCodeVariable *entryVariable)
static std::string type(const Node *n)
Definition: view.cpp:255
static std::string strfmt(Args... args)
Definition: strfmt.hpp:35
util::HashSet< ControlFlowGraphNode * > points
std::unordered_map< ControlFlowGraphEdge *, util::HashSet< ControlFlowGraphEdge * > > edges
TailControlledLoop(ControlFlowGraphNode *entry, BasicBlock *i, BasicBlock *r)