Path: blob/main/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
35266 views
//===-- WebAssemblyCFGStackify.cpp - CFG Stackification -------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7///8/// \file9/// This file implements a CFG stacking pass.10///11/// This pass inserts BLOCK, LOOP, and TRY markers to mark the start of scopes,12/// since scope boundaries serve as the labels for WebAssembly's control13/// transfers.14///15/// This is sufficient to convert arbitrary CFGs into a form that works on16/// WebAssembly, provided that all loops are single-entry.17///18/// In case we use exceptions, this pass also fixes mismatches in unwind19/// destinations created during transforming CFG into wasm structured format.20///21//===----------------------------------------------------------------------===//2223#include "Utils/WebAssemblyTypeUtilities.h"24#include "WebAssembly.h"25#include "WebAssemblyExceptionInfo.h"26#include "WebAssemblyMachineFunctionInfo.h"27#include "WebAssemblySortRegion.h"28#include "WebAssemblySubtarget.h"29#include "WebAssemblyUtilities.h"30#include "llvm/ADT/Statistic.h"31#include "llvm/CodeGen/MachineDominators.h"32#include "llvm/CodeGen/MachineInstrBuilder.h"33#include "llvm/CodeGen/MachineLoopInfo.h"34#include "llvm/CodeGen/WasmEHFuncInfo.h"35#include "llvm/MC/MCAsmInfo.h"36#include "llvm/Target/TargetMachine.h"37using namespace llvm;38using WebAssembly::SortRegionInfo;3940#define DEBUG_TYPE "wasm-cfg-stackify"4142STATISTIC(NumCallUnwindMismatches, "Number of call unwind mismatches found");43STATISTIC(NumCatchUnwindMismatches, "Number of catch unwind mismatches found");4445namespace {46class WebAssemblyCFGStackify final : public MachineFunctionPass {47StringRef getPassName() const override { return "WebAssembly CFG Stackify"; }4849void getAnalysisUsage(AnalysisUsage &AU) const override {50AU.addRequired<MachineDominatorTreeWrapperPass>();51AU.addRequired<MachineLoopInfoWrapperPass>();52AU.addRequired<WebAssemblyExceptionInfo>();53MachineFunctionPass::getAnalysisUsage(AU);54}5556bool runOnMachineFunction(MachineFunction &MF) override;5758// For each block whose label represents the end of a scope, record the block59// which holds the beginning of the scope. This will allow us to quickly skip60// over scoped regions when walking blocks.61SmallVector<MachineBasicBlock *, 8> ScopeTops;62void updateScopeTops(MachineBasicBlock *Begin, MachineBasicBlock *End) {63int EndNo = End->getNumber();64if (!ScopeTops[EndNo] || ScopeTops[EndNo]->getNumber() > Begin->getNumber())65ScopeTops[EndNo] = Begin;66}6768// Placing markers.69void placeMarkers(MachineFunction &MF);70void placeBlockMarker(MachineBasicBlock &MBB);71void placeLoopMarker(MachineBasicBlock &MBB);72void placeTryMarker(MachineBasicBlock &MBB);7374// Exception handling related functions75bool fixCallUnwindMismatches(MachineFunction &MF);76bool fixCatchUnwindMismatches(MachineFunction &MF);77void addTryDelegate(MachineInstr *RangeBegin, MachineInstr *RangeEnd,78MachineBasicBlock *DelegateDest);79void recalculateScopeTops(MachineFunction &MF);80void removeUnnecessaryInstrs(MachineFunction &MF);8182// Wrap-up83using EndMarkerInfo =84std::pair<const MachineBasicBlock *, const MachineInstr *>;85unsigned getBranchDepth(const SmallVectorImpl<EndMarkerInfo> &Stack,86const MachineBasicBlock *MBB);87unsigned getDelegateDepth(const SmallVectorImpl<EndMarkerInfo> &Stack,88const MachineBasicBlock *MBB);89unsigned getRethrowDepth(const SmallVectorImpl<EndMarkerInfo> &Stack,90const MachineBasicBlock *EHPadToRethrow);91void rewriteDepthImmediates(MachineFunction &MF);92void fixEndsAtEndOfFunction(MachineFunction &MF);93void cleanupFunctionData(MachineFunction &MF);9495// For each BLOCK|LOOP|TRY, the corresponding END_(BLOCK|LOOP|TRY) or DELEGATE96// (in case of TRY).97DenseMap<const MachineInstr *, MachineInstr *> BeginToEnd;98// For each END_(BLOCK|LOOP|TRY) or DELEGATE, the corresponding99// BLOCK|LOOP|TRY.100DenseMap<const MachineInstr *, MachineInstr *> EndToBegin;101// <TRY marker, EH pad> map102DenseMap<const MachineInstr *, MachineBasicBlock *> TryToEHPad;103// <EH pad, TRY marker> map104DenseMap<const MachineBasicBlock *, MachineInstr *> EHPadToTry;105106// We need an appendix block to place 'end_loop' or 'end_try' marker when the107// loop / exception bottom block is the last block in a function108MachineBasicBlock *AppendixBB = nullptr;109MachineBasicBlock *getAppendixBlock(MachineFunction &MF) {110if (!AppendixBB) {111AppendixBB = MF.CreateMachineBasicBlock();112// Give it a fake predecessor so that AsmPrinter prints its label.113AppendixBB->addSuccessor(AppendixBB);114MF.push_back(AppendixBB);115}116return AppendixBB;117}118119// Before running rewriteDepthImmediates function, 'delegate' has a BB as its120// destination operand. getFakeCallerBlock() returns a fake BB that will be121// used for the operand when 'delegate' needs to rethrow to the caller. This122// will be rewritten as an immediate value that is the number of block depths123// + 1 in rewriteDepthImmediates, and this fake BB will be removed at the end124// of the pass.125MachineBasicBlock *FakeCallerBB = nullptr;126MachineBasicBlock *getFakeCallerBlock(MachineFunction &MF) {127if (!FakeCallerBB)128FakeCallerBB = MF.CreateMachineBasicBlock();129return FakeCallerBB;130}131132// Helper functions to register / unregister scope information created by133// marker instructions.134void registerScope(MachineInstr *Begin, MachineInstr *End);135void registerTryScope(MachineInstr *Begin, MachineInstr *End,136MachineBasicBlock *EHPad);137void unregisterScope(MachineInstr *Begin);138139public:140static char ID; // Pass identification, replacement for typeid141WebAssemblyCFGStackify() : MachineFunctionPass(ID) {}142~WebAssemblyCFGStackify() override { releaseMemory(); }143void releaseMemory() override;144};145} // end anonymous namespace146147char WebAssemblyCFGStackify::ID = 0;148INITIALIZE_PASS(WebAssemblyCFGStackify, DEBUG_TYPE,149"Insert BLOCK/LOOP/TRY markers for WebAssembly scopes", false,150false)151152FunctionPass *llvm::createWebAssemblyCFGStackify() {153return new WebAssemblyCFGStackify();154}155156/// Test whether Pred has any terminators explicitly branching to MBB, as157/// opposed to falling through. Note that it's possible (eg. in unoptimized158/// code) for a branch instruction to both branch to a block and fallthrough159/// to it, so we check the actual branch operands to see if there are any160/// explicit mentions.161static bool explicitlyBranchesTo(MachineBasicBlock *Pred,162MachineBasicBlock *MBB) {163for (MachineInstr &MI : Pred->terminators())164for (MachineOperand &MO : MI.explicit_operands())165if (MO.isMBB() && MO.getMBB() == MBB)166return true;167return false;168}169170// Returns an iterator to the earliest position possible within the MBB,171// satisfying the restrictions given by BeforeSet and AfterSet. BeforeSet172// contains instructions that should go before the marker, and AfterSet contains173// ones that should go after the marker. In this function, AfterSet is only174// used for validation checking.175template <typename Container>176static MachineBasicBlock::iterator177getEarliestInsertPos(MachineBasicBlock *MBB, const Container &BeforeSet,178const Container &AfterSet) {179auto InsertPos = MBB->end();180while (InsertPos != MBB->begin()) {181if (BeforeSet.count(&*std::prev(InsertPos))) {182#ifndef NDEBUG183// Validation check184for (auto Pos = InsertPos, E = MBB->begin(); Pos != E; --Pos)185assert(!AfterSet.count(&*std::prev(Pos)));186#endif187break;188}189--InsertPos;190}191return InsertPos;192}193194// Returns an iterator to the latest position possible within the MBB,195// satisfying the restrictions given by BeforeSet and AfterSet. BeforeSet196// contains instructions that should go before the marker, and AfterSet contains197// ones that should go after the marker. In this function, BeforeSet is only198// used for validation checking.199template <typename Container>200static MachineBasicBlock::iterator201getLatestInsertPos(MachineBasicBlock *MBB, const Container &BeforeSet,202const Container &AfterSet) {203auto InsertPos = MBB->begin();204while (InsertPos != MBB->end()) {205if (AfterSet.count(&*InsertPos)) {206#ifndef NDEBUG207// Validation check208for (auto Pos = InsertPos, E = MBB->end(); Pos != E; ++Pos)209assert(!BeforeSet.count(&*Pos));210#endif211break;212}213++InsertPos;214}215return InsertPos;216}217218void WebAssemblyCFGStackify::registerScope(MachineInstr *Begin,219MachineInstr *End) {220BeginToEnd[Begin] = End;221EndToBegin[End] = Begin;222}223224// When 'End' is not an 'end_try' but 'delegate, EHPad is nullptr.225void WebAssemblyCFGStackify::registerTryScope(MachineInstr *Begin,226MachineInstr *End,227MachineBasicBlock *EHPad) {228registerScope(Begin, End);229TryToEHPad[Begin] = EHPad;230EHPadToTry[EHPad] = Begin;231}232233void WebAssemblyCFGStackify::unregisterScope(MachineInstr *Begin) {234assert(BeginToEnd.count(Begin));235MachineInstr *End = BeginToEnd[Begin];236assert(EndToBegin.count(End));237BeginToEnd.erase(Begin);238EndToBegin.erase(End);239MachineBasicBlock *EHPad = TryToEHPad.lookup(Begin);240if (EHPad) {241assert(EHPadToTry.count(EHPad));242TryToEHPad.erase(Begin);243EHPadToTry.erase(EHPad);244}245}246247/// Insert a BLOCK marker for branches to MBB (if needed).248// TODO Consider a more generalized way of handling block (and also loop and249// try) signatures when we implement the multi-value proposal later.250void WebAssemblyCFGStackify::placeBlockMarker(MachineBasicBlock &MBB) {251assert(!MBB.isEHPad());252MachineFunction &MF = *MBB.getParent();253auto &MDT = getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();254const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();255const auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();256257// First compute the nearest common dominator of all forward non-fallthrough258// predecessors so that we minimize the time that the BLOCK is on the stack,259// which reduces overall stack height.260MachineBasicBlock *Header = nullptr;261bool IsBranchedTo = false;262int MBBNumber = MBB.getNumber();263for (MachineBasicBlock *Pred : MBB.predecessors()) {264if (Pred->getNumber() < MBBNumber) {265Header = Header ? MDT.findNearestCommonDominator(Header, Pred) : Pred;266if (explicitlyBranchesTo(Pred, &MBB))267IsBranchedTo = true;268}269}270if (!Header)271return;272if (!IsBranchedTo)273return;274275assert(&MBB != &MF.front() && "Header blocks shouldn't have predecessors");276MachineBasicBlock *LayoutPred = MBB.getPrevNode();277278// If the nearest common dominator is inside a more deeply nested context,279// walk out to the nearest scope which isn't more deeply nested.280for (MachineFunction::iterator I(LayoutPred), E(Header); I != E; --I) {281if (MachineBasicBlock *ScopeTop = ScopeTops[I->getNumber()]) {282if (ScopeTop->getNumber() > Header->getNumber()) {283// Skip over an intervening scope.284I = std::next(ScopeTop->getIterator());285} else {286// We found a scope level at an appropriate depth.287Header = ScopeTop;288break;289}290}291}292293// Decide where in Header to put the BLOCK.294295// Instructions that should go before the BLOCK.296SmallPtrSet<const MachineInstr *, 4> BeforeSet;297// Instructions that should go after the BLOCK.298SmallPtrSet<const MachineInstr *, 4> AfterSet;299for (const auto &MI : *Header) {300// If there is a previously placed LOOP marker and the bottom block of the301// loop is above MBB, it should be after the BLOCK, because the loop is302// nested in this BLOCK. Otherwise it should be before the BLOCK.303if (MI.getOpcode() == WebAssembly::LOOP) {304auto *LoopBottom = BeginToEnd[&MI]->getParent()->getPrevNode();305if (MBB.getNumber() > LoopBottom->getNumber())306AfterSet.insert(&MI);307#ifndef NDEBUG308else309BeforeSet.insert(&MI);310#endif311}312313// If there is a previously placed BLOCK/TRY marker and its corresponding314// END marker is before the current BLOCK's END marker, that should be315// placed after this BLOCK. Otherwise it should be placed before this BLOCK316// marker.317if (MI.getOpcode() == WebAssembly::BLOCK ||318MI.getOpcode() == WebAssembly::TRY) {319if (BeginToEnd[&MI]->getParent()->getNumber() <= MBB.getNumber())320AfterSet.insert(&MI);321#ifndef NDEBUG322else323BeforeSet.insert(&MI);324#endif325}326327#ifndef NDEBUG328// All END_(BLOCK|LOOP|TRY) markers should be before the BLOCK.329if (MI.getOpcode() == WebAssembly::END_BLOCK ||330MI.getOpcode() == WebAssembly::END_LOOP ||331MI.getOpcode() == WebAssembly::END_TRY)332BeforeSet.insert(&MI);333#endif334335// Terminators should go after the BLOCK.336if (MI.isTerminator())337AfterSet.insert(&MI);338}339340// Local expression tree should go after the BLOCK.341for (auto I = Header->getFirstTerminator(), E = Header->begin(); I != E;342--I) {343if (std::prev(I)->isDebugInstr() || std::prev(I)->isPosition())344continue;345if (WebAssembly::isChild(*std::prev(I), MFI))346AfterSet.insert(&*std::prev(I));347else348break;349}350351// Add the BLOCK.352WebAssembly::BlockType ReturnType = WebAssembly::BlockType::Void;353auto InsertPos = getLatestInsertPos(Header, BeforeSet, AfterSet);354MachineInstr *Begin =355BuildMI(*Header, InsertPos, Header->findDebugLoc(InsertPos),356TII.get(WebAssembly::BLOCK))357.addImm(int64_t(ReturnType));358359// Decide where in Header to put the END_BLOCK.360BeforeSet.clear();361AfterSet.clear();362for (auto &MI : MBB) {363#ifndef NDEBUG364// END_BLOCK should precede existing LOOP and TRY markers.365if (MI.getOpcode() == WebAssembly::LOOP ||366MI.getOpcode() == WebAssembly::TRY)367AfterSet.insert(&MI);368#endif369370// If there is a previously placed END_LOOP marker and the header of the371// loop is above this block's header, the END_LOOP should be placed after372// the BLOCK, because the loop contains this block. Otherwise the END_LOOP373// should be placed before the BLOCK. The same for END_TRY.374if (MI.getOpcode() == WebAssembly::END_LOOP ||375MI.getOpcode() == WebAssembly::END_TRY) {376if (EndToBegin[&MI]->getParent()->getNumber() >= Header->getNumber())377BeforeSet.insert(&MI);378#ifndef NDEBUG379else380AfterSet.insert(&MI);381#endif382}383}384385// Mark the end of the block.386InsertPos = getEarliestInsertPos(&MBB, BeforeSet, AfterSet);387MachineInstr *End = BuildMI(MBB, InsertPos, MBB.findPrevDebugLoc(InsertPos),388TII.get(WebAssembly::END_BLOCK));389registerScope(Begin, End);390391// Track the farthest-spanning scope that ends at this point.392updateScopeTops(Header, &MBB);393}394395/// Insert a LOOP marker for a loop starting at MBB (if it's a loop header).396void WebAssemblyCFGStackify::placeLoopMarker(MachineBasicBlock &MBB) {397MachineFunction &MF = *MBB.getParent();398const auto &MLI = getAnalysis<MachineLoopInfoWrapperPass>().getLI();399const auto &WEI = getAnalysis<WebAssemblyExceptionInfo>();400SortRegionInfo SRI(MLI, WEI);401const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();402403MachineLoop *Loop = MLI.getLoopFor(&MBB);404if (!Loop || Loop->getHeader() != &MBB)405return;406407// The operand of a LOOP is the first block after the loop. If the loop is the408// bottom of the function, insert a dummy block at the end.409MachineBasicBlock *Bottom = SRI.getBottom(Loop);410auto Iter = std::next(Bottom->getIterator());411if (Iter == MF.end()) {412getAppendixBlock(MF);413Iter = std::next(Bottom->getIterator());414}415MachineBasicBlock *AfterLoop = &*Iter;416417// Decide where in Header to put the LOOP.418SmallPtrSet<const MachineInstr *, 4> BeforeSet;419SmallPtrSet<const MachineInstr *, 4> AfterSet;420for (const auto &MI : MBB) {421// LOOP marker should be after any existing loop that ends here. Otherwise422// we assume the instruction belongs to the loop.423if (MI.getOpcode() == WebAssembly::END_LOOP)424BeforeSet.insert(&MI);425#ifndef NDEBUG426else427AfterSet.insert(&MI);428#endif429}430431// Mark the beginning of the loop.432auto InsertPos = getEarliestInsertPos(&MBB, BeforeSet, AfterSet);433MachineInstr *Begin = BuildMI(MBB, InsertPos, MBB.findDebugLoc(InsertPos),434TII.get(WebAssembly::LOOP))435.addImm(int64_t(WebAssembly::BlockType::Void));436437// Decide where in Header to put the END_LOOP.438BeforeSet.clear();439AfterSet.clear();440#ifndef NDEBUG441for (const auto &MI : MBB)442// Existing END_LOOP markers belong to parent loops of this loop443if (MI.getOpcode() == WebAssembly::END_LOOP)444AfterSet.insert(&MI);445#endif446447// Mark the end of the loop (using arbitrary debug location that branched to448// the loop end as its location).449InsertPos = getEarliestInsertPos(AfterLoop, BeforeSet, AfterSet);450DebugLoc EndDL = AfterLoop->pred_empty()451? DebugLoc()452: (*AfterLoop->pred_rbegin())->findBranchDebugLoc();453MachineInstr *End =454BuildMI(*AfterLoop, InsertPos, EndDL, TII.get(WebAssembly::END_LOOP));455registerScope(Begin, End);456457assert((!ScopeTops[AfterLoop->getNumber()] ||458ScopeTops[AfterLoop->getNumber()]->getNumber() < MBB.getNumber()) &&459"With block sorting the outermost loop for a block should be first.");460updateScopeTops(&MBB, AfterLoop);461}462463void WebAssemblyCFGStackify::placeTryMarker(MachineBasicBlock &MBB) {464assert(MBB.isEHPad());465MachineFunction &MF = *MBB.getParent();466auto &MDT = getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();467const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();468const auto &MLI = getAnalysis<MachineLoopInfoWrapperPass>().getLI();469const auto &WEI = getAnalysis<WebAssemblyExceptionInfo>();470SortRegionInfo SRI(MLI, WEI);471const auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();472473// Compute the nearest common dominator of all unwind predecessors474MachineBasicBlock *Header = nullptr;475int MBBNumber = MBB.getNumber();476for (auto *Pred : MBB.predecessors()) {477if (Pred->getNumber() < MBBNumber) {478Header = Header ? MDT.findNearestCommonDominator(Header, Pred) : Pred;479assert(!explicitlyBranchesTo(Pred, &MBB) &&480"Explicit branch to an EH pad!");481}482}483if (!Header)484return;485486// If this try is at the bottom of the function, insert a dummy block at the487// end.488WebAssemblyException *WE = WEI.getExceptionFor(&MBB);489assert(WE);490MachineBasicBlock *Bottom = SRI.getBottom(WE);491492auto Iter = std::next(Bottom->getIterator());493if (Iter == MF.end()) {494getAppendixBlock(MF);495Iter = std::next(Bottom->getIterator());496}497MachineBasicBlock *Cont = &*Iter;498499assert(Cont != &MF.front());500MachineBasicBlock *LayoutPred = Cont->getPrevNode();501502// If the nearest common dominator is inside a more deeply nested context,503// walk out to the nearest scope which isn't more deeply nested.504for (MachineFunction::iterator I(LayoutPred), E(Header); I != E; --I) {505if (MachineBasicBlock *ScopeTop = ScopeTops[I->getNumber()]) {506if (ScopeTop->getNumber() > Header->getNumber()) {507// Skip over an intervening scope.508I = std::next(ScopeTop->getIterator());509} else {510// We found a scope level at an appropriate depth.511Header = ScopeTop;512break;513}514}515}516517// Decide where in Header to put the TRY.518519// Instructions that should go before the TRY.520SmallPtrSet<const MachineInstr *, 4> BeforeSet;521// Instructions that should go after the TRY.522SmallPtrSet<const MachineInstr *, 4> AfterSet;523for (const auto &MI : *Header) {524// If there is a previously placed LOOP marker and the bottom block of the525// loop is above MBB, it should be after the TRY, because the loop is nested526// in this TRY. Otherwise it should be before the TRY.527if (MI.getOpcode() == WebAssembly::LOOP) {528auto *LoopBottom = BeginToEnd[&MI]->getParent()->getPrevNode();529if (MBB.getNumber() > LoopBottom->getNumber())530AfterSet.insert(&MI);531#ifndef NDEBUG532else533BeforeSet.insert(&MI);534#endif535}536537// All previously inserted BLOCK/TRY markers should be after the TRY because538// they are all nested trys.539if (MI.getOpcode() == WebAssembly::BLOCK ||540MI.getOpcode() == WebAssembly::TRY)541AfterSet.insert(&MI);542543#ifndef NDEBUG544// All END_(BLOCK/LOOP/TRY) markers should be before the TRY.545if (MI.getOpcode() == WebAssembly::END_BLOCK ||546MI.getOpcode() == WebAssembly::END_LOOP ||547MI.getOpcode() == WebAssembly::END_TRY)548BeforeSet.insert(&MI);549#endif550551// Terminators should go after the TRY.552if (MI.isTerminator())553AfterSet.insert(&MI);554}555556// If Header unwinds to MBB (= Header contains 'invoke'), the try block should557// contain the call within it. So the call should go after the TRY. The558// exception is when the header's terminator is a rethrow instruction, in559// which case that instruction, not a call instruction before it, is gonna560// throw.561MachineInstr *ThrowingCall = nullptr;562if (MBB.isPredecessor(Header)) {563auto TermPos = Header->getFirstTerminator();564if (TermPos == Header->end() ||565TermPos->getOpcode() != WebAssembly::RETHROW) {566for (auto &MI : reverse(*Header)) {567if (MI.isCall()) {568AfterSet.insert(&MI);569ThrowingCall = &MI;570// Possibly throwing calls are usually wrapped by EH_LABEL571// instructions. We don't want to split them and the call.572if (MI.getIterator() != Header->begin() &&573std::prev(MI.getIterator())->isEHLabel()) {574AfterSet.insert(&*std::prev(MI.getIterator()));575ThrowingCall = &*std::prev(MI.getIterator());576}577break;578}579}580}581}582583// Local expression tree should go after the TRY.584// For BLOCK placement, we start the search from the previous instruction of a585// BB's terminator, but in TRY's case, we should start from the previous586// instruction of a call that can throw, or a EH_LABEL that precedes the call,587// because the return values of the call's previous instructions can be588// stackified and consumed by the throwing call.589auto SearchStartPt = ThrowingCall ? MachineBasicBlock::iterator(ThrowingCall)590: Header->getFirstTerminator();591for (auto I = SearchStartPt, E = Header->begin(); I != E; --I) {592if (std::prev(I)->isDebugInstr() || std::prev(I)->isPosition())593continue;594if (WebAssembly::isChild(*std::prev(I), MFI))595AfterSet.insert(&*std::prev(I));596else597break;598}599600// Add the TRY.601auto InsertPos = getLatestInsertPos(Header, BeforeSet, AfterSet);602MachineInstr *Begin =603BuildMI(*Header, InsertPos, Header->findDebugLoc(InsertPos),604TII.get(WebAssembly::TRY))605.addImm(int64_t(WebAssembly::BlockType::Void));606607// Decide where in Header to put the END_TRY.608BeforeSet.clear();609AfterSet.clear();610for (const auto &MI : *Cont) {611#ifndef NDEBUG612// END_TRY should precede existing LOOP and BLOCK markers.613if (MI.getOpcode() == WebAssembly::LOOP ||614MI.getOpcode() == WebAssembly::BLOCK)615AfterSet.insert(&MI);616617// All END_TRY markers placed earlier belong to exceptions that contains618// this one.619if (MI.getOpcode() == WebAssembly::END_TRY)620AfterSet.insert(&MI);621#endif622623// If there is a previously placed END_LOOP marker and its header is after624// where TRY marker is, this loop is contained within the 'catch' part, so625// the END_TRY marker should go after that. Otherwise, the whole try-catch626// is contained within this loop, so the END_TRY should go before that.627if (MI.getOpcode() == WebAssembly::END_LOOP) {628// For a LOOP to be after TRY, LOOP's BB should be after TRY's BB; if they629// are in the same BB, LOOP is always before TRY.630if (EndToBegin[&MI]->getParent()->getNumber() > Header->getNumber())631BeforeSet.insert(&MI);632#ifndef NDEBUG633else634AfterSet.insert(&MI);635#endif636}637638// It is not possible for an END_BLOCK to be already in this block.639}640641// Mark the end of the TRY.642InsertPos = getEarliestInsertPos(Cont, BeforeSet, AfterSet);643MachineInstr *End =644BuildMI(*Cont, InsertPos, Bottom->findBranchDebugLoc(),645TII.get(WebAssembly::END_TRY));646registerTryScope(Begin, End, &MBB);647648// Track the farthest-spanning scope that ends at this point. We create two649// mappings: (BB with 'end_try' -> BB with 'try') and (BB with 'catch' -> BB650// with 'try'). We need to create 'catch' -> 'try' mapping here too because651// markers should not span across 'catch'. For example, this should not652// happen:653//654// try655// block --| (X)656// catch |657// end_block --|658// end_try659for (auto *End : {&MBB, Cont})660updateScopeTops(Header, End);661}662663void WebAssemblyCFGStackify::removeUnnecessaryInstrs(MachineFunction &MF) {664const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();665666// When there is an unconditional branch right before a catch instruction and667// it branches to the end of end_try marker, we don't need the branch, because668// if there is no exception, the control flow transfers to that point anyway.669// bb0:670// try671// ...672// br bb2 <- Not necessary673// bb1 (ehpad):674// catch675// ...676// bb2: <- Continuation BB677// end678//679// A more involved case: When the BB where 'end' is located is an another EH680// pad, the Cont (= continuation) BB is that EH pad's 'end' BB. For example,681// bb0:682// try683// try684// ...685// br bb3 <- Not necessary686// bb1 (ehpad):687// catch688// bb2 (ehpad):689// end690// catch691// ...692// bb3: <- Continuation BB693// end694//695// When the EH pad at hand is bb1, its matching end_try is in bb2. But it is696// another EH pad, so bb0's continuation BB becomes bb3. So 'br bb3' in the697// code can be deleted. This is why we run 'while' until 'Cont' is not an EH698// pad.699for (auto &MBB : MF) {700if (!MBB.isEHPad())701continue;702703MachineBasicBlock *TBB = nullptr, *FBB = nullptr;704SmallVector<MachineOperand, 4> Cond;705MachineBasicBlock *EHPadLayoutPred = MBB.getPrevNode();706707MachineBasicBlock *Cont = &MBB;708while (Cont->isEHPad()) {709MachineInstr *Try = EHPadToTry[Cont];710MachineInstr *EndTry = BeginToEnd[Try];711// We started from an EH pad, so the end marker cannot be a delegate712assert(EndTry->getOpcode() != WebAssembly::DELEGATE);713Cont = EndTry->getParent();714}715716bool Analyzable = !TII.analyzeBranch(*EHPadLayoutPred, TBB, FBB, Cond);717// This condition means either718// 1. This BB ends with a single unconditional branch whose destinaion is719// Cont.720// 2. This BB ends with a conditional branch followed by an unconditional721// branch, and the unconditional branch's destination is Cont.722// In both cases, we want to remove the last (= unconditional) branch.723if (Analyzable && ((Cond.empty() && TBB && TBB == Cont) ||724(!Cond.empty() && FBB && FBB == Cont))) {725bool ErasedUncondBr = false;726(void)ErasedUncondBr;727for (auto I = EHPadLayoutPred->end(), E = EHPadLayoutPred->begin();728I != E; --I) {729auto PrevI = std::prev(I);730if (PrevI->isTerminator()) {731assert(PrevI->getOpcode() == WebAssembly::BR);732PrevI->eraseFromParent();733ErasedUncondBr = true;734break;735}736}737assert(ErasedUncondBr && "Unconditional branch not erased!");738}739}740741// When there are block / end_block markers that overlap with try / end_try742// markers, and the block and try markers' return types are the same, the743// block /end_block markers are not necessary, because try / end_try markers744// also can serve as boundaries for branches.745// block <- Not necessary746// try747// ...748// catch749// ...750// end751// end <- Not necessary752SmallVector<MachineInstr *, 32> ToDelete;753for (auto &MBB : MF) {754for (auto &MI : MBB) {755if (MI.getOpcode() != WebAssembly::TRY)756continue;757MachineInstr *Try = &MI, *EndTry = BeginToEnd[Try];758if (EndTry->getOpcode() == WebAssembly::DELEGATE)759continue;760761MachineBasicBlock *TryBB = Try->getParent();762MachineBasicBlock *Cont = EndTry->getParent();763int64_t RetType = Try->getOperand(0).getImm();764for (auto B = Try->getIterator(), E = std::next(EndTry->getIterator());765B != TryBB->begin() && E != Cont->end() &&766std::prev(B)->getOpcode() == WebAssembly::BLOCK &&767E->getOpcode() == WebAssembly::END_BLOCK &&768std::prev(B)->getOperand(0).getImm() == RetType;769--B, ++E) {770ToDelete.push_back(&*std::prev(B));771ToDelete.push_back(&*E);772}773}774}775for (auto *MI : ToDelete) {776if (MI->getOpcode() == WebAssembly::BLOCK)777unregisterScope(MI);778MI->eraseFromParent();779}780}781782// When MBB is split into MBB and Split, we should unstackify defs in MBB that783// have their uses in Split.784static void unstackifyVRegsUsedInSplitBB(MachineBasicBlock &MBB,785MachineBasicBlock &Split) {786MachineFunction &MF = *MBB.getParent();787const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();788auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();789auto &MRI = MF.getRegInfo();790791for (auto &MI : Split) {792for (auto &MO : MI.explicit_uses()) {793if (!MO.isReg() || MO.getReg().isPhysical())794continue;795if (MachineInstr *Def = MRI.getUniqueVRegDef(MO.getReg()))796if (Def->getParent() == &MBB)797MFI.unstackifyVReg(MO.getReg());798}799}800801// In RegStackify, when a register definition is used multiple times,802// Reg = INST ...803// INST ..., Reg, ...804// INST ..., Reg, ...805// INST ..., Reg, ...806//807// we introduce a TEE, which has the following form:808// DefReg = INST ...809// TeeReg, Reg = TEE_... DefReg810// INST ..., TeeReg, ...811// INST ..., Reg, ...812// INST ..., Reg, ...813// with DefReg and TeeReg stackified but Reg not stackified.814//815// But the invariant that TeeReg should be stackified can be violated while we816// unstackify registers in the split BB above. In this case, we convert TEEs817// into two COPYs. This COPY will be eventually eliminated in ExplicitLocals.818// DefReg = INST ...819// TeeReg = COPY DefReg820// Reg = COPY DefReg821// INST ..., TeeReg, ...822// INST ..., Reg, ...823// INST ..., Reg, ...824for (MachineInstr &MI : llvm::make_early_inc_range(MBB)) {825if (!WebAssembly::isTee(MI.getOpcode()))826continue;827Register TeeReg = MI.getOperand(0).getReg();828Register Reg = MI.getOperand(1).getReg();829Register DefReg = MI.getOperand(2).getReg();830if (!MFI.isVRegStackified(TeeReg)) {831// Now we are not using TEE anymore, so unstackify DefReg too832MFI.unstackifyVReg(DefReg);833unsigned CopyOpc =834WebAssembly::getCopyOpcodeForRegClass(MRI.getRegClass(DefReg));835BuildMI(MBB, &MI, MI.getDebugLoc(), TII.get(CopyOpc), TeeReg)836.addReg(DefReg);837BuildMI(MBB, &MI, MI.getDebugLoc(), TII.get(CopyOpc), Reg).addReg(DefReg);838MI.eraseFromParent();839}840}841}842843// Wrap the given range of instruction with try-delegate. RangeBegin and844// RangeEnd are inclusive.845void WebAssemblyCFGStackify::addTryDelegate(MachineInstr *RangeBegin,846MachineInstr *RangeEnd,847MachineBasicBlock *DelegateDest) {848auto *BeginBB = RangeBegin->getParent();849auto *EndBB = RangeEnd->getParent();850MachineFunction &MF = *BeginBB->getParent();851const auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();852const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();853854// Local expression tree before the first call of this range should go855// after the nested TRY.856SmallPtrSet<const MachineInstr *, 4> AfterSet;857AfterSet.insert(RangeBegin);858for (auto I = MachineBasicBlock::iterator(RangeBegin), E = BeginBB->begin();859I != E; --I) {860if (std::prev(I)->isDebugInstr() || std::prev(I)->isPosition())861continue;862if (WebAssembly::isChild(*std::prev(I), MFI))863AfterSet.insert(&*std::prev(I));864else865break;866}867868// Create the nested try instruction.869auto TryPos = getLatestInsertPos(870BeginBB, SmallPtrSet<const MachineInstr *, 4>(), AfterSet);871MachineInstr *Try = BuildMI(*BeginBB, TryPos, RangeBegin->getDebugLoc(),872TII.get(WebAssembly::TRY))873.addImm(int64_t(WebAssembly::BlockType::Void));874875// Create a BB to insert the 'delegate' instruction.876MachineBasicBlock *DelegateBB = MF.CreateMachineBasicBlock();877// If the destination of 'delegate' is not the caller, adds the destination to878// the BB's successors.879if (DelegateDest != FakeCallerBB)880DelegateBB->addSuccessor(DelegateDest);881882auto SplitPos = std::next(RangeEnd->getIterator());883if (SplitPos == EndBB->end()) {884// If the range's end instruction is at the end of the BB, insert the new885// delegate BB after the current BB.886MF.insert(std::next(EndBB->getIterator()), DelegateBB);887EndBB->addSuccessor(DelegateBB);888889} else {890// When the split pos is in the middle of a BB, we split the BB into two and891// put the 'delegate' BB in between. We normally create a split BB and make892// it a successor of the original BB (PostSplit == true), but in case the BB893// is an EH pad and the split pos is before 'catch', we should preserve the894// BB's property, including that it is an EH pad, in the later part of the895// BB, where 'catch' is. In this case we set PostSplit to false.896bool PostSplit = true;897if (EndBB->isEHPad()) {898for (auto I = MachineBasicBlock::iterator(SplitPos), E = EndBB->end();899I != E; ++I) {900if (WebAssembly::isCatch(I->getOpcode())) {901PostSplit = false;902break;903}904}905}906907MachineBasicBlock *PreBB = nullptr, *PostBB = nullptr;908if (PostSplit) {909// If the range's end instruction is in the middle of the BB, we split the910// BB into two and insert the delegate BB in between.911// - Before:912// bb:913// range_end914// other_insts915//916// - After:917// pre_bb: (previous 'bb')918// range_end919// delegate_bb: (new)920// delegate921// post_bb: (new)922// other_insts923PreBB = EndBB;924PostBB = MF.CreateMachineBasicBlock();925MF.insert(std::next(PreBB->getIterator()), PostBB);926MF.insert(std::next(PreBB->getIterator()), DelegateBB);927PostBB->splice(PostBB->end(), PreBB, SplitPos, PreBB->end());928PostBB->transferSuccessors(PreBB);929} else {930// - Before:931// ehpad:932// range_end933// catch934// ...935//936// - After:937// pre_bb: (new)938// range_end939// delegate_bb: (new)940// delegate941// post_bb: (previous 'ehpad')942// catch943// ...944assert(EndBB->isEHPad());945PreBB = MF.CreateMachineBasicBlock();946PostBB = EndBB;947MF.insert(PostBB->getIterator(), PreBB);948MF.insert(PostBB->getIterator(), DelegateBB);949PreBB->splice(PreBB->end(), PostBB, PostBB->begin(), SplitPos);950// We don't need to transfer predecessors of the EH pad to 'PreBB',951// because an EH pad's predecessors are all through unwind edges and they952// should still unwind to the EH pad, not PreBB.953}954unstackifyVRegsUsedInSplitBB(*PreBB, *PostBB);955PreBB->addSuccessor(DelegateBB);956PreBB->addSuccessor(PostBB);957}958959// Add 'delegate' instruction in the delegate BB created above.960MachineInstr *Delegate = BuildMI(DelegateBB, RangeEnd->getDebugLoc(),961TII.get(WebAssembly::DELEGATE))962.addMBB(DelegateDest);963registerTryScope(Try, Delegate, nullptr);964}965966bool WebAssemblyCFGStackify::fixCallUnwindMismatches(MachineFunction &MF) {967// Linearizing the control flow by placing TRY / END_TRY markers can create968// mismatches in unwind destinations for throwing instructions, such as calls.969//970// We use the 'delegate' instruction to fix the unwind mismatches. 'delegate'971// instruction delegates an exception to an outer 'catch'. It can target not972// only 'catch' but all block-like structures including another 'delegate',973// but with slightly different semantics than branches. When it targets a974// 'catch', it will delegate the exception to that catch. It is being975// discussed how to define the semantics when 'delegate''s target is a non-try976// block: it will either be a validation failure or it will target the next977// outer try-catch. But anyway our LLVM backend currently does not generate978// such code. The example below illustrates where the 'delegate' instruction979// in the middle will delegate the exception to, depending on the value of N.980// try981// try982// block983// try984// try985// call @foo986// delegate N ;; Where will this delegate to?987// catch ;; N == 0988// end989// end ;; N == 1 (invalid; will not be generated)990// delegate ;; N == 2991// catch ;; N == 3992// end993// ;; N == 4 (to caller)994995// 1. When an instruction may throw, but the EH pad it will unwind to can be996// different from the original CFG.997//998// Example: we have the following CFG:999// bb0:1000// call @foo ; if it throws, unwind to bb21001// bb1:1002// call @bar ; if it throws, unwind to bb31003// bb2 (ehpad):1004// catch1005// ...1006// bb3 (ehpad)1007// catch1008// ...1009//1010// And the CFG is sorted in this order. Then after placing TRY markers, it1011// will look like: (BB markers are omitted)1012// try1013// try1014// call @foo1015// call @bar ;; if it throws, unwind to bb31016// catch ;; ehpad (bb2)1017// ...1018// end_try1019// catch ;; ehpad (bb3)1020// ...1021// end_try1022//1023// Now if bar() throws, it is going to end up ip in bb2, not bb3, where it1024// is supposed to end up. We solve this problem by wrapping the mismatching1025// call with an inner try-delegate that rethrows the exception to the right1026// 'catch'.1027//1028// try1029// try1030// call @foo1031// try ;; (new)1032// call @bar1033// delegate 1 (bb3) ;; (new)1034// catch ;; ehpad (bb2)1035// ...1036// end_try1037// catch ;; ehpad (bb3)1038// ...1039// end_try1040//1041// ---1042// 2. The same as 1, but in this case an instruction unwinds to a caller1043// function and not another EH pad.1044//1045// Example: we have the following CFG:1046// bb0:1047// call @foo ; if it throws, unwind to bb21048// bb1:1049// call @bar ; if it throws, unwind to caller1050// bb2 (ehpad):1051// catch1052// ...1053//1054// And the CFG is sorted in this order. Then after placing TRY markers, it1055// will look like:1056// try1057// call @foo1058// call @bar ;; if it throws, unwind to caller1059// catch ;; ehpad (bb2)1060// ...1061// end_try1062//1063// Now if bar() throws, it is going to end up ip in bb2, when it is supposed1064// throw up to the caller. We solve this problem in the same way, but in this1065// case 'delegate's immediate argument is the number of block depths + 1,1066// which means it rethrows to the caller.1067// try1068// call @foo1069// try ;; (new)1070// call @bar1071// delegate 1 (caller) ;; (new)1072// catch ;; ehpad (bb2)1073// ...1074// end_try1075//1076// Before rewriteDepthImmediates, delegate's argument is a BB. In case of the1077// caller, it will take a fake BB generated by getFakeCallerBlock(), which1078// will be converted to a correct immediate argument later.1079//1080// In case there are multiple calls in a BB that may throw to the caller, they1081// can be wrapped together in one nested try-delegate scope. (In 1, this1082// couldn't happen, because may-throwing instruction there had an unwind1083// destination, i.e., it was an invoke before, and there could be only one1084// invoke within a BB.)10851086SmallVector<const MachineBasicBlock *, 8> EHPadStack;1087// Range of intructions to be wrapped in a new nested try/catch. A range1088// exists in a single BB and does not span multiple BBs.1089using TryRange = std::pair<MachineInstr *, MachineInstr *>;1090// In original CFG, <unwind destination BB, a vector of try ranges>1091DenseMap<MachineBasicBlock *, SmallVector<TryRange, 4>> UnwindDestToTryRanges;10921093// Gather possibly throwing calls (i.e., previously invokes) whose current1094// unwind destination is not the same as the original CFG. (Case 1)10951096for (auto &MBB : reverse(MF)) {1097bool SeenThrowableInstInBB = false;1098for (auto &MI : reverse(MBB)) {1099if (MI.getOpcode() == WebAssembly::TRY)1100EHPadStack.pop_back();1101else if (WebAssembly::isCatch(MI.getOpcode()))1102EHPadStack.push_back(MI.getParent());11031104// In this loop we only gather calls that have an EH pad to unwind. So1105// there will be at most 1 such call (= invoke) in a BB, so after we've1106// seen one, we can skip the rest of BB. Also if MBB has no EH pad1107// successor or MI does not throw, this is not an invoke.1108if (SeenThrowableInstInBB || !MBB.hasEHPadSuccessor() ||1109!WebAssembly::mayThrow(MI))1110continue;1111SeenThrowableInstInBB = true;11121113// If the EH pad on the stack top is where this instruction should unwind1114// next, we're good.1115MachineBasicBlock *UnwindDest = getFakeCallerBlock(MF);1116for (auto *Succ : MBB.successors()) {1117// Even though semantically a BB can have multiple successors in case an1118// exception is not caught by a catchpad, in our backend implementation1119// it is guaranteed that a BB can have at most one EH pad successor. For1120// details, refer to comments in findWasmUnwindDestinations function in1121// SelectionDAGBuilder.cpp.1122if (Succ->isEHPad()) {1123UnwindDest = Succ;1124break;1125}1126}1127if (EHPadStack.back() == UnwindDest)1128continue;11291130// Include EH_LABELs in the range before and afer the invoke1131MachineInstr *RangeBegin = &MI, *RangeEnd = &MI;1132if (RangeBegin->getIterator() != MBB.begin() &&1133std::prev(RangeBegin->getIterator())->isEHLabel())1134RangeBegin = &*std::prev(RangeBegin->getIterator());1135if (std::next(RangeEnd->getIterator()) != MBB.end() &&1136std::next(RangeEnd->getIterator())->isEHLabel())1137RangeEnd = &*std::next(RangeEnd->getIterator());11381139// If not, record the range.1140UnwindDestToTryRanges[UnwindDest].push_back(1141TryRange(RangeBegin, RangeEnd));1142LLVM_DEBUG(dbgs() << "- Call unwind mismatch: MBB = " << MBB.getName()1143<< "\nCall = " << MI1144<< "\nOriginal dest = " << UnwindDest->getName()1145<< " Current dest = " << EHPadStack.back()->getName()1146<< "\n\n");1147}1148}11491150assert(EHPadStack.empty());11511152// Gather possibly throwing calls that are supposed to unwind up to the caller1153// if they throw, but currently unwind to an incorrect destination. Unlike the1154// loop above, there can be multiple calls within a BB that unwind to the1155// caller, which we should group together in a range. (Case 2)11561157MachineInstr *RangeBegin = nullptr, *RangeEnd = nullptr; // inclusive11581159// Record the range.1160auto RecordCallerMismatchRange = [&](const MachineBasicBlock *CurrentDest) {1161UnwindDestToTryRanges[getFakeCallerBlock(MF)].push_back(1162TryRange(RangeBegin, RangeEnd));1163LLVM_DEBUG(dbgs() << "- Call unwind mismatch: MBB = "1164<< RangeBegin->getParent()->getName()1165<< "\nRange begin = " << *RangeBegin1166<< "Range end = " << *RangeEnd1167<< "\nOriginal dest = caller Current dest = "1168<< CurrentDest->getName() << "\n\n");1169RangeBegin = RangeEnd = nullptr; // Reset range pointers1170};11711172for (auto &MBB : reverse(MF)) {1173bool SeenThrowableInstInBB = false;1174for (auto &MI : reverse(MBB)) {1175bool MayThrow = WebAssembly::mayThrow(MI);11761177// If MBB has an EH pad successor and this is the last instruction that1178// may throw, this instruction unwinds to the EH pad and not to the1179// caller.1180if (MBB.hasEHPadSuccessor() && MayThrow && !SeenThrowableInstInBB)1181SeenThrowableInstInBB = true;11821183// We wrap up the current range when we see a marker even if we haven't1184// finished a BB.1185else if (RangeEnd && WebAssembly::isMarker(MI.getOpcode()))1186RecordCallerMismatchRange(EHPadStack.back());11871188// If EHPadStack is empty, that means it correctly unwinds to the caller1189// if it throws, so we're good. If MI does not throw, we're good too.1190else if (EHPadStack.empty() || !MayThrow) {1191}11921193// We found an instruction that unwinds to the caller but currently has an1194// incorrect unwind destination. Create a new range or increment the1195// currently existing range.1196else {1197if (!RangeEnd)1198RangeBegin = RangeEnd = &MI;1199else1200RangeBegin = &MI;1201}12021203// Update EHPadStack.1204if (MI.getOpcode() == WebAssembly::TRY)1205EHPadStack.pop_back();1206else if (WebAssembly::isCatch(MI.getOpcode()))1207EHPadStack.push_back(MI.getParent());1208}12091210if (RangeEnd)1211RecordCallerMismatchRange(EHPadStack.back());1212}12131214assert(EHPadStack.empty());12151216// We don't have any unwind destination mismatches to resolve.1217if (UnwindDestToTryRanges.empty())1218return false;12191220// Now we fix the mismatches by wrapping calls with inner try-delegates.1221for (auto &P : UnwindDestToTryRanges) {1222NumCallUnwindMismatches += P.second.size();1223MachineBasicBlock *UnwindDest = P.first;1224auto &TryRanges = P.second;12251226for (auto Range : TryRanges) {1227MachineInstr *RangeBegin = nullptr, *RangeEnd = nullptr;1228std::tie(RangeBegin, RangeEnd) = Range;1229auto *MBB = RangeBegin->getParent();12301231// If this BB has an EH pad successor, i.e., ends with an 'invoke', now we1232// are going to wrap the invoke with try-delegate, making the 'delegate'1233// BB the new successor instead, so remove the EH pad succesor here. The1234// BB may not have an EH pad successor if calls in this BB throw to the1235// caller.1236MachineBasicBlock *EHPad = nullptr;1237for (auto *Succ : MBB->successors()) {1238if (Succ->isEHPad()) {1239EHPad = Succ;1240break;1241}1242}1243if (EHPad)1244MBB->removeSuccessor(EHPad);12451246addTryDelegate(RangeBegin, RangeEnd, UnwindDest);1247}1248}12491250return true;1251}12521253bool WebAssemblyCFGStackify::fixCatchUnwindMismatches(MachineFunction &MF) {1254// There is another kind of unwind destination mismatches besides call unwind1255// mismatches, which we will call "catch unwind mismatches". See this example1256// after the marker placement:1257// try1258// try1259// call @foo1260// catch __cpp_exception ;; ehpad A (next unwind dest: caller)1261// ...1262// end_try1263// catch_all ;; ehpad B1264// ...1265// end_try1266//1267// 'call @foo's unwind destination is the ehpad A. But suppose 'call @foo'1268// throws a foreign exception that is not caught by ehpad A, and its next1269// destination should be the caller. But after control flow linearization,1270// another EH pad can be placed in between (e.g. ehpad B here), making the1271// next unwind destination incorrect. In this case, the foreign exception1272// will instead go to ehpad B and will be caught there instead. In this1273// example the correct next unwind destination is the caller, but it can be1274// another outer catch in other cases.1275//1276// There is no specific 'call' or 'throw' instruction to wrap with a1277// try-delegate, so we wrap the whole try-catch-end with a try-delegate and1278// make it rethrow to the right destination, as in the example below:1279// try1280// try ;; (new)1281// try1282// call @foo1283// catch __cpp_exception ;; ehpad A (next unwind dest: caller)1284// ...1285// end_try1286// delegate 1 (caller) ;; (new)1287// catch_all ;; ehpad B1288// ...1289// end_try12901291const auto *EHInfo = MF.getWasmEHFuncInfo();1292assert(EHInfo);1293SmallVector<const MachineBasicBlock *, 8> EHPadStack;1294// For EH pads that have catch unwind mismatches, a map of <EH pad, its1295// correct unwind destination>.1296DenseMap<MachineBasicBlock *, MachineBasicBlock *> EHPadToUnwindDest;12971298for (auto &MBB : reverse(MF)) {1299for (auto &MI : reverse(MBB)) {1300if (MI.getOpcode() == WebAssembly::TRY)1301EHPadStack.pop_back();1302else if (MI.getOpcode() == WebAssembly::DELEGATE)1303EHPadStack.push_back(&MBB);1304else if (WebAssembly::isCatch(MI.getOpcode())) {1305auto *EHPad = &MBB;13061307// catch_all always catches an exception, so we don't need to do1308// anything1309if (MI.getOpcode() == WebAssembly::CATCH_ALL) {1310}13111312// This can happen when the unwind dest was removed during the1313// optimization, e.g. because it was unreachable.1314else if (EHPadStack.empty() && EHInfo->hasUnwindDest(EHPad)) {1315LLVM_DEBUG(dbgs() << "EHPad (" << EHPad->getName()1316<< "'s unwind destination does not exist anymore"1317<< "\n\n");1318}13191320// The EHPad's next unwind destination is the caller, but we incorrectly1321// unwind to another EH pad.1322else if (!EHPadStack.empty() && !EHInfo->hasUnwindDest(EHPad)) {1323EHPadToUnwindDest[EHPad] = getFakeCallerBlock(MF);1324LLVM_DEBUG(dbgs()1325<< "- Catch unwind mismatch:\nEHPad = " << EHPad->getName()1326<< " Original dest = caller Current dest = "1327<< EHPadStack.back()->getName() << "\n\n");1328}13291330// The EHPad's next unwind destination is an EH pad, whereas we1331// incorrectly unwind to another EH pad.1332else if (!EHPadStack.empty() && EHInfo->hasUnwindDest(EHPad)) {1333auto *UnwindDest = EHInfo->getUnwindDest(EHPad);1334if (EHPadStack.back() != UnwindDest) {1335EHPadToUnwindDest[EHPad] = UnwindDest;1336LLVM_DEBUG(dbgs() << "- Catch unwind mismatch:\nEHPad = "1337<< EHPad->getName() << " Original dest = "1338<< UnwindDest->getName() << " Current dest = "1339<< EHPadStack.back()->getName() << "\n\n");1340}1341}13421343EHPadStack.push_back(EHPad);1344}1345}1346}13471348assert(EHPadStack.empty());1349if (EHPadToUnwindDest.empty())1350return false;1351NumCatchUnwindMismatches += EHPadToUnwindDest.size();1352SmallPtrSet<MachineBasicBlock *, 4> NewEndTryBBs;13531354for (auto &P : EHPadToUnwindDest) {1355MachineBasicBlock *EHPad = P.first;1356MachineBasicBlock *UnwindDest = P.second;1357MachineInstr *Try = EHPadToTry[EHPad];1358MachineInstr *EndTry = BeginToEnd[Try];1359addTryDelegate(Try, EndTry, UnwindDest);1360NewEndTryBBs.insert(EndTry->getParent());1361}13621363// Adding a try-delegate wrapping an existing try-catch-end can make existing1364// branch destination BBs invalid. For example,1365//1366// - Before:1367// bb0:1368// block1369// br bb31370// bb1:1371// try1372// ...1373// bb2: (ehpad)1374// catch1375// bb3:1376// end_try1377// end_block ;; 'br bb3' targets here1378//1379// Suppose this try-catch-end has a catch unwind mismatch, so we need to wrap1380// this with a try-delegate. Then this becomes:1381//1382// - After:1383// bb0:1384// block1385// br bb3 ;; invalid destination!1386// bb1:1387// try ;; (new instruction)1388// try1389// ...1390// bb2: (ehpad)1391// catch1392// bb3:1393// end_try ;; 'br bb3' still incorrectly targets here!1394// delegate_bb: ;; (new BB)1395// delegate ;; (new instruction)1396// split_bb: ;; (new BB)1397// end_block1398//1399// Now 'br bb3' incorrectly branches to an inner scope.1400//1401// As we can see in this case, when branches target a BB that has both1402// 'end_try' and 'end_block' and the BB is split to insert a 'delegate', we1403// have to remap existing branch destinations so that they target not the1404// 'end_try' BB but the new 'end_block' BB. There can be multiple 'delegate's1405// in between, so we try to find the next BB with 'end_block' instruction. In1406// this example, the 'br bb3' instruction should be remapped to 'br split_bb'.1407for (auto &MBB : MF) {1408for (auto &MI : MBB) {1409if (MI.isTerminator()) {1410for (auto &MO : MI.operands()) {1411if (MO.isMBB() && NewEndTryBBs.count(MO.getMBB())) {1412auto *BrDest = MO.getMBB();1413bool FoundEndBlock = false;1414for (; std::next(BrDest->getIterator()) != MF.end();1415BrDest = BrDest->getNextNode()) {1416for (const auto &MI : *BrDest) {1417if (MI.getOpcode() == WebAssembly::END_BLOCK) {1418FoundEndBlock = true;1419break;1420}1421}1422if (FoundEndBlock)1423break;1424}1425assert(FoundEndBlock);1426MO.setMBB(BrDest);1427}1428}1429}1430}1431}14321433return true;1434}14351436void WebAssemblyCFGStackify::recalculateScopeTops(MachineFunction &MF) {1437// Renumber BBs and recalculate ScopeTop info because new BBs might have been1438// created and inserted during fixing unwind mismatches.1439MF.RenumberBlocks();1440ScopeTops.clear();1441ScopeTops.resize(MF.getNumBlockIDs());1442for (auto &MBB : reverse(MF)) {1443for (auto &MI : reverse(MBB)) {1444if (ScopeTops[MBB.getNumber()])1445break;1446switch (MI.getOpcode()) {1447case WebAssembly::END_BLOCK:1448case WebAssembly::END_LOOP:1449case WebAssembly::END_TRY:1450case WebAssembly::DELEGATE:1451updateScopeTops(EndToBegin[&MI]->getParent(), &MBB);1452break;1453case WebAssembly::CATCH:1454case WebAssembly::CATCH_ALL:1455updateScopeTops(EHPadToTry[&MBB]->getParent(), &MBB);1456break;1457}1458}1459}1460}14611462/// In normal assembly languages, when the end of a function is unreachable,1463/// because the function ends in an infinite loop or a noreturn call or similar,1464/// it isn't necessary to worry about the function return type at the end of1465/// the function, because it's never reached. However, in WebAssembly, blocks1466/// that end at the function end need to have a return type signature that1467/// matches the function signature, even though it's unreachable. This function1468/// checks for such cases and fixes up the signatures.1469void WebAssemblyCFGStackify::fixEndsAtEndOfFunction(MachineFunction &MF) {1470const auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();14711472if (MFI.getResults().empty())1473return;14741475// MCInstLower will add the proper types to multivalue signatures based on the1476// function return type1477WebAssembly::BlockType RetType =1478MFI.getResults().size() > 11479? WebAssembly::BlockType::Multivalue1480: WebAssembly::BlockType(1481WebAssembly::toValType(MFI.getResults().front()));14821483SmallVector<MachineBasicBlock::reverse_iterator, 4> Worklist;1484Worklist.push_back(MF.rbegin()->rbegin());14851486auto Process = [&](MachineBasicBlock::reverse_iterator It) {1487auto *MBB = It->getParent();1488while (It != MBB->rend()) {1489MachineInstr &MI = *It++;1490if (MI.isPosition() || MI.isDebugInstr())1491continue;1492switch (MI.getOpcode()) {1493case WebAssembly::END_TRY: {1494// If a 'try''s return type is fixed, both its try body and catch body1495// should satisfy the return type, so we need to search 'end'1496// instructions before its corresponding 'catch' too.1497auto *EHPad = TryToEHPad.lookup(EndToBegin[&MI]);1498assert(EHPad);1499auto NextIt =1500std::next(WebAssembly::findCatch(EHPad)->getReverseIterator());1501if (NextIt != EHPad->rend())1502Worklist.push_back(NextIt);1503[[fallthrough]];1504}1505case WebAssembly::END_BLOCK:1506case WebAssembly::END_LOOP:1507case WebAssembly::DELEGATE:1508EndToBegin[&MI]->getOperand(0).setImm(int32_t(RetType));1509continue;1510default:1511// Something other than an `end`. We're done for this BB.1512return;1513}1514}1515// We've reached the beginning of a BB. Continue the search in the previous1516// BB.1517Worklist.push_back(MBB->getPrevNode()->rbegin());1518};15191520while (!Worklist.empty())1521Process(Worklist.pop_back_val());1522}15231524// WebAssembly functions end with an end instruction, as if the function body1525// were a block.1526static void appendEndToFunction(MachineFunction &MF,1527const WebAssemblyInstrInfo &TII) {1528BuildMI(MF.back(), MF.back().end(),1529MF.back().findPrevDebugLoc(MF.back().end()),1530TII.get(WebAssembly::END_FUNCTION));1531}15321533/// Insert LOOP/TRY/BLOCK markers at appropriate places.1534void WebAssemblyCFGStackify::placeMarkers(MachineFunction &MF) {1535// We allocate one more than the number of blocks in the function to1536// accommodate for the possible fake block we may insert at the end.1537ScopeTops.resize(MF.getNumBlockIDs() + 1);1538// Place the LOOP for MBB if MBB is the header of a loop.1539for (auto &MBB : MF)1540placeLoopMarker(MBB);15411542const MCAsmInfo *MCAI = MF.getTarget().getMCAsmInfo();1543for (auto &MBB : MF) {1544if (MBB.isEHPad()) {1545// Place the TRY for MBB if MBB is the EH pad of an exception.1546if (MCAI->getExceptionHandlingType() == ExceptionHandling::Wasm &&1547MF.getFunction().hasPersonalityFn())1548placeTryMarker(MBB);1549} else {1550// Place the BLOCK for MBB if MBB is branched to from above.1551placeBlockMarker(MBB);1552}1553}1554// Fix mismatches in unwind destinations induced by linearizing the code.1555if (MCAI->getExceptionHandlingType() == ExceptionHandling::Wasm &&1556MF.getFunction().hasPersonalityFn()) {1557bool Changed = fixCallUnwindMismatches(MF);1558Changed |= fixCatchUnwindMismatches(MF);1559if (Changed)1560recalculateScopeTops(MF);1561}1562}15631564unsigned WebAssemblyCFGStackify::getBranchDepth(1565const SmallVectorImpl<EndMarkerInfo> &Stack, const MachineBasicBlock *MBB) {1566unsigned Depth = 0;1567for (auto X : reverse(Stack)) {1568if (X.first == MBB)1569break;1570++Depth;1571}1572assert(Depth < Stack.size() && "Branch destination should be in scope");1573return Depth;1574}15751576unsigned WebAssemblyCFGStackify::getDelegateDepth(1577const SmallVectorImpl<EndMarkerInfo> &Stack, const MachineBasicBlock *MBB) {1578if (MBB == FakeCallerBB)1579return Stack.size();1580// Delegate's destination is either a catch or a another delegate BB. When the1581// destination is another delegate, we can compute the argument in the same1582// way as branches, because the target delegate BB only contains the single1583// delegate instruction.1584if (!MBB->isEHPad()) // Target is a delegate BB1585return getBranchDepth(Stack, MBB);15861587// When the delegate's destination is a catch BB, we need to use its1588// corresponding try's end_try BB because Stack contains each marker's end BB.1589// Also we need to check if the end marker instruction matches, because a1590// single BB can contain multiple end markers, like this:1591// bb:1592// END_BLOCK1593// END_TRY1594// END_BLOCK1595// END_TRY1596// ...1597//1598// In case of branches getting the immediate that targets any of these is1599// fine, but delegate has to exactly target the correct try.1600unsigned Depth = 0;1601const MachineInstr *EndTry = BeginToEnd[EHPadToTry[MBB]];1602for (auto X : reverse(Stack)) {1603if (X.first == EndTry->getParent() && X.second == EndTry)1604break;1605++Depth;1606}1607assert(Depth < Stack.size() && "Delegate destination should be in scope");1608return Depth;1609}16101611unsigned WebAssemblyCFGStackify::getRethrowDepth(1612const SmallVectorImpl<EndMarkerInfo> &Stack,1613const MachineBasicBlock *EHPadToRethrow) {1614unsigned Depth = 0;1615for (auto X : reverse(Stack)) {1616const MachineInstr *End = X.second;1617if (End->getOpcode() == WebAssembly::END_TRY) {1618auto *EHPad = TryToEHPad[EndToBegin[End]];1619if (EHPadToRethrow == EHPad)1620break;1621}1622++Depth;1623}1624assert(Depth < Stack.size() && "Rethrow destination should be in scope");1625return Depth;1626}16271628void WebAssemblyCFGStackify::rewriteDepthImmediates(MachineFunction &MF) {1629// Now rewrite references to basic blocks to be depth immediates.1630SmallVector<EndMarkerInfo, 8> Stack;1631for (auto &MBB : reverse(MF)) {1632for (MachineInstr &MI : llvm::reverse(MBB)) {1633switch (MI.getOpcode()) {1634case WebAssembly::BLOCK:1635case WebAssembly::TRY:1636assert(ScopeTops[Stack.back().first->getNumber()]->getNumber() <=1637MBB.getNumber() &&1638"Block/try marker should be balanced");1639Stack.pop_back();1640break;16411642case WebAssembly::LOOP:1643assert(Stack.back().first == &MBB && "Loop top should be balanced");1644Stack.pop_back();1645break;16461647case WebAssembly::END_BLOCK:1648case WebAssembly::END_TRY:1649Stack.push_back(std::make_pair(&MBB, &MI));1650break;16511652case WebAssembly::END_LOOP:1653Stack.push_back(std::make_pair(EndToBegin[&MI]->getParent(), &MI));1654break;16551656default:1657if (MI.isTerminator()) {1658// Rewrite MBB operands to be depth immediates.1659SmallVector<MachineOperand, 4> Ops(MI.operands());1660while (MI.getNumOperands() > 0)1661MI.removeOperand(MI.getNumOperands() - 1);1662for (auto MO : Ops) {1663if (MO.isMBB()) {1664if (MI.getOpcode() == WebAssembly::DELEGATE)1665MO = MachineOperand::CreateImm(1666getDelegateDepth(Stack, MO.getMBB()));1667else if (MI.getOpcode() == WebAssembly::RETHROW)1668MO = MachineOperand::CreateImm(1669getRethrowDepth(Stack, MO.getMBB()));1670else1671MO = MachineOperand::CreateImm(1672getBranchDepth(Stack, MO.getMBB()));1673}1674MI.addOperand(MF, MO);1675}1676}16771678if (MI.getOpcode() == WebAssembly::DELEGATE)1679Stack.push_back(std::make_pair(&MBB, &MI));1680break;1681}1682}1683}1684assert(Stack.empty() && "Control flow should be balanced");1685}16861687void WebAssemblyCFGStackify::cleanupFunctionData(MachineFunction &MF) {1688if (FakeCallerBB)1689MF.deleteMachineBasicBlock(FakeCallerBB);1690AppendixBB = FakeCallerBB = nullptr;1691}16921693void WebAssemblyCFGStackify::releaseMemory() {1694ScopeTops.clear();1695BeginToEnd.clear();1696EndToBegin.clear();1697TryToEHPad.clear();1698EHPadToTry.clear();1699}17001701bool WebAssemblyCFGStackify::runOnMachineFunction(MachineFunction &MF) {1702LLVM_DEBUG(dbgs() << "********** CFG Stackifying **********\n"1703"********** Function: "1704<< MF.getName() << '\n');1705const MCAsmInfo *MCAI = MF.getTarget().getMCAsmInfo();17061707releaseMemory();17081709// Liveness is not tracked for VALUE_STACK physreg.1710MF.getRegInfo().invalidateLiveness();17111712// Place the BLOCK/LOOP/TRY markers to indicate the beginnings of scopes.1713placeMarkers(MF);17141715// Remove unnecessary instructions possibly introduced by try/end_trys.1716if (MCAI->getExceptionHandlingType() == ExceptionHandling::Wasm &&1717MF.getFunction().hasPersonalityFn())1718removeUnnecessaryInstrs(MF);17191720// Convert MBB operands in terminators to relative depth immediates.1721rewriteDepthImmediates(MF);17221723// Fix up block/loop/try signatures at the end of the function to conform to1724// WebAssembly's rules.1725fixEndsAtEndOfFunction(MF);17261727// Add an end instruction at the end of the function body.1728const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();1729if (!MF.getSubtarget<WebAssemblySubtarget>()1730.getTargetTriple()1731.isOSBinFormatELF())1732appendEndToFunction(MF, TII);17331734cleanupFunctionData(MF);17351736MF.getInfo<WebAssemblyFunctionInfo>()->setCFGStackified();1737return true;1738}173917401741