Jlm
ssa.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 
10 #include <jlm/llvm/ir/ssa.hpp>
11 
12 #include <unordered_set>
13 
14 namespace jlm::llvm
15 {
16 
17 void
19 {
20  JLM_ASSERT(is_valid(cfg));
21 
22  auto collect_phi_blocks = [](ControlFlowGraph & cfg)
23  {
24  std::unordered_set<BasicBlock *> phi_blocks;
25  for (auto & bb : cfg)
26  {
27  if (is<SsaPhiOperation>(bb.first()))
28  phi_blocks.insert(&bb);
29  }
30 
31  return phi_blocks;
32  };
33 
34  auto eliminate_phis =
35  [](ControlFlowGraph & cfg, const std::unordered_set<BasicBlock *> & phi_blocks)
36  {
37  if (phi_blocks.empty())
38  return;
39 
40  auto firstbb = static_cast<BasicBlock *>(cfg.entry()->OutEdge(0)->sink());
41 
42  for (auto phi_block : phi_blocks)
43  {
44  auto ass_block = BasicBlock::create(cfg);
45  auto & tacs = phi_block->tacs();
46 
47  // For each incoming basic block, create a new basic block where phi operands are stored
48  // All incoming edges get routed through the corresponding intermediate basic block
49 
50  // Mapping from original incoming block to intermediate block
51  std::unordered_map<ControlFlowGraphNode *, BasicBlock *> intermediateBlocks;
52 
53  // Make a copy of the original inEdges to avoid iterator invalidation
54  std::vector<ControlFlowGraphEdge *> originalInEdges;
55  for (auto & inEdge : phi_block->InEdges())
56  originalInEdges.push_back(&inEdge);
57 
58  // For each inEdge, route it through a corresponding intermediate block instead
59  for (auto inEdge : originalInEdges)
60  {
61  auto source = inEdge->source();
62  BasicBlock * intermediate = nullptr;
63 
64  if (intermediateBlocks.find(source) == intermediateBlocks.end())
65  {
66  intermediate = BasicBlock::create(cfg);
67  intermediate->add_outedge(ass_block);
68  intermediateBlocks[source] = intermediate;
69  }
70  else
71  {
72  intermediate = intermediateBlocks[source];
73  }
74 
75  // Re-route this in-edge through the intermediate
76  inEdge->divert(intermediate);
77  }
78  // Finally give the phi_block a single input
79  ass_block->add_outedge(phi_block);
80  JLM_ASSERT(phi_block->NumInEdges() == 1);
81 
82  // For each phi operation, move its operands to the corresponding intermediate blocks instead
83  while (tacs.first())
84  {
85  auto phitac = tacs.first();
86  if (!is<SsaPhiOperation>(phitac))
87  break;
88 
89  const auto phi = static_cast<const SsaPhiOperation *>(&phitac->operation());
90 
91  // Instead of having a phi operation, extract its result and give it to an undef operation
92  auto phiresult = std::move(phitac->results()[0]);
93  auto undef = firstbb->append_first(UndefValueOperation::Create(std::move(phiresult)));
94 
95  // Create a mutable variable that will hold the value of the phi result
96  auto variable = cfg.module().create_variable(phi->Type());
97 
98  JLM_ASSERT(phitac->noperands() == intermediateBlocks.size());
99  for (size_t n = 0; n < phitac->noperands(); n++)
100  {
101  auto incoming = phi->GetIncomingNode(n);
102  auto intermediate = intermediateBlocks[incoming];
103  JLM_ASSERT(intermediate != nullptr);
104 
105  intermediate->append_last(AssignmentOperation::create(phitac->operand(n), variable));
106  }
107 
108  // In the assignment block, store the variable into the result of the undef operation
109  ass_block->append_last(AssignmentOperation::create(variable, undef->result(0)));
110 
111  // Remove the phi three address code
112  tacs.drop_first();
113  }
114  }
115  };
116 
117  auto phi_blocks = collect_phi_blocks(cfg);
118  eliminate_phis(cfg, phi_blocks);
119 }
120 
121 }
static std::unique_ptr< llvm::ThreeAddressCode > create(const Variable *rhs, const Variable *lhs)
Definition: operators.hpp:117
static BasicBlock * create(ControlFlowGraph &cfg)
Definition: basic-block.cpp:37
ControlFlowGraphNode * sink() const noexcept
Definition: cfg-node.hpp:57
ControlFlowGraphEdge * add_outedge(ControlFlowGraphNode *sink)
Definition: cfg-node.hpp:130
ControlFlowGraphEdge * OutEdge(size_t n) const
Definition: cfg-node.hpp:115
EntryNode * entry() const noexcept
Definition: cfg.hpp:205
InterProceduralGraphModule & module() const noexcept
Definition: cfg.hpp:246
llvm::Variable * create_variable(std::shared_ptr< const jlm::rvsdg::Type > type, const std::string &name)
static jlm::rvsdg::Output * Create(rvsdg::Region &region, std::shared_ptr< const jlm::rvsdg::Type > type)
Definition: operators.hpp:1024
#define JLM_ASSERT(x)
Definition: common.hpp:16
Global memory state passed between functions.
void destruct_ssa(ControlFlowGraph &cfg)
Definition: ssa.cpp:18
bool is_valid(const ControlFlowGraph &cfg)