1*0b57cec5SDimitry Andric //=- WebAssemblyFixIrreducibleControlFlow.cpp - Fix irreducible control flow -//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric ///
9*0b57cec5SDimitry Andric /// \file
10*0b57cec5SDimitry Andric /// This file implements a pass that removes irreducible control flow.
11*0b57cec5SDimitry Andric /// Irreducible control flow means multiple-entry loops, which this pass
12*0b57cec5SDimitry Andric /// transforms to have a single entry.
13*0b57cec5SDimitry Andric ///
14*0b57cec5SDimitry Andric /// Note that LLVM has a generic pass that lowers irreducible control flow, but
15*0b57cec5SDimitry Andric /// it linearizes control flow, turning diamonds into two triangles, which is
16*0b57cec5SDimitry Andric /// both unnecessary and undesirable for WebAssembly.
17*0b57cec5SDimitry Andric ///
18*0b57cec5SDimitry Andric /// The big picture: We recursively process each "region", defined as a group
19*0b57cec5SDimitry Andric /// of blocks with a single entry and no branches back to that entry. A region
20*0b57cec5SDimitry Andric /// may be the entire function body, or the inner part of a loop, i.e., the
21*0b57cec5SDimitry Andric /// loop's body without branches back to the loop entry. In each region we fix
22*0b57cec5SDimitry Andric /// up multi-entry loops by adding a new block that can dispatch to each of the
23*0b57cec5SDimitry Andric /// loop entries, based on the value of a label "helper" variable, and we
24*0b57cec5SDimitry Andric /// replace direct branches to the entries with assignments to the label
25*0b57cec5SDimitry Andric /// variable and a branch to the dispatch block. Then the dispatch block is the
26*0b57cec5SDimitry Andric /// single entry in the loop containing the previous multiple entries. After
27*0b57cec5SDimitry Andric /// ensuring all the loops in a region are reducible, we recurse into them. The
28*0b57cec5SDimitry Andric /// total time complexity of this pass is:
29*0b57cec5SDimitry Andric ///
30*0b57cec5SDimitry Andric ///   O(NumBlocks * NumNestedLoops * NumIrreducibleLoops +
31*0b57cec5SDimitry Andric ///     NumLoops * NumLoops)
32*0b57cec5SDimitry Andric ///
33*0b57cec5SDimitry Andric /// This pass is similar to what the Relooper [1] does. Both identify looping
34*0b57cec5SDimitry Andric /// code that requires multiple entries, and resolve it in a similar way (in
35*0b57cec5SDimitry Andric /// Relooper terminology, we implement a Multiple shape in a Loop shape). Note
36*0b57cec5SDimitry Andric /// also that like the Relooper, we implement a "minimal" intervention: we only
37*0b57cec5SDimitry Andric /// use the "label" helper for the blocks we absolutely must and no others. We
38*0b57cec5SDimitry Andric /// also prioritize code size and do not duplicate code in order to resolve
39*0b57cec5SDimitry Andric /// irreducibility. The graph algorithms for finding loops and entries and so
40*0b57cec5SDimitry Andric /// forth are also similar to the Relooper. The main differences between this
41*0b57cec5SDimitry Andric /// pass and the Relooper are:
42*0b57cec5SDimitry Andric ///
43*0b57cec5SDimitry Andric ///  * We just care about irreducibility, so we just look at loops.
44*0b57cec5SDimitry Andric ///  * The Relooper emits structured control flow (with ifs etc.), while we
45*0b57cec5SDimitry Andric ///    emit a CFG.
46*0b57cec5SDimitry Andric ///
47*0b57cec5SDimitry Andric /// [1] Alon Zakai. 2011. Emscripten: an LLVM-to-JavaScript compiler. In
48*0b57cec5SDimitry Andric /// Proceedings of the ACM international conference companion on Object oriented
49*0b57cec5SDimitry Andric /// programming systems languages and applications companion (SPLASH '11). ACM,
50*0b57cec5SDimitry Andric /// New York, NY, USA, 301-312. DOI=10.1145/2048147.2048224
51*0b57cec5SDimitry Andric /// http://doi.acm.org/10.1145/2048147.2048224
52*0b57cec5SDimitry Andric ///
53*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
54*0b57cec5SDimitry Andric 
55*0b57cec5SDimitry Andric #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
56*0b57cec5SDimitry Andric #include "WebAssembly.h"
57*0b57cec5SDimitry Andric #include "WebAssemblySubtarget.h"
58*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
59*0b57cec5SDimitry Andric using namespace llvm;
60*0b57cec5SDimitry Andric 
61*0b57cec5SDimitry Andric #define DEBUG_TYPE "wasm-fix-irreducible-control-flow"
62*0b57cec5SDimitry Andric 
63*0b57cec5SDimitry Andric namespace {
64*0b57cec5SDimitry Andric 
65*0b57cec5SDimitry Andric using BlockVector = SmallVector<MachineBasicBlock *, 4>;
66*0b57cec5SDimitry Andric using BlockSet = SmallPtrSet<MachineBasicBlock *, 4>;
67*0b57cec5SDimitry Andric 
68*0b57cec5SDimitry Andric // Calculates reachability in a region. Ignores branches to blocks outside of
69*0b57cec5SDimitry Andric // the region, and ignores branches to the region entry (for the case where
70*0b57cec5SDimitry Andric // the region is the inner part of a loop).
71*0b57cec5SDimitry Andric class ReachabilityGraph {
72*0b57cec5SDimitry Andric public:
73*0b57cec5SDimitry Andric   ReachabilityGraph(MachineBasicBlock *Entry, const BlockSet &Blocks)
74*0b57cec5SDimitry Andric       : Entry(Entry), Blocks(Blocks) {
75*0b57cec5SDimitry Andric #ifndef NDEBUG
76*0b57cec5SDimitry Andric     // The region must have a single entry.
77*0b57cec5SDimitry Andric     for (auto *MBB : Blocks) {
78*0b57cec5SDimitry Andric       if (MBB != Entry) {
79*0b57cec5SDimitry Andric         for (auto *Pred : MBB->predecessors()) {
80*0b57cec5SDimitry Andric           assert(inRegion(Pred));
81*0b57cec5SDimitry Andric         }
82*0b57cec5SDimitry Andric       }
83*0b57cec5SDimitry Andric     }
84*0b57cec5SDimitry Andric #endif
85*0b57cec5SDimitry Andric     calculate();
86*0b57cec5SDimitry Andric   }
87*0b57cec5SDimitry Andric 
88*0b57cec5SDimitry Andric   bool canReach(MachineBasicBlock *From, MachineBasicBlock *To) const {
89*0b57cec5SDimitry Andric     assert(inRegion(From) && inRegion(To));
90*0b57cec5SDimitry Andric     auto I = Reachable.find(From);
91*0b57cec5SDimitry Andric     if (I == Reachable.end())
92*0b57cec5SDimitry Andric       return false;
93*0b57cec5SDimitry Andric     return I->second.count(To);
94*0b57cec5SDimitry Andric   }
95*0b57cec5SDimitry Andric 
96*0b57cec5SDimitry Andric   // "Loopers" are blocks that are in a loop. We detect these by finding blocks
97*0b57cec5SDimitry Andric   // that can reach themselves.
98*0b57cec5SDimitry Andric   const BlockSet &getLoopers() const { return Loopers; }
99*0b57cec5SDimitry Andric 
100*0b57cec5SDimitry Andric   // Get all blocks that are loop entries.
101*0b57cec5SDimitry Andric   const BlockSet &getLoopEntries() const { return LoopEntries; }
102*0b57cec5SDimitry Andric 
103*0b57cec5SDimitry Andric   // Get all blocks that enter a particular loop from outside.
104*0b57cec5SDimitry Andric   const BlockSet &getLoopEnterers(MachineBasicBlock *LoopEntry) const {
105*0b57cec5SDimitry Andric     assert(inRegion(LoopEntry));
106*0b57cec5SDimitry Andric     auto I = LoopEnterers.find(LoopEntry);
107*0b57cec5SDimitry Andric     assert(I != LoopEnterers.end());
108*0b57cec5SDimitry Andric     return I->second;
109*0b57cec5SDimitry Andric   }
110*0b57cec5SDimitry Andric 
111*0b57cec5SDimitry Andric private:
112*0b57cec5SDimitry Andric   MachineBasicBlock *Entry;
113*0b57cec5SDimitry Andric   const BlockSet &Blocks;
114*0b57cec5SDimitry Andric 
115*0b57cec5SDimitry Andric   BlockSet Loopers, LoopEntries;
116*0b57cec5SDimitry Andric   DenseMap<MachineBasicBlock *, BlockSet> LoopEnterers;
117*0b57cec5SDimitry Andric 
118*0b57cec5SDimitry Andric   bool inRegion(MachineBasicBlock *MBB) const { return Blocks.count(MBB); }
119*0b57cec5SDimitry Andric 
120*0b57cec5SDimitry Andric   // Maps a block to all the other blocks it can reach.
121*0b57cec5SDimitry Andric   DenseMap<MachineBasicBlock *, BlockSet> Reachable;
122*0b57cec5SDimitry Andric 
123*0b57cec5SDimitry Andric   void calculate() {
124*0b57cec5SDimitry Andric     // Reachability computation work list. Contains pairs of recent additions
125*0b57cec5SDimitry Andric     // (A, B) where we just added a link A => B.
126*0b57cec5SDimitry Andric     using BlockPair = std::pair<MachineBasicBlock *, MachineBasicBlock *>;
127*0b57cec5SDimitry Andric     SmallVector<BlockPair, 4> WorkList;
128*0b57cec5SDimitry Andric 
129*0b57cec5SDimitry Andric     // Add all relevant direct branches.
130*0b57cec5SDimitry Andric     for (auto *MBB : Blocks) {
131*0b57cec5SDimitry Andric       for (auto *Succ : MBB->successors()) {
132*0b57cec5SDimitry Andric         if (Succ != Entry && inRegion(Succ)) {
133*0b57cec5SDimitry Andric           Reachable[MBB].insert(Succ);
134*0b57cec5SDimitry Andric           WorkList.emplace_back(MBB, Succ);
135*0b57cec5SDimitry Andric         }
136*0b57cec5SDimitry Andric       }
137*0b57cec5SDimitry Andric     }
138*0b57cec5SDimitry Andric 
139*0b57cec5SDimitry Andric     while (!WorkList.empty()) {
140*0b57cec5SDimitry Andric       MachineBasicBlock *MBB, *Succ;
141*0b57cec5SDimitry Andric       std::tie(MBB, Succ) = WorkList.pop_back_val();
142*0b57cec5SDimitry Andric       assert(inRegion(MBB) && Succ != Entry && inRegion(Succ));
143*0b57cec5SDimitry Andric       if (MBB != Entry) {
144*0b57cec5SDimitry Andric         // We recently added MBB => Succ, and that means we may have enabled
145*0b57cec5SDimitry Andric         // Pred => MBB => Succ.
146*0b57cec5SDimitry Andric         for (auto *Pred : MBB->predecessors()) {
147*0b57cec5SDimitry Andric           if (Reachable[Pred].insert(Succ).second) {
148*0b57cec5SDimitry Andric             WorkList.emplace_back(Pred, Succ);
149*0b57cec5SDimitry Andric           }
150*0b57cec5SDimitry Andric         }
151*0b57cec5SDimitry Andric       }
152*0b57cec5SDimitry Andric     }
153*0b57cec5SDimitry Andric 
154*0b57cec5SDimitry Andric     // Blocks that can return to themselves are in a loop.
155*0b57cec5SDimitry Andric     for (auto *MBB : Blocks) {
156*0b57cec5SDimitry Andric       if (canReach(MBB, MBB)) {
157*0b57cec5SDimitry Andric         Loopers.insert(MBB);
158*0b57cec5SDimitry Andric       }
159*0b57cec5SDimitry Andric     }
160*0b57cec5SDimitry Andric     assert(!Loopers.count(Entry));
161*0b57cec5SDimitry Andric 
162*0b57cec5SDimitry Andric     // Find the loop entries - loopers reachable from blocks not in that loop -
163*0b57cec5SDimitry Andric     // and those outside blocks that reach them, the "loop enterers".
164*0b57cec5SDimitry Andric     for (auto *Looper : Loopers) {
165*0b57cec5SDimitry Andric       for (auto *Pred : Looper->predecessors()) {
166*0b57cec5SDimitry Andric         // Pred can reach Looper. If Looper can reach Pred, it is in the loop;
167*0b57cec5SDimitry Andric         // otherwise, it is a block that enters into the loop.
168*0b57cec5SDimitry Andric         if (!canReach(Looper, Pred)) {
169*0b57cec5SDimitry Andric           LoopEntries.insert(Looper);
170*0b57cec5SDimitry Andric           LoopEnterers[Looper].insert(Pred);
171*0b57cec5SDimitry Andric         }
172*0b57cec5SDimitry Andric       }
173*0b57cec5SDimitry Andric     }
174*0b57cec5SDimitry Andric   }
175*0b57cec5SDimitry Andric };
176*0b57cec5SDimitry Andric 
177*0b57cec5SDimitry Andric // Finds the blocks in a single-entry loop, given the loop entry and the
178*0b57cec5SDimitry Andric // list of blocks that enter the loop.
179*0b57cec5SDimitry Andric class LoopBlocks {
180*0b57cec5SDimitry Andric public:
181*0b57cec5SDimitry Andric   LoopBlocks(MachineBasicBlock *Entry, const BlockSet &Enterers)
182*0b57cec5SDimitry Andric       : Entry(Entry), Enterers(Enterers) {
183*0b57cec5SDimitry Andric     calculate();
184*0b57cec5SDimitry Andric   }
185*0b57cec5SDimitry Andric 
186*0b57cec5SDimitry Andric   BlockSet &getBlocks() { return Blocks; }
187*0b57cec5SDimitry Andric 
188*0b57cec5SDimitry Andric private:
189*0b57cec5SDimitry Andric   MachineBasicBlock *Entry;
190*0b57cec5SDimitry Andric   const BlockSet &Enterers;
191*0b57cec5SDimitry Andric 
192*0b57cec5SDimitry Andric   BlockSet Blocks;
193*0b57cec5SDimitry Andric 
194*0b57cec5SDimitry Andric   void calculate() {
195*0b57cec5SDimitry Andric     // Going backwards from the loop entry, if we ignore the blocks entering
196*0b57cec5SDimitry Andric     // from outside, we will traverse all the blocks in the loop.
197*0b57cec5SDimitry Andric     BlockVector WorkList;
198*0b57cec5SDimitry Andric     BlockSet AddedToWorkList;
199*0b57cec5SDimitry Andric     Blocks.insert(Entry);
200*0b57cec5SDimitry Andric     for (auto *Pred : Entry->predecessors()) {
201*0b57cec5SDimitry Andric       if (!Enterers.count(Pred)) {
202*0b57cec5SDimitry Andric         WorkList.push_back(Pred);
203*0b57cec5SDimitry Andric         AddedToWorkList.insert(Pred);
204*0b57cec5SDimitry Andric       }
205*0b57cec5SDimitry Andric     }
206*0b57cec5SDimitry Andric 
207*0b57cec5SDimitry Andric     while (!WorkList.empty()) {
208*0b57cec5SDimitry Andric       auto *MBB = WorkList.pop_back_val();
209*0b57cec5SDimitry Andric       assert(!Enterers.count(MBB));
210*0b57cec5SDimitry Andric       if (Blocks.insert(MBB).second) {
211*0b57cec5SDimitry Andric         for (auto *Pred : MBB->predecessors()) {
212*0b57cec5SDimitry Andric           if (!AddedToWorkList.count(Pred)) {
213*0b57cec5SDimitry Andric             WorkList.push_back(Pred);
214*0b57cec5SDimitry Andric             AddedToWorkList.insert(Pred);
215*0b57cec5SDimitry Andric           }
216*0b57cec5SDimitry Andric         }
217*0b57cec5SDimitry Andric       }
218*0b57cec5SDimitry Andric     }
219*0b57cec5SDimitry Andric   }
220*0b57cec5SDimitry Andric };
221*0b57cec5SDimitry Andric 
222*0b57cec5SDimitry Andric class WebAssemblyFixIrreducibleControlFlow final : public MachineFunctionPass {
223*0b57cec5SDimitry Andric   StringRef getPassName() const override {
224*0b57cec5SDimitry Andric     return "WebAssembly Fix Irreducible Control Flow";
225*0b57cec5SDimitry Andric   }
226*0b57cec5SDimitry Andric 
227*0b57cec5SDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override;
228*0b57cec5SDimitry Andric 
229*0b57cec5SDimitry Andric   bool processRegion(MachineBasicBlock *Entry, BlockSet &Blocks,
230*0b57cec5SDimitry Andric                      MachineFunction &MF);
231*0b57cec5SDimitry Andric 
232*0b57cec5SDimitry Andric   void makeSingleEntryLoop(BlockSet &Entries, BlockSet &Blocks,
233*0b57cec5SDimitry Andric                            MachineFunction &MF, const ReachabilityGraph &Graph);
234*0b57cec5SDimitry Andric 
235*0b57cec5SDimitry Andric public:
236*0b57cec5SDimitry Andric   static char ID; // Pass identification, replacement for typeid
237*0b57cec5SDimitry Andric   WebAssemblyFixIrreducibleControlFlow() : MachineFunctionPass(ID) {}
238*0b57cec5SDimitry Andric };
239*0b57cec5SDimitry Andric 
240*0b57cec5SDimitry Andric bool WebAssemblyFixIrreducibleControlFlow::processRegion(
241*0b57cec5SDimitry Andric     MachineBasicBlock *Entry, BlockSet &Blocks, MachineFunction &MF) {
242*0b57cec5SDimitry Andric   bool Changed = false;
243*0b57cec5SDimitry Andric 
244*0b57cec5SDimitry Andric   // Remove irreducibility before processing child loops, which may take
245*0b57cec5SDimitry Andric   // multiple iterations.
246*0b57cec5SDimitry Andric   while (true) {
247*0b57cec5SDimitry Andric     ReachabilityGraph Graph(Entry, Blocks);
248*0b57cec5SDimitry Andric 
249*0b57cec5SDimitry Andric     bool FoundIrreducibility = false;
250*0b57cec5SDimitry Andric 
251*0b57cec5SDimitry Andric     for (auto *LoopEntry : Graph.getLoopEntries()) {
252*0b57cec5SDimitry Andric       // Find mutual entries - all entries which can reach this one, and
253*0b57cec5SDimitry Andric       // are reached by it (that always includes LoopEntry itself). All mutual
254*0b57cec5SDimitry Andric       // entries must be in the same loop, so if we have more than one, then we
255*0b57cec5SDimitry Andric       // have irreducible control flow.
256*0b57cec5SDimitry Andric       //
257*0b57cec5SDimitry Andric       // Note that irreducibility may involve inner loops, e.g. imagine A
258*0b57cec5SDimitry Andric       // starts one loop, and it has B inside it which starts an inner loop.
259*0b57cec5SDimitry Andric       // If we add a branch from all the way on the outside to B, then in a
260*0b57cec5SDimitry Andric       // sense B is no longer an "inner" loop, semantically speaking. We will
261*0b57cec5SDimitry Andric       // fix that irreducibility by adding a block that dispatches to either
262*0b57cec5SDimitry Andric       // either A or B, so B will no longer be an inner loop in our output.
263*0b57cec5SDimitry Andric       // (A fancier approach might try to keep it as such.)
264*0b57cec5SDimitry Andric       //
265*0b57cec5SDimitry Andric       // Note that we still need to recurse into inner loops later, to handle
266*0b57cec5SDimitry Andric       // the case where the irreducibility is entirely nested - we would not
267*0b57cec5SDimitry Andric       // be able to identify that at this point, since the enclosing loop is
268*0b57cec5SDimitry Andric       // a group of blocks all of whom can reach each other. (We'll see the
269*0b57cec5SDimitry Andric       // irreducibility after removing branches to the top of that enclosing
270*0b57cec5SDimitry Andric       // loop.)
271*0b57cec5SDimitry Andric       BlockSet MutualLoopEntries;
272*0b57cec5SDimitry Andric       MutualLoopEntries.insert(LoopEntry);
273*0b57cec5SDimitry Andric       for (auto *OtherLoopEntry : Graph.getLoopEntries()) {
274*0b57cec5SDimitry Andric         if (OtherLoopEntry != LoopEntry &&
275*0b57cec5SDimitry Andric             Graph.canReach(LoopEntry, OtherLoopEntry) &&
276*0b57cec5SDimitry Andric             Graph.canReach(OtherLoopEntry, LoopEntry)) {
277*0b57cec5SDimitry Andric           MutualLoopEntries.insert(OtherLoopEntry);
278*0b57cec5SDimitry Andric         }
279*0b57cec5SDimitry Andric       }
280*0b57cec5SDimitry Andric 
281*0b57cec5SDimitry Andric       if (MutualLoopEntries.size() > 1) {
282*0b57cec5SDimitry Andric         makeSingleEntryLoop(MutualLoopEntries, Blocks, MF, Graph);
283*0b57cec5SDimitry Andric         FoundIrreducibility = true;
284*0b57cec5SDimitry Andric         Changed = true;
285*0b57cec5SDimitry Andric         break;
286*0b57cec5SDimitry Andric       }
287*0b57cec5SDimitry Andric     }
288*0b57cec5SDimitry Andric     // Only go on to actually process the inner loops when we are done
289*0b57cec5SDimitry Andric     // removing irreducible control flow and changing the graph. Modifying
290*0b57cec5SDimitry Andric     // the graph as we go is possible, and that might let us avoid looking at
291*0b57cec5SDimitry Andric     // the already-fixed loops again if we are careful, but all that is
292*0b57cec5SDimitry Andric     // complex and bug-prone. Since irreducible loops are rare, just starting
293*0b57cec5SDimitry Andric     // another iteration is best.
294*0b57cec5SDimitry Andric     if (FoundIrreducibility) {
295*0b57cec5SDimitry Andric       continue;
296*0b57cec5SDimitry Andric     }
297*0b57cec5SDimitry Andric 
298*0b57cec5SDimitry Andric     for (auto *LoopEntry : Graph.getLoopEntries()) {
299*0b57cec5SDimitry Andric       LoopBlocks InnerBlocks(LoopEntry, Graph.getLoopEnterers(LoopEntry));
300*0b57cec5SDimitry Andric       // Each of these calls to processRegion may change the graph, but are
301*0b57cec5SDimitry Andric       // guaranteed not to interfere with each other. The only changes we make
302*0b57cec5SDimitry Andric       // to the graph are to add blocks on the way to a loop entry. As the
303*0b57cec5SDimitry Andric       // loops are disjoint, that means we may only alter branches that exit
304*0b57cec5SDimitry Andric       // another loop, which are ignored when recursing into that other loop
305*0b57cec5SDimitry Andric       // anyhow.
306*0b57cec5SDimitry Andric       if (processRegion(LoopEntry, InnerBlocks.getBlocks(), MF)) {
307*0b57cec5SDimitry Andric         Changed = true;
308*0b57cec5SDimitry Andric       }
309*0b57cec5SDimitry Andric     }
310*0b57cec5SDimitry Andric 
311*0b57cec5SDimitry Andric     return Changed;
312*0b57cec5SDimitry Andric   }
313*0b57cec5SDimitry Andric }
314*0b57cec5SDimitry Andric 
315*0b57cec5SDimitry Andric // Given a set of entries to a single loop, create a single entry for that
316*0b57cec5SDimitry Andric // loop by creating a dispatch block for them, routing control flow using
317*0b57cec5SDimitry Andric // a helper variable. Also updates Blocks with any new blocks created, so
318*0b57cec5SDimitry Andric // that we properly track all the blocks in the region. But this does not update
319*0b57cec5SDimitry Andric // ReachabilityGraph; this will be updated in the caller of this function as
320*0b57cec5SDimitry Andric // needed.
321*0b57cec5SDimitry Andric void WebAssemblyFixIrreducibleControlFlow::makeSingleEntryLoop(
322*0b57cec5SDimitry Andric     BlockSet &Entries, BlockSet &Blocks, MachineFunction &MF,
323*0b57cec5SDimitry Andric     const ReachabilityGraph &Graph) {
324*0b57cec5SDimitry Andric   assert(Entries.size() >= 2);
325*0b57cec5SDimitry Andric 
326*0b57cec5SDimitry Andric   // Sort the entries to ensure a deterministic build.
327*0b57cec5SDimitry Andric   BlockVector SortedEntries(Entries.begin(), Entries.end());
328*0b57cec5SDimitry Andric   llvm::sort(SortedEntries,
329*0b57cec5SDimitry Andric              [&](const MachineBasicBlock *A, const MachineBasicBlock *B) {
330*0b57cec5SDimitry Andric                auto ANum = A->getNumber();
331*0b57cec5SDimitry Andric                auto BNum = B->getNumber();
332*0b57cec5SDimitry Andric                return ANum < BNum;
333*0b57cec5SDimitry Andric              });
334*0b57cec5SDimitry Andric 
335*0b57cec5SDimitry Andric #ifndef NDEBUG
336*0b57cec5SDimitry Andric   for (auto Block : SortedEntries)
337*0b57cec5SDimitry Andric     assert(Block->getNumber() != -1);
338*0b57cec5SDimitry Andric   if (SortedEntries.size() > 1) {
339*0b57cec5SDimitry Andric     for (auto I = SortedEntries.begin(), E = SortedEntries.end() - 1; I != E;
340*0b57cec5SDimitry Andric          ++I) {
341*0b57cec5SDimitry Andric       auto ANum = (*I)->getNumber();
342*0b57cec5SDimitry Andric       auto BNum = (*(std::next(I)))->getNumber();
343*0b57cec5SDimitry Andric       assert(ANum != BNum);
344*0b57cec5SDimitry Andric     }
345*0b57cec5SDimitry Andric   }
346*0b57cec5SDimitry Andric #endif
347*0b57cec5SDimitry Andric 
348*0b57cec5SDimitry Andric   // Create a dispatch block which will contain a jump table to the entries.
349*0b57cec5SDimitry Andric   MachineBasicBlock *Dispatch = MF.CreateMachineBasicBlock();
350*0b57cec5SDimitry Andric   MF.insert(MF.end(), Dispatch);
351*0b57cec5SDimitry Andric   Blocks.insert(Dispatch);
352*0b57cec5SDimitry Andric 
353*0b57cec5SDimitry Andric   // Add the jump table.
354*0b57cec5SDimitry Andric   const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
355*0b57cec5SDimitry Andric   MachineInstrBuilder MIB =
356*0b57cec5SDimitry Andric       BuildMI(Dispatch, DebugLoc(), TII.get(WebAssembly::BR_TABLE_I32));
357*0b57cec5SDimitry Andric 
358*0b57cec5SDimitry Andric   // Add the register which will be used to tell the jump table which block to
359*0b57cec5SDimitry Andric   // jump to.
360*0b57cec5SDimitry Andric   MachineRegisterInfo &MRI = MF.getRegInfo();
361*0b57cec5SDimitry Andric   unsigned Reg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
362*0b57cec5SDimitry Andric   MIB.addReg(Reg);
363*0b57cec5SDimitry Andric 
364*0b57cec5SDimitry Andric   // Compute the indices in the superheader, one for each bad block, and
365*0b57cec5SDimitry Andric   // add them as successors.
366*0b57cec5SDimitry Andric   DenseMap<MachineBasicBlock *, unsigned> Indices;
367*0b57cec5SDimitry Andric   for (auto *Entry : SortedEntries) {
368*0b57cec5SDimitry Andric     auto Pair = Indices.insert(std::make_pair(Entry, 0));
369*0b57cec5SDimitry Andric     assert(Pair.second);
370*0b57cec5SDimitry Andric 
371*0b57cec5SDimitry Andric     unsigned Index = MIB.getInstr()->getNumExplicitOperands() - 1;
372*0b57cec5SDimitry Andric     Pair.first->second = Index;
373*0b57cec5SDimitry Andric 
374*0b57cec5SDimitry Andric     MIB.addMBB(Entry);
375*0b57cec5SDimitry Andric     Dispatch->addSuccessor(Entry);
376*0b57cec5SDimitry Andric   }
377*0b57cec5SDimitry Andric 
378*0b57cec5SDimitry Andric   // Rewrite the problematic successors for every block that wants to reach
379*0b57cec5SDimitry Andric   // the bad blocks. For simplicity, we just introduce a new block for every
380*0b57cec5SDimitry Andric   // edge we need to rewrite. (Fancier things are possible.)
381*0b57cec5SDimitry Andric 
382*0b57cec5SDimitry Andric   BlockVector AllPreds;
383*0b57cec5SDimitry Andric   for (auto *Entry : SortedEntries) {
384*0b57cec5SDimitry Andric     for (auto *Pred : Entry->predecessors()) {
385*0b57cec5SDimitry Andric       if (Pred != Dispatch) {
386*0b57cec5SDimitry Andric         AllPreds.push_back(Pred);
387*0b57cec5SDimitry Andric       }
388*0b57cec5SDimitry Andric     }
389*0b57cec5SDimitry Andric   }
390*0b57cec5SDimitry Andric 
391*0b57cec5SDimitry Andric   // This set stores predecessors within this loop.
392*0b57cec5SDimitry Andric   DenseSet<MachineBasicBlock *> InLoop;
393*0b57cec5SDimitry Andric   for (auto *Pred : AllPreds) {
394*0b57cec5SDimitry Andric     for (auto *Entry : Pred->successors()) {
395*0b57cec5SDimitry Andric       if (!Entries.count(Entry))
396*0b57cec5SDimitry Andric         continue;
397*0b57cec5SDimitry Andric       if (Graph.canReach(Entry, Pred)) {
398*0b57cec5SDimitry Andric         InLoop.insert(Pred);
399*0b57cec5SDimitry Andric         break;
400*0b57cec5SDimitry Andric       }
401*0b57cec5SDimitry Andric     }
402*0b57cec5SDimitry Andric   }
403*0b57cec5SDimitry Andric 
404*0b57cec5SDimitry Andric   // Record if each entry has a layout predecessor. This map stores
405*0b57cec5SDimitry Andric   // <<Predecessor is within the loop?, loop entry>, layout predecessor>
406*0b57cec5SDimitry Andric   std::map<std::pair<bool, MachineBasicBlock *>, MachineBasicBlock *>
407*0b57cec5SDimitry Andric       EntryToLayoutPred;
408*0b57cec5SDimitry Andric   for (auto *Pred : AllPreds)
409*0b57cec5SDimitry Andric     for (auto *Entry : Pred->successors())
410*0b57cec5SDimitry Andric       if (Entries.count(Entry) && Pred->isLayoutSuccessor(Entry))
411*0b57cec5SDimitry Andric         EntryToLayoutPred[std::make_pair(InLoop.count(Pred), Entry)] = Pred;
412*0b57cec5SDimitry Andric 
413*0b57cec5SDimitry Andric   // We need to create at most two routing blocks per entry: one for
414*0b57cec5SDimitry Andric   // predecessors outside the loop and one for predecessors inside the loop.
415*0b57cec5SDimitry Andric   // This map stores
416*0b57cec5SDimitry Andric   // <<Predecessor is within the loop?, loop entry>, routing block>
417*0b57cec5SDimitry Andric   std::map<std::pair<bool, MachineBasicBlock *>, MachineBasicBlock *> Map;
418*0b57cec5SDimitry Andric   for (auto *Pred : AllPreds) {
419*0b57cec5SDimitry Andric     bool PredInLoop = InLoop.count(Pred);
420*0b57cec5SDimitry Andric     for (auto *Entry : Pred->successors()) {
421*0b57cec5SDimitry Andric       if (!Entries.count(Entry) ||
422*0b57cec5SDimitry Andric           Map.count(std::make_pair(InLoop.count(Pred), Entry)))
423*0b57cec5SDimitry Andric         continue;
424*0b57cec5SDimitry Andric       // If there exists a layout predecessor of this entry and this predecessor
425*0b57cec5SDimitry Andric       // is not that, we rather create a routing block after that layout
426*0b57cec5SDimitry Andric       // predecessor to save a branch.
427*0b57cec5SDimitry Andric       if (EntryToLayoutPred.count(std::make_pair(PredInLoop, Entry)) &&
428*0b57cec5SDimitry Andric           EntryToLayoutPred[std::make_pair(PredInLoop, Entry)] != Pred)
429*0b57cec5SDimitry Andric         continue;
430*0b57cec5SDimitry Andric 
431*0b57cec5SDimitry Andric       // This is a successor we need to rewrite.
432*0b57cec5SDimitry Andric       MachineBasicBlock *Routing = MF.CreateMachineBasicBlock();
433*0b57cec5SDimitry Andric       MF.insert(Pred->isLayoutSuccessor(Entry)
434*0b57cec5SDimitry Andric                     ? MachineFunction::iterator(Entry)
435*0b57cec5SDimitry Andric                     : MF.end(),
436*0b57cec5SDimitry Andric                 Routing);
437*0b57cec5SDimitry Andric       Blocks.insert(Routing);
438*0b57cec5SDimitry Andric 
439*0b57cec5SDimitry Andric       // Set the jump table's register of the index of the block we wish to
440*0b57cec5SDimitry Andric       // jump to, and jump to the jump table.
441*0b57cec5SDimitry Andric       BuildMI(Routing, DebugLoc(), TII.get(WebAssembly::CONST_I32), Reg)
442*0b57cec5SDimitry Andric           .addImm(Indices[Entry]);
443*0b57cec5SDimitry Andric       BuildMI(Routing, DebugLoc(), TII.get(WebAssembly::BR)).addMBB(Dispatch);
444*0b57cec5SDimitry Andric       Routing->addSuccessor(Dispatch);
445*0b57cec5SDimitry Andric       Map[std::make_pair(PredInLoop, Entry)] = Routing;
446*0b57cec5SDimitry Andric     }
447*0b57cec5SDimitry Andric   }
448*0b57cec5SDimitry Andric 
449*0b57cec5SDimitry Andric   for (auto *Pred : AllPreds) {
450*0b57cec5SDimitry Andric     bool PredInLoop = InLoop.count(Pred);
451*0b57cec5SDimitry Andric     // Remap the terminator operands and the successor list.
452*0b57cec5SDimitry Andric     for (MachineInstr &Term : Pred->terminators())
453*0b57cec5SDimitry Andric       for (auto &Op : Term.explicit_uses())
454*0b57cec5SDimitry Andric         if (Op.isMBB() && Indices.count(Op.getMBB()))
455*0b57cec5SDimitry Andric           Op.setMBB(Map[std::make_pair(PredInLoop, Op.getMBB())]);
456*0b57cec5SDimitry Andric 
457*0b57cec5SDimitry Andric     for (auto *Succ : Pred->successors()) {
458*0b57cec5SDimitry Andric       if (!Entries.count(Succ))
459*0b57cec5SDimitry Andric         continue;
460*0b57cec5SDimitry Andric       auto *Routing = Map[std::make_pair(PredInLoop, Succ)];
461*0b57cec5SDimitry Andric       Pred->replaceSuccessor(Succ, Routing);
462*0b57cec5SDimitry Andric     }
463*0b57cec5SDimitry Andric   }
464*0b57cec5SDimitry Andric 
465*0b57cec5SDimitry Andric   // Create a fake default label, because br_table requires one.
466*0b57cec5SDimitry Andric   MIB.addMBB(MIB.getInstr()
467*0b57cec5SDimitry Andric                  ->getOperand(MIB.getInstr()->getNumExplicitOperands() - 1)
468*0b57cec5SDimitry Andric                  .getMBB());
469*0b57cec5SDimitry Andric }
470*0b57cec5SDimitry Andric 
471*0b57cec5SDimitry Andric } // end anonymous namespace
472*0b57cec5SDimitry Andric 
473*0b57cec5SDimitry Andric char WebAssemblyFixIrreducibleControlFlow::ID = 0;
474*0b57cec5SDimitry Andric INITIALIZE_PASS(WebAssemblyFixIrreducibleControlFlow, DEBUG_TYPE,
475*0b57cec5SDimitry Andric                 "Removes irreducible control flow", false, false)
476*0b57cec5SDimitry Andric 
477*0b57cec5SDimitry Andric FunctionPass *llvm::createWebAssemblyFixIrreducibleControlFlow() {
478*0b57cec5SDimitry Andric   return new WebAssemblyFixIrreducibleControlFlow();
479*0b57cec5SDimitry Andric }
480*0b57cec5SDimitry Andric 
481*0b57cec5SDimitry Andric bool WebAssemblyFixIrreducibleControlFlow::runOnMachineFunction(
482*0b57cec5SDimitry Andric     MachineFunction &MF) {
483*0b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "********** Fixing Irreducible Control Flow **********\n"
484*0b57cec5SDimitry Andric                        "********** Function: "
485*0b57cec5SDimitry Andric                     << MF.getName() << '\n');
486*0b57cec5SDimitry Andric 
487*0b57cec5SDimitry Andric   // Start the recursive process on the entire function body.
488*0b57cec5SDimitry Andric   BlockSet AllBlocks;
489*0b57cec5SDimitry Andric   for (auto &MBB : MF) {
490*0b57cec5SDimitry Andric     AllBlocks.insert(&MBB);
491*0b57cec5SDimitry Andric   }
492*0b57cec5SDimitry Andric 
493*0b57cec5SDimitry Andric   if (LLVM_UNLIKELY(processRegion(&*MF.begin(), AllBlocks, MF))) {
494*0b57cec5SDimitry Andric     // We rewrote part of the function; recompute relevant things.
495*0b57cec5SDimitry Andric     MF.getRegInfo().invalidateLiveness();
496*0b57cec5SDimitry Andric     MF.RenumberBlocks();
497*0b57cec5SDimitry Andric     return true;
498*0b57cec5SDimitry Andric   }
499*0b57cec5SDimitry Andric 
500*0b57cec5SDimitry Andric   return false;
501*0b57cec5SDimitry Andric }
502