xref: /freebsd/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyExceptionInfo.cpp (revision 5ffd83dbcc34f10e07f6d3e968ae6365869615f4)
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"
20480093f4SDimitry 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.
49*5ffd83dbSDimitry Andric   SmallVector<std::unique_ptr<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;
54*5ffd83dbSDimitry Andric     auto WE = std::make_unique<WebAssemblyException>(EHPad);
55*5ffd83dbSDimitry Andric     discoverAndMapException(WE.get(), MDT, MDF);
56*5ffd83dbSDimitry Andric     Exceptions.push_back(std::move(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 
67*5ffd83dbSDimitry Andric   SmallVector<WebAssemblyException*, 8> ExceptionPointers;
68*5ffd83dbSDimitry Andric   ExceptionPointers.reserve(Exceptions.size());
69*5ffd83dbSDimitry Andric 
700b57cec5SDimitry Andric   // Add subexceptions to exceptions
71*5ffd83dbSDimitry Andric   for (auto &WE : Exceptions) {
72*5ffd83dbSDimitry Andric     ExceptionPointers.push_back(WE.get());
730b57cec5SDimitry Andric     if (WE->getParentException())
74*5ffd83dbSDimitry Andric       WE->getParentException()->getSubExceptions().push_back(std::move(WE));
750b57cec5SDimitry Andric     else
76*5ffd83dbSDimitry Andric       addTopLevelException(std::move(WE));
770b57cec5SDimitry Andric   }
780b57cec5SDimitry Andric 
790b57cec5SDimitry Andric   // For convenience, Blocks and SubExceptions are inserted in postorder.
800b57cec5SDimitry Andric   // Reverse the lists.
81*5ffd83dbSDimitry Andric   for (auto *WE : ExceptionPointers) {
820b57cec5SDimitry Andric     WE->reverseBlock();
830b57cec5SDimitry Andric     std::reverse(WE->getSubExceptions().begin(), WE->getSubExceptions().end());
840b57cec5SDimitry Andric   }
850b57cec5SDimitry Andric }
860b57cec5SDimitry Andric 
870b57cec5SDimitry Andric void WebAssemblyExceptionInfo::releaseMemory() {
880b57cec5SDimitry Andric   BBMap.clear();
890b57cec5SDimitry Andric   TopLevelExceptions.clear();
900b57cec5SDimitry Andric }
910b57cec5SDimitry Andric 
920b57cec5SDimitry Andric void WebAssemblyExceptionInfo::getAnalysisUsage(AnalysisUsage &AU) const {
930b57cec5SDimitry Andric   AU.setPreservesAll();
940b57cec5SDimitry Andric   AU.addRequired<MachineDominatorTree>();
950b57cec5SDimitry Andric   AU.addRequired<MachineDominanceFrontier>();
960b57cec5SDimitry Andric   MachineFunctionPass::getAnalysisUsage(AU);
970b57cec5SDimitry Andric }
980b57cec5SDimitry Andric 
990b57cec5SDimitry Andric void WebAssemblyExceptionInfo::discoverAndMapException(
1000b57cec5SDimitry Andric     WebAssemblyException *WE, const MachineDominatorTree &MDT,
1010b57cec5SDimitry Andric     const MachineDominanceFrontier &MDF) {
1020b57cec5SDimitry Andric   unsigned NumBlocks = 0;
1030b57cec5SDimitry Andric   unsigned NumSubExceptions = 0;
1040b57cec5SDimitry Andric 
1050b57cec5SDimitry Andric   // Map blocks that belong to a catchpad / cleanuppad
1060b57cec5SDimitry Andric   MachineBasicBlock *EHPad = WE->getEHPad();
1070b57cec5SDimitry Andric   SmallVector<MachineBasicBlock *, 8> WL;
1080b57cec5SDimitry Andric   WL.push_back(EHPad);
1090b57cec5SDimitry Andric   while (!WL.empty()) {
1100b57cec5SDimitry Andric     MachineBasicBlock *MBB = WL.pop_back_val();
1110b57cec5SDimitry Andric 
1120b57cec5SDimitry Andric     // Find its outermost discovered exception. If this is a discovered block,
1130b57cec5SDimitry Andric     // check if it is already discovered to be a subexception of this exception.
1140b57cec5SDimitry Andric     WebAssemblyException *SubE = getOutermostException(MBB);
1150b57cec5SDimitry Andric     if (SubE) {
1160b57cec5SDimitry Andric       if (SubE != WE) {
1170b57cec5SDimitry Andric         // Discover a subexception of this exception.
1180b57cec5SDimitry Andric         SubE->setParentException(WE);
1190b57cec5SDimitry Andric         ++NumSubExceptions;
1200b57cec5SDimitry Andric         NumBlocks += SubE->getBlocksVector().capacity();
1210b57cec5SDimitry Andric         // All blocks that belong to this subexception have been already
1220b57cec5SDimitry Andric         // discovered. Skip all of them. Add the subexception's landing pad's
1230b57cec5SDimitry Andric         // dominance frontier to the worklist.
1240b57cec5SDimitry Andric         for (auto &Frontier : MDF.find(SubE->getEHPad())->second)
1250b57cec5SDimitry Andric           if (MDT.dominates(EHPad, Frontier))
1260b57cec5SDimitry Andric             WL.push_back(Frontier);
1270b57cec5SDimitry Andric       }
1280b57cec5SDimitry Andric       continue;
1290b57cec5SDimitry Andric     }
1300b57cec5SDimitry Andric 
1310b57cec5SDimitry Andric     // This is an undiscovered block. Map it to the current exception.
1320b57cec5SDimitry Andric     changeExceptionFor(MBB, WE);
1330b57cec5SDimitry Andric     ++NumBlocks;
1340b57cec5SDimitry Andric 
1350b57cec5SDimitry Andric     // Add successors dominated by the current BB to the worklist.
1360b57cec5SDimitry Andric     for (auto *Succ : MBB->successors())
1370b57cec5SDimitry Andric       if (MDT.dominates(EHPad, Succ))
1380b57cec5SDimitry Andric         WL.push_back(Succ);
1390b57cec5SDimitry Andric   }
1400b57cec5SDimitry Andric 
1410b57cec5SDimitry Andric   WE->getSubExceptions().reserve(NumSubExceptions);
1420b57cec5SDimitry Andric   WE->reserveBlocks(NumBlocks);
1430b57cec5SDimitry Andric }
1440b57cec5SDimitry Andric 
1450b57cec5SDimitry Andric WebAssemblyException *
1460b57cec5SDimitry Andric WebAssemblyExceptionInfo::getOutermostException(MachineBasicBlock *MBB) const {
1470b57cec5SDimitry Andric   WebAssemblyException *WE = getExceptionFor(MBB);
1480b57cec5SDimitry Andric   if (WE) {
1490b57cec5SDimitry Andric     while (WebAssemblyException *Parent = WE->getParentException())
1500b57cec5SDimitry Andric       WE = Parent;
1510b57cec5SDimitry Andric   }
1520b57cec5SDimitry Andric   return WE;
1530b57cec5SDimitry Andric }
1540b57cec5SDimitry Andric 
1550b57cec5SDimitry Andric void WebAssemblyException::print(raw_ostream &OS, unsigned Depth) const {
1560b57cec5SDimitry Andric   OS.indent(Depth * 2) << "Exception at depth " << getExceptionDepth()
1570b57cec5SDimitry Andric                        << " containing: ";
1580b57cec5SDimitry Andric 
1590b57cec5SDimitry Andric   for (unsigned I = 0; I < getBlocks().size(); ++I) {
1600b57cec5SDimitry Andric     MachineBasicBlock *MBB = getBlocks()[I];
1610b57cec5SDimitry Andric     if (I)
1620b57cec5SDimitry Andric       OS << ", ";
1630b57cec5SDimitry Andric     OS << "%bb." << MBB->getNumber();
1640b57cec5SDimitry Andric     if (const auto *BB = MBB->getBasicBlock())
1650b57cec5SDimitry Andric       if (BB->hasName())
1660b57cec5SDimitry Andric         OS << "." << BB->getName();
1670b57cec5SDimitry Andric 
1680b57cec5SDimitry Andric     if (getEHPad() == MBB)
1690b57cec5SDimitry Andric       OS << " (landing-pad)";
1700b57cec5SDimitry Andric   }
1710b57cec5SDimitry Andric   OS << "\n";
1720b57cec5SDimitry Andric 
1730b57cec5SDimitry Andric   for (auto &SubE : SubExceptions)
1740b57cec5SDimitry Andric     SubE->print(OS, Depth + 2);
1750b57cec5SDimitry Andric }
1760b57cec5SDimitry Andric 
1770b57cec5SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
1780b57cec5SDimitry Andric LLVM_DUMP_METHOD void WebAssemblyException::dump() const { print(dbgs()); }
1790b57cec5SDimitry Andric #endif
1800b57cec5SDimitry Andric 
1810b57cec5SDimitry Andric raw_ostream &operator<<(raw_ostream &OS, const WebAssemblyException &WE) {
1820b57cec5SDimitry Andric   WE.print(OS);
1830b57cec5SDimitry Andric   return OS;
1840b57cec5SDimitry Andric }
1850b57cec5SDimitry Andric 
1860b57cec5SDimitry Andric void WebAssemblyExceptionInfo::print(raw_ostream &OS, const Module *) const {
187*5ffd83dbSDimitry Andric   for (auto &WE : TopLevelExceptions)
1880b57cec5SDimitry Andric     WE->print(OS);
1890b57cec5SDimitry Andric }
190