blob: be77222f87338470d4721792145aedaa41043e44 [file] [log] [blame]
Dan Gohmand7a2eea2016-03-09 02:01:14 +00001//=- WebAssemblyFixIrreducibleControlFlow.cpp - Fix irreducible control flow -//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9///
10/// \file
11/// \brief This file implements a pass that transforms irreducible control flow
12/// into reducible control flow. Irreducible control flow means multiple-entry
13/// loops; they appear as CFG cycles that are not recorded in MachineLoopInfo
14/// due to being unnatural.
15///
16/// TODO: The transformation implemented here handles all irreducible control
17/// flow, without exponential code-size expansion, though it does so by creating
18/// inefficient code in many cases. Ideally, we should add other
19/// transformations, including code-duplicating cases, which can be more
20/// efficient in common cases, and they can fall back to this conservative
21/// implementation as needed.
22///
23//===----------------------------------------------------------------------===//
24
25#include "WebAssembly.h"
26#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
27#include "WebAssemblyMachineFunctionInfo.h"
28#include "WebAssemblySubtarget.h"
29#include "llvm/ADT/PriorityQueue.h"
30#include "llvm/ADT/SCCIterator.h"
31#include "llvm/ADT/SetVector.h"
32#include "llvm/CodeGen/MachineDominators.h"
33#include "llvm/CodeGen/MachineFunction.h"
34#include "llvm/CodeGen/MachineInstrBuilder.h"
35#include "llvm/CodeGen/MachineLoopInfo.h"
36#include "llvm/CodeGen/MachineRegisterInfo.h"
37#include "llvm/CodeGen/Passes.h"
38#include "llvm/Support/Debug.h"
39#include "llvm/Support/raw_ostream.h"
40using namespace llvm;
41
42#define DEBUG_TYPE "wasm-fix-irreducible-control-flow"
43
44namespace {
45class WebAssemblyFixIrreducibleControlFlow final : public MachineFunctionPass {
46 const char *getPassName() const override {
47 return "WebAssembly Fix Irreducible Control Flow";
48 }
49
50 void getAnalysisUsage(AnalysisUsage &AU) const override {
51 AU.setPreservesCFG();
52 AU.addRequired<MachineDominatorTree>();
53 AU.addPreserved<MachineDominatorTree>();
54 AU.addRequired<MachineLoopInfo>();
55 AU.addPreserved<MachineLoopInfo>();
56 MachineFunctionPass::getAnalysisUsage(AU);
57 }
58
59 bool runOnMachineFunction(MachineFunction &MF) override;
60
61 bool VisitLoop(MachineFunction &MF, MachineLoopInfo &MLI, MachineLoop *Loop);
62
63public:
64 static char ID; // Pass identification, replacement for typeid
65 WebAssemblyFixIrreducibleControlFlow() : MachineFunctionPass(ID) {}
66};
67} // end anonymous namespace
68
69char WebAssemblyFixIrreducibleControlFlow::ID = 0;
70FunctionPass *llvm::createWebAssemblyFixIrreducibleControlFlow() {
71 return new WebAssemblyFixIrreducibleControlFlow();
72}
73
74namespace {
75
76/// A utility for walking the blocks of a loop, handling a nested inner
77/// loop as a monolithic conceptual block.
78class MetaBlock {
79 MachineBasicBlock *Block;
80 SmallVector<MachineBasicBlock *, 2> Preds;
81 SmallVector<MachineBasicBlock *, 2> Succs;
82
83public:
84 explicit MetaBlock(MachineBasicBlock *MBB)
85 : Block(MBB), Preds(MBB->pred_begin(), MBB->pred_end()),
86 Succs(MBB->succ_begin(), MBB->succ_end()) {}
87
88 explicit MetaBlock(MachineLoop *Loop) : Block(Loop->getHeader()) {
89 Loop->getExitBlocks(Succs);
90 for (MachineBasicBlock *Pred : Block->predecessors())
91 if (!Loop->contains(Pred))
92 Preds.push_back(Pred);
93 }
94
95 MachineBasicBlock *getBlock() const { return Block; }
96
97 const SmallVectorImpl<MachineBasicBlock *> &predecessors() const {
98 return Preds;
99 }
100 const SmallVectorImpl<MachineBasicBlock *> &successors() const {
101 return Succs;
102 }
103
104 bool operator==(const MetaBlock &MBB) { return Block == MBB.Block; }
105 bool operator!=(const MetaBlock &MBB) { return Block != MBB.Block; }
106};
107
108class SuccessorList : public MetaBlock {
109 size_t Index;
110 size_t Num;
111
112public:
113 explicit SuccessorList(MachineBasicBlock *MBB)
114 : MetaBlock(MBB), Index(0), Num(successors().size()) {}
115
116 explicit SuccessorList(MachineLoop *Loop)
117 : MetaBlock(Loop), Index(0), Num(successors().size()) {}
118
119 bool HasNext() const { return Index != Num; }
120
121 MachineBasicBlock *Next() {
122 assert(HasNext());
123 return successors()[Index++];
124 }
125};
126
127} // end anonymous namespace
128
129bool WebAssemblyFixIrreducibleControlFlow::VisitLoop(MachineFunction &MF,
130 MachineLoopInfo &MLI,
131 MachineLoop *Loop) {
132 MachineBasicBlock *Header = Loop ? Loop->getHeader() : &*MF.begin();
133 SetVector<MachineBasicBlock *> RewriteSuccs;
134
135 // DFS through Loop's body, looking for for irreducible control flow. Loop is
136 // natural, and we stay in its body, and we treat any nested loops
137 // monolithically, so any cycles we encounter indicate irreducibility.
138 SmallPtrSet<MachineBasicBlock *, 8> OnStack;
139 SmallPtrSet<MachineBasicBlock *, 8> Visited;
140 SmallVector<SuccessorList, 4> LoopWorklist;
141 LoopWorklist.push_back(SuccessorList(Header));
142 OnStack.insert(Header);
143 Visited.insert(Header);
144 while (!LoopWorklist.empty()) {
145 SuccessorList &Top = LoopWorklist.back();
146 if (Top.HasNext()) {
147 MachineBasicBlock *Next = Top.Next();
148 if (Next == Header || (Loop && !Loop->contains(Next)))
149 continue;
150 if (LLVM_LIKELY(OnStack.insert(Next).second)) {
151 if (!Visited.insert(Next).second) {
152 OnStack.erase(Next);
153 continue;
154 }
155 MachineLoop *InnerLoop = MLI.getLoopFor(Next);
156 if (InnerLoop != Loop)
157 LoopWorklist.push_back(SuccessorList(InnerLoop));
158 else
159 LoopWorklist.push_back(SuccessorList(Next));
160 } else {
161 RewriteSuccs.insert(Top.getBlock());
162 }
163 continue;
164 }
165 OnStack.erase(Top.getBlock());
166 LoopWorklist.pop_back();
167 }
168
169 // Most likely, we didn't find any irreducible control flow.
170 if (LLVM_LIKELY(RewriteSuccs.empty()))
171 return false;
172
173 DEBUG(dbgs() << "Irreducible control flow detected!\n");
174
175 // Ok. We have irreducible control flow! Create a dispatch block which will
176 // contains a jump table to any block in the problematic set of blocks.
177 MachineBasicBlock *Dispatch = MF.CreateMachineBasicBlock();
178 MF.insert(MF.end(), Dispatch);
179 MLI.changeLoopFor(Dispatch, Loop);
180
181 // Add the jump table.
182 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
183 MachineInstrBuilder MIB = BuildMI(*Dispatch, Dispatch->end(), DebugLoc(),
184 TII.get(WebAssembly::BR_TABLE_I32));
185
186 // Add the register which will be used to tell the jump table which block to
187 // jump to.
188 MachineRegisterInfo &MRI = MF.getRegInfo();
189 unsigned Reg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
190 MIB.addReg(Reg);
191
192 // Collect all the blocks which need to have their successors rewritten,
193 // add the successors to the jump table, and remember their index.
194 DenseMap<MachineBasicBlock *, unsigned> Indices;
195 SmallVector<MachineBasicBlock *, 4> SuccWorklist(RewriteSuccs.begin(),
196 RewriteSuccs.end());
197 while (!SuccWorklist.empty()) {
198 MachineBasicBlock *MBB = SuccWorklist.pop_back_val();
199 auto Pair = Indices.insert(std::make_pair(MBB, 0));
200 if (!Pair.second)
201 continue;
202
203 unsigned Index = MIB.getInstr()->getNumOperands() - 1;
204 DEBUG(dbgs() << "MBB#" << MBB->getNumber() << " has index " << Index
205 << "\n");
206
207 Pair.first->second = Index;
208 for (auto Pred : MBB->predecessors())
209 RewriteSuccs.insert(Pred);
210
211 MIB.addMBB(MBB);
212 Dispatch->addSuccessor(MBB);
213
214 MetaBlock Meta(MBB);
215 for (auto *Succ : Meta.successors())
216 if (Succ != Header && (!Loop || Loop->contains(Succ)))
217 SuccWorklist.push_back(Succ);
218 }
219
220 // Rewrite the problematic successors for every block in RewriteSuccs.
221 // For simplicity, we just introduce a new block for every edge we need to
222 // rewrite. Fancier things are possible.
223 for (MachineBasicBlock *MBB : RewriteSuccs) {
224 DenseMap<MachineBasicBlock *, MachineBasicBlock *> Map;
225 for (auto *Succ : MBB->successors()) {
226 if (!Indices.count(Succ))
227 continue;
228
229 MachineBasicBlock *Split = MF.CreateMachineBasicBlock();
230 MF.insert(MBB->isLayoutSuccessor(Succ) ? MachineFunction::iterator(Succ)
231 : MF.end(),
232 Split);
233 MLI.changeLoopFor(Split, Loop);
234
235 // Set the jump table's register of the index of the block we wish to
236 // jump to, and jump to the jump table.
237 BuildMI(*Split, Split->end(), DebugLoc(), TII.get(WebAssembly::CONST_I32),
238 Reg)
239 .addImm(Indices[Succ]);
240 BuildMI(*Split, Split->end(), DebugLoc(), TII.get(WebAssembly::BR))
241 .addMBB(Dispatch);
242 Split->addSuccessor(Dispatch);
243 Map[Succ] = Split;
244 }
245 // Remap the terminator operands and the successor list.
246 for (MachineInstr &Term : MBB->terminators())
247 for (auto &Op : Term.explicit_uses())
248 if (Op.isMBB() && Indices.count(Op.getMBB()))
249 Op.setMBB(Map[Op.getMBB()]);
250 for (auto Rewrite : Map)
251 MBB->replaceSuccessor(Rewrite.first, Rewrite.second);
252 }
253
254 // Create a fake default label, because br_table requires one.
255 MIB.addMBB(MIB.getInstr()
256 ->getOperand(MIB.getInstr()->getNumExplicitOperands() - 1)
257 .getMBB());
258
259 return true;
260}
261
262bool WebAssemblyFixIrreducibleControlFlow::runOnMachineFunction(
263 MachineFunction &MF) {
264 DEBUG(dbgs() << "********** Fixing Irreducible Control Flow **********\n"
265 "********** Function: "
266 << MF.getName() << '\n');
267
268 bool Changed = false;
269 auto &MLI = getAnalysis<MachineLoopInfo>();
270
271 // Visit the function body, which is identified as a null loop.
272 Changed |= VisitLoop(MF, MLI, nullptr);
273
274 // Visit all the loops.
275 SmallVector<MachineLoop *, 8> Worklist(MLI.begin(), MLI.end());
276 while (!Worklist.empty()) {
277 MachineLoop *CurLoop = Worklist.pop_back_val();
278 Worklist.append(CurLoop->begin(), CurLoop->end());
279 Changed |= VisitLoop(MF, MLI, CurLoop);
280 }
281
282 // If we made any changes, completely recompute everything.
283 if (LLVM_UNLIKELY(Changed)) {
284 DEBUG(dbgs() << "Recomputing dominators and loops.\n");
285 MF.getRegInfo().invalidateLiveness();
286 MF.RenumberBlocks();
287 getAnalysis<MachineDominatorTree>().runOnMachineFunction(MF);
288 MLI.runOnMachineFunction(MF);
289 }
290
291 return Changed;
292}