14ba319b5SDimitry Andric //===--- WebAssemblyExceptionInfo.cpp - Exception Infomation --------------===//
24ba319b5SDimitry Andric //
34ba319b5SDimitry Andric // The LLVM Compiler Infrastructure
44ba319b5SDimitry Andric //
54ba319b5SDimitry Andric // This file is distributed under the University of Illinois Open Source
64ba319b5SDimitry Andric // License. See LICENSE.TXT for details.
74ba319b5SDimitry Andric //
84ba319b5SDimitry Andric //===----------------------------------------------------------------------===//
94ba319b5SDimitry Andric ///
104ba319b5SDimitry Andric /// \file
114ba319b5SDimitry Andric /// \brief This file implements WebAssemblyException information analysis.
124ba319b5SDimitry Andric ///
134ba319b5SDimitry Andric //===----------------------------------------------------------------------===//
144ba319b5SDimitry Andric
154ba319b5SDimitry Andric #include "WebAssemblyExceptionInfo.h"
164ba319b5SDimitry Andric #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
17*b5893f02SDimitry Andric #include "WebAssemblyUtilities.h"
184ba319b5SDimitry Andric #include "llvm/ADT/PostOrderIterator.h"
194ba319b5SDimitry Andric #include "llvm/CodeGen/MachineDominanceFrontier.h"
204ba319b5SDimitry Andric #include "llvm/CodeGen/MachineDominators.h"
214ba319b5SDimitry Andric
224ba319b5SDimitry Andric using namespace llvm;
234ba319b5SDimitry Andric
244ba319b5SDimitry Andric #define DEBUG_TYPE "wasm-exception-info"
254ba319b5SDimitry Andric
264ba319b5SDimitry Andric char WebAssemblyExceptionInfo::ID = 0;
274ba319b5SDimitry Andric
284ba319b5SDimitry Andric INITIALIZE_PASS_BEGIN(WebAssemblyExceptionInfo, DEBUG_TYPE,
294ba319b5SDimitry Andric "WebAssembly Exception Information", true, true)
INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree)304ba319b5SDimitry Andric INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree)
314ba319b5SDimitry Andric INITIALIZE_PASS_DEPENDENCY(MachineDominanceFrontier)
324ba319b5SDimitry Andric INITIALIZE_PASS_END(WebAssemblyExceptionInfo, DEBUG_TYPE,
334ba319b5SDimitry Andric "WebAssembly Exception Information", true, true)
344ba319b5SDimitry Andric
35*b5893f02SDimitry Andric bool WebAssemblyExceptionInfo::runOnMachineFunction(MachineFunction &MF) {
36*b5893f02SDimitry Andric LLVM_DEBUG(dbgs() << "********** Exception Info Calculation **********\n"
37*b5893f02SDimitry Andric "********** Function: "
38*b5893f02SDimitry Andric << MF.getName() << '\n');
394ba319b5SDimitry Andric releaseMemory();
404ba319b5SDimitry Andric auto &MDT = getAnalysis<MachineDominatorTree>();
414ba319b5SDimitry Andric auto &MDF = getAnalysis<MachineDominanceFrontier>();
424ba319b5SDimitry Andric recalculate(MDT, MDF);
434ba319b5SDimitry Andric return false;
444ba319b5SDimitry Andric }
454ba319b5SDimitry Andric
recalculate(MachineDominatorTree & MDT,const MachineDominanceFrontier & MDF)464ba319b5SDimitry Andric void WebAssemblyExceptionInfo::recalculate(
474ba319b5SDimitry Andric MachineDominatorTree &MDT, const MachineDominanceFrontier &MDF) {
484ba319b5SDimitry Andric // Postorder traversal of the dominator tree.
494ba319b5SDimitry Andric SmallVector<WebAssemblyException *, 8> Exceptions;
504ba319b5SDimitry Andric for (auto DomNode : post_order(&MDT)) {
514ba319b5SDimitry Andric MachineBasicBlock *EHPad = DomNode->getBlock();
524ba319b5SDimitry Andric if (!EHPad->isEHPad())
534ba319b5SDimitry Andric continue;
544ba319b5SDimitry Andric // We group catch & catch-all terminate pads together, so skip the second
554ba319b5SDimitry Andric // one
564ba319b5SDimitry Andric if (WebAssembly::isCatchAllTerminatePad(*EHPad))
574ba319b5SDimitry Andric continue;
584ba319b5SDimitry Andric auto *WE = new WebAssemblyException(EHPad);
594ba319b5SDimitry Andric discoverAndMapException(WE, MDT, MDF);
604ba319b5SDimitry Andric Exceptions.push_back(WE);
614ba319b5SDimitry Andric }
624ba319b5SDimitry Andric
634ba319b5SDimitry Andric // Add BBs to exceptions
644ba319b5SDimitry Andric for (auto DomNode : post_order(&MDT)) {
654ba319b5SDimitry Andric MachineBasicBlock *MBB = DomNode->getBlock();
664ba319b5SDimitry Andric WebAssemblyException *WE = getExceptionFor(MBB);
674ba319b5SDimitry Andric for (; WE; WE = WE->getParentException())
684ba319b5SDimitry Andric WE->addBlock(MBB);
694ba319b5SDimitry Andric }
704ba319b5SDimitry Andric
714ba319b5SDimitry Andric // Add subexceptions to exceptions
724ba319b5SDimitry Andric for (auto *WE : Exceptions) {
734ba319b5SDimitry Andric if (WE->getParentException())
744ba319b5SDimitry Andric WE->getParentException()->getSubExceptions().push_back(WE);
754ba319b5SDimitry Andric else
764ba319b5SDimitry Andric addTopLevelException(WE);
774ba319b5SDimitry Andric }
784ba319b5SDimitry Andric
794ba319b5SDimitry Andric // For convenience, Blocks and SubExceptions are inserted in postorder.
804ba319b5SDimitry Andric // Reverse the lists.
814ba319b5SDimitry Andric for (auto *WE : Exceptions) {
824ba319b5SDimitry Andric WE->reverseBlock();
834ba319b5SDimitry Andric std::reverse(WE->getSubExceptions().begin(), WE->getSubExceptions().end());
844ba319b5SDimitry Andric }
854ba319b5SDimitry Andric }
864ba319b5SDimitry Andric
releaseMemory()874ba319b5SDimitry Andric void WebAssemblyExceptionInfo::releaseMemory() {
884ba319b5SDimitry Andric BBMap.clear();
894ba319b5SDimitry Andric DeleteContainerPointers(TopLevelExceptions);
904ba319b5SDimitry Andric TopLevelExceptions.clear();
914ba319b5SDimitry Andric }
924ba319b5SDimitry Andric
getAnalysisUsage(AnalysisUsage & AU) const934ba319b5SDimitry Andric void WebAssemblyExceptionInfo::getAnalysisUsage(AnalysisUsage &AU) const {
944ba319b5SDimitry Andric AU.setPreservesAll();
954ba319b5SDimitry Andric AU.addRequired<MachineDominatorTree>();
964ba319b5SDimitry Andric AU.addRequired<MachineDominanceFrontier>();
974ba319b5SDimitry Andric MachineFunctionPass::getAnalysisUsage(AU);
984ba319b5SDimitry Andric }
994ba319b5SDimitry Andric
discoverAndMapException(WebAssemblyException * WE,const MachineDominatorTree & MDT,const MachineDominanceFrontier & MDF)1004ba319b5SDimitry Andric void WebAssemblyExceptionInfo::discoverAndMapException(
1014ba319b5SDimitry Andric WebAssemblyException *WE, const MachineDominatorTree &MDT,
1024ba319b5SDimitry Andric const MachineDominanceFrontier &MDF) {
1034ba319b5SDimitry Andric unsigned NumBlocks = 0;
1044ba319b5SDimitry Andric unsigned NumSubExceptions = 0;
1054ba319b5SDimitry Andric
1064ba319b5SDimitry Andric // Map blocks that belong to a catchpad / cleanuppad
1074ba319b5SDimitry Andric MachineBasicBlock *EHPad = WE->getEHPad();
1084ba319b5SDimitry Andric
1094ba319b5SDimitry Andric // We group catch & catch-all terminate pads together within an exception
1104ba319b5SDimitry Andric if (WebAssembly::isCatchTerminatePad(*EHPad)) {
1114ba319b5SDimitry Andric assert(EHPad->succ_size() == 1 &&
1124ba319b5SDimitry Andric "Catch terminate pad has more than one successors");
1134ba319b5SDimitry Andric changeExceptionFor(EHPad, WE);
1144ba319b5SDimitry Andric changeExceptionFor(*(EHPad->succ_begin()), WE);
1154ba319b5SDimitry Andric return;
1164ba319b5SDimitry Andric }
1174ba319b5SDimitry Andric
1184ba319b5SDimitry Andric SmallVector<MachineBasicBlock *, 8> WL;
1194ba319b5SDimitry Andric WL.push_back(EHPad);
1204ba319b5SDimitry Andric while (!WL.empty()) {
1214ba319b5SDimitry Andric MachineBasicBlock *MBB = WL.pop_back_val();
1224ba319b5SDimitry Andric
1234ba319b5SDimitry Andric // Find its outermost discovered exception. If this is a discovered block,
1244ba319b5SDimitry Andric // check if it is already discovered to be a subexception of this exception.
1254ba319b5SDimitry Andric WebAssemblyException *SubE = getOutermostException(MBB);
1264ba319b5SDimitry Andric if (SubE) {
1274ba319b5SDimitry Andric if (SubE != WE) {
1284ba319b5SDimitry Andric // Discover a subexception of this exception.
1294ba319b5SDimitry Andric SubE->setParentException(WE);
1304ba319b5SDimitry Andric ++NumSubExceptions;
1314ba319b5SDimitry Andric NumBlocks += SubE->getBlocksVector().capacity();
1324ba319b5SDimitry Andric // All blocks that belong to this subexception have been already
1334ba319b5SDimitry Andric // discovered. Skip all of them. Add the subexception's landing pad's
1344ba319b5SDimitry Andric // dominance frontier to the worklist.
1354ba319b5SDimitry Andric for (auto &Frontier : MDF.find(SubE->getEHPad())->second)
1364ba319b5SDimitry Andric if (MDT.dominates(EHPad, Frontier))
1374ba319b5SDimitry Andric WL.push_back(Frontier);
1384ba319b5SDimitry Andric }
1394ba319b5SDimitry Andric continue;
1404ba319b5SDimitry Andric }
1414ba319b5SDimitry Andric
1424ba319b5SDimitry Andric // This is an undiscovered block. Map it to the current exception.
1434ba319b5SDimitry Andric changeExceptionFor(MBB, WE);
1444ba319b5SDimitry Andric ++NumBlocks;
1454ba319b5SDimitry Andric
1464ba319b5SDimitry Andric // Add successors dominated by the current BB to the worklist.
1474ba319b5SDimitry Andric for (auto *Succ : MBB->successors())
1484ba319b5SDimitry Andric if (MDT.dominates(EHPad, Succ))
1494ba319b5SDimitry Andric WL.push_back(Succ);
1504ba319b5SDimitry Andric }
1514ba319b5SDimitry Andric
1524ba319b5SDimitry Andric WE->getSubExceptions().reserve(NumSubExceptions);
1534ba319b5SDimitry Andric WE->reserveBlocks(NumBlocks);
1544ba319b5SDimitry Andric }
1554ba319b5SDimitry Andric
1564ba319b5SDimitry Andric WebAssemblyException *
getOutermostException(MachineBasicBlock * MBB) const1574ba319b5SDimitry Andric WebAssemblyExceptionInfo::getOutermostException(MachineBasicBlock *MBB) const {
1584ba319b5SDimitry Andric WebAssemblyException *WE = getExceptionFor(MBB);
1594ba319b5SDimitry Andric if (WE) {
1604ba319b5SDimitry Andric while (WebAssemblyException *Parent = WE->getParentException())
1614ba319b5SDimitry Andric WE = Parent;
1624ba319b5SDimitry Andric }
1634ba319b5SDimitry Andric return WE;
1644ba319b5SDimitry Andric }
1654ba319b5SDimitry Andric
print(raw_ostream & OS,unsigned Depth) const1664ba319b5SDimitry Andric void WebAssemblyException::print(raw_ostream &OS, unsigned Depth) const {
1674ba319b5SDimitry Andric OS.indent(Depth * 2) << "Exception at depth " << getExceptionDepth()
1684ba319b5SDimitry Andric << " containing: ";
1694ba319b5SDimitry Andric
1704ba319b5SDimitry Andric for (unsigned I = 0; I < getBlocks().size(); ++I) {
1714ba319b5SDimitry Andric MachineBasicBlock *MBB = getBlocks()[I];
1724ba319b5SDimitry Andric if (I)
1734ba319b5SDimitry Andric OS << ", ";
1744ba319b5SDimitry Andric OS << "%bb." << MBB->getNumber();
1754ba319b5SDimitry Andric if (const auto *BB = MBB->getBasicBlock())
1764ba319b5SDimitry Andric if (BB->hasName())
1774ba319b5SDimitry Andric OS << "." << BB->getName();
1784ba319b5SDimitry Andric
1794ba319b5SDimitry Andric if (getEHPad() == MBB)
1804ba319b5SDimitry Andric OS << " (landing-pad)";
1814ba319b5SDimitry Andric }
1824ba319b5SDimitry Andric OS << "\n";
1834ba319b5SDimitry Andric
1844ba319b5SDimitry Andric for (auto &SubE : SubExceptions)
1854ba319b5SDimitry Andric SubE->print(OS, Depth + 2);
1864ba319b5SDimitry Andric }
1874ba319b5SDimitry Andric
1884ba319b5SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
dump() const1894ba319b5SDimitry Andric LLVM_DUMP_METHOD void WebAssemblyException::dump() const { print(dbgs()); }
1904ba319b5SDimitry Andric #endif
1914ba319b5SDimitry Andric
operator <<(raw_ostream & OS,const WebAssemblyException & WE)1924ba319b5SDimitry Andric raw_ostream &operator<<(raw_ostream &OS, const WebAssemblyException &WE) {
1934ba319b5SDimitry Andric WE.print(OS);
1944ba319b5SDimitry Andric return OS;
1954ba319b5SDimitry Andric }
1964ba319b5SDimitry Andric
print(raw_ostream & OS,const Module *) const1974ba319b5SDimitry Andric void WebAssemblyExceptionInfo::print(raw_ostream &OS, const Module *) const {
1984ba319b5SDimitry Andric for (auto *WE : TopLevelExceptions)
1994ba319b5SDimitry Andric WE->print(OS);
2004ba319b5SDimitry Andric }
201