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" 598bcb0991SDimitry 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 69*5ffd83dbSDimitry Andric static BlockVector getSortedEntries(const BlockSet &Entries) { 70*5ffd83dbSDimitry Andric BlockVector SortedEntries(Entries.begin(), Entries.end()); 71*5ffd83dbSDimitry Andric llvm::sort(SortedEntries, 72*5ffd83dbSDimitry Andric [](const MachineBasicBlock *A, const MachineBasicBlock *B) { 73*5ffd83dbSDimitry Andric auto ANum = A->getNumber(); 74*5ffd83dbSDimitry Andric auto BNum = B->getNumber(); 75*5ffd83dbSDimitry Andric return ANum < BNum; 76*5ffd83dbSDimitry Andric }); 77*5ffd83dbSDimitry Andric return SortedEntries; 78*5ffd83dbSDimitry Andric } 79*5ffd83dbSDimitry Andric 800b57cec5SDimitry Andric // Calculates reachability in a region. Ignores branches to blocks outside of 810b57cec5SDimitry Andric // the region, and ignores branches to the region entry (for the case where 820b57cec5SDimitry Andric // the region is the inner part of a loop). 830b57cec5SDimitry Andric class ReachabilityGraph { 840b57cec5SDimitry Andric public: 850b57cec5SDimitry Andric ReachabilityGraph(MachineBasicBlock *Entry, const BlockSet &Blocks) 860b57cec5SDimitry Andric : Entry(Entry), Blocks(Blocks) { 870b57cec5SDimitry Andric #ifndef NDEBUG 880b57cec5SDimitry Andric // The region must have a single entry. 890b57cec5SDimitry Andric for (auto *MBB : Blocks) { 900b57cec5SDimitry Andric if (MBB != Entry) { 910b57cec5SDimitry Andric for (auto *Pred : MBB->predecessors()) { 920b57cec5SDimitry Andric assert(inRegion(Pred)); 930b57cec5SDimitry Andric } 940b57cec5SDimitry Andric } 950b57cec5SDimitry Andric } 960b57cec5SDimitry Andric #endif 970b57cec5SDimitry Andric calculate(); 980b57cec5SDimitry Andric } 990b57cec5SDimitry Andric 1000b57cec5SDimitry Andric bool canReach(MachineBasicBlock *From, MachineBasicBlock *To) const { 1010b57cec5SDimitry Andric assert(inRegion(From) && inRegion(To)); 1020b57cec5SDimitry Andric auto I = Reachable.find(From); 1030b57cec5SDimitry Andric if (I == Reachable.end()) 1040b57cec5SDimitry Andric return false; 1050b57cec5SDimitry Andric return I->second.count(To); 1060b57cec5SDimitry Andric } 1070b57cec5SDimitry Andric 1080b57cec5SDimitry Andric // "Loopers" are blocks that are in a loop. We detect these by finding blocks 1090b57cec5SDimitry Andric // that can reach themselves. 1100b57cec5SDimitry Andric const BlockSet &getLoopers() const { return Loopers; } 1110b57cec5SDimitry Andric 1120b57cec5SDimitry Andric // Get all blocks that are loop entries. 1130b57cec5SDimitry Andric const BlockSet &getLoopEntries() const { return LoopEntries; } 1140b57cec5SDimitry Andric 1150b57cec5SDimitry Andric // Get all blocks that enter a particular loop from outside. 1160b57cec5SDimitry Andric const BlockSet &getLoopEnterers(MachineBasicBlock *LoopEntry) const { 1170b57cec5SDimitry Andric assert(inRegion(LoopEntry)); 1180b57cec5SDimitry Andric auto I = LoopEnterers.find(LoopEntry); 1190b57cec5SDimitry Andric assert(I != LoopEnterers.end()); 1200b57cec5SDimitry Andric return I->second; 1210b57cec5SDimitry Andric } 1220b57cec5SDimitry Andric 1230b57cec5SDimitry Andric private: 1240b57cec5SDimitry Andric MachineBasicBlock *Entry; 1250b57cec5SDimitry Andric const BlockSet &Blocks; 1260b57cec5SDimitry Andric 1270b57cec5SDimitry Andric BlockSet Loopers, LoopEntries; 1280b57cec5SDimitry Andric DenseMap<MachineBasicBlock *, BlockSet> LoopEnterers; 1290b57cec5SDimitry Andric 1300b57cec5SDimitry Andric bool inRegion(MachineBasicBlock *MBB) const { return Blocks.count(MBB); } 1310b57cec5SDimitry Andric 1320b57cec5SDimitry Andric // Maps a block to all the other blocks it can reach. 1330b57cec5SDimitry Andric DenseMap<MachineBasicBlock *, BlockSet> Reachable; 1340b57cec5SDimitry Andric 1350b57cec5SDimitry Andric void calculate() { 1360b57cec5SDimitry Andric // Reachability computation work list. Contains pairs of recent additions 1370b57cec5SDimitry Andric // (A, B) where we just added a link A => B. 1380b57cec5SDimitry Andric using BlockPair = std::pair<MachineBasicBlock *, MachineBasicBlock *>; 1390b57cec5SDimitry Andric SmallVector<BlockPair, 4> WorkList; 1400b57cec5SDimitry Andric 1410b57cec5SDimitry Andric // Add all relevant direct branches. 1420b57cec5SDimitry Andric for (auto *MBB : Blocks) { 1430b57cec5SDimitry Andric for (auto *Succ : MBB->successors()) { 1440b57cec5SDimitry Andric if (Succ != Entry && inRegion(Succ)) { 1450b57cec5SDimitry Andric Reachable[MBB].insert(Succ); 1460b57cec5SDimitry Andric WorkList.emplace_back(MBB, Succ); 1470b57cec5SDimitry Andric } 1480b57cec5SDimitry Andric } 1490b57cec5SDimitry Andric } 1500b57cec5SDimitry Andric 1510b57cec5SDimitry Andric while (!WorkList.empty()) { 1520b57cec5SDimitry Andric MachineBasicBlock *MBB, *Succ; 1530b57cec5SDimitry Andric std::tie(MBB, Succ) = WorkList.pop_back_val(); 1540b57cec5SDimitry Andric assert(inRegion(MBB) && Succ != Entry && inRegion(Succ)); 1550b57cec5SDimitry Andric if (MBB != Entry) { 1560b57cec5SDimitry Andric // We recently added MBB => Succ, and that means we may have enabled 1570b57cec5SDimitry Andric // Pred => MBB => Succ. 1580b57cec5SDimitry Andric for (auto *Pred : MBB->predecessors()) { 1590b57cec5SDimitry Andric if (Reachable[Pred].insert(Succ).second) { 1600b57cec5SDimitry Andric WorkList.emplace_back(Pred, Succ); 1610b57cec5SDimitry Andric } 1620b57cec5SDimitry Andric } 1630b57cec5SDimitry Andric } 1640b57cec5SDimitry Andric } 1650b57cec5SDimitry Andric 1660b57cec5SDimitry Andric // Blocks that can return to themselves are in a loop. 1670b57cec5SDimitry Andric for (auto *MBB : Blocks) { 1680b57cec5SDimitry Andric if (canReach(MBB, MBB)) { 1690b57cec5SDimitry Andric Loopers.insert(MBB); 1700b57cec5SDimitry Andric } 1710b57cec5SDimitry Andric } 1720b57cec5SDimitry Andric assert(!Loopers.count(Entry)); 1730b57cec5SDimitry Andric 1740b57cec5SDimitry Andric // Find the loop entries - loopers reachable from blocks not in that loop - 1750b57cec5SDimitry Andric // and those outside blocks that reach them, the "loop enterers". 1760b57cec5SDimitry Andric for (auto *Looper : Loopers) { 1770b57cec5SDimitry Andric for (auto *Pred : Looper->predecessors()) { 1780b57cec5SDimitry Andric // Pred can reach Looper. If Looper can reach Pred, it is in the loop; 1790b57cec5SDimitry Andric // otherwise, it is a block that enters into the loop. 1800b57cec5SDimitry Andric if (!canReach(Looper, Pred)) { 1810b57cec5SDimitry Andric LoopEntries.insert(Looper); 1820b57cec5SDimitry Andric LoopEnterers[Looper].insert(Pred); 1830b57cec5SDimitry Andric } 1840b57cec5SDimitry Andric } 1850b57cec5SDimitry Andric } 1860b57cec5SDimitry Andric } 1870b57cec5SDimitry Andric }; 1880b57cec5SDimitry Andric 1890b57cec5SDimitry Andric // Finds the blocks in a single-entry loop, given the loop entry and the 1900b57cec5SDimitry Andric // list of blocks that enter the loop. 1910b57cec5SDimitry Andric class LoopBlocks { 1920b57cec5SDimitry Andric public: 1930b57cec5SDimitry Andric LoopBlocks(MachineBasicBlock *Entry, const BlockSet &Enterers) 1940b57cec5SDimitry Andric : Entry(Entry), Enterers(Enterers) { 1950b57cec5SDimitry Andric calculate(); 1960b57cec5SDimitry Andric } 1970b57cec5SDimitry Andric 1980b57cec5SDimitry Andric BlockSet &getBlocks() { return Blocks; } 1990b57cec5SDimitry Andric 2000b57cec5SDimitry Andric private: 2010b57cec5SDimitry Andric MachineBasicBlock *Entry; 2020b57cec5SDimitry Andric const BlockSet &Enterers; 2030b57cec5SDimitry Andric 2040b57cec5SDimitry Andric BlockSet Blocks; 2050b57cec5SDimitry Andric 2060b57cec5SDimitry Andric void calculate() { 2070b57cec5SDimitry Andric // Going backwards from the loop entry, if we ignore the blocks entering 2080b57cec5SDimitry Andric // from outside, we will traverse all the blocks in the loop. 2090b57cec5SDimitry Andric BlockVector WorkList; 2100b57cec5SDimitry Andric BlockSet AddedToWorkList; 2110b57cec5SDimitry Andric Blocks.insert(Entry); 2120b57cec5SDimitry Andric for (auto *Pred : Entry->predecessors()) { 2130b57cec5SDimitry Andric if (!Enterers.count(Pred)) { 2140b57cec5SDimitry Andric WorkList.push_back(Pred); 2150b57cec5SDimitry Andric AddedToWorkList.insert(Pred); 2160b57cec5SDimitry Andric } 2170b57cec5SDimitry Andric } 2180b57cec5SDimitry Andric 2190b57cec5SDimitry Andric while (!WorkList.empty()) { 2200b57cec5SDimitry Andric auto *MBB = WorkList.pop_back_val(); 2210b57cec5SDimitry Andric assert(!Enterers.count(MBB)); 2220b57cec5SDimitry Andric if (Blocks.insert(MBB).second) { 2230b57cec5SDimitry Andric for (auto *Pred : MBB->predecessors()) { 2240b57cec5SDimitry Andric if (!AddedToWorkList.count(Pred)) { 2250b57cec5SDimitry Andric WorkList.push_back(Pred); 2260b57cec5SDimitry Andric AddedToWorkList.insert(Pred); 2270b57cec5SDimitry Andric } 2280b57cec5SDimitry Andric } 2290b57cec5SDimitry Andric } 2300b57cec5SDimitry Andric } 2310b57cec5SDimitry Andric } 2320b57cec5SDimitry Andric }; 2330b57cec5SDimitry Andric 2340b57cec5SDimitry Andric class WebAssemblyFixIrreducibleControlFlow final : public MachineFunctionPass { 2350b57cec5SDimitry Andric StringRef getPassName() const override { 2360b57cec5SDimitry Andric return "WebAssembly Fix Irreducible Control Flow"; 2370b57cec5SDimitry Andric } 2380b57cec5SDimitry Andric 2390b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 2400b57cec5SDimitry Andric 2410b57cec5SDimitry Andric bool processRegion(MachineBasicBlock *Entry, BlockSet &Blocks, 2420b57cec5SDimitry Andric MachineFunction &MF); 2430b57cec5SDimitry Andric 2440b57cec5SDimitry Andric void makeSingleEntryLoop(BlockSet &Entries, BlockSet &Blocks, 2450b57cec5SDimitry Andric MachineFunction &MF, const ReachabilityGraph &Graph); 2460b57cec5SDimitry Andric 2470b57cec5SDimitry Andric public: 2480b57cec5SDimitry Andric static char ID; // Pass identification, replacement for typeid 2490b57cec5SDimitry Andric WebAssemblyFixIrreducibleControlFlow() : MachineFunctionPass(ID) {} 2500b57cec5SDimitry Andric }; 2510b57cec5SDimitry Andric 2520b57cec5SDimitry Andric bool WebAssemblyFixIrreducibleControlFlow::processRegion( 2530b57cec5SDimitry Andric MachineBasicBlock *Entry, BlockSet &Blocks, MachineFunction &MF) { 2540b57cec5SDimitry Andric bool Changed = false; 2550b57cec5SDimitry Andric // Remove irreducibility before processing child loops, which may take 2560b57cec5SDimitry Andric // multiple iterations. 2570b57cec5SDimitry Andric while (true) { 2580b57cec5SDimitry Andric ReachabilityGraph Graph(Entry, Blocks); 2590b57cec5SDimitry Andric 2600b57cec5SDimitry Andric bool FoundIrreducibility = false; 2610b57cec5SDimitry Andric 262*5ffd83dbSDimitry Andric for (auto *LoopEntry : getSortedEntries(Graph.getLoopEntries())) { 2630b57cec5SDimitry Andric // Find mutual entries - all entries which can reach this one, and 2640b57cec5SDimitry Andric // are reached by it (that always includes LoopEntry itself). All mutual 2650b57cec5SDimitry Andric // entries must be in the same loop, so if we have more than one, then we 2660b57cec5SDimitry Andric // have irreducible control flow. 2670b57cec5SDimitry Andric // 268*5ffd83dbSDimitry Andric // (Note that we need to sort the entries here, as otherwise the order can 269*5ffd83dbSDimitry Andric // matter: being mutual is a symmetric relationship, and each set of 270*5ffd83dbSDimitry Andric // mutuals will be handled properly no matter which we see first. However, 271*5ffd83dbSDimitry Andric // there can be multiple disjoint sets of mutuals, and which we process 272*5ffd83dbSDimitry Andric // first changes the output.) 273*5ffd83dbSDimitry Andric // 2740b57cec5SDimitry Andric // Note that irreducibility may involve inner loops, e.g. imagine A 2750b57cec5SDimitry Andric // starts one loop, and it has B inside it which starts an inner loop. 2760b57cec5SDimitry Andric // If we add a branch from all the way on the outside to B, then in a 2770b57cec5SDimitry Andric // sense B is no longer an "inner" loop, semantically speaking. We will 2780b57cec5SDimitry Andric // fix that irreducibility by adding a block that dispatches to either 2790b57cec5SDimitry Andric // either A or B, so B will no longer be an inner loop in our output. 2800b57cec5SDimitry Andric // (A fancier approach might try to keep it as such.) 2810b57cec5SDimitry Andric // 2820b57cec5SDimitry Andric // Note that we still need to recurse into inner loops later, to handle 2830b57cec5SDimitry Andric // the case where the irreducibility is entirely nested - we would not 2840b57cec5SDimitry Andric // be able to identify that at this point, since the enclosing loop is 2850b57cec5SDimitry Andric // a group of blocks all of whom can reach each other. (We'll see the 2860b57cec5SDimitry Andric // irreducibility after removing branches to the top of that enclosing 2870b57cec5SDimitry Andric // loop.) 2880b57cec5SDimitry Andric BlockSet MutualLoopEntries; 2890b57cec5SDimitry Andric MutualLoopEntries.insert(LoopEntry); 2900b57cec5SDimitry Andric for (auto *OtherLoopEntry : Graph.getLoopEntries()) { 2910b57cec5SDimitry Andric if (OtherLoopEntry != LoopEntry && 2920b57cec5SDimitry Andric Graph.canReach(LoopEntry, OtherLoopEntry) && 2930b57cec5SDimitry Andric Graph.canReach(OtherLoopEntry, LoopEntry)) { 2940b57cec5SDimitry Andric MutualLoopEntries.insert(OtherLoopEntry); 2950b57cec5SDimitry Andric } 2960b57cec5SDimitry Andric } 2970b57cec5SDimitry Andric 2980b57cec5SDimitry Andric if (MutualLoopEntries.size() > 1) { 2990b57cec5SDimitry Andric makeSingleEntryLoop(MutualLoopEntries, Blocks, MF, Graph); 3000b57cec5SDimitry Andric FoundIrreducibility = true; 3010b57cec5SDimitry Andric Changed = true; 3020b57cec5SDimitry Andric break; 3030b57cec5SDimitry Andric } 3040b57cec5SDimitry Andric } 3050b57cec5SDimitry Andric // Only go on to actually process the inner loops when we are done 3060b57cec5SDimitry Andric // removing irreducible control flow and changing the graph. Modifying 3070b57cec5SDimitry Andric // the graph as we go is possible, and that might let us avoid looking at 3080b57cec5SDimitry Andric // the already-fixed loops again if we are careful, but all that is 3090b57cec5SDimitry Andric // complex and bug-prone. Since irreducible loops are rare, just starting 3100b57cec5SDimitry Andric // another iteration is best. 3110b57cec5SDimitry Andric if (FoundIrreducibility) { 3120b57cec5SDimitry Andric continue; 3130b57cec5SDimitry Andric } 3140b57cec5SDimitry Andric 3150b57cec5SDimitry Andric for (auto *LoopEntry : Graph.getLoopEntries()) { 3160b57cec5SDimitry Andric LoopBlocks InnerBlocks(LoopEntry, Graph.getLoopEnterers(LoopEntry)); 3170b57cec5SDimitry Andric // Each of these calls to processRegion may change the graph, but are 3180b57cec5SDimitry Andric // guaranteed not to interfere with each other. The only changes we make 3190b57cec5SDimitry Andric // to the graph are to add blocks on the way to a loop entry. As the 3200b57cec5SDimitry Andric // loops are disjoint, that means we may only alter branches that exit 3210b57cec5SDimitry Andric // another loop, which are ignored when recursing into that other loop 3220b57cec5SDimitry Andric // anyhow. 3230b57cec5SDimitry Andric if (processRegion(LoopEntry, InnerBlocks.getBlocks(), MF)) { 3240b57cec5SDimitry Andric Changed = true; 3250b57cec5SDimitry Andric } 3260b57cec5SDimitry Andric } 3270b57cec5SDimitry Andric 3280b57cec5SDimitry Andric return Changed; 3290b57cec5SDimitry Andric } 3300b57cec5SDimitry Andric } 3310b57cec5SDimitry Andric 3320b57cec5SDimitry Andric // Given a set of entries to a single loop, create a single entry for that 3330b57cec5SDimitry Andric // loop by creating a dispatch block for them, routing control flow using 3340b57cec5SDimitry Andric // a helper variable. Also updates Blocks with any new blocks created, so 3350b57cec5SDimitry Andric // that we properly track all the blocks in the region. But this does not update 3360b57cec5SDimitry Andric // ReachabilityGraph; this will be updated in the caller of this function as 3370b57cec5SDimitry Andric // needed. 3380b57cec5SDimitry Andric void WebAssemblyFixIrreducibleControlFlow::makeSingleEntryLoop( 3390b57cec5SDimitry Andric BlockSet &Entries, BlockSet &Blocks, MachineFunction &MF, 3400b57cec5SDimitry Andric const ReachabilityGraph &Graph) { 3410b57cec5SDimitry Andric assert(Entries.size() >= 2); 3420b57cec5SDimitry Andric 3430b57cec5SDimitry Andric // Sort the entries to ensure a deterministic build. 344*5ffd83dbSDimitry Andric BlockVector SortedEntries = getSortedEntries(Entries); 3450b57cec5SDimitry Andric 3460b57cec5SDimitry Andric #ifndef NDEBUG 3470b57cec5SDimitry Andric for (auto Block : SortedEntries) 3480b57cec5SDimitry Andric assert(Block->getNumber() != -1); 3490b57cec5SDimitry Andric if (SortedEntries.size() > 1) { 3500b57cec5SDimitry Andric for (auto I = SortedEntries.begin(), E = SortedEntries.end() - 1; I != E; 3510b57cec5SDimitry Andric ++I) { 3520b57cec5SDimitry Andric auto ANum = (*I)->getNumber(); 3530b57cec5SDimitry Andric auto BNum = (*(std::next(I)))->getNumber(); 3540b57cec5SDimitry Andric assert(ANum != BNum); 3550b57cec5SDimitry Andric } 3560b57cec5SDimitry Andric } 3570b57cec5SDimitry Andric #endif 3580b57cec5SDimitry Andric 3590b57cec5SDimitry Andric // Create a dispatch block which will contain a jump table to the entries. 3600b57cec5SDimitry Andric MachineBasicBlock *Dispatch = MF.CreateMachineBasicBlock(); 3610b57cec5SDimitry Andric MF.insert(MF.end(), Dispatch); 3620b57cec5SDimitry Andric Blocks.insert(Dispatch); 3630b57cec5SDimitry Andric 3640b57cec5SDimitry Andric // Add the jump table. 3650b57cec5SDimitry Andric const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 3660b57cec5SDimitry Andric MachineInstrBuilder MIB = 3670b57cec5SDimitry Andric BuildMI(Dispatch, DebugLoc(), TII.get(WebAssembly::BR_TABLE_I32)); 3680b57cec5SDimitry Andric 3690b57cec5SDimitry Andric // Add the register which will be used to tell the jump table which block to 3700b57cec5SDimitry Andric // jump to. 3710b57cec5SDimitry Andric MachineRegisterInfo &MRI = MF.getRegInfo(); 3728bcb0991SDimitry Andric Register Reg = MRI.createVirtualRegister(&WebAssembly::I32RegClass); 3730b57cec5SDimitry Andric MIB.addReg(Reg); 3740b57cec5SDimitry Andric 3750b57cec5SDimitry Andric // Compute the indices in the superheader, one for each bad block, and 3760b57cec5SDimitry Andric // add them as successors. 3770b57cec5SDimitry Andric DenseMap<MachineBasicBlock *, unsigned> Indices; 3780b57cec5SDimitry Andric for (auto *Entry : SortedEntries) { 3790b57cec5SDimitry Andric auto Pair = Indices.insert(std::make_pair(Entry, 0)); 3800b57cec5SDimitry Andric assert(Pair.second); 3810b57cec5SDimitry Andric 3820b57cec5SDimitry Andric unsigned Index = MIB.getInstr()->getNumExplicitOperands() - 1; 3830b57cec5SDimitry Andric Pair.first->second = Index; 3840b57cec5SDimitry Andric 3850b57cec5SDimitry Andric MIB.addMBB(Entry); 3860b57cec5SDimitry Andric Dispatch->addSuccessor(Entry); 3870b57cec5SDimitry Andric } 3880b57cec5SDimitry Andric 3890b57cec5SDimitry Andric // Rewrite the problematic successors for every block that wants to reach 3900b57cec5SDimitry Andric // the bad blocks. For simplicity, we just introduce a new block for every 3910b57cec5SDimitry Andric // edge we need to rewrite. (Fancier things are possible.) 3920b57cec5SDimitry Andric 3930b57cec5SDimitry Andric BlockVector AllPreds; 3940b57cec5SDimitry Andric for (auto *Entry : SortedEntries) { 3950b57cec5SDimitry Andric for (auto *Pred : Entry->predecessors()) { 3960b57cec5SDimitry Andric if (Pred != Dispatch) { 3970b57cec5SDimitry Andric AllPreds.push_back(Pred); 3980b57cec5SDimitry Andric } 3990b57cec5SDimitry Andric } 4000b57cec5SDimitry Andric } 4010b57cec5SDimitry Andric 4020b57cec5SDimitry Andric // This set stores predecessors within this loop. 4030b57cec5SDimitry Andric DenseSet<MachineBasicBlock *> InLoop; 4040b57cec5SDimitry Andric for (auto *Pred : AllPreds) { 4050b57cec5SDimitry Andric for (auto *Entry : Pred->successors()) { 4060b57cec5SDimitry Andric if (!Entries.count(Entry)) 4070b57cec5SDimitry Andric continue; 4080b57cec5SDimitry Andric if (Graph.canReach(Entry, Pred)) { 4090b57cec5SDimitry Andric InLoop.insert(Pred); 4100b57cec5SDimitry Andric break; 4110b57cec5SDimitry Andric } 4120b57cec5SDimitry Andric } 4130b57cec5SDimitry Andric } 4140b57cec5SDimitry Andric 4150b57cec5SDimitry Andric // Record if each entry has a layout predecessor. This map stores 416*5ffd83dbSDimitry Andric // <<loop entry, Predecessor is within the loop?>, layout predecessor> 417*5ffd83dbSDimitry Andric DenseMap<PointerIntPair<MachineBasicBlock *, 1, bool>, MachineBasicBlock *> 4180b57cec5SDimitry Andric EntryToLayoutPred; 419*5ffd83dbSDimitry Andric for (auto *Pred : AllPreds) { 420*5ffd83dbSDimitry Andric bool PredInLoop = InLoop.count(Pred); 4210b57cec5SDimitry Andric for (auto *Entry : Pred->successors()) 4220b57cec5SDimitry Andric if (Entries.count(Entry) && Pred->isLayoutSuccessor(Entry)) 423*5ffd83dbSDimitry Andric EntryToLayoutPred[{Entry, PredInLoop}] = Pred; 424*5ffd83dbSDimitry Andric } 4250b57cec5SDimitry Andric 4260b57cec5SDimitry Andric // We need to create at most two routing blocks per entry: one for 4270b57cec5SDimitry Andric // predecessors outside the loop and one for predecessors inside the loop. 4280b57cec5SDimitry Andric // This map stores 429*5ffd83dbSDimitry Andric // <<loop entry, Predecessor is within the loop?>, routing block> 430*5ffd83dbSDimitry Andric DenseMap<PointerIntPair<MachineBasicBlock *, 1, bool>, MachineBasicBlock *> 431*5ffd83dbSDimitry Andric Map; 4320b57cec5SDimitry Andric for (auto *Pred : AllPreds) { 4330b57cec5SDimitry Andric bool PredInLoop = InLoop.count(Pred); 4340b57cec5SDimitry Andric for (auto *Entry : Pred->successors()) { 435*5ffd83dbSDimitry Andric if (!Entries.count(Entry) || Map.count({Entry, PredInLoop})) 4360b57cec5SDimitry Andric continue; 4370b57cec5SDimitry Andric // If there exists a layout predecessor of this entry and this predecessor 4380b57cec5SDimitry Andric // is not that, we rather create a routing block after that layout 4390b57cec5SDimitry Andric // predecessor to save a branch. 440*5ffd83dbSDimitry Andric if (auto *OtherPred = EntryToLayoutPred.lookup({Entry, PredInLoop})) 441*5ffd83dbSDimitry Andric if (OtherPred != Pred) 4420b57cec5SDimitry Andric continue; 4430b57cec5SDimitry Andric 4440b57cec5SDimitry Andric // This is a successor we need to rewrite. 4450b57cec5SDimitry Andric MachineBasicBlock *Routing = MF.CreateMachineBasicBlock(); 4460b57cec5SDimitry Andric MF.insert(Pred->isLayoutSuccessor(Entry) 4470b57cec5SDimitry Andric ? MachineFunction::iterator(Entry) 4480b57cec5SDimitry Andric : MF.end(), 4490b57cec5SDimitry Andric Routing); 4500b57cec5SDimitry Andric Blocks.insert(Routing); 4510b57cec5SDimitry Andric 4520b57cec5SDimitry Andric // Set the jump table's register of the index of the block we wish to 4530b57cec5SDimitry Andric // jump to, and jump to the jump table. 4540b57cec5SDimitry Andric BuildMI(Routing, DebugLoc(), TII.get(WebAssembly::CONST_I32), Reg) 4550b57cec5SDimitry Andric .addImm(Indices[Entry]); 4560b57cec5SDimitry Andric BuildMI(Routing, DebugLoc(), TII.get(WebAssembly::BR)).addMBB(Dispatch); 4570b57cec5SDimitry Andric Routing->addSuccessor(Dispatch); 458*5ffd83dbSDimitry Andric Map[{Entry, PredInLoop}] = Routing; 4590b57cec5SDimitry Andric } 4600b57cec5SDimitry Andric } 4610b57cec5SDimitry Andric 4620b57cec5SDimitry Andric for (auto *Pred : AllPreds) { 4630b57cec5SDimitry Andric bool PredInLoop = InLoop.count(Pred); 4640b57cec5SDimitry Andric // Remap the terminator operands and the successor list. 4650b57cec5SDimitry Andric for (MachineInstr &Term : Pred->terminators()) 4660b57cec5SDimitry Andric for (auto &Op : Term.explicit_uses()) 4670b57cec5SDimitry Andric if (Op.isMBB() && Indices.count(Op.getMBB())) 468*5ffd83dbSDimitry Andric Op.setMBB(Map[{Op.getMBB(), PredInLoop}]); 4690b57cec5SDimitry Andric 4700b57cec5SDimitry Andric for (auto *Succ : Pred->successors()) { 4710b57cec5SDimitry Andric if (!Entries.count(Succ)) 4720b57cec5SDimitry Andric continue; 473*5ffd83dbSDimitry Andric auto *Routing = Map[{Succ, PredInLoop}]; 4740b57cec5SDimitry Andric Pred->replaceSuccessor(Succ, Routing); 4750b57cec5SDimitry Andric } 4760b57cec5SDimitry Andric } 4770b57cec5SDimitry Andric 4780b57cec5SDimitry Andric // Create a fake default label, because br_table requires one. 4790b57cec5SDimitry Andric MIB.addMBB(MIB.getInstr() 4800b57cec5SDimitry Andric ->getOperand(MIB.getInstr()->getNumExplicitOperands() - 1) 4810b57cec5SDimitry Andric .getMBB()); 4820b57cec5SDimitry Andric } 4830b57cec5SDimitry Andric 4840b57cec5SDimitry Andric } // end anonymous namespace 4850b57cec5SDimitry Andric 4860b57cec5SDimitry Andric char WebAssemblyFixIrreducibleControlFlow::ID = 0; 4870b57cec5SDimitry Andric INITIALIZE_PASS(WebAssemblyFixIrreducibleControlFlow, DEBUG_TYPE, 4880b57cec5SDimitry Andric "Removes irreducible control flow", false, false) 4890b57cec5SDimitry Andric 4900b57cec5SDimitry Andric FunctionPass *llvm::createWebAssemblyFixIrreducibleControlFlow() { 4910b57cec5SDimitry Andric return new WebAssemblyFixIrreducibleControlFlow(); 4920b57cec5SDimitry Andric } 4930b57cec5SDimitry Andric 4940b57cec5SDimitry Andric bool WebAssemblyFixIrreducibleControlFlow::runOnMachineFunction( 4950b57cec5SDimitry Andric MachineFunction &MF) { 4960b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "********** Fixing Irreducible Control Flow **********\n" 4970b57cec5SDimitry Andric "********** Function: " 4980b57cec5SDimitry Andric << MF.getName() << '\n'); 4990b57cec5SDimitry Andric 5000b57cec5SDimitry Andric // Start the recursive process on the entire function body. 5010b57cec5SDimitry Andric BlockSet AllBlocks; 5020b57cec5SDimitry Andric for (auto &MBB : MF) { 5030b57cec5SDimitry Andric AllBlocks.insert(&MBB); 5040b57cec5SDimitry Andric } 5050b57cec5SDimitry Andric 5060b57cec5SDimitry Andric if (LLVM_UNLIKELY(processRegion(&*MF.begin(), AllBlocks, MF))) { 5070b57cec5SDimitry Andric // We rewrote part of the function; recompute relevant things. 5080b57cec5SDimitry Andric MF.getRegInfo().invalidateLiveness(); 5090b57cec5SDimitry Andric MF.RenumberBlocks(); 5100b57cec5SDimitry Andric return true; 5110b57cec5SDimitry Andric } 5120b57cec5SDimitry Andric 5130b57cec5SDimitry Andric return false; 5140b57cec5SDimitry Andric } 515