xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyExceptionInfo.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
1*0b57cec5SDimitry Andric //===--- WebAssemblyExceptionInfo.cpp - Exception Infomation --------------===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric ///
9*0b57cec5SDimitry Andric /// \file
10*0b57cec5SDimitry Andric /// \brief This file implements WebAssemblyException information analysis.
11*0b57cec5SDimitry Andric ///
12*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
13*0b57cec5SDimitry Andric 
14*0b57cec5SDimitry Andric #include "WebAssemblyExceptionInfo.h"
15*0b57cec5SDimitry Andric #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
16*0b57cec5SDimitry Andric #include "WebAssemblyUtilities.h"
17*0b57cec5SDimitry Andric #include "llvm/ADT/PostOrderIterator.h"
18*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineDominanceFrontier.h"
19*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineDominators.h"
20*0b57cec5SDimitry Andric 
21*0b57cec5SDimitry Andric using namespace llvm;
22*0b57cec5SDimitry Andric 
23*0b57cec5SDimitry Andric #define DEBUG_TYPE "wasm-exception-info"
24*0b57cec5SDimitry Andric 
25*0b57cec5SDimitry Andric char WebAssemblyExceptionInfo::ID = 0;
26*0b57cec5SDimitry Andric 
27*0b57cec5SDimitry Andric INITIALIZE_PASS_BEGIN(WebAssemblyExceptionInfo, DEBUG_TYPE,
28*0b57cec5SDimitry Andric                       "WebAssembly Exception Information", true, true)
29*0b57cec5SDimitry Andric INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree)
30*0b57cec5SDimitry Andric INITIALIZE_PASS_DEPENDENCY(MachineDominanceFrontier)
31*0b57cec5SDimitry Andric INITIALIZE_PASS_END(WebAssemblyExceptionInfo, DEBUG_TYPE,
32*0b57cec5SDimitry Andric                     "WebAssembly Exception Information", true, true)
33*0b57cec5SDimitry Andric 
34*0b57cec5SDimitry Andric bool WebAssemblyExceptionInfo::runOnMachineFunction(MachineFunction &MF) {
35*0b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "********** Exception Info Calculation **********\n"
36*0b57cec5SDimitry Andric                        "********** Function: "
37*0b57cec5SDimitry Andric                     << MF.getName() << '\n');
38*0b57cec5SDimitry Andric   releaseMemory();
39*0b57cec5SDimitry Andric   auto &MDT = getAnalysis<MachineDominatorTree>();
40*0b57cec5SDimitry Andric   auto &MDF = getAnalysis<MachineDominanceFrontier>();
41*0b57cec5SDimitry Andric   recalculate(MDT, MDF);
42*0b57cec5SDimitry Andric   return false;
43*0b57cec5SDimitry Andric }
44*0b57cec5SDimitry Andric 
45*0b57cec5SDimitry Andric void WebAssemblyExceptionInfo::recalculate(
46*0b57cec5SDimitry Andric     MachineDominatorTree &MDT, const MachineDominanceFrontier &MDF) {
47*0b57cec5SDimitry Andric   // Postorder traversal of the dominator tree.
48*0b57cec5SDimitry Andric   SmallVector<WebAssemblyException *, 8> Exceptions;
49*0b57cec5SDimitry Andric   for (auto DomNode : post_order(&MDT)) {
50*0b57cec5SDimitry Andric     MachineBasicBlock *EHPad = DomNode->getBlock();
51*0b57cec5SDimitry Andric     if (!EHPad->isEHPad())
52*0b57cec5SDimitry Andric       continue;
53*0b57cec5SDimitry Andric     auto *WE = new WebAssemblyException(EHPad);
54*0b57cec5SDimitry Andric     discoverAndMapException(WE, MDT, MDF);
55*0b57cec5SDimitry Andric     Exceptions.push_back(WE);
56*0b57cec5SDimitry Andric   }
57*0b57cec5SDimitry Andric 
58*0b57cec5SDimitry Andric   // Add BBs to exceptions
59*0b57cec5SDimitry Andric   for (auto DomNode : post_order(&MDT)) {
60*0b57cec5SDimitry Andric     MachineBasicBlock *MBB = DomNode->getBlock();
61*0b57cec5SDimitry Andric     WebAssemblyException *WE = getExceptionFor(MBB);
62*0b57cec5SDimitry Andric     for (; WE; WE = WE->getParentException())
63*0b57cec5SDimitry Andric       WE->addBlock(MBB);
64*0b57cec5SDimitry Andric   }
65*0b57cec5SDimitry Andric 
66*0b57cec5SDimitry Andric   // Add subexceptions to exceptions
67*0b57cec5SDimitry Andric   for (auto *WE : Exceptions) {
68*0b57cec5SDimitry Andric     if (WE->getParentException())
69*0b57cec5SDimitry Andric       WE->getParentException()->getSubExceptions().push_back(WE);
70*0b57cec5SDimitry Andric     else
71*0b57cec5SDimitry Andric       addTopLevelException(WE);
72*0b57cec5SDimitry Andric   }
73*0b57cec5SDimitry Andric 
74*0b57cec5SDimitry Andric   // For convenience, Blocks and SubExceptions are inserted in postorder.
75*0b57cec5SDimitry Andric   // Reverse the lists.
76*0b57cec5SDimitry Andric   for (auto *WE : Exceptions) {
77*0b57cec5SDimitry Andric     WE->reverseBlock();
78*0b57cec5SDimitry Andric     std::reverse(WE->getSubExceptions().begin(), WE->getSubExceptions().end());
79*0b57cec5SDimitry Andric   }
80*0b57cec5SDimitry Andric }
81*0b57cec5SDimitry Andric 
82*0b57cec5SDimitry Andric void WebAssemblyExceptionInfo::releaseMemory() {
83*0b57cec5SDimitry Andric   BBMap.clear();
84*0b57cec5SDimitry Andric   DeleteContainerPointers(TopLevelExceptions);
85*0b57cec5SDimitry Andric   TopLevelExceptions.clear();
86*0b57cec5SDimitry Andric }
87*0b57cec5SDimitry Andric 
88*0b57cec5SDimitry Andric void WebAssemblyExceptionInfo::getAnalysisUsage(AnalysisUsage &AU) const {
89*0b57cec5SDimitry Andric   AU.setPreservesAll();
90*0b57cec5SDimitry Andric   AU.addRequired<MachineDominatorTree>();
91*0b57cec5SDimitry Andric   AU.addRequired<MachineDominanceFrontier>();
92*0b57cec5SDimitry Andric   MachineFunctionPass::getAnalysisUsage(AU);
93*0b57cec5SDimitry Andric }
94*0b57cec5SDimitry Andric 
95*0b57cec5SDimitry Andric void WebAssemblyExceptionInfo::discoverAndMapException(
96*0b57cec5SDimitry Andric     WebAssemblyException *WE, const MachineDominatorTree &MDT,
97*0b57cec5SDimitry Andric     const MachineDominanceFrontier &MDF) {
98*0b57cec5SDimitry Andric   unsigned NumBlocks = 0;
99*0b57cec5SDimitry Andric   unsigned NumSubExceptions = 0;
100*0b57cec5SDimitry Andric 
101*0b57cec5SDimitry Andric   // Map blocks that belong to a catchpad / cleanuppad
102*0b57cec5SDimitry Andric   MachineBasicBlock *EHPad = WE->getEHPad();
103*0b57cec5SDimitry Andric   SmallVector<MachineBasicBlock *, 8> WL;
104*0b57cec5SDimitry Andric   WL.push_back(EHPad);
105*0b57cec5SDimitry Andric   while (!WL.empty()) {
106*0b57cec5SDimitry Andric     MachineBasicBlock *MBB = WL.pop_back_val();
107*0b57cec5SDimitry Andric 
108*0b57cec5SDimitry Andric     // Find its outermost discovered exception. If this is a discovered block,
109*0b57cec5SDimitry Andric     // check if it is already discovered to be a subexception of this exception.
110*0b57cec5SDimitry Andric     WebAssemblyException *SubE = getOutermostException(MBB);
111*0b57cec5SDimitry Andric     if (SubE) {
112*0b57cec5SDimitry Andric       if (SubE != WE) {
113*0b57cec5SDimitry Andric         // Discover a subexception of this exception.
114*0b57cec5SDimitry Andric         SubE->setParentException(WE);
115*0b57cec5SDimitry Andric         ++NumSubExceptions;
116*0b57cec5SDimitry Andric         NumBlocks += SubE->getBlocksVector().capacity();
117*0b57cec5SDimitry Andric         // All blocks that belong to this subexception have been already
118*0b57cec5SDimitry Andric         // discovered. Skip all of them. Add the subexception's landing pad's
119*0b57cec5SDimitry Andric         // dominance frontier to the worklist.
120*0b57cec5SDimitry Andric         for (auto &Frontier : MDF.find(SubE->getEHPad())->second)
121*0b57cec5SDimitry Andric           if (MDT.dominates(EHPad, Frontier))
122*0b57cec5SDimitry Andric             WL.push_back(Frontier);
123*0b57cec5SDimitry Andric       }
124*0b57cec5SDimitry Andric       continue;
125*0b57cec5SDimitry Andric     }
126*0b57cec5SDimitry Andric 
127*0b57cec5SDimitry Andric     // This is an undiscovered block. Map it to the current exception.
128*0b57cec5SDimitry Andric     changeExceptionFor(MBB, WE);
129*0b57cec5SDimitry Andric     ++NumBlocks;
130*0b57cec5SDimitry Andric 
131*0b57cec5SDimitry Andric     // Add successors dominated by the current BB to the worklist.
132*0b57cec5SDimitry Andric     for (auto *Succ : MBB->successors())
133*0b57cec5SDimitry Andric       if (MDT.dominates(EHPad, Succ))
134*0b57cec5SDimitry Andric         WL.push_back(Succ);
135*0b57cec5SDimitry Andric   }
136*0b57cec5SDimitry Andric 
137*0b57cec5SDimitry Andric   WE->getSubExceptions().reserve(NumSubExceptions);
138*0b57cec5SDimitry Andric   WE->reserveBlocks(NumBlocks);
139*0b57cec5SDimitry Andric }
140*0b57cec5SDimitry Andric 
141*0b57cec5SDimitry Andric WebAssemblyException *
142*0b57cec5SDimitry Andric WebAssemblyExceptionInfo::getOutermostException(MachineBasicBlock *MBB) const {
143*0b57cec5SDimitry Andric   WebAssemblyException *WE = getExceptionFor(MBB);
144*0b57cec5SDimitry Andric   if (WE) {
145*0b57cec5SDimitry Andric     while (WebAssemblyException *Parent = WE->getParentException())
146*0b57cec5SDimitry Andric       WE = Parent;
147*0b57cec5SDimitry Andric   }
148*0b57cec5SDimitry Andric   return WE;
149*0b57cec5SDimitry Andric }
150*0b57cec5SDimitry Andric 
151*0b57cec5SDimitry Andric void WebAssemblyException::print(raw_ostream &OS, unsigned Depth) const {
152*0b57cec5SDimitry Andric   OS.indent(Depth * 2) << "Exception at depth " << getExceptionDepth()
153*0b57cec5SDimitry Andric                        << " containing: ";
154*0b57cec5SDimitry Andric 
155*0b57cec5SDimitry Andric   for (unsigned I = 0; I < getBlocks().size(); ++I) {
156*0b57cec5SDimitry Andric     MachineBasicBlock *MBB = getBlocks()[I];
157*0b57cec5SDimitry Andric     if (I)
158*0b57cec5SDimitry Andric       OS << ", ";
159*0b57cec5SDimitry Andric     OS << "%bb." << MBB->getNumber();
160*0b57cec5SDimitry Andric     if (const auto *BB = MBB->getBasicBlock())
161*0b57cec5SDimitry Andric       if (BB->hasName())
162*0b57cec5SDimitry Andric         OS << "." << BB->getName();
163*0b57cec5SDimitry Andric 
164*0b57cec5SDimitry Andric     if (getEHPad() == MBB)
165*0b57cec5SDimitry Andric       OS << " (landing-pad)";
166*0b57cec5SDimitry Andric   }
167*0b57cec5SDimitry Andric   OS << "\n";
168*0b57cec5SDimitry Andric 
169*0b57cec5SDimitry Andric   for (auto &SubE : SubExceptions)
170*0b57cec5SDimitry Andric     SubE->print(OS, Depth + 2);
171*0b57cec5SDimitry Andric }
172*0b57cec5SDimitry Andric 
173*0b57cec5SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
174*0b57cec5SDimitry Andric LLVM_DUMP_METHOD void WebAssemblyException::dump() const { print(dbgs()); }
175*0b57cec5SDimitry Andric #endif
176*0b57cec5SDimitry Andric 
177*0b57cec5SDimitry Andric raw_ostream &operator<<(raw_ostream &OS, const WebAssemblyException &WE) {
178*0b57cec5SDimitry Andric   WE.print(OS);
179*0b57cec5SDimitry Andric   return OS;
180*0b57cec5SDimitry Andric }
181*0b57cec5SDimitry Andric 
182*0b57cec5SDimitry Andric void WebAssemblyExceptionInfo::print(raw_ostream &OS, const Module *) const {
183*0b57cec5SDimitry Andric   for (auto *WE : TopLevelExceptions)
184*0b57cec5SDimitry Andric     WE->print(OS);
185*0b57cec5SDimitry Andric }
186