Jlm
Loading...
Searching...
No Matches
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
14namespace jlm::llvm
15{
16
17void
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)
static BasicBlock * create(ControlFlowGraph &cfg)
ControlFlowGraphNode * sink() const noexcept
Definition cfg-node.hpp:57
ControlFlowGraphEdge * OutEdge(size_t n) const
Definition cfg-node.hpp:115
ControlFlowGraphEdge * add_outedge(ControlFlowGraphNode *sink)
Definition cfg-node.hpp:130
EntryNode * entry() const noexcept
Definition cfg.hpp:206
InterProceduralGraphModule & module() const noexcept
Definition cfg.hpp:247
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)
#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)