1//===--- WebAssemblyExceptionInfo.cpp - Exception Infomation --------------===//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//===----------------------------------------------------------------------===//
10/// \brief This file implements WebAssemblyException information analysis.
12//===----------------------------------------------------------------------===//
28 #define DEBUG_TYPE "wasm-exception-info"
33 "WebAssembly Exception Information",
true,
true)
37 "WebAssembly Exception Information",
true,
true)
40 LLVM_DEBUG(
dbgs() <<
"********** Exception Info Calculation **********\n"
41 "********** Function: "
42 << MF.getName() <<
'\n');
44 if (MF.getTarget().getMCAsmInfo()->getExceptionHandlingType() !=
46 !MF.getFunction().hasPersonalityFn())
55// Check if Dst is reachable from Src using BFS. Search only within BBs
56// dominated by Header.
71 for (
auto *Succ :
MBB->successors())
81 // Postorder traversal of the dominator tree.
87 auto WE = std::make_unique<WebAssemblyException>(EHPad);
88 discoverAndMapException(WE.get(), MDT, MDF);
92 // WasmEHFuncInfo contains a map of <catchpad, its next unwind destination>,
93 // which means, if an exception is not caught by the catchpad, it should end
94 // up in the next unwind destination stored in this data structure. (It is
95 // written as catchswitch's 'unwind' destination in ll files.) The below is an
96 // intuitive example of their relationship in C++ code:
99 // } catch (int) { // catchpad
100 // ... // this catch (int) { ... } is grouped as an exception
102 // } catch (...) { // next unwind destination
104 // (The example is try-catches for illustration purpose, but the unwind
105 // destination can be also a cleanuppad generated by destructor calls.) So the
106 // unwind destination is in the outside of the catchpad's exception.
108 // We group exceptions in this analysis simply by including all BBs dominated
109 // by an EH pad. But in case the EH pad's unwind destination does not have any
110 // children outside of the exception, that unwind destination ends up also
111 // being dominated by the EH pad and included in the exception, which is not
112 // semantically correct, because it unwinds/rethrows into an inner scope.
114 // Here we extract those unwind destinations from their (incorrect) parent
115 // exception. Note that the unwind destinations may not be an immediate
116 // children of the parent exception, so we have to traverse the parent chain.
118 // We should traverse BBs in the preorder of the dominator tree, because
119 // otherwise the result can be incorrect. For example, when there are three
120 // exceptions A, B, and C and A > B > C (> is subexception relationship here),
121 // and A's unwind destination is B and B's is C. When we visit B before A, we
122 // end up extracting C only out of B but not out of A.
131 if (!EHInfo->hasUnwindDest(EHPad))
133 auto *UnwindDest = EHInfo->getUnwindDest(EHPad);
136 if (SrcWE->contains(DstWE)) {
137 UnwindWEVec.
push_back(std::make_pair(SrcWE, DstWE));
139 << DstWE->getEHPad()->getNumber() <<
"."
140 << DstWE->getEHPad()->getName()
141 <<
"'s exception is taken out of "
142 << SrcWE->getEHPad()->getNumber() <<
"."
143 << SrcWE->getEHPad()->getName() <<
"'s exception\n");
144 DstWE->setParentException(SrcWE->getParentException());
148 // After fixing subexception relationship between unwind destinations above,
149 // there can still be remaining discrepancies.
151 // For example, suppose Exception A is dominated by EHPad A and Exception B is
152 // dominated by EHPad B. EHPad A's unwind destination is EHPad B, but because
153 // EHPad B is dominated by EHPad A, the initial grouping makes Exception B a
154 // subexception of Exception A, and we fix it by taking Exception B out of
155 // Exception A above. But there can still be remaining BBs within Exception A
156 // that are reachable from Exception B. These BBs semantically don't belong
157 // to Exception A and were not a part of this 'catch' clause or cleanup code
158 // in the original code, but they just happened to be grouped within Exception
159 // A because they were dominated by EHPad A. We fix this case by taking those
160 // BBs out of the incorrect exception and all its subexceptions that it
163 // 1. First, we take out remaining incorrect subexceptions. This part is
164 // easier, because we haven't added BBs to exceptions yet, we only need to
165 // change parent exception pointer.
172 // For each source EHPad -> unwind destination EHPad
173 for (
auto &
P : UnwindWEVec) {
174 auto *SrcWE =
P.first;
175 auto *DstWE =
P.second;
176 // If WE (the current EH pad's exception) is still contained in SrcWE but
177 // reachable from DstWE that was taken out of SrcWE above, we have to take
178 // out WE out of SrcWE too.
179 if (WE != SrcWE && SrcWE->contains(WE) && !DstWE->contains(WE) &&
183 << WE->getEHPad()->getNumber() <<
"."
184 << WE->getEHPad()->getName()
185 <<
"'s exception is taken out of "
186 << SrcWE->getEHPad()->getNumber() <<
"."
187 << SrcWE->getEHPad()->getName() <<
"'s exception\n");
188 WE->setParentException(SrcWE->getParentException());
193 // Add BBs to exceptions' block set. This is a preparation to take out
194 // remaining incorect BBs from exceptions, because we need to iterate over BBs
195 // for each exception.
203 // 2. We take out remaining individual BBs out. Now we have added BBs to each
204 // exceptions' BlockSet, when we take a BB out of an exception, we need to fix
206 for (
auto &
P : UnwindWEVec) {
207 auto *SrcWE =
P.first;
208 auto *DstWE =
P.second;
211 if (
MBB->isEHPad()) {
213 SrcWE->getEHPad(), MDT) &&
214 "We already handled EH pads above");
220 <<
MBB->getName() <<
" is\n");
222 while (InnerWE != SrcWE) {
226 <<
"'s exception\n");
230 LLVM_DEBUG(
dbgs() <<
" removed from " << SrcWE->getEHPad()->getNumber()
231 <<
"." << SrcWE->getEHPad()->getName()
232 <<
"'s exception\n");
234 if (SrcWE->getParentException())
235 SrcWE->getParentException()->addToBlocksSet(
MBB);
242 // Add BBs to exceptions' block vector
253 // Add subexceptions to exceptions
254 for (
auto &WE : Exceptions) {
256 if (WE->getParentException())
257 WE->getParentException()->getSubExceptions().push_back(std::move(WE));
262 // For convenience, Blocks and SubExceptions are inserted in postorder.
263 // Reverse the lists.
264 for (
auto *WE : ExceptionPointers) {
266 std::reverse(WE->getSubExceptions().begin(), WE->getSubExceptions().end());
272 TopLevelExceptions.clear();
282void WebAssemblyExceptionInfo::discoverAndMapException(
285 unsigned NumBlocks = 0;
286 unsigned NumSubExceptions = 0;
288 // Map blocks that belong to a catchpad / cleanuppad
292 while (!WL.
empty()) {
295 // Find its outermost discovered exception. If this is a discovered block,
296 // check if it is already discovered to be a subexception of this exception.
300 // Discover a subexception of this exception.
304 // All blocks that belong to this subexception have been already
305 // discovered. Skip all of them. Add the subexception's landing pad's
306 // dominance frontier to the worklist.
307 for (
auto &Frontier : MDF.
find(SubE->
getEHPad())->second)
314 // This is an undiscovered block. Map it to the current exception.
318 // Add successors dominated by the current BB to the worklist.
346 OS <<
"%bb." <<
MBB->getNumber();
347 if (
const auto *BB =
MBB->getBasicBlock())
349 OS <<
"." << BB->getName();
352 OS <<
" (landing-pad)";
356 for (
auto &SubE : SubExceptions)
360#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
370 for (
auto &WE : TopLevelExceptions)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
#define LLVM_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds.
This file builds on the ADT/GraphTraits.h file to build generic depth first graph iterator.
#define INITIALIZE_PASS_DEPENDENCY(depName)
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
This file builds on the ADT/GraphTraits.h file to build a generic graph post order iterator.
static bool isReachableAmongDominated(const MachineBasicBlock *Src, const MachineBasicBlock *Dst, const MachineBasicBlock *Header, const MachineDominatorTree &MDT)
This file implements WebAssemblyException information analysis.
This file contains the declaration of the WebAssembly-specific utility functions.
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
void setPreservesAll()
Set by analyses that do not transform their input at all.
bool isEHPad() const
Returns true if the block is a landing pad.
int getNumber() const
MachineBasicBlocks are uniquely numbered at the function level, unless they're not in a MachineFuncti...
iterator_range< succ_iterator > successors()
LLVM_ABI StringRef getName() const
Return the name of the corresponding LLVM basic block, or an empty string.
iterator find(MachineBasicBlock *B)
Analysis pass which computes a MachineDominatorTree.
DominatorTree Class - Concrete subclass of DominatorTreeBase that is used to compute a normal dominat...
bool dominates(const MachineInstr *A, const MachineInstr *B) const
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
const WasmEHFuncInfo * getWasmEHFuncInfo() const
getWasmEHFuncInfo - Return information about how the current function uses Wasm exception handling.
A Module instance is used to store all the information related to an LLVM module.
AnalysisType & getAnalysis() const
getAnalysis<AnalysisType>() - This function is used by subclasses to get to the analysis information ...
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
void reserve(size_type N)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
WebAssemblyExceptionInfo()
void changeExceptionFor(const MachineBasicBlock *MBB, WebAssemblyException *WE)
bool runOnMachineFunction(MachineFunction &) override
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
void addTopLevelException(std::unique_ptr< WebAssemblyException > WE)
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
void recalculate(MachineFunction &MF, MachineDominatorTree &MDT, const MachineDominanceFrontier &MDF)
WebAssemblyException * getExceptionFor(const MachineBasicBlock *MBB) const
void print(raw_ostream &OS, const Module *M=nullptr) const override
print - Print out the internal state of the pass.
void releaseMemory() override
releaseMemory() - This member can be implemented by a pass if it wants to be able to release its memo...
void print(raw_ostream &OS, unsigned Depth=0) const
MachineBasicBlock * getEHPad() const
void addToBlocksSet(MachineBasicBlock *MBB)
void reserveBlocks(unsigned Size)
const std::vector< std::unique_ptr< WebAssemblyException > > & getSubExceptions() const
ArrayRef< MachineBasicBlock * > getBlocks() const
std::vector< MachineBasicBlock * > & getBlocksVector()
WebAssemblyException * getParentException() const
void removeFromBlocksSet(MachineBasicBlock *MBB)
unsigned getExceptionDepth() const
void setParentException(WebAssemblyException *WE)
void addToBlocksVector(MachineBasicBlock *MBB)
This class implements an extremely fast bulk output stream that can only output to a stream.
raw_ostream & indent(unsigned NumSpaces)
indent - Insert 'NumSpaces' spaces.
This is an optimization pass for GlobalISel generic memory operations.
void dump(const SparseBitVector< ElementSize > &LHS, raw_ostream &out)
@ Wasm
WebAssembly Exception Handling.
iterator_range< po_iterator< T > > post_order(const T &G)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
raw_ostream & operator<<(raw_ostream &OS, const APFixedPoint &FX)
iterator_range< df_iterator< T > > depth_first(const T &G)