17d523365SDimitry Andric //===-- WebAssemblyCFGStackify.cpp - CFG Stackification -------------------===//
27d523365SDimitry Andric //
37d523365SDimitry Andric //                     The LLVM Compiler Infrastructure
47d523365SDimitry Andric //
57d523365SDimitry Andric // This file is distributed under the University of Illinois Open Source
67d523365SDimitry Andric // License. See LICENSE.TXT for details.
77d523365SDimitry Andric //
87d523365SDimitry Andric //===----------------------------------------------------------------------===//
97d523365SDimitry Andric ///
107d523365SDimitry Andric /// \file
114ba319b5SDimitry Andric /// This file implements a CFG stacking pass.
127d523365SDimitry Andric ///
13*b5893f02SDimitry Andric /// This pass inserts BLOCK, LOOP, and TRY markers to mark the start of scopes,
14*b5893f02SDimitry Andric /// since scope boundaries serve as the labels for WebAssembly's control
15*b5893f02SDimitry Andric /// transfers.
167d523365SDimitry Andric ///
177d523365SDimitry Andric /// This is sufficient to convert arbitrary CFGs into a form that works on
187d523365SDimitry Andric /// WebAssembly, provided that all loops are single-entry.
197d523365SDimitry Andric ///
20*b5893f02SDimitry Andric /// In case we use exceptions, this pass also fixes mismatches in unwind
21*b5893f02SDimitry Andric /// destinations created during transforming CFG into wasm structured format.
22*b5893f02SDimitry Andric ///
237d523365SDimitry Andric //===----------------------------------------------------------------------===//
247d523365SDimitry Andric 
257d523365SDimitry Andric #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
26db17bf38SDimitry Andric #include "WebAssembly.h"
27*b5893f02SDimitry Andric #include "WebAssemblyExceptionInfo.h"
283ca95b02SDimitry Andric #include "WebAssemblyMachineFunctionInfo.h"
297d523365SDimitry Andric #include "WebAssemblySubtarget.h"
30d88c1a5aSDimitry Andric #include "WebAssemblyUtilities.h"
317d523365SDimitry Andric #include "llvm/CodeGen/MachineDominators.h"
327d523365SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
337d523365SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
347d523365SDimitry Andric #include "llvm/CodeGen/MachineLoopInfo.h"
35444ed5c5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
367d523365SDimitry Andric #include "llvm/CodeGen/Passes.h"
37*b5893f02SDimitry Andric #include "llvm/CodeGen/WasmEHFuncInfo.h"
38*b5893f02SDimitry Andric #include "llvm/MC/MCAsmInfo.h"
397d523365SDimitry Andric #include "llvm/Support/Debug.h"
407d523365SDimitry Andric #include "llvm/Support/raw_ostream.h"
417d523365SDimitry Andric using namespace llvm;
427d523365SDimitry Andric 
437d523365SDimitry Andric #define DEBUG_TYPE "wasm-cfg-stackify"
447d523365SDimitry Andric 
457d523365SDimitry Andric namespace {
467d523365SDimitry Andric class WebAssemblyCFGStackify final : public MachineFunctionPass {
getPassName() const47d88c1a5aSDimitry Andric   StringRef getPassName() const override { return "WebAssembly CFG Stackify"; }
487d523365SDimitry Andric 
getAnalysisUsage(AnalysisUsage & AU) const497d523365SDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override {
507d523365SDimitry Andric     AU.addRequired<MachineDominatorTree>();
517d523365SDimitry Andric     AU.addRequired<MachineLoopInfo>();
52*b5893f02SDimitry Andric     AU.addRequired<WebAssemblyExceptionInfo>();
537d523365SDimitry Andric     MachineFunctionPass::getAnalysisUsage(AU);
547d523365SDimitry Andric   }
557d523365SDimitry Andric 
567d523365SDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override;
577d523365SDimitry Andric 
58*b5893f02SDimitry Andric   // For each block whose label represents the end of a scope, record the block
59*b5893f02SDimitry Andric   // which holds the beginning of the scope. This will allow us to quickly skip
60*b5893f02SDimitry Andric   // over scoped regions when walking blocks.
61*b5893f02SDimitry Andric   SmallVector<MachineBasicBlock *, 8> ScopeTops;
62*b5893f02SDimitry Andric 
63*b5893f02SDimitry Andric   void placeMarkers(MachineFunction &MF);
64*b5893f02SDimitry Andric   void placeBlockMarker(MachineBasicBlock &MBB);
65*b5893f02SDimitry Andric   void placeLoopMarker(MachineBasicBlock &MBB);
66*b5893f02SDimitry Andric   void placeTryMarker(MachineBasicBlock &MBB);
67*b5893f02SDimitry Andric   void rewriteDepthImmediates(MachineFunction &MF);
68*b5893f02SDimitry Andric   void fixEndsAtEndOfFunction(MachineFunction &MF);
69*b5893f02SDimitry Andric 
70*b5893f02SDimitry Andric   // For each BLOCK|LOOP|TRY, the corresponding END_(BLOCK|LOOP|TRY).
71*b5893f02SDimitry Andric   DenseMap<const MachineInstr *, MachineInstr *> BeginToEnd;
72*b5893f02SDimitry Andric   // For each END_(BLOCK|LOOP|TRY), the corresponding BLOCK|LOOP|TRY.
73*b5893f02SDimitry Andric   DenseMap<const MachineInstr *, MachineInstr *> EndToBegin;
74*b5893f02SDimitry Andric   // <TRY marker, EH pad> map
75*b5893f02SDimitry Andric   DenseMap<const MachineInstr *, MachineBasicBlock *> TryToEHPad;
76*b5893f02SDimitry Andric   // <EH pad, TRY marker> map
77*b5893f02SDimitry Andric   DenseMap<const MachineBasicBlock *, MachineInstr *> EHPadToTry;
78*b5893f02SDimitry Andric   // <LOOP|TRY marker, Loop/exception bottom BB> map
79*b5893f02SDimitry Andric   DenseMap<const MachineInstr *, MachineBasicBlock *> BeginToBottom;
80*b5893f02SDimitry Andric 
81*b5893f02SDimitry Andric   // Helper functions to register scope information created by marker
82*b5893f02SDimitry Andric   // instructions.
83*b5893f02SDimitry Andric   void registerScope(MachineInstr *Begin, MachineInstr *End);
84*b5893f02SDimitry Andric   void registerTryScope(MachineInstr *Begin, MachineInstr *End,
85*b5893f02SDimitry Andric                         MachineBasicBlock *EHPad);
86*b5893f02SDimitry Andric 
87*b5893f02SDimitry Andric   MachineBasicBlock *getBottom(const MachineInstr *Begin);
88*b5893f02SDimitry Andric 
897d523365SDimitry Andric public:
907d523365SDimitry Andric   static char ID; // Pass identification, replacement for typeid
WebAssemblyCFGStackify()917d523365SDimitry Andric   WebAssemblyCFGStackify() : MachineFunctionPass(ID) {}
~WebAssemblyCFGStackify()92*b5893f02SDimitry Andric   ~WebAssemblyCFGStackify() override { releaseMemory(); }
93*b5893f02SDimitry Andric   void releaseMemory() override;
947d523365SDimitry Andric };
957d523365SDimitry Andric } // end anonymous namespace
967d523365SDimitry Andric 
977d523365SDimitry Andric char WebAssemblyCFGStackify::ID = 0;
984ba319b5SDimitry Andric INITIALIZE_PASS(WebAssemblyCFGStackify, DEBUG_TYPE,
99*b5893f02SDimitry Andric                 "Insert BLOCK and LOOP markers for WebAssembly scopes", false,
100*b5893f02SDimitry Andric                 false)
1014ba319b5SDimitry Andric 
createWebAssemblyCFGStackify()1027d523365SDimitry Andric FunctionPass *llvm::createWebAssemblyCFGStackify() {
1037d523365SDimitry Andric   return new WebAssemblyCFGStackify();
1047d523365SDimitry Andric }
1057d523365SDimitry Andric 
1067d523365SDimitry Andric /// Test whether Pred has any terminators explicitly branching to MBB, as
1077d523365SDimitry Andric /// opposed to falling through. Note that it's possible (eg. in unoptimized
1087d523365SDimitry Andric /// code) for a branch instruction to both branch to a block and fallthrough
1097d523365SDimitry Andric /// to it, so we check the actual branch operands to see if there are any
1107d523365SDimitry Andric /// explicit mentions.
ExplicitlyBranchesTo(MachineBasicBlock * Pred,MachineBasicBlock * MBB)111444ed5c5SDimitry Andric static bool ExplicitlyBranchesTo(MachineBasicBlock *Pred,
112444ed5c5SDimitry Andric                                  MachineBasicBlock *MBB) {
1137d523365SDimitry Andric   for (MachineInstr &MI : Pred->terminators())
114*b5893f02SDimitry Andric     // Even if a rethrow takes a BB argument, it is not a branch
115*b5893f02SDimitry Andric     if (!WebAssembly::isRethrow(MI))
1167d523365SDimitry Andric       for (MachineOperand &MO : MI.explicit_operands())
1177d523365SDimitry Andric         if (MO.isMBB() && MO.getMBB() == MBB)
1187d523365SDimitry Andric           return true;
1197d523365SDimitry Andric   return false;
1207d523365SDimitry Andric }
1217d523365SDimitry Andric 
122*b5893f02SDimitry Andric // Returns an iterator to the earliest position possible within the MBB,
123*b5893f02SDimitry Andric // satisfying the restrictions given by BeforeSet and AfterSet. BeforeSet
124*b5893f02SDimitry Andric // contains instructions that should go before the marker, and AfterSet contains
125*b5893f02SDimitry Andric // ones that should go after the marker. In this function, AfterSet is only
126*b5893f02SDimitry Andric // used for sanity checking.
127*b5893f02SDimitry Andric static MachineBasicBlock::iterator
GetEarliestInsertPos(MachineBasicBlock * MBB,const SmallPtrSet<const MachineInstr *,4> & BeforeSet,const SmallPtrSet<const MachineInstr *,4> & AfterSet)128*b5893f02SDimitry Andric GetEarliestInsertPos(MachineBasicBlock *MBB,
129*b5893f02SDimitry Andric                      const SmallPtrSet<const MachineInstr *, 4> &BeforeSet,
130*b5893f02SDimitry Andric                      const SmallPtrSet<const MachineInstr *, 4> &AfterSet) {
131*b5893f02SDimitry Andric   auto InsertPos = MBB->end();
132*b5893f02SDimitry Andric   while (InsertPos != MBB->begin()) {
133*b5893f02SDimitry Andric     if (BeforeSet.count(&*std::prev(InsertPos))) {
134*b5893f02SDimitry Andric #ifndef NDEBUG
135*b5893f02SDimitry Andric       // Sanity check
136*b5893f02SDimitry Andric       for (auto Pos = InsertPos, E = MBB->begin(); Pos != E; --Pos)
137*b5893f02SDimitry Andric         assert(!AfterSet.count(&*std::prev(Pos)));
138*b5893f02SDimitry Andric #endif
139*b5893f02SDimitry Andric       break;
140*b5893f02SDimitry Andric     }
141*b5893f02SDimitry Andric     --InsertPos;
142*b5893f02SDimitry Andric   }
143*b5893f02SDimitry Andric   return InsertPos;
144*b5893f02SDimitry Andric }
145*b5893f02SDimitry Andric 
146*b5893f02SDimitry Andric // Returns an iterator to the latest position possible within the MBB,
147*b5893f02SDimitry Andric // satisfying the restrictions given by BeforeSet and AfterSet. BeforeSet
148*b5893f02SDimitry Andric // contains instructions that should go before the marker, and AfterSet contains
149*b5893f02SDimitry Andric // ones that should go after the marker. In this function, BeforeSet is only
150*b5893f02SDimitry Andric // used for sanity checking.
151*b5893f02SDimitry Andric static MachineBasicBlock::iterator
GetLatestInsertPos(MachineBasicBlock * MBB,const SmallPtrSet<const MachineInstr *,4> & BeforeSet,const SmallPtrSet<const MachineInstr *,4> & AfterSet)152*b5893f02SDimitry Andric GetLatestInsertPos(MachineBasicBlock *MBB,
153*b5893f02SDimitry Andric                    const SmallPtrSet<const MachineInstr *, 4> &BeforeSet,
154*b5893f02SDimitry Andric                    const SmallPtrSet<const MachineInstr *, 4> &AfterSet) {
155*b5893f02SDimitry Andric   auto InsertPos = MBB->begin();
156*b5893f02SDimitry Andric   while (InsertPos != MBB->end()) {
157*b5893f02SDimitry Andric     if (AfterSet.count(&*InsertPos)) {
158*b5893f02SDimitry Andric #ifndef NDEBUG
159*b5893f02SDimitry Andric       // Sanity check
160*b5893f02SDimitry Andric       for (auto Pos = InsertPos, E = MBB->end(); Pos != E; ++Pos)
161*b5893f02SDimitry Andric         assert(!BeforeSet.count(&*Pos));
162*b5893f02SDimitry Andric #endif
163*b5893f02SDimitry Andric       break;
164*b5893f02SDimitry Andric     }
165*b5893f02SDimitry Andric     ++InsertPos;
166*b5893f02SDimitry Andric   }
167*b5893f02SDimitry Andric   return InsertPos;
168*b5893f02SDimitry Andric }
169*b5893f02SDimitry Andric 
registerScope(MachineInstr * Begin,MachineInstr * End)170*b5893f02SDimitry Andric void WebAssemblyCFGStackify::registerScope(MachineInstr *Begin,
171*b5893f02SDimitry Andric                                            MachineInstr *End) {
172*b5893f02SDimitry Andric   BeginToEnd[Begin] = End;
173*b5893f02SDimitry Andric   EndToBegin[End] = Begin;
174*b5893f02SDimitry Andric }
175*b5893f02SDimitry Andric 
registerTryScope(MachineInstr * Begin,MachineInstr * End,MachineBasicBlock * EHPad)176*b5893f02SDimitry Andric void WebAssemblyCFGStackify::registerTryScope(MachineInstr *Begin,
177*b5893f02SDimitry Andric                                               MachineInstr *End,
178*b5893f02SDimitry Andric                                               MachineBasicBlock *EHPad) {
179*b5893f02SDimitry Andric   registerScope(Begin, End);
180*b5893f02SDimitry Andric   TryToEHPad[Begin] = EHPad;
181*b5893f02SDimitry Andric   EHPadToTry[EHPad] = Begin;
182*b5893f02SDimitry Andric }
183*b5893f02SDimitry Andric 
184*b5893f02SDimitry Andric // Given a LOOP/TRY marker, returns its bottom BB. Use cached information if any
185*b5893f02SDimitry Andric // to prevent recomputation.
186*b5893f02SDimitry Andric MachineBasicBlock *
getBottom(const MachineInstr * Begin)187*b5893f02SDimitry Andric WebAssemblyCFGStackify::getBottom(const MachineInstr *Begin) {
188*b5893f02SDimitry Andric   const auto &MLI = getAnalysis<MachineLoopInfo>();
189*b5893f02SDimitry Andric   const auto &WEI = getAnalysis<WebAssemblyExceptionInfo>();
190*b5893f02SDimitry Andric   if (BeginToBottom.count(Begin))
191*b5893f02SDimitry Andric     return BeginToBottom[Begin];
192*b5893f02SDimitry Andric   if (Begin->getOpcode() == WebAssembly::LOOP) {
193*b5893f02SDimitry Andric     MachineLoop *L = MLI.getLoopFor(Begin->getParent());
194*b5893f02SDimitry Andric     assert(L);
195*b5893f02SDimitry Andric     BeginToBottom[Begin] = WebAssembly::getBottom(L);
196*b5893f02SDimitry Andric   } else if (Begin->getOpcode() == WebAssembly::TRY) {
197*b5893f02SDimitry Andric     WebAssemblyException *WE = WEI.getExceptionFor(TryToEHPad[Begin]);
198*b5893f02SDimitry Andric     assert(WE);
199*b5893f02SDimitry Andric     BeginToBottom[Begin] = WebAssembly::getBottom(WE);
200*b5893f02SDimitry Andric   } else
201*b5893f02SDimitry Andric     assert(false);
202*b5893f02SDimitry Andric   return BeginToBottom[Begin];
203*b5893f02SDimitry Andric }
204*b5893f02SDimitry Andric 
2057d523365SDimitry Andric /// Insert a BLOCK marker for branches to MBB (if needed).
placeBlockMarker(MachineBasicBlock & MBB)206*b5893f02SDimitry Andric void WebAssemblyCFGStackify::placeBlockMarker(MachineBasicBlock &MBB) {
207*b5893f02SDimitry Andric   // This should have been handled in placeTryMarker.
208*b5893f02SDimitry Andric   if (MBB.isEHPad())
209*b5893f02SDimitry Andric     return;
210*b5893f02SDimitry Andric 
211*b5893f02SDimitry Andric   MachineFunction &MF = *MBB.getParent();
212*b5893f02SDimitry Andric   auto &MDT = getAnalysis<MachineDominatorTree>();
213*b5893f02SDimitry Andric   const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
214*b5893f02SDimitry Andric   const auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
215*b5893f02SDimitry Andric 
2167d523365SDimitry Andric   // First compute the nearest common dominator of all forward non-fallthrough
2177d523365SDimitry Andric   // predecessors so that we minimize the time that the BLOCK is on the stack,
2187d523365SDimitry Andric   // which reduces overall stack height.
2197d523365SDimitry Andric   MachineBasicBlock *Header = nullptr;
2207d523365SDimitry Andric   bool IsBranchedTo = false;
2217d523365SDimitry Andric   int MBBNumber = MBB.getNumber();
222*b5893f02SDimitry Andric   for (MachineBasicBlock *Pred : MBB.predecessors()) {
2237d523365SDimitry Andric     if (Pred->getNumber() < MBBNumber) {
2247d523365SDimitry Andric       Header = Header ? MDT.findNearestCommonDominator(Header, Pred) : Pred;
2257d523365SDimitry Andric       if (ExplicitlyBranchesTo(Pred, &MBB))
2267d523365SDimitry Andric         IsBranchedTo = true;
2277d523365SDimitry Andric     }
228*b5893f02SDimitry Andric   }
2297d523365SDimitry Andric   if (!Header)
2307d523365SDimitry Andric     return;
2317d523365SDimitry Andric   if (!IsBranchedTo)
2327d523365SDimitry Andric     return;
2337d523365SDimitry Andric 
2347d523365SDimitry Andric   assert(&MBB != &MF.front() && "Header blocks shouldn't have predecessors");
235d88c1a5aSDimitry Andric   MachineBasicBlock *LayoutPred = &*std::prev(MachineFunction::iterator(&MBB));
2367d523365SDimitry Andric 
2377d523365SDimitry Andric   // If the nearest common dominator is inside a more deeply nested context,
2387d523365SDimitry Andric   // walk out to the nearest scope which isn't more deeply nested.
2397d523365SDimitry Andric   for (MachineFunction::iterator I(LayoutPred), E(Header); I != E; --I) {
2407d523365SDimitry Andric     if (MachineBasicBlock *ScopeTop = ScopeTops[I->getNumber()]) {
2417d523365SDimitry Andric       if (ScopeTop->getNumber() > Header->getNumber()) {
2427d523365SDimitry Andric         // Skip over an intervening scope.
243d88c1a5aSDimitry Andric         I = std::next(MachineFunction::iterator(ScopeTop));
2447d523365SDimitry Andric       } else {
2457d523365SDimitry Andric         // We found a scope level at an appropriate depth.
2467d523365SDimitry Andric         Header = ScopeTop;
2477d523365SDimitry Andric         break;
2487d523365SDimitry Andric       }
2497d523365SDimitry Andric     }
2507d523365SDimitry Andric   }
2517d523365SDimitry Andric 
2527d523365SDimitry Andric   // Decide where in Header to put the BLOCK.
253*b5893f02SDimitry Andric 
254*b5893f02SDimitry Andric   // Instructions that should go before the BLOCK.
255*b5893f02SDimitry Andric   SmallPtrSet<const MachineInstr *, 4> BeforeSet;
256*b5893f02SDimitry Andric   // Instructions that should go after the BLOCK.
257*b5893f02SDimitry Andric   SmallPtrSet<const MachineInstr *, 4> AfterSet;
258*b5893f02SDimitry Andric   for (const auto &MI : *Header) {
259*b5893f02SDimitry Andric     // If there is a previously placed LOOP/TRY marker and the bottom block of
260*b5893f02SDimitry Andric     // the loop/exception is above MBB, it should be after the BLOCK, because
261*b5893f02SDimitry Andric     // the loop/exception is nested in this block. Otherwise it should be before
262*b5893f02SDimitry Andric     // the BLOCK.
263*b5893f02SDimitry Andric     if (MI.getOpcode() == WebAssembly::LOOP ||
264*b5893f02SDimitry Andric         MI.getOpcode() == WebAssembly::TRY) {
265*b5893f02SDimitry Andric       if (MBB.getNumber() > getBottom(&MI)->getNumber())
266*b5893f02SDimitry Andric         AfterSet.insert(&MI);
267*b5893f02SDimitry Andric #ifndef NDEBUG
268*b5893f02SDimitry Andric       else
269*b5893f02SDimitry Andric         BeforeSet.insert(&MI);
270*b5893f02SDimitry Andric #endif
271*b5893f02SDimitry Andric     }
272*b5893f02SDimitry Andric 
273*b5893f02SDimitry Andric     // All previously inserted BLOCK markers should be after the BLOCK because
274*b5893f02SDimitry Andric     // they are all nested blocks.
275*b5893f02SDimitry Andric     if (MI.getOpcode() == WebAssembly::BLOCK)
276*b5893f02SDimitry Andric       AfterSet.insert(&MI);
277*b5893f02SDimitry Andric 
278*b5893f02SDimitry Andric #ifndef NDEBUG
279*b5893f02SDimitry Andric     // All END_(BLOCK|LOOP|TRY) markers should be before the BLOCK.
280*b5893f02SDimitry Andric     if (MI.getOpcode() == WebAssembly::END_BLOCK ||
281*b5893f02SDimitry Andric         MI.getOpcode() == WebAssembly::END_LOOP ||
282*b5893f02SDimitry Andric         MI.getOpcode() == WebAssembly::END_TRY)
283*b5893f02SDimitry Andric       BeforeSet.insert(&MI);
284*b5893f02SDimitry Andric #endif
285*b5893f02SDimitry Andric 
286*b5893f02SDimitry Andric     // Terminators should go after the BLOCK.
287*b5893f02SDimitry Andric     if (MI.isTerminator())
288*b5893f02SDimitry Andric       AfterSet.insert(&MI);
289*b5893f02SDimitry Andric   }
290*b5893f02SDimitry Andric 
291*b5893f02SDimitry Andric   // Local expression tree should go after the BLOCK.
292*b5893f02SDimitry Andric   for (auto I = Header->getFirstTerminator(), E = Header->begin(); I != E;
293*b5893f02SDimitry Andric        --I) {
294*b5893f02SDimitry Andric     if (std::prev(I)->isDebugInstr() || std::prev(I)->isPosition())
295*b5893f02SDimitry Andric       continue;
296*b5893f02SDimitry Andric     if (WebAssembly::isChild(*std::prev(I), MFI))
297*b5893f02SDimitry Andric       AfterSet.insert(&*std::prev(I));
298*b5893f02SDimitry Andric     else
299*b5893f02SDimitry Andric       break;
3007d523365SDimitry Andric   }
3017d523365SDimitry Andric 
3027d523365SDimitry Andric   // Add the BLOCK.
303*b5893f02SDimitry Andric   auto InsertPos = GetLatestInsertPos(Header, BeforeSet, AfterSet);
3044ba319b5SDimitry Andric   MachineInstr *Begin =
3054ba319b5SDimitry Andric       BuildMI(*Header, InsertPos, Header->findDebugLoc(InsertPos),
306d88c1a5aSDimitry Andric               TII.get(WebAssembly::BLOCK))
307d88c1a5aSDimitry Andric           .addImm(int64_t(WebAssembly::ExprType::Void));
308444ed5c5SDimitry Andric 
309*b5893f02SDimitry Andric   // Decide where in Header to put the END_BLOCK.
310*b5893f02SDimitry Andric   BeforeSet.clear();
311*b5893f02SDimitry Andric   AfterSet.clear();
312*b5893f02SDimitry Andric   for (auto &MI : MBB) {
313*b5893f02SDimitry Andric #ifndef NDEBUG
314*b5893f02SDimitry Andric     // END_BLOCK should precede existing LOOP and TRY markers.
315*b5893f02SDimitry Andric     if (MI.getOpcode() == WebAssembly::LOOP ||
316*b5893f02SDimitry Andric         MI.getOpcode() == WebAssembly::TRY)
317*b5893f02SDimitry Andric       AfterSet.insert(&MI);
318*b5893f02SDimitry Andric #endif
319*b5893f02SDimitry Andric 
320*b5893f02SDimitry Andric     // If there is a previously placed END_LOOP marker and the header of the
321*b5893f02SDimitry Andric     // loop is above this block's header, the END_LOOP should be placed after
322*b5893f02SDimitry Andric     // the BLOCK, because the loop contains this block. Otherwise the END_LOOP
323*b5893f02SDimitry Andric     // should be placed before the BLOCK. The same for END_TRY.
324*b5893f02SDimitry Andric     if (MI.getOpcode() == WebAssembly::END_LOOP ||
325*b5893f02SDimitry Andric         MI.getOpcode() == WebAssembly::END_TRY) {
326*b5893f02SDimitry Andric       if (EndToBegin[&MI]->getParent()->getNumber() >= Header->getNumber())
327*b5893f02SDimitry Andric         BeforeSet.insert(&MI);
328*b5893f02SDimitry Andric #ifndef NDEBUG
329*b5893f02SDimitry Andric       else
330*b5893f02SDimitry Andric         AfterSet.insert(&MI);
331*b5893f02SDimitry Andric #endif
332*b5893f02SDimitry Andric     }
333*b5893f02SDimitry Andric   }
334*b5893f02SDimitry Andric 
335444ed5c5SDimitry Andric   // Mark the end of the block.
336*b5893f02SDimitry Andric   InsertPos = GetEarliestInsertPos(&MBB, BeforeSet, AfterSet);
3374ba319b5SDimitry Andric   MachineInstr *End = BuildMI(MBB, InsertPos, MBB.findPrevDebugLoc(InsertPos),
338d88c1a5aSDimitry Andric                               TII.get(WebAssembly::END_BLOCK));
339*b5893f02SDimitry Andric   registerScope(Begin, End);
3407d523365SDimitry Andric 
3417d523365SDimitry Andric   // Track the farthest-spanning scope that ends at this point.
3427d523365SDimitry Andric   int Number = MBB.getNumber();
3437d523365SDimitry Andric   if (!ScopeTops[Number] ||
3447d523365SDimitry Andric       ScopeTops[Number]->getNumber() > Header->getNumber())
3457d523365SDimitry Andric     ScopeTops[Number] = Header;
3467d523365SDimitry Andric }
3477d523365SDimitry Andric 
3487d523365SDimitry Andric /// Insert a LOOP marker for a loop starting at MBB (if it's a loop header).
placeLoopMarker(MachineBasicBlock & MBB)349*b5893f02SDimitry Andric void WebAssemblyCFGStackify::placeLoopMarker(MachineBasicBlock &MBB) {
350*b5893f02SDimitry Andric   MachineFunction &MF = *MBB.getParent();
351*b5893f02SDimitry Andric   const auto &MLI = getAnalysis<MachineLoopInfo>();
352*b5893f02SDimitry Andric   const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
353*b5893f02SDimitry Andric 
3547d523365SDimitry Andric   MachineLoop *Loop = MLI.getLoopFor(&MBB);
3557d523365SDimitry Andric   if (!Loop || Loop->getHeader() != &MBB)
3567d523365SDimitry Andric     return;
3577d523365SDimitry Andric 
3587d523365SDimitry Andric   // The operand of a LOOP is the first block after the loop. If the loop is the
3597d523365SDimitry Andric   // bottom of the function, insert a dummy block at the end.
3604ba319b5SDimitry Andric   MachineBasicBlock *Bottom = WebAssembly::getBottom(Loop);
361d88c1a5aSDimitry Andric   auto Iter = std::next(MachineFunction::iterator(Bottom));
3627d523365SDimitry Andric   if (Iter == MF.end()) {
3637d523365SDimitry Andric     MachineBasicBlock *Label = MF.CreateMachineBasicBlock();
3647d523365SDimitry Andric     // Give it a fake predecessor so that AsmPrinter prints its label.
3657d523365SDimitry Andric     Label->addSuccessor(Label);
3667d523365SDimitry Andric     MF.push_back(Label);
367d88c1a5aSDimitry Andric     Iter = std::next(MachineFunction::iterator(Bottom));
3687d523365SDimitry Andric   }
3697d523365SDimitry Andric   MachineBasicBlock *AfterLoop = &*Iter;
3707d523365SDimitry Andric 
371*b5893f02SDimitry Andric   // Decide where in Header to put the LOOP.
372*b5893f02SDimitry Andric   SmallPtrSet<const MachineInstr *, 4> BeforeSet;
373*b5893f02SDimitry Andric   SmallPtrSet<const MachineInstr *, 4> AfterSet;
374*b5893f02SDimitry Andric   for (const auto &MI : MBB) {
375*b5893f02SDimitry Andric     // LOOP marker should be after any existing loop that ends here. Otherwise
376*b5893f02SDimitry Andric     // we assume the instruction belongs to the loop.
377*b5893f02SDimitry Andric     if (MI.getOpcode() == WebAssembly::END_LOOP)
378*b5893f02SDimitry Andric       BeforeSet.insert(&MI);
379*b5893f02SDimitry Andric #ifndef NDEBUG
380*b5893f02SDimitry Andric     else
381*b5893f02SDimitry Andric       AfterSet.insert(&MI);
382*b5893f02SDimitry Andric #endif
383*b5893f02SDimitry Andric   }
384*b5893f02SDimitry Andric 
385*b5893f02SDimitry Andric   // Mark the beginning of the loop.
386*b5893f02SDimitry Andric   auto InsertPos = GetEarliestInsertPos(&MBB, BeforeSet, AfterSet);
3874ba319b5SDimitry Andric   MachineInstr *Begin = BuildMI(MBB, InsertPos, MBB.findDebugLoc(InsertPos),
388d88c1a5aSDimitry Andric                                 TII.get(WebAssembly::LOOP))
389d88c1a5aSDimitry Andric                             .addImm(int64_t(WebAssembly::ExprType::Void));
390444ed5c5SDimitry Andric 
391*b5893f02SDimitry Andric   // Decide where in Header to put the END_LOOP.
392*b5893f02SDimitry Andric   BeforeSet.clear();
393*b5893f02SDimitry Andric   AfterSet.clear();
394*b5893f02SDimitry Andric #ifndef NDEBUG
395*b5893f02SDimitry Andric   for (const auto &MI : MBB)
396*b5893f02SDimitry Andric     // Existing END_LOOP markers belong to parent loops of this loop
397*b5893f02SDimitry Andric     if (MI.getOpcode() == WebAssembly::END_LOOP)
398*b5893f02SDimitry Andric       AfterSet.insert(&MI);
399*b5893f02SDimitry Andric #endif
400*b5893f02SDimitry Andric 
401*b5893f02SDimitry Andric   // Mark the end of the loop (using arbitrary debug location that branched to
402*b5893f02SDimitry Andric   // the loop end as its location).
403*b5893f02SDimitry Andric   InsertPos = GetEarliestInsertPos(AfterLoop, BeforeSet, AfterSet);
4044ba319b5SDimitry Andric   DebugLoc EndDL = (*AfterLoop->pred_rbegin())->findBranchDebugLoc();
405*b5893f02SDimitry Andric   MachineInstr *End =
406*b5893f02SDimitry Andric       BuildMI(*AfterLoop, InsertPos, EndDL, TII.get(WebAssembly::END_LOOP));
407*b5893f02SDimitry Andric   registerScope(Begin, End);
4087d523365SDimitry Andric 
4097d523365SDimitry Andric   assert((!ScopeTops[AfterLoop->getNumber()] ||
4107d523365SDimitry Andric           ScopeTops[AfterLoop->getNumber()]->getNumber() < MBB.getNumber()) &&
4113ca95b02SDimitry Andric          "With block sorting the outermost loop for a block should be first.");
4127d523365SDimitry Andric   if (!ScopeTops[AfterLoop->getNumber()])
4137d523365SDimitry Andric     ScopeTops[AfterLoop->getNumber()] = &MBB;
4147d523365SDimitry Andric }
4157d523365SDimitry Andric 
placeTryMarker(MachineBasicBlock & MBB)416*b5893f02SDimitry Andric void WebAssemblyCFGStackify::placeTryMarker(MachineBasicBlock &MBB) {
417*b5893f02SDimitry Andric   if (!MBB.isEHPad())
418*b5893f02SDimitry Andric     return;
419*b5893f02SDimitry Andric 
420*b5893f02SDimitry Andric   // catch_all terminate pad is grouped together with catch terminate pad and
421*b5893f02SDimitry Andric   // does not need a separate TRY and END_TRY marker.
422*b5893f02SDimitry Andric   if (WebAssembly::isCatchAllTerminatePad(MBB))
423*b5893f02SDimitry Andric     return;
424*b5893f02SDimitry Andric 
425*b5893f02SDimitry Andric   MachineFunction &MF = *MBB.getParent();
426*b5893f02SDimitry Andric   auto &MDT = getAnalysis<MachineDominatorTree>();
427*b5893f02SDimitry Andric   const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
428*b5893f02SDimitry Andric   const auto &WEI = getAnalysis<WebAssemblyExceptionInfo>();
429*b5893f02SDimitry Andric   const auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
430*b5893f02SDimitry Andric 
431*b5893f02SDimitry Andric   // Compute the nearest common dominator of all unwind predecessors
432*b5893f02SDimitry Andric   MachineBasicBlock *Header = nullptr;
433*b5893f02SDimitry Andric   int MBBNumber = MBB.getNumber();
434*b5893f02SDimitry Andric   for (auto *Pred : MBB.predecessors()) {
435*b5893f02SDimitry Andric     if (Pred->getNumber() < MBBNumber) {
436*b5893f02SDimitry Andric       Header = Header ? MDT.findNearestCommonDominator(Header, Pred) : Pred;
437*b5893f02SDimitry Andric       assert(!ExplicitlyBranchesTo(Pred, &MBB) &&
438*b5893f02SDimitry Andric              "Explicit branch to an EH pad!");
439*b5893f02SDimitry Andric     }
440*b5893f02SDimitry Andric   }
441*b5893f02SDimitry Andric   if (!Header)
442*b5893f02SDimitry Andric     return;
443*b5893f02SDimitry Andric 
444*b5893f02SDimitry Andric   // If this try is at the bottom of the function, insert a dummy block at the
445*b5893f02SDimitry Andric   // end.
446*b5893f02SDimitry Andric   WebAssemblyException *WE = WEI.getExceptionFor(&MBB);
447*b5893f02SDimitry Andric   assert(WE);
448*b5893f02SDimitry Andric   MachineBasicBlock *Bottom = WebAssembly::getBottom(WE);
449*b5893f02SDimitry Andric 
450*b5893f02SDimitry Andric   auto Iter = std::next(MachineFunction::iterator(Bottom));
451*b5893f02SDimitry Andric   if (Iter == MF.end()) {
452*b5893f02SDimitry Andric     MachineBasicBlock *Label = MF.CreateMachineBasicBlock();
453*b5893f02SDimitry Andric     // Give it a fake predecessor so that AsmPrinter prints its label.
454*b5893f02SDimitry Andric     Label->addSuccessor(Label);
455*b5893f02SDimitry Andric     MF.push_back(Label);
456*b5893f02SDimitry Andric     Iter = std::next(MachineFunction::iterator(Bottom));
457*b5893f02SDimitry Andric   }
458*b5893f02SDimitry Andric   MachineBasicBlock *AfterTry = &*Iter;
459*b5893f02SDimitry Andric 
460*b5893f02SDimitry Andric   assert(AfterTry != &MF.front());
461*b5893f02SDimitry Andric   MachineBasicBlock *LayoutPred =
462*b5893f02SDimitry Andric       &*std::prev(MachineFunction::iterator(AfterTry));
463*b5893f02SDimitry Andric 
464*b5893f02SDimitry Andric   // If the nearest common dominator is inside a more deeply nested context,
465*b5893f02SDimitry Andric   // walk out to the nearest scope which isn't more deeply nested.
466*b5893f02SDimitry Andric   for (MachineFunction::iterator I(LayoutPred), E(Header); I != E; --I) {
467*b5893f02SDimitry Andric     if (MachineBasicBlock *ScopeTop = ScopeTops[I->getNumber()]) {
468*b5893f02SDimitry Andric       if (ScopeTop->getNumber() > Header->getNumber()) {
469*b5893f02SDimitry Andric         // Skip over an intervening scope.
470*b5893f02SDimitry Andric         I = std::next(MachineFunction::iterator(ScopeTop));
471*b5893f02SDimitry Andric       } else {
472*b5893f02SDimitry Andric         // We found a scope level at an appropriate depth.
473*b5893f02SDimitry Andric         Header = ScopeTop;
474*b5893f02SDimitry Andric         break;
475*b5893f02SDimitry Andric       }
476*b5893f02SDimitry Andric     }
477*b5893f02SDimitry Andric   }
478*b5893f02SDimitry Andric 
479*b5893f02SDimitry Andric   // Decide where in Header to put the TRY.
480*b5893f02SDimitry Andric 
481*b5893f02SDimitry Andric   // Instructions that should go before the BLOCK.
482*b5893f02SDimitry Andric   SmallPtrSet<const MachineInstr *, 4> BeforeSet;
483*b5893f02SDimitry Andric   // Instructions that should go after the BLOCK.
484*b5893f02SDimitry Andric   SmallPtrSet<const MachineInstr *, 4> AfterSet;
485*b5893f02SDimitry Andric   for (const auto &MI : *Header) {
486*b5893f02SDimitry Andric     // If there is a previously placed LOOP marker and the bottom block of
487*b5893f02SDimitry Andric     // the loop is above MBB, the LOOP should be after the TRY, because the
488*b5893f02SDimitry Andric     // loop is nested in this try. Otherwise it should be before the TRY.
489*b5893f02SDimitry Andric     if (MI.getOpcode() == WebAssembly::LOOP) {
490*b5893f02SDimitry Andric       if (MBB.getNumber() > Bottom->getNumber())
491*b5893f02SDimitry Andric         AfterSet.insert(&MI);
492*b5893f02SDimitry Andric #ifndef NDEBUG
493*b5893f02SDimitry Andric       else
494*b5893f02SDimitry Andric         BeforeSet.insert(&MI);
495*b5893f02SDimitry Andric #endif
496*b5893f02SDimitry Andric     }
497*b5893f02SDimitry Andric 
498*b5893f02SDimitry Andric     // All previously inserted TRY markers should be after the TRY because they
499*b5893f02SDimitry Andric     // are all nested trys.
500*b5893f02SDimitry Andric     if (MI.getOpcode() == WebAssembly::TRY)
501*b5893f02SDimitry Andric       AfterSet.insert(&MI);
502*b5893f02SDimitry Andric 
503*b5893f02SDimitry Andric #ifndef NDEBUG
504*b5893f02SDimitry Andric     // All END_(LOOP/TRY) markers should be before the TRY.
505*b5893f02SDimitry Andric     if (MI.getOpcode() == WebAssembly::END_LOOP ||
506*b5893f02SDimitry Andric         MI.getOpcode() == WebAssembly::END_TRY)
507*b5893f02SDimitry Andric       BeforeSet.insert(&MI);
508*b5893f02SDimitry Andric #endif
509*b5893f02SDimitry Andric 
510*b5893f02SDimitry Andric     // Terminators should go after the TRY.
511*b5893f02SDimitry Andric     if (MI.isTerminator())
512*b5893f02SDimitry Andric       AfterSet.insert(&MI);
513*b5893f02SDimitry Andric   }
514*b5893f02SDimitry Andric 
515*b5893f02SDimitry Andric   // Local expression tree should go after the TRY.
516*b5893f02SDimitry Andric   for (auto I = Header->getFirstTerminator(), E = Header->begin(); I != E;
517*b5893f02SDimitry Andric        --I) {
518*b5893f02SDimitry Andric     if (std::prev(I)->isDebugInstr() || std::prev(I)->isPosition())
519*b5893f02SDimitry Andric       continue;
520*b5893f02SDimitry Andric     if (WebAssembly::isChild(*std::prev(I), MFI))
521*b5893f02SDimitry Andric       AfterSet.insert(&*std::prev(I));
522*b5893f02SDimitry Andric     else
523*b5893f02SDimitry Andric       break;
524*b5893f02SDimitry Andric   }
525*b5893f02SDimitry Andric 
526*b5893f02SDimitry Andric   // If Header unwinds to MBB (= Header contains 'invoke'), the try block should
527*b5893f02SDimitry Andric   // contain the call within it. So the call should go after the TRY. The
528*b5893f02SDimitry Andric   // exception is when the header's terminator is a rethrow instruction, in
529*b5893f02SDimitry Andric   // which case that instruction, not a call instruction before it, is gonna
530*b5893f02SDimitry Andric   // throw.
531*b5893f02SDimitry Andric   if (MBB.isPredecessor(Header)) {
532*b5893f02SDimitry Andric     auto TermPos = Header->getFirstTerminator();
533*b5893f02SDimitry Andric     if (TermPos == Header->end() || !WebAssembly::isRethrow(*TermPos)) {
534*b5893f02SDimitry Andric       for (const auto &MI : reverse(*Header)) {
535*b5893f02SDimitry Andric         if (MI.isCall()) {
536*b5893f02SDimitry Andric           AfterSet.insert(&MI);
537*b5893f02SDimitry Andric           break;
538*b5893f02SDimitry Andric         }
539*b5893f02SDimitry Andric       }
540*b5893f02SDimitry Andric     }
541*b5893f02SDimitry Andric   }
542*b5893f02SDimitry Andric 
543*b5893f02SDimitry Andric   // Add the TRY.
544*b5893f02SDimitry Andric   auto InsertPos = GetLatestInsertPos(Header, BeforeSet, AfterSet);
545*b5893f02SDimitry Andric   MachineInstr *Begin =
546*b5893f02SDimitry Andric       BuildMI(*Header, InsertPos, Header->findDebugLoc(InsertPos),
547*b5893f02SDimitry Andric               TII.get(WebAssembly::TRY))
548*b5893f02SDimitry Andric           .addImm(int64_t(WebAssembly::ExprType::Void));
549*b5893f02SDimitry Andric 
550*b5893f02SDimitry Andric   // Decide where in Header to put the END_TRY.
551*b5893f02SDimitry Andric   BeforeSet.clear();
552*b5893f02SDimitry Andric   AfterSet.clear();
553*b5893f02SDimitry Andric   for (const auto &MI : *AfterTry) {
554*b5893f02SDimitry Andric #ifndef NDEBUG
555*b5893f02SDimitry Andric     // END_TRY should precede existing LOOP markers.
556*b5893f02SDimitry Andric     if (MI.getOpcode() == WebAssembly::LOOP)
557*b5893f02SDimitry Andric       AfterSet.insert(&MI);
558*b5893f02SDimitry Andric 
559*b5893f02SDimitry Andric     // All END_TRY markers placed earlier belong to exceptions that contains
560*b5893f02SDimitry Andric     // this one.
561*b5893f02SDimitry Andric     if (MI.getOpcode() == WebAssembly::END_TRY)
562*b5893f02SDimitry Andric       AfterSet.insert(&MI);
563*b5893f02SDimitry Andric #endif
564*b5893f02SDimitry Andric 
565*b5893f02SDimitry Andric     // If there is a previously placed END_LOOP marker and its header is after
566*b5893f02SDimitry Andric     // where TRY marker is, this loop is contained within the 'catch' part, so
567*b5893f02SDimitry Andric     // the END_TRY marker should go after that. Otherwise, the whole try-catch
568*b5893f02SDimitry Andric     // is contained within this loop, so the END_TRY should go before that.
569*b5893f02SDimitry Andric     if (MI.getOpcode() == WebAssembly::END_LOOP) {
570*b5893f02SDimitry Andric       if (EndToBegin[&MI]->getParent()->getNumber() >= Header->getNumber())
571*b5893f02SDimitry Andric         BeforeSet.insert(&MI);
572*b5893f02SDimitry Andric #ifndef NDEBUG
573*b5893f02SDimitry Andric       else
574*b5893f02SDimitry Andric         AfterSet.insert(&MI);
575*b5893f02SDimitry Andric #endif
576*b5893f02SDimitry Andric     }
577*b5893f02SDimitry Andric   }
578*b5893f02SDimitry Andric 
579*b5893f02SDimitry Andric   // Mark the end of the TRY.
580*b5893f02SDimitry Andric   InsertPos = GetEarliestInsertPos(AfterTry, BeforeSet, AfterSet);
581*b5893f02SDimitry Andric   MachineInstr *End =
582*b5893f02SDimitry Andric       BuildMI(*AfterTry, InsertPos, Bottom->findBranchDebugLoc(),
583*b5893f02SDimitry Andric               TII.get(WebAssembly::END_TRY));
584*b5893f02SDimitry Andric   registerTryScope(Begin, End, &MBB);
585*b5893f02SDimitry Andric 
586*b5893f02SDimitry Andric   // Track the farthest-spanning scope that ends at this point.
587*b5893f02SDimitry Andric   int Number = AfterTry->getNumber();
588*b5893f02SDimitry Andric   if (!ScopeTops[Number] ||
589*b5893f02SDimitry Andric       ScopeTops[Number]->getNumber() > Header->getNumber())
590*b5893f02SDimitry Andric     ScopeTops[Number] = Header;
591*b5893f02SDimitry Andric }
592*b5893f02SDimitry Andric 
593444ed5c5SDimitry Andric static unsigned
GetDepth(const SmallVectorImpl<const MachineBasicBlock * > & Stack,const MachineBasicBlock * MBB)594444ed5c5SDimitry Andric GetDepth(const SmallVectorImpl<const MachineBasicBlock *> &Stack,
595444ed5c5SDimitry Andric          const MachineBasicBlock *MBB) {
596444ed5c5SDimitry Andric   unsigned Depth = 0;
597444ed5c5SDimitry Andric   for (auto X : reverse(Stack)) {
598444ed5c5SDimitry Andric     if (X == MBB)
599444ed5c5SDimitry Andric       break;
600444ed5c5SDimitry Andric     ++Depth;
601444ed5c5SDimitry Andric   }
602444ed5c5SDimitry Andric   assert(Depth < Stack.size() && "Branch destination should be in scope");
603444ed5c5SDimitry Andric   return Depth;
604444ed5c5SDimitry Andric }
605444ed5c5SDimitry Andric 
606d88c1a5aSDimitry Andric /// In normal assembly languages, when the end of a function is unreachable,
607d88c1a5aSDimitry Andric /// because the function ends in an infinite loop or a noreturn call or similar,
608d88c1a5aSDimitry Andric /// it isn't necessary to worry about the function return type at the end of
609d88c1a5aSDimitry Andric /// the function, because it's never reached. However, in WebAssembly, blocks
610d88c1a5aSDimitry Andric /// that end at the function end need to have a return type signature that
611d88c1a5aSDimitry Andric /// matches the function signature, even though it's unreachable. This function
612d88c1a5aSDimitry Andric /// checks for such cases and fixes up the signatures.
fixEndsAtEndOfFunction(MachineFunction & MF)613*b5893f02SDimitry Andric void WebAssemblyCFGStackify::fixEndsAtEndOfFunction(MachineFunction &MF) {
614*b5893f02SDimitry Andric   const auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
615d88c1a5aSDimitry Andric   assert(MFI.getResults().size() <= 1);
616d88c1a5aSDimitry Andric 
617d88c1a5aSDimitry Andric   if (MFI.getResults().empty())
618d88c1a5aSDimitry Andric     return;
619d88c1a5aSDimitry Andric 
620d88c1a5aSDimitry Andric   WebAssembly::ExprType retType;
621d88c1a5aSDimitry Andric   switch (MFI.getResults().front().SimpleTy) {
622*b5893f02SDimitry Andric   case MVT::i32:
623*b5893f02SDimitry Andric     retType = WebAssembly::ExprType::I32;
624*b5893f02SDimitry Andric     break;
625*b5893f02SDimitry Andric   case MVT::i64:
626*b5893f02SDimitry Andric     retType = WebAssembly::ExprType::I64;
627*b5893f02SDimitry Andric     break;
628*b5893f02SDimitry Andric   case MVT::f32:
629*b5893f02SDimitry Andric     retType = WebAssembly::ExprType::F32;
630*b5893f02SDimitry Andric     break;
631*b5893f02SDimitry Andric   case MVT::f64:
632*b5893f02SDimitry Andric     retType = WebAssembly::ExprType::F64;
633*b5893f02SDimitry Andric     break;
634*b5893f02SDimitry Andric   case MVT::v16i8:
635*b5893f02SDimitry Andric   case MVT::v8i16:
636*b5893f02SDimitry Andric   case MVT::v4i32:
637*b5893f02SDimitry Andric   case MVT::v2i64:
638*b5893f02SDimitry Andric   case MVT::v4f32:
639*b5893f02SDimitry Andric   case MVT::v2f64:
640*b5893f02SDimitry Andric     retType = WebAssembly::ExprType::V128;
641*b5893f02SDimitry Andric     break;
642*b5893f02SDimitry Andric   case MVT::ExceptRef:
643*b5893f02SDimitry Andric     retType = WebAssembly::ExprType::ExceptRef;
644*b5893f02SDimitry Andric     break;
645*b5893f02SDimitry Andric   default:
646*b5893f02SDimitry Andric     llvm_unreachable("unexpected return type");
647d88c1a5aSDimitry Andric   }
648d88c1a5aSDimitry Andric 
649d88c1a5aSDimitry Andric   for (MachineBasicBlock &MBB : reverse(MF)) {
650d88c1a5aSDimitry Andric     for (MachineInstr &MI : reverse(MBB)) {
6514ba319b5SDimitry Andric       if (MI.isPosition() || MI.isDebugInstr())
652d88c1a5aSDimitry Andric         continue;
653d88c1a5aSDimitry Andric       if (MI.getOpcode() == WebAssembly::END_BLOCK) {
654*b5893f02SDimitry Andric         EndToBegin[&MI]->getOperand(0).setImm(int32_t(retType));
655d88c1a5aSDimitry Andric         continue;
656d88c1a5aSDimitry Andric       }
657d88c1a5aSDimitry Andric       if (MI.getOpcode() == WebAssembly::END_LOOP) {
658*b5893f02SDimitry Andric         EndToBegin[&MI]->getOperand(0).setImm(int32_t(retType));
659d88c1a5aSDimitry Andric         continue;
660d88c1a5aSDimitry Andric       }
661d88c1a5aSDimitry Andric       // Something other than an `end`. We're done.
662d88c1a5aSDimitry Andric       return;
663d88c1a5aSDimitry Andric     }
664d88c1a5aSDimitry Andric   }
665d88c1a5aSDimitry Andric }
666d88c1a5aSDimitry Andric 
6677a7e6055SDimitry Andric // WebAssembly functions end with an end instruction, as if the function body
6687a7e6055SDimitry Andric // were a block.
AppendEndToFunction(MachineFunction & MF,const WebAssemblyInstrInfo & TII)669*b5893f02SDimitry Andric static void AppendEndToFunction(MachineFunction &MF,
6707a7e6055SDimitry Andric                                 const WebAssemblyInstrInfo &TII) {
6714ba319b5SDimitry Andric   BuildMI(MF.back(), MF.back().end(),
6724ba319b5SDimitry Andric           MF.back().findPrevDebugLoc(MF.back().end()),
6737a7e6055SDimitry Andric           TII.get(WebAssembly::END_FUNCTION));
6747a7e6055SDimitry Andric }
6757a7e6055SDimitry Andric 
676*b5893f02SDimitry Andric /// Insert LOOP/TRY/BLOCK markers at appropriate places.
placeMarkers(MachineFunction & MF)677*b5893f02SDimitry Andric void WebAssemblyCFGStackify::placeMarkers(MachineFunction &MF) {
678*b5893f02SDimitry Andric   const MCAsmInfo *MCAI = MF.getTarget().getMCAsmInfo();
679*b5893f02SDimitry Andric   // We allocate one more than the number of blocks in the function to
680*b5893f02SDimitry Andric   // accommodate for the possible fake block we may insert at the end.
681*b5893f02SDimitry Andric   ScopeTops.resize(MF.getNumBlockIDs() + 1);
6827d523365SDimitry Andric   // Place the LOOP for MBB if MBB is the header of a loop.
683*b5893f02SDimitry Andric   for (auto &MBB : MF)
684*b5893f02SDimitry Andric     placeLoopMarker(MBB);
685*b5893f02SDimitry Andric   // Place the TRY for MBB if MBB is the EH pad of an exception.
686*b5893f02SDimitry Andric   if (MCAI->getExceptionHandlingType() == ExceptionHandling::Wasm &&
687*b5893f02SDimitry Andric       MF.getFunction().hasPersonalityFn())
688*b5893f02SDimitry Andric     for (auto &MBB : MF)
689*b5893f02SDimitry Andric       placeTryMarker(MBB);
6907d523365SDimitry Andric   // Place the BLOCK for MBB if MBB is branched to from above.
691*b5893f02SDimitry Andric   for (auto &MBB : MF)
692*b5893f02SDimitry Andric     placeBlockMarker(MBB);
6937d523365SDimitry Andric }
6947d523365SDimitry Andric 
rewriteDepthImmediates(MachineFunction & MF)695*b5893f02SDimitry Andric void WebAssemblyCFGStackify::rewriteDepthImmediates(MachineFunction &MF) {
696*b5893f02SDimitry Andric   const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
697444ed5c5SDimitry Andric   // Now rewrite references to basic blocks to be depth immediates.
698*b5893f02SDimitry Andric   // We need two stacks: one for normal scopes and the other for EH pad scopes.
699*b5893f02SDimitry Andric   // EH pad stack is used to rewrite depths in rethrow instructions.
700444ed5c5SDimitry Andric   SmallVector<const MachineBasicBlock *, 8> Stack;
701*b5893f02SDimitry Andric   SmallVector<const MachineBasicBlock *, 8> EHPadStack;
702444ed5c5SDimitry Andric   for (auto &MBB : reverse(MF)) {
703*b5893f02SDimitry Andric     for (auto I = MBB.rbegin(), E = MBB.rend(); I != E; ++I) {
704*b5893f02SDimitry Andric       MachineInstr &MI = *I;
705444ed5c5SDimitry Andric       switch (MI.getOpcode()) {
706444ed5c5SDimitry Andric       case WebAssembly::BLOCK:
707*b5893f02SDimitry Andric         assert(ScopeTops[Stack.back()->getNumber()]->getNumber() <=
708*b5893f02SDimitry Andric                    MBB.getNumber() &&
709*b5893f02SDimitry Andric                "Block/try should be balanced");
710444ed5c5SDimitry Andric         Stack.pop_back();
711444ed5c5SDimitry Andric         break;
712*b5893f02SDimitry Andric 
713*b5893f02SDimitry Andric       case WebAssembly::TRY:
714*b5893f02SDimitry Andric         assert(ScopeTops[Stack.back()->getNumber()]->getNumber() <=
715*b5893f02SDimitry Andric                    MBB.getNumber() &&
716*b5893f02SDimitry Andric                "Block/try marker should be balanced");
717*b5893f02SDimitry Andric         Stack.pop_back();
718*b5893f02SDimitry Andric         EHPadStack.pop_back();
719*b5893f02SDimitry Andric         break;
720*b5893f02SDimitry Andric 
721*b5893f02SDimitry Andric       case WebAssembly::CATCH_I32:
722*b5893f02SDimitry Andric       case WebAssembly::CATCH_I64:
723*b5893f02SDimitry Andric       case WebAssembly::CATCH_ALL:
724*b5893f02SDimitry Andric         // Currently the only case there are more than one catch for a try is
725*b5893f02SDimitry Andric         // for catch terminate pad, in the form of
726*b5893f02SDimitry Andric         //   try
727*b5893f02SDimitry Andric         //   catch
728*b5893f02SDimitry Andric         //     call @__clang_call_terminate
729*b5893f02SDimitry Andric         //     unreachable
730*b5893f02SDimitry Andric         //   catch_all
731*b5893f02SDimitry Andric         //     call @std::terminate
732*b5893f02SDimitry Andric         //     unreachable
733*b5893f02SDimitry Andric         //   end
734*b5893f02SDimitry Andric         // So we shouldn't push the current BB for the second catch_all block
735*b5893f02SDimitry Andric         // here.
736*b5893f02SDimitry Andric         if (!WebAssembly::isCatchAllTerminatePad(MBB))
737*b5893f02SDimitry Andric           EHPadStack.push_back(&MBB);
738*b5893f02SDimitry Andric         break;
739*b5893f02SDimitry Andric 
740444ed5c5SDimitry Andric       case WebAssembly::LOOP:
741444ed5c5SDimitry Andric         assert(Stack.back() == &MBB && "Loop top should be balanced");
742444ed5c5SDimitry Andric         Stack.pop_back();
743444ed5c5SDimitry Andric         break;
744*b5893f02SDimitry Andric 
745444ed5c5SDimitry Andric       case WebAssembly::END_BLOCK:
746*b5893f02SDimitry Andric       case WebAssembly::END_TRY:
747444ed5c5SDimitry Andric         Stack.push_back(&MBB);
748444ed5c5SDimitry Andric         break;
749*b5893f02SDimitry Andric 
750444ed5c5SDimitry Andric       case WebAssembly::END_LOOP:
751*b5893f02SDimitry Andric         Stack.push_back(EndToBegin[&MI]->getParent());
752444ed5c5SDimitry Andric         break;
753*b5893f02SDimitry Andric 
754*b5893f02SDimitry Andric       case WebAssembly::RETHROW: {
755*b5893f02SDimitry Andric         // Rewrite MBB operands to be depth immediates.
756*b5893f02SDimitry Andric         unsigned EHPadDepth = GetDepth(EHPadStack, MI.getOperand(0).getMBB());
757*b5893f02SDimitry Andric         MI.RemoveOperand(0);
758*b5893f02SDimitry Andric         MI.addOperand(MF, MachineOperand::CreateImm(EHPadDepth));
759*b5893f02SDimitry Andric         break;
760*b5893f02SDimitry Andric       }
761*b5893f02SDimitry Andric 
762*b5893f02SDimitry Andric       case WebAssembly::RETHROW_TO_CALLER: {
763*b5893f02SDimitry Andric         MachineInstr *Rethrow =
764*b5893f02SDimitry Andric             BuildMI(MBB, MI, MI.getDebugLoc(), TII.get(WebAssembly::RETHROW))
765*b5893f02SDimitry Andric                 .addImm(EHPadStack.size());
766*b5893f02SDimitry Andric         MI.eraseFromParent();
767*b5893f02SDimitry Andric         I = MachineBasicBlock::reverse_iterator(Rethrow);
768*b5893f02SDimitry Andric         break;
769*b5893f02SDimitry Andric       }
770*b5893f02SDimitry Andric 
771444ed5c5SDimitry Andric       default:
772444ed5c5SDimitry Andric         if (MI.isTerminator()) {
773444ed5c5SDimitry Andric           // Rewrite MBB operands to be depth immediates.
774444ed5c5SDimitry Andric           SmallVector<MachineOperand, 4> Ops(MI.operands());
775444ed5c5SDimitry Andric           while (MI.getNumOperands() > 0)
776444ed5c5SDimitry Andric             MI.RemoveOperand(MI.getNumOperands() - 1);
777444ed5c5SDimitry Andric           for (auto MO : Ops) {
778444ed5c5SDimitry Andric             if (MO.isMBB())
779444ed5c5SDimitry Andric               MO = MachineOperand::CreateImm(GetDepth(Stack, MO.getMBB()));
780444ed5c5SDimitry Andric             MI.addOperand(MF, MO);
7817d523365SDimitry Andric           }
782444ed5c5SDimitry Andric         }
783444ed5c5SDimitry Andric         break;
784444ed5c5SDimitry Andric       }
785444ed5c5SDimitry Andric     }
786444ed5c5SDimitry Andric   }
787444ed5c5SDimitry Andric   assert(Stack.empty() && "Control flow should be balanced");
788*b5893f02SDimitry Andric }
789d88c1a5aSDimitry Andric 
releaseMemory()790*b5893f02SDimitry Andric void WebAssemblyCFGStackify::releaseMemory() {
791*b5893f02SDimitry Andric   ScopeTops.clear();
792*b5893f02SDimitry Andric   BeginToEnd.clear();
793*b5893f02SDimitry Andric   EndToBegin.clear();
794*b5893f02SDimitry Andric   TryToEHPad.clear();
795*b5893f02SDimitry Andric   EHPadToTry.clear();
796*b5893f02SDimitry Andric   BeginToBottom.clear();
797444ed5c5SDimitry Andric }
7987d523365SDimitry Andric 
runOnMachineFunction(MachineFunction & MF)7997d523365SDimitry Andric bool WebAssemblyCFGStackify::runOnMachineFunction(MachineFunction &MF) {
8004ba319b5SDimitry Andric   LLVM_DEBUG(dbgs() << "********** CFG Stackifying **********\n"
8017d523365SDimitry Andric                        "********** Function: "
8027d523365SDimitry Andric                     << MF.getName() << '\n');
8037d523365SDimitry Andric 
804*b5893f02SDimitry Andric   releaseMemory();
805*b5893f02SDimitry Andric 
806d88c1a5aSDimitry Andric   // Liveness is not tracked for VALUE_STACK physreg.
807444ed5c5SDimitry Andric   MF.getRegInfo().invalidateLiveness();
8087d523365SDimitry Andric 
809*b5893f02SDimitry Andric   // Place the BLOCK/LOOP/TRY markers to indicate the beginnings of scopes.
810*b5893f02SDimitry Andric   placeMarkers(MF);
811*b5893f02SDimitry Andric 
812*b5893f02SDimitry Andric   // Convert MBB operands in terminators to relative depth immediates.
813*b5893f02SDimitry Andric   rewriteDepthImmediates(MF);
814*b5893f02SDimitry Andric 
815*b5893f02SDimitry Andric   // Fix up block/loop/try signatures at the end of the function to conform to
816*b5893f02SDimitry Andric   // WebAssembly's rules.
817*b5893f02SDimitry Andric   fixEndsAtEndOfFunction(MF);
818*b5893f02SDimitry Andric 
819*b5893f02SDimitry Andric   // Add an end instruction at the end of the function body.
820*b5893f02SDimitry Andric   const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
821*b5893f02SDimitry Andric   if (!MF.getSubtarget<WebAssemblySubtarget>()
822*b5893f02SDimitry Andric            .getTargetTriple()
823*b5893f02SDimitry Andric            .isOSBinFormatELF())
824*b5893f02SDimitry Andric     AppendEndToFunction(MF, TII);
8257d523365SDimitry Andric 
8267d523365SDimitry Andric   return true;
8277d523365SDimitry Andric }
828