10b57cec5SDimitry Andric //=- WebAssemblyFixIrreducibleControlFlow.cpp - Fix irreducible control flow -// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric /// 90b57cec5SDimitry Andric /// \file 100b57cec5SDimitry Andric /// This file implements a pass that removes irreducible control flow. 110b57cec5SDimitry Andric /// Irreducible control flow means multiple-entry loops, which this pass 120b57cec5SDimitry Andric /// transforms to have a single entry. 130b57cec5SDimitry Andric /// 140b57cec5SDimitry Andric /// Note that LLVM has a generic pass that lowers irreducible control flow, but 150b57cec5SDimitry Andric /// it linearizes control flow, turning diamonds into two triangles, which is 160b57cec5SDimitry Andric /// both unnecessary and undesirable for WebAssembly. 170b57cec5SDimitry Andric /// 180b57cec5SDimitry Andric /// The big picture: We recursively process each "region", defined as a group 190b57cec5SDimitry Andric /// of blocks with a single entry and no branches back to that entry. A region 200b57cec5SDimitry Andric /// may be the entire function body, or the inner part of a loop, i.e., the 210b57cec5SDimitry Andric /// loop's body without branches back to the loop entry. In each region we fix 220b57cec5SDimitry Andric /// up multi-entry loops by adding a new block that can dispatch to each of the 230b57cec5SDimitry Andric /// loop entries, based on the value of a label "helper" variable, and we 240b57cec5SDimitry Andric /// replace direct branches to the entries with assignments to the label 250b57cec5SDimitry Andric /// variable and a branch to the dispatch block. Then the dispatch block is the 260b57cec5SDimitry Andric /// single entry in the loop containing the previous multiple entries. After 270b57cec5SDimitry Andric /// ensuring all the loops in a region are reducible, we recurse into them. The 280b57cec5SDimitry Andric /// total time complexity of this pass is: 290b57cec5SDimitry Andric /// 300b57cec5SDimitry Andric /// O(NumBlocks * NumNestedLoops * NumIrreducibleLoops + 310b57cec5SDimitry Andric /// NumLoops * NumLoops) 320b57cec5SDimitry Andric /// 330b57cec5SDimitry Andric /// This pass is similar to what the Relooper [1] does. Both identify looping 340b57cec5SDimitry Andric /// code that requires multiple entries, and resolve it in a similar way (in 350b57cec5SDimitry Andric /// Relooper terminology, we implement a Multiple shape in a Loop shape). Note 360b57cec5SDimitry Andric /// also that like the Relooper, we implement a "minimal" intervention: we only 370b57cec5SDimitry Andric /// use the "label" helper for the blocks we absolutely must and no others. We 380b57cec5SDimitry Andric /// also prioritize code size and do not duplicate code in order to resolve 390b57cec5SDimitry Andric /// irreducibility. The graph algorithms for finding loops and entries and so 400b57cec5SDimitry Andric /// forth are also similar to the Relooper. The main differences between this 410b57cec5SDimitry Andric /// pass and the Relooper are: 420b57cec5SDimitry Andric /// 430b57cec5SDimitry Andric /// * We just care about irreducibility, so we just look at loops. 440b57cec5SDimitry Andric /// * The Relooper emits structured control flow (with ifs etc.), while we 450b57cec5SDimitry Andric /// emit a CFG. 460b57cec5SDimitry Andric /// 470b57cec5SDimitry Andric /// [1] Alon Zakai. 2011. Emscripten: an LLVM-to-JavaScript compiler. In 480b57cec5SDimitry Andric /// Proceedings of the ACM international conference companion on Object oriented 490b57cec5SDimitry Andric /// programming systems languages and applications companion (SPLASH '11). ACM, 500b57cec5SDimitry Andric /// New York, NY, USA, 301-312. DOI=10.1145/2048147.2048224 510b57cec5SDimitry Andric /// http://doi.acm.org/10.1145/2048147.2048224 520b57cec5SDimitry Andric /// 530b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 540b57cec5SDimitry Andric 550b57cec5SDimitry Andric #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" 560b57cec5SDimitry Andric #include "WebAssembly.h" 570b57cec5SDimitry Andric #include "WebAssemblySubtarget.h" 580b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 59*8bcb0991SDimitry Andric #include "llvm/Support/Debug.h" 600b57cec5SDimitry Andric using namespace llvm; 610b57cec5SDimitry Andric 620b57cec5SDimitry Andric #define DEBUG_TYPE "wasm-fix-irreducible-control-flow" 630b57cec5SDimitry Andric 640b57cec5SDimitry Andric namespace { 650b57cec5SDimitry Andric 660b57cec5SDimitry Andric using BlockVector = SmallVector<MachineBasicBlock *, 4>; 670b57cec5SDimitry Andric using BlockSet = SmallPtrSet<MachineBasicBlock *, 4>; 680b57cec5SDimitry Andric 690b57cec5SDimitry Andric // Calculates reachability in a region. Ignores branches to blocks outside of 700b57cec5SDimitry Andric // the region, and ignores branches to the region entry (for the case where 710b57cec5SDimitry Andric // the region is the inner part of a loop). 720b57cec5SDimitry Andric class ReachabilityGraph { 730b57cec5SDimitry Andric public: 740b57cec5SDimitry Andric ReachabilityGraph(MachineBasicBlock *Entry, const BlockSet &Blocks) 750b57cec5SDimitry Andric : Entry(Entry), Blocks(Blocks) { 760b57cec5SDimitry Andric #ifndef NDEBUG 770b57cec5SDimitry Andric // The region must have a single entry. 780b57cec5SDimitry Andric for (auto *MBB : Blocks) { 790b57cec5SDimitry Andric if (MBB != Entry) { 800b57cec5SDimitry Andric for (auto *Pred : MBB->predecessors()) { 810b57cec5SDimitry Andric assert(inRegion(Pred)); 820b57cec5SDimitry Andric } 830b57cec5SDimitry Andric } 840b57cec5SDimitry Andric } 850b57cec5SDimitry Andric #endif 860b57cec5SDimitry Andric calculate(); 870b57cec5SDimitry Andric } 880b57cec5SDimitry Andric 890b57cec5SDimitry Andric bool canReach(MachineBasicBlock *From, MachineBasicBlock *To) const { 900b57cec5SDimitry Andric assert(inRegion(From) && inRegion(To)); 910b57cec5SDimitry Andric auto I = Reachable.find(From); 920b57cec5SDimitry Andric if (I == Reachable.end()) 930b57cec5SDimitry Andric return false; 940b57cec5SDimitry Andric return I->second.count(To); 950b57cec5SDimitry Andric } 960b57cec5SDimitry Andric 970b57cec5SDimitry Andric // "Loopers" are blocks that are in a loop. We detect these by finding blocks 980b57cec5SDimitry Andric // that can reach themselves. 990b57cec5SDimitry Andric const BlockSet &getLoopers() const { return Loopers; } 1000b57cec5SDimitry Andric 1010b57cec5SDimitry Andric // Get all blocks that are loop entries. 1020b57cec5SDimitry Andric const BlockSet &getLoopEntries() const { return LoopEntries; } 1030b57cec5SDimitry Andric 1040b57cec5SDimitry Andric // Get all blocks that enter a particular loop from outside. 1050b57cec5SDimitry Andric const BlockSet &getLoopEnterers(MachineBasicBlock *LoopEntry) const { 1060b57cec5SDimitry Andric assert(inRegion(LoopEntry)); 1070b57cec5SDimitry Andric auto I = LoopEnterers.find(LoopEntry); 1080b57cec5SDimitry Andric assert(I != LoopEnterers.end()); 1090b57cec5SDimitry Andric return I->second; 1100b57cec5SDimitry Andric } 1110b57cec5SDimitry Andric 1120b57cec5SDimitry Andric private: 1130b57cec5SDimitry Andric MachineBasicBlock *Entry; 1140b57cec5SDimitry Andric const BlockSet &Blocks; 1150b57cec5SDimitry Andric 1160b57cec5SDimitry Andric BlockSet Loopers, LoopEntries; 1170b57cec5SDimitry Andric DenseMap<MachineBasicBlock *, BlockSet> LoopEnterers; 1180b57cec5SDimitry Andric 1190b57cec5SDimitry Andric bool inRegion(MachineBasicBlock *MBB) const { return Blocks.count(MBB); } 1200b57cec5SDimitry Andric 1210b57cec5SDimitry Andric // Maps a block to all the other blocks it can reach. 1220b57cec5SDimitry Andric DenseMap<MachineBasicBlock *, BlockSet> Reachable; 1230b57cec5SDimitry Andric 1240b57cec5SDimitry Andric void calculate() { 1250b57cec5SDimitry Andric // Reachability computation work list. Contains pairs of recent additions 1260b57cec5SDimitry Andric // (A, B) where we just added a link A => B. 1270b57cec5SDimitry Andric using BlockPair = std::pair<MachineBasicBlock *, MachineBasicBlock *>; 1280b57cec5SDimitry Andric SmallVector<BlockPair, 4> WorkList; 1290b57cec5SDimitry Andric 1300b57cec5SDimitry Andric // Add all relevant direct branches. 1310b57cec5SDimitry Andric for (auto *MBB : Blocks) { 1320b57cec5SDimitry Andric for (auto *Succ : MBB->successors()) { 1330b57cec5SDimitry Andric if (Succ != Entry && inRegion(Succ)) { 1340b57cec5SDimitry Andric Reachable[MBB].insert(Succ); 1350b57cec5SDimitry Andric WorkList.emplace_back(MBB, Succ); 1360b57cec5SDimitry Andric } 1370b57cec5SDimitry Andric } 1380b57cec5SDimitry Andric } 1390b57cec5SDimitry Andric 1400b57cec5SDimitry Andric while (!WorkList.empty()) { 1410b57cec5SDimitry Andric MachineBasicBlock *MBB, *Succ; 1420b57cec5SDimitry Andric std::tie(MBB, Succ) = WorkList.pop_back_val(); 1430b57cec5SDimitry Andric assert(inRegion(MBB) && Succ != Entry && inRegion(Succ)); 1440b57cec5SDimitry Andric if (MBB != Entry) { 1450b57cec5SDimitry Andric // We recently added MBB => Succ, and that means we may have enabled 1460b57cec5SDimitry Andric // Pred => MBB => Succ. 1470b57cec5SDimitry Andric for (auto *Pred : MBB->predecessors()) { 1480b57cec5SDimitry Andric if (Reachable[Pred].insert(Succ).second) { 1490b57cec5SDimitry Andric WorkList.emplace_back(Pred, Succ); 1500b57cec5SDimitry Andric } 1510b57cec5SDimitry Andric } 1520b57cec5SDimitry Andric } 1530b57cec5SDimitry Andric } 1540b57cec5SDimitry Andric 1550b57cec5SDimitry Andric // Blocks that can return to themselves are in a loop. 1560b57cec5SDimitry Andric for (auto *MBB : Blocks) { 1570b57cec5SDimitry Andric if (canReach(MBB, MBB)) { 1580b57cec5SDimitry Andric Loopers.insert(MBB); 1590b57cec5SDimitry Andric } 1600b57cec5SDimitry Andric } 1610b57cec5SDimitry Andric assert(!Loopers.count(Entry)); 1620b57cec5SDimitry Andric 1630b57cec5SDimitry Andric // Find the loop entries - loopers reachable from blocks not in that loop - 1640b57cec5SDimitry Andric // and those outside blocks that reach them, the "loop enterers". 1650b57cec5SDimitry Andric for (auto *Looper : Loopers) { 1660b57cec5SDimitry Andric for (auto *Pred : Looper->predecessors()) { 1670b57cec5SDimitry Andric // Pred can reach Looper. If Looper can reach Pred, it is in the loop; 1680b57cec5SDimitry Andric // otherwise, it is a block that enters into the loop. 1690b57cec5SDimitry Andric if (!canReach(Looper, Pred)) { 1700b57cec5SDimitry Andric LoopEntries.insert(Looper); 1710b57cec5SDimitry Andric LoopEnterers[Looper].insert(Pred); 1720b57cec5SDimitry Andric } 1730b57cec5SDimitry Andric } 1740b57cec5SDimitry Andric } 1750b57cec5SDimitry Andric } 1760b57cec5SDimitry Andric }; 1770b57cec5SDimitry Andric 1780b57cec5SDimitry Andric // Finds the blocks in a single-entry loop, given the loop entry and the 1790b57cec5SDimitry Andric // list of blocks that enter the loop. 1800b57cec5SDimitry Andric class LoopBlocks { 1810b57cec5SDimitry Andric public: 1820b57cec5SDimitry Andric LoopBlocks(MachineBasicBlock *Entry, const BlockSet &Enterers) 1830b57cec5SDimitry Andric : Entry(Entry), Enterers(Enterers) { 1840b57cec5SDimitry Andric calculate(); 1850b57cec5SDimitry Andric } 1860b57cec5SDimitry Andric 1870b57cec5SDimitry Andric BlockSet &getBlocks() { return Blocks; } 1880b57cec5SDimitry Andric 1890b57cec5SDimitry Andric private: 1900b57cec5SDimitry Andric MachineBasicBlock *Entry; 1910b57cec5SDimitry Andric const BlockSet &Enterers; 1920b57cec5SDimitry Andric 1930b57cec5SDimitry Andric BlockSet Blocks; 1940b57cec5SDimitry Andric 1950b57cec5SDimitry Andric void calculate() { 1960b57cec5SDimitry Andric // Going backwards from the loop entry, if we ignore the blocks entering 1970b57cec5SDimitry Andric // from outside, we will traverse all the blocks in the loop. 1980b57cec5SDimitry Andric BlockVector WorkList; 1990b57cec5SDimitry Andric BlockSet AddedToWorkList; 2000b57cec5SDimitry Andric Blocks.insert(Entry); 2010b57cec5SDimitry Andric for (auto *Pred : Entry->predecessors()) { 2020b57cec5SDimitry Andric if (!Enterers.count(Pred)) { 2030b57cec5SDimitry Andric WorkList.push_back(Pred); 2040b57cec5SDimitry Andric AddedToWorkList.insert(Pred); 2050b57cec5SDimitry Andric } 2060b57cec5SDimitry Andric } 2070b57cec5SDimitry Andric 2080b57cec5SDimitry Andric while (!WorkList.empty()) { 2090b57cec5SDimitry Andric auto *MBB = WorkList.pop_back_val(); 2100b57cec5SDimitry Andric assert(!Enterers.count(MBB)); 2110b57cec5SDimitry Andric if (Blocks.insert(MBB).second) { 2120b57cec5SDimitry Andric for (auto *Pred : MBB->predecessors()) { 2130b57cec5SDimitry Andric if (!AddedToWorkList.count(Pred)) { 2140b57cec5SDimitry Andric WorkList.push_back(Pred); 2150b57cec5SDimitry Andric AddedToWorkList.insert(Pred); 2160b57cec5SDimitry Andric } 2170b57cec5SDimitry Andric } 2180b57cec5SDimitry Andric } 2190b57cec5SDimitry Andric } 2200b57cec5SDimitry Andric } 2210b57cec5SDimitry Andric }; 2220b57cec5SDimitry Andric 2230b57cec5SDimitry Andric class WebAssemblyFixIrreducibleControlFlow final : public MachineFunctionPass { 2240b57cec5SDimitry Andric StringRef getPassName() const override { 2250b57cec5SDimitry Andric return "WebAssembly Fix Irreducible Control Flow"; 2260b57cec5SDimitry Andric } 2270b57cec5SDimitry Andric 2280b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 2290b57cec5SDimitry Andric 2300b57cec5SDimitry Andric bool processRegion(MachineBasicBlock *Entry, BlockSet &Blocks, 2310b57cec5SDimitry Andric MachineFunction &MF); 2320b57cec5SDimitry Andric 2330b57cec5SDimitry Andric void makeSingleEntryLoop(BlockSet &Entries, BlockSet &Blocks, 2340b57cec5SDimitry Andric MachineFunction &MF, const ReachabilityGraph &Graph); 2350b57cec5SDimitry Andric 2360b57cec5SDimitry Andric public: 2370b57cec5SDimitry Andric static char ID; // Pass identification, replacement for typeid 2380b57cec5SDimitry Andric WebAssemblyFixIrreducibleControlFlow() : MachineFunctionPass(ID) {} 2390b57cec5SDimitry Andric }; 2400b57cec5SDimitry Andric 2410b57cec5SDimitry Andric bool WebAssemblyFixIrreducibleControlFlow::processRegion( 2420b57cec5SDimitry Andric MachineBasicBlock *Entry, BlockSet &Blocks, MachineFunction &MF) { 2430b57cec5SDimitry Andric bool Changed = false; 2440b57cec5SDimitry Andric 2450b57cec5SDimitry Andric // Remove irreducibility before processing child loops, which may take 2460b57cec5SDimitry Andric // multiple iterations. 2470b57cec5SDimitry Andric while (true) { 2480b57cec5SDimitry Andric ReachabilityGraph Graph(Entry, Blocks); 2490b57cec5SDimitry Andric 2500b57cec5SDimitry Andric bool FoundIrreducibility = false; 2510b57cec5SDimitry Andric 2520b57cec5SDimitry Andric for (auto *LoopEntry : Graph.getLoopEntries()) { 2530b57cec5SDimitry Andric // Find mutual entries - all entries which can reach this one, and 2540b57cec5SDimitry Andric // are reached by it (that always includes LoopEntry itself). All mutual 2550b57cec5SDimitry Andric // entries must be in the same loop, so if we have more than one, then we 2560b57cec5SDimitry Andric // have irreducible control flow. 2570b57cec5SDimitry Andric // 2580b57cec5SDimitry Andric // Note that irreducibility may involve inner loops, e.g. imagine A 2590b57cec5SDimitry Andric // starts one loop, and it has B inside it which starts an inner loop. 2600b57cec5SDimitry Andric // If we add a branch from all the way on the outside to B, then in a 2610b57cec5SDimitry Andric // sense B is no longer an "inner" loop, semantically speaking. We will 2620b57cec5SDimitry Andric // fix that irreducibility by adding a block that dispatches to either 2630b57cec5SDimitry Andric // either A or B, so B will no longer be an inner loop in our output. 2640b57cec5SDimitry Andric // (A fancier approach might try to keep it as such.) 2650b57cec5SDimitry Andric // 2660b57cec5SDimitry Andric // Note that we still need to recurse into inner loops later, to handle 2670b57cec5SDimitry Andric // the case where the irreducibility is entirely nested - we would not 2680b57cec5SDimitry Andric // be able to identify that at this point, since the enclosing loop is 2690b57cec5SDimitry Andric // a group of blocks all of whom can reach each other. (We'll see the 2700b57cec5SDimitry Andric // irreducibility after removing branches to the top of that enclosing 2710b57cec5SDimitry Andric // loop.) 2720b57cec5SDimitry Andric BlockSet MutualLoopEntries; 2730b57cec5SDimitry Andric MutualLoopEntries.insert(LoopEntry); 2740b57cec5SDimitry Andric for (auto *OtherLoopEntry : Graph.getLoopEntries()) { 2750b57cec5SDimitry Andric if (OtherLoopEntry != LoopEntry && 2760b57cec5SDimitry Andric Graph.canReach(LoopEntry, OtherLoopEntry) && 2770b57cec5SDimitry Andric Graph.canReach(OtherLoopEntry, LoopEntry)) { 2780b57cec5SDimitry Andric MutualLoopEntries.insert(OtherLoopEntry); 2790b57cec5SDimitry Andric } 2800b57cec5SDimitry Andric } 2810b57cec5SDimitry Andric 2820b57cec5SDimitry Andric if (MutualLoopEntries.size() > 1) { 2830b57cec5SDimitry Andric makeSingleEntryLoop(MutualLoopEntries, Blocks, MF, Graph); 2840b57cec5SDimitry Andric FoundIrreducibility = true; 2850b57cec5SDimitry Andric Changed = true; 2860b57cec5SDimitry Andric break; 2870b57cec5SDimitry Andric } 2880b57cec5SDimitry Andric } 2890b57cec5SDimitry Andric // Only go on to actually process the inner loops when we are done 2900b57cec5SDimitry Andric // removing irreducible control flow and changing the graph. Modifying 2910b57cec5SDimitry Andric // the graph as we go is possible, and that might let us avoid looking at 2920b57cec5SDimitry Andric // the already-fixed loops again if we are careful, but all that is 2930b57cec5SDimitry Andric // complex and bug-prone. Since irreducible loops are rare, just starting 2940b57cec5SDimitry Andric // another iteration is best. 2950b57cec5SDimitry Andric if (FoundIrreducibility) { 2960b57cec5SDimitry Andric continue; 2970b57cec5SDimitry Andric } 2980b57cec5SDimitry Andric 2990b57cec5SDimitry Andric for (auto *LoopEntry : Graph.getLoopEntries()) { 3000b57cec5SDimitry Andric LoopBlocks InnerBlocks(LoopEntry, Graph.getLoopEnterers(LoopEntry)); 3010b57cec5SDimitry Andric // Each of these calls to processRegion may change the graph, but are 3020b57cec5SDimitry Andric // guaranteed not to interfere with each other. The only changes we make 3030b57cec5SDimitry Andric // to the graph are to add blocks on the way to a loop entry. As the 3040b57cec5SDimitry Andric // loops are disjoint, that means we may only alter branches that exit 3050b57cec5SDimitry Andric // another loop, which are ignored when recursing into that other loop 3060b57cec5SDimitry Andric // anyhow. 3070b57cec5SDimitry Andric if (processRegion(LoopEntry, InnerBlocks.getBlocks(), MF)) { 3080b57cec5SDimitry Andric Changed = true; 3090b57cec5SDimitry Andric } 3100b57cec5SDimitry Andric } 3110b57cec5SDimitry Andric 3120b57cec5SDimitry Andric return Changed; 3130b57cec5SDimitry Andric } 3140b57cec5SDimitry Andric } 3150b57cec5SDimitry Andric 3160b57cec5SDimitry Andric // Given a set of entries to a single loop, create a single entry for that 3170b57cec5SDimitry Andric // loop by creating a dispatch block for them, routing control flow using 3180b57cec5SDimitry Andric // a helper variable. Also updates Blocks with any new blocks created, so 3190b57cec5SDimitry Andric // that we properly track all the blocks in the region. But this does not update 3200b57cec5SDimitry Andric // ReachabilityGraph; this will be updated in the caller of this function as 3210b57cec5SDimitry Andric // needed. 3220b57cec5SDimitry Andric void WebAssemblyFixIrreducibleControlFlow::makeSingleEntryLoop( 3230b57cec5SDimitry Andric BlockSet &Entries, BlockSet &Blocks, MachineFunction &MF, 3240b57cec5SDimitry Andric const ReachabilityGraph &Graph) { 3250b57cec5SDimitry Andric assert(Entries.size() >= 2); 3260b57cec5SDimitry Andric 3270b57cec5SDimitry Andric // Sort the entries to ensure a deterministic build. 3280b57cec5SDimitry Andric BlockVector SortedEntries(Entries.begin(), Entries.end()); 3290b57cec5SDimitry Andric llvm::sort(SortedEntries, 3300b57cec5SDimitry Andric [&](const MachineBasicBlock *A, const MachineBasicBlock *B) { 3310b57cec5SDimitry Andric auto ANum = A->getNumber(); 3320b57cec5SDimitry Andric auto BNum = B->getNumber(); 3330b57cec5SDimitry Andric return ANum < BNum; 3340b57cec5SDimitry Andric }); 3350b57cec5SDimitry Andric 3360b57cec5SDimitry Andric #ifndef NDEBUG 3370b57cec5SDimitry Andric for (auto Block : SortedEntries) 3380b57cec5SDimitry Andric assert(Block->getNumber() != -1); 3390b57cec5SDimitry Andric if (SortedEntries.size() > 1) { 3400b57cec5SDimitry Andric for (auto I = SortedEntries.begin(), E = SortedEntries.end() - 1; I != E; 3410b57cec5SDimitry Andric ++I) { 3420b57cec5SDimitry Andric auto ANum = (*I)->getNumber(); 3430b57cec5SDimitry Andric auto BNum = (*(std::next(I)))->getNumber(); 3440b57cec5SDimitry Andric assert(ANum != BNum); 3450b57cec5SDimitry Andric } 3460b57cec5SDimitry Andric } 3470b57cec5SDimitry Andric #endif 3480b57cec5SDimitry Andric 3490b57cec5SDimitry Andric // Create a dispatch block which will contain a jump table to the entries. 3500b57cec5SDimitry Andric MachineBasicBlock *Dispatch = MF.CreateMachineBasicBlock(); 3510b57cec5SDimitry Andric MF.insert(MF.end(), Dispatch); 3520b57cec5SDimitry Andric Blocks.insert(Dispatch); 3530b57cec5SDimitry Andric 3540b57cec5SDimitry Andric // Add the jump table. 3550b57cec5SDimitry Andric const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 3560b57cec5SDimitry Andric MachineInstrBuilder MIB = 3570b57cec5SDimitry Andric BuildMI(Dispatch, DebugLoc(), TII.get(WebAssembly::BR_TABLE_I32)); 3580b57cec5SDimitry Andric 3590b57cec5SDimitry Andric // Add the register which will be used to tell the jump table which block to 3600b57cec5SDimitry Andric // jump to. 3610b57cec5SDimitry Andric MachineRegisterInfo &MRI = MF.getRegInfo(); 362*8bcb0991SDimitry Andric Register Reg = MRI.createVirtualRegister(&WebAssembly::I32RegClass); 3630b57cec5SDimitry Andric MIB.addReg(Reg); 3640b57cec5SDimitry Andric 3650b57cec5SDimitry Andric // Compute the indices in the superheader, one for each bad block, and 3660b57cec5SDimitry Andric // add them as successors. 3670b57cec5SDimitry Andric DenseMap<MachineBasicBlock *, unsigned> Indices; 3680b57cec5SDimitry Andric for (auto *Entry : SortedEntries) { 3690b57cec5SDimitry Andric auto Pair = Indices.insert(std::make_pair(Entry, 0)); 3700b57cec5SDimitry Andric assert(Pair.second); 3710b57cec5SDimitry Andric 3720b57cec5SDimitry Andric unsigned Index = MIB.getInstr()->getNumExplicitOperands() - 1; 3730b57cec5SDimitry Andric Pair.first->second = Index; 3740b57cec5SDimitry Andric 3750b57cec5SDimitry Andric MIB.addMBB(Entry); 3760b57cec5SDimitry Andric Dispatch->addSuccessor(Entry); 3770b57cec5SDimitry Andric } 3780b57cec5SDimitry Andric 3790b57cec5SDimitry Andric // Rewrite the problematic successors for every block that wants to reach 3800b57cec5SDimitry Andric // the bad blocks. For simplicity, we just introduce a new block for every 3810b57cec5SDimitry Andric // edge we need to rewrite. (Fancier things are possible.) 3820b57cec5SDimitry Andric 3830b57cec5SDimitry Andric BlockVector AllPreds; 3840b57cec5SDimitry Andric for (auto *Entry : SortedEntries) { 3850b57cec5SDimitry Andric for (auto *Pred : Entry->predecessors()) { 3860b57cec5SDimitry Andric if (Pred != Dispatch) { 3870b57cec5SDimitry Andric AllPreds.push_back(Pred); 3880b57cec5SDimitry Andric } 3890b57cec5SDimitry Andric } 3900b57cec5SDimitry Andric } 3910b57cec5SDimitry Andric 3920b57cec5SDimitry Andric // This set stores predecessors within this loop. 3930b57cec5SDimitry Andric DenseSet<MachineBasicBlock *> InLoop; 3940b57cec5SDimitry Andric for (auto *Pred : AllPreds) { 3950b57cec5SDimitry Andric for (auto *Entry : Pred->successors()) { 3960b57cec5SDimitry Andric if (!Entries.count(Entry)) 3970b57cec5SDimitry Andric continue; 3980b57cec5SDimitry Andric if (Graph.canReach(Entry, Pred)) { 3990b57cec5SDimitry Andric InLoop.insert(Pred); 4000b57cec5SDimitry Andric break; 4010b57cec5SDimitry Andric } 4020b57cec5SDimitry Andric } 4030b57cec5SDimitry Andric } 4040b57cec5SDimitry Andric 4050b57cec5SDimitry Andric // Record if each entry has a layout predecessor. This map stores 4060b57cec5SDimitry Andric // <<Predecessor is within the loop?, loop entry>, layout predecessor> 4070b57cec5SDimitry Andric std::map<std::pair<bool, MachineBasicBlock *>, MachineBasicBlock *> 4080b57cec5SDimitry Andric EntryToLayoutPred; 4090b57cec5SDimitry Andric for (auto *Pred : AllPreds) 4100b57cec5SDimitry Andric for (auto *Entry : Pred->successors()) 4110b57cec5SDimitry Andric if (Entries.count(Entry) && Pred->isLayoutSuccessor(Entry)) 4120b57cec5SDimitry Andric EntryToLayoutPred[std::make_pair(InLoop.count(Pred), Entry)] = Pred; 4130b57cec5SDimitry Andric 4140b57cec5SDimitry Andric // We need to create at most two routing blocks per entry: one for 4150b57cec5SDimitry Andric // predecessors outside the loop and one for predecessors inside the loop. 4160b57cec5SDimitry Andric // This map stores 4170b57cec5SDimitry Andric // <<Predecessor is within the loop?, loop entry>, routing block> 4180b57cec5SDimitry Andric std::map<std::pair<bool, MachineBasicBlock *>, MachineBasicBlock *> Map; 4190b57cec5SDimitry Andric for (auto *Pred : AllPreds) { 4200b57cec5SDimitry Andric bool PredInLoop = InLoop.count(Pred); 4210b57cec5SDimitry Andric for (auto *Entry : Pred->successors()) { 4220b57cec5SDimitry Andric if (!Entries.count(Entry) || 4230b57cec5SDimitry Andric Map.count(std::make_pair(InLoop.count(Pred), Entry))) 4240b57cec5SDimitry Andric continue; 4250b57cec5SDimitry Andric // If there exists a layout predecessor of this entry and this predecessor 4260b57cec5SDimitry Andric // is not that, we rather create a routing block after that layout 4270b57cec5SDimitry Andric // predecessor to save a branch. 4280b57cec5SDimitry Andric if (EntryToLayoutPred.count(std::make_pair(PredInLoop, Entry)) && 4290b57cec5SDimitry Andric EntryToLayoutPred[std::make_pair(PredInLoop, Entry)] != Pred) 4300b57cec5SDimitry Andric continue; 4310b57cec5SDimitry Andric 4320b57cec5SDimitry Andric // This is a successor we need to rewrite. 4330b57cec5SDimitry Andric MachineBasicBlock *Routing = MF.CreateMachineBasicBlock(); 4340b57cec5SDimitry Andric MF.insert(Pred->isLayoutSuccessor(Entry) 4350b57cec5SDimitry Andric ? MachineFunction::iterator(Entry) 4360b57cec5SDimitry Andric : MF.end(), 4370b57cec5SDimitry Andric Routing); 4380b57cec5SDimitry Andric Blocks.insert(Routing); 4390b57cec5SDimitry Andric 4400b57cec5SDimitry Andric // Set the jump table's register of the index of the block we wish to 4410b57cec5SDimitry Andric // jump to, and jump to the jump table. 4420b57cec5SDimitry Andric BuildMI(Routing, DebugLoc(), TII.get(WebAssembly::CONST_I32), Reg) 4430b57cec5SDimitry Andric .addImm(Indices[Entry]); 4440b57cec5SDimitry Andric BuildMI(Routing, DebugLoc(), TII.get(WebAssembly::BR)).addMBB(Dispatch); 4450b57cec5SDimitry Andric Routing->addSuccessor(Dispatch); 4460b57cec5SDimitry Andric Map[std::make_pair(PredInLoop, Entry)] = Routing; 4470b57cec5SDimitry Andric } 4480b57cec5SDimitry Andric } 4490b57cec5SDimitry Andric 4500b57cec5SDimitry Andric for (auto *Pred : AllPreds) { 4510b57cec5SDimitry Andric bool PredInLoop = InLoop.count(Pred); 4520b57cec5SDimitry Andric // Remap the terminator operands and the successor list. 4530b57cec5SDimitry Andric for (MachineInstr &Term : Pred->terminators()) 4540b57cec5SDimitry Andric for (auto &Op : Term.explicit_uses()) 4550b57cec5SDimitry Andric if (Op.isMBB() && Indices.count(Op.getMBB())) 4560b57cec5SDimitry Andric Op.setMBB(Map[std::make_pair(PredInLoop, Op.getMBB())]); 4570b57cec5SDimitry Andric 4580b57cec5SDimitry Andric for (auto *Succ : Pred->successors()) { 4590b57cec5SDimitry Andric if (!Entries.count(Succ)) 4600b57cec5SDimitry Andric continue; 4610b57cec5SDimitry Andric auto *Routing = Map[std::make_pair(PredInLoop, Succ)]; 4620b57cec5SDimitry Andric Pred->replaceSuccessor(Succ, Routing); 4630b57cec5SDimitry Andric } 4640b57cec5SDimitry Andric } 4650b57cec5SDimitry Andric 4660b57cec5SDimitry Andric // Create a fake default label, because br_table requires one. 4670b57cec5SDimitry Andric MIB.addMBB(MIB.getInstr() 4680b57cec5SDimitry Andric ->getOperand(MIB.getInstr()->getNumExplicitOperands() - 1) 4690b57cec5SDimitry Andric .getMBB()); 4700b57cec5SDimitry Andric } 4710b57cec5SDimitry Andric 4720b57cec5SDimitry Andric } // end anonymous namespace 4730b57cec5SDimitry Andric 4740b57cec5SDimitry Andric char WebAssemblyFixIrreducibleControlFlow::ID = 0; 4750b57cec5SDimitry Andric INITIALIZE_PASS(WebAssemblyFixIrreducibleControlFlow, DEBUG_TYPE, 4760b57cec5SDimitry Andric "Removes irreducible control flow", false, false) 4770b57cec5SDimitry Andric 4780b57cec5SDimitry Andric FunctionPass *llvm::createWebAssemblyFixIrreducibleControlFlow() { 4790b57cec5SDimitry Andric return new WebAssemblyFixIrreducibleControlFlow(); 4800b57cec5SDimitry Andric } 4810b57cec5SDimitry Andric 4820b57cec5SDimitry Andric bool WebAssemblyFixIrreducibleControlFlow::runOnMachineFunction( 4830b57cec5SDimitry Andric MachineFunction &MF) { 4840b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "********** Fixing Irreducible Control Flow **********\n" 4850b57cec5SDimitry Andric "********** Function: " 4860b57cec5SDimitry Andric << MF.getName() << '\n'); 4870b57cec5SDimitry Andric 4880b57cec5SDimitry Andric // Start the recursive process on the entire function body. 4890b57cec5SDimitry Andric BlockSet AllBlocks; 4900b57cec5SDimitry Andric for (auto &MBB : MF) { 4910b57cec5SDimitry Andric AllBlocks.insert(&MBB); 4920b57cec5SDimitry Andric } 4930b57cec5SDimitry Andric 4940b57cec5SDimitry Andric if (LLVM_UNLIKELY(processRegion(&*MF.begin(), AllBlocks, MF))) { 4950b57cec5SDimitry Andric // We rewrote part of the function; recompute relevant things. 4960b57cec5SDimitry Andric MF.getRegInfo().invalidateLiveness(); 4970b57cec5SDimitry Andric MF.RenumberBlocks(); 4980b57cec5SDimitry Andric return true; 4990b57cec5SDimitry Andric } 5000b57cec5SDimitry Andric 5010b57cec5SDimitry Andric return false; 5020b57cec5SDimitry Andric } 503