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