xref: /freebsd/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyExceptionInfo.cpp (revision 480093f4440d54b30b3025afeac24b48f2ba7a2e)
10b57cec5SDimitry Andric //===--- WebAssemblyExceptionInfo.cpp - Exception Infomation --------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric ///
90b57cec5SDimitry Andric /// \file
100b57cec5SDimitry Andric /// \brief This file implements WebAssemblyException information analysis.
110b57cec5SDimitry Andric ///
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "WebAssemblyExceptionInfo.h"
150b57cec5SDimitry Andric #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
160b57cec5SDimitry Andric #include "WebAssemblyUtilities.h"
170b57cec5SDimitry Andric #include "llvm/ADT/PostOrderIterator.h"
180b57cec5SDimitry Andric #include "llvm/CodeGen/MachineDominanceFrontier.h"
190b57cec5SDimitry Andric #include "llvm/CodeGen/MachineDominators.h"
20*480093f4SDimitry Andric #include "llvm/InitializePasses.h"
210b57cec5SDimitry Andric 
220b57cec5SDimitry Andric using namespace llvm;
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric #define DEBUG_TYPE "wasm-exception-info"
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric char WebAssemblyExceptionInfo::ID = 0;
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric INITIALIZE_PASS_BEGIN(WebAssemblyExceptionInfo, DEBUG_TYPE,
290b57cec5SDimitry Andric                       "WebAssembly Exception Information", true, true)
300b57cec5SDimitry Andric INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree)
310b57cec5SDimitry Andric INITIALIZE_PASS_DEPENDENCY(MachineDominanceFrontier)
320b57cec5SDimitry Andric INITIALIZE_PASS_END(WebAssemblyExceptionInfo, DEBUG_TYPE,
330b57cec5SDimitry Andric                     "WebAssembly Exception Information", true, true)
340b57cec5SDimitry Andric 
350b57cec5SDimitry Andric bool WebAssemblyExceptionInfo::runOnMachineFunction(MachineFunction &MF) {
360b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "********** Exception Info Calculation **********\n"
370b57cec5SDimitry Andric                        "********** Function: "
380b57cec5SDimitry Andric                     << MF.getName() << '\n');
390b57cec5SDimitry Andric   releaseMemory();
400b57cec5SDimitry Andric   auto &MDT = getAnalysis<MachineDominatorTree>();
410b57cec5SDimitry Andric   auto &MDF = getAnalysis<MachineDominanceFrontier>();
420b57cec5SDimitry Andric   recalculate(MDT, MDF);
430b57cec5SDimitry Andric   return false;
440b57cec5SDimitry Andric }
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric void WebAssemblyExceptionInfo::recalculate(
470b57cec5SDimitry Andric     MachineDominatorTree &MDT, const MachineDominanceFrontier &MDF) {
480b57cec5SDimitry Andric   // Postorder traversal of the dominator tree.
490b57cec5SDimitry Andric   SmallVector<WebAssemblyException *, 8> Exceptions;
500b57cec5SDimitry Andric   for (auto DomNode : post_order(&MDT)) {
510b57cec5SDimitry Andric     MachineBasicBlock *EHPad = DomNode->getBlock();
520b57cec5SDimitry Andric     if (!EHPad->isEHPad())
530b57cec5SDimitry Andric       continue;
540b57cec5SDimitry Andric     auto *WE = new WebAssemblyException(EHPad);
550b57cec5SDimitry Andric     discoverAndMapException(WE, MDT, MDF);
560b57cec5SDimitry Andric     Exceptions.push_back(WE);
570b57cec5SDimitry Andric   }
580b57cec5SDimitry Andric 
590b57cec5SDimitry Andric   // Add BBs to exceptions
600b57cec5SDimitry Andric   for (auto DomNode : post_order(&MDT)) {
610b57cec5SDimitry Andric     MachineBasicBlock *MBB = DomNode->getBlock();
620b57cec5SDimitry Andric     WebAssemblyException *WE = getExceptionFor(MBB);
630b57cec5SDimitry Andric     for (; WE; WE = WE->getParentException())
640b57cec5SDimitry Andric       WE->addBlock(MBB);
650b57cec5SDimitry Andric   }
660b57cec5SDimitry Andric 
670b57cec5SDimitry Andric   // Add subexceptions to exceptions
680b57cec5SDimitry Andric   for (auto *WE : Exceptions) {
690b57cec5SDimitry Andric     if (WE->getParentException())
700b57cec5SDimitry Andric       WE->getParentException()->getSubExceptions().push_back(WE);
710b57cec5SDimitry Andric     else
720b57cec5SDimitry Andric       addTopLevelException(WE);
730b57cec5SDimitry Andric   }
740b57cec5SDimitry Andric 
750b57cec5SDimitry Andric   // For convenience, Blocks and SubExceptions are inserted in postorder.
760b57cec5SDimitry Andric   // Reverse the lists.
770b57cec5SDimitry Andric   for (auto *WE : Exceptions) {
780b57cec5SDimitry Andric     WE->reverseBlock();
790b57cec5SDimitry Andric     std::reverse(WE->getSubExceptions().begin(), WE->getSubExceptions().end());
800b57cec5SDimitry Andric   }
810b57cec5SDimitry Andric }
820b57cec5SDimitry Andric 
830b57cec5SDimitry Andric void WebAssemblyExceptionInfo::releaseMemory() {
840b57cec5SDimitry Andric   BBMap.clear();
850b57cec5SDimitry Andric   DeleteContainerPointers(TopLevelExceptions);
860b57cec5SDimitry Andric   TopLevelExceptions.clear();
870b57cec5SDimitry Andric }
880b57cec5SDimitry Andric 
890b57cec5SDimitry Andric void WebAssemblyExceptionInfo::getAnalysisUsage(AnalysisUsage &AU) const {
900b57cec5SDimitry Andric   AU.setPreservesAll();
910b57cec5SDimitry Andric   AU.addRequired<MachineDominatorTree>();
920b57cec5SDimitry Andric   AU.addRequired<MachineDominanceFrontier>();
930b57cec5SDimitry Andric   MachineFunctionPass::getAnalysisUsage(AU);
940b57cec5SDimitry Andric }
950b57cec5SDimitry Andric 
960b57cec5SDimitry Andric void WebAssemblyExceptionInfo::discoverAndMapException(
970b57cec5SDimitry Andric     WebAssemblyException *WE, const MachineDominatorTree &MDT,
980b57cec5SDimitry Andric     const MachineDominanceFrontier &MDF) {
990b57cec5SDimitry Andric   unsigned NumBlocks = 0;
1000b57cec5SDimitry Andric   unsigned NumSubExceptions = 0;
1010b57cec5SDimitry Andric 
1020b57cec5SDimitry Andric   // Map blocks that belong to a catchpad / cleanuppad
1030b57cec5SDimitry Andric   MachineBasicBlock *EHPad = WE->getEHPad();
1040b57cec5SDimitry Andric   SmallVector<MachineBasicBlock *, 8> WL;
1050b57cec5SDimitry Andric   WL.push_back(EHPad);
1060b57cec5SDimitry Andric   while (!WL.empty()) {
1070b57cec5SDimitry Andric     MachineBasicBlock *MBB = WL.pop_back_val();
1080b57cec5SDimitry Andric 
1090b57cec5SDimitry Andric     // Find its outermost discovered exception. If this is a discovered block,
1100b57cec5SDimitry Andric     // check if it is already discovered to be a subexception of this exception.
1110b57cec5SDimitry Andric     WebAssemblyException *SubE = getOutermostException(MBB);
1120b57cec5SDimitry Andric     if (SubE) {
1130b57cec5SDimitry Andric       if (SubE != WE) {
1140b57cec5SDimitry Andric         // Discover a subexception of this exception.
1150b57cec5SDimitry Andric         SubE->setParentException(WE);
1160b57cec5SDimitry Andric         ++NumSubExceptions;
1170b57cec5SDimitry Andric         NumBlocks += SubE->getBlocksVector().capacity();
1180b57cec5SDimitry Andric         // All blocks that belong to this subexception have been already
1190b57cec5SDimitry Andric         // discovered. Skip all of them. Add the subexception's landing pad's
1200b57cec5SDimitry Andric         // dominance frontier to the worklist.
1210b57cec5SDimitry Andric         for (auto &Frontier : MDF.find(SubE->getEHPad())->second)
1220b57cec5SDimitry Andric           if (MDT.dominates(EHPad, Frontier))
1230b57cec5SDimitry Andric             WL.push_back(Frontier);
1240b57cec5SDimitry Andric       }
1250b57cec5SDimitry Andric       continue;
1260b57cec5SDimitry Andric     }
1270b57cec5SDimitry Andric 
1280b57cec5SDimitry Andric     // This is an undiscovered block. Map it to the current exception.
1290b57cec5SDimitry Andric     changeExceptionFor(MBB, WE);
1300b57cec5SDimitry Andric     ++NumBlocks;
1310b57cec5SDimitry Andric 
1320b57cec5SDimitry Andric     // Add successors dominated by the current BB to the worklist.
1330b57cec5SDimitry Andric     for (auto *Succ : MBB->successors())
1340b57cec5SDimitry Andric       if (MDT.dominates(EHPad, Succ))
1350b57cec5SDimitry Andric         WL.push_back(Succ);
1360b57cec5SDimitry Andric   }
1370b57cec5SDimitry Andric 
1380b57cec5SDimitry Andric   WE->getSubExceptions().reserve(NumSubExceptions);
1390b57cec5SDimitry Andric   WE->reserveBlocks(NumBlocks);
1400b57cec5SDimitry Andric }
1410b57cec5SDimitry Andric 
1420b57cec5SDimitry Andric WebAssemblyException *
1430b57cec5SDimitry Andric WebAssemblyExceptionInfo::getOutermostException(MachineBasicBlock *MBB) const {
1440b57cec5SDimitry Andric   WebAssemblyException *WE = getExceptionFor(MBB);
1450b57cec5SDimitry Andric   if (WE) {
1460b57cec5SDimitry Andric     while (WebAssemblyException *Parent = WE->getParentException())
1470b57cec5SDimitry Andric       WE = Parent;
1480b57cec5SDimitry Andric   }
1490b57cec5SDimitry Andric   return WE;
1500b57cec5SDimitry Andric }
1510b57cec5SDimitry Andric 
1520b57cec5SDimitry Andric void WebAssemblyException::print(raw_ostream &OS, unsigned Depth) const {
1530b57cec5SDimitry Andric   OS.indent(Depth * 2) << "Exception at depth " << getExceptionDepth()
1540b57cec5SDimitry Andric                        << " containing: ";
1550b57cec5SDimitry Andric 
1560b57cec5SDimitry Andric   for (unsigned I = 0; I < getBlocks().size(); ++I) {
1570b57cec5SDimitry Andric     MachineBasicBlock *MBB = getBlocks()[I];
1580b57cec5SDimitry Andric     if (I)
1590b57cec5SDimitry Andric       OS << ", ";
1600b57cec5SDimitry Andric     OS << "%bb." << MBB->getNumber();
1610b57cec5SDimitry Andric     if (const auto *BB = MBB->getBasicBlock())
1620b57cec5SDimitry Andric       if (BB->hasName())
1630b57cec5SDimitry Andric         OS << "." << BB->getName();
1640b57cec5SDimitry Andric 
1650b57cec5SDimitry Andric     if (getEHPad() == MBB)
1660b57cec5SDimitry Andric       OS << " (landing-pad)";
1670b57cec5SDimitry Andric   }
1680b57cec5SDimitry Andric   OS << "\n";
1690b57cec5SDimitry Andric 
1700b57cec5SDimitry Andric   for (auto &SubE : SubExceptions)
1710b57cec5SDimitry Andric     SubE->print(OS, Depth + 2);
1720b57cec5SDimitry Andric }
1730b57cec5SDimitry Andric 
1740b57cec5SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
1750b57cec5SDimitry Andric LLVM_DUMP_METHOD void WebAssemblyException::dump() const { print(dbgs()); }
1760b57cec5SDimitry Andric #endif
1770b57cec5SDimitry Andric 
1780b57cec5SDimitry Andric raw_ostream &operator<<(raw_ostream &OS, const WebAssemblyException &WE) {
1790b57cec5SDimitry Andric   WE.print(OS);
1800b57cec5SDimitry Andric   return OS;
1810b57cec5SDimitry Andric }
1820b57cec5SDimitry Andric 
1830b57cec5SDimitry Andric void WebAssemblyExceptionInfo::print(raw_ostream &OS, const Module *) const {
1840b57cec5SDimitry Andric   for (auto *WE : TopLevelExceptions)
1850b57cec5SDimitry Andric     WE->print(OS);
1860b57cec5SDimitry Andric }
187