| //===-- WebAssemblyExceptionInfo.h - WebAssembly Exception Info -*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| /// |
| /// \file |
| /// \brief This file implements WebAssemblyException information analysis. |
| /// |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_LIB_TARGET_WEBASSEMBLY_WEBASSEMBLYEXCEPTIONINFO_H |
| #define LLVM_LIB_TARGET_WEBASSEMBLY_WEBASSEMBLYEXCEPTIONINFO_H |
| |
| #include "WebAssembly.h" |
| #include "llvm/ADT/SetVector.h" |
| #include "llvm/CodeGen/MachineFunctionPass.h" |
| |
| namespace llvm { |
| |
| class MachineDominatorTree; |
| class MachineDominanceFrontier; |
| |
| // WebAssembly instructions for exception handling are structured as follows: |
| // try |
| // instructions* |
| // catch ----| |
| // instructions* | -> A WebAssemblyException consists of this region |
| // end ----| |
| // |
| // A WebAssemblyException object contains BBs that belong to a 'catch' part of |
| // the try-catch-end structure to be created later. 'try' and 'end' markers |
| // are not present at this stage and will be generated in CFGStackify pass. |
| // Because CFGSort requires all the BBs within a catch part to be sorted |
| // together as it does for loops, this pass calculates the nesting structure of |
| // catch part of exceptions in a function. |
| // |
| // An exception catch part is defined as a BB with catch instruction and all |
| // other BBs dominated by this BB. |
| class WebAssemblyException { |
| MachineBasicBlock *EHPad = nullptr; |
| |
| WebAssemblyException *ParentException = nullptr; |
| std::vector<std::unique_ptr<WebAssemblyException>> SubExceptions; |
| std::vector<MachineBasicBlock *> Blocks; |
| SmallPtrSet<MachineBasicBlock *, 8> BlockSet; |
| |
| public: |
| WebAssemblyException(MachineBasicBlock *EHPad) : EHPad(EHPad) {} |
| WebAssemblyException(const WebAssemblyException &) = delete; |
| const WebAssemblyException &operator=(const WebAssemblyException &) = delete; |
| |
| MachineBasicBlock *getEHPad() const { return EHPad; } |
| MachineBasicBlock *getHeader() const { return EHPad; } |
| WebAssemblyException *getParentException() const { return ParentException; } |
| void setParentException(WebAssemblyException *WE) { ParentException = WE; } |
| |
| bool contains(const WebAssemblyException *WE) const { |
| if (WE == this) |
| return true; |
| if (!WE) |
| return false; |
| return contains(WE->getParentException()); |
| } |
| bool contains(const MachineBasicBlock *MBB) const { |
| return BlockSet.count(MBB); |
| } |
| |
| void addToBlocksSet(MachineBasicBlock *MBB) { BlockSet.insert(MBB); } |
| void removeFromBlocksSet(MachineBasicBlock *MBB) { BlockSet.erase(MBB); } |
| void addToBlocksVector(MachineBasicBlock *MBB) { Blocks.push_back(MBB); } |
| void addBlock(MachineBasicBlock *MBB) { |
| Blocks.push_back(MBB); |
| BlockSet.insert(MBB); |
| } |
| ArrayRef<MachineBasicBlock *> getBlocks() const { return Blocks; } |
| using block_iterator = typename ArrayRef<MachineBasicBlock *>::const_iterator; |
| block_iterator block_begin() const { return getBlocks().begin(); } |
| block_iterator block_end() const { return getBlocks().end(); } |
| inline iterator_range<block_iterator> blocks() const { |
| return make_range(block_begin(), block_end()); |
| } |
| unsigned getNumBlocks() const { return Blocks.size(); } |
| std::vector<MachineBasicBlock *> &getBlocksVector() { return Blocks; } |
| SmallPtrSetImpl<MachineBasicBlock *> &getBlocksSet() { return BlockSet; } |
| |
| const std::vector<std::unique_ptr<WebAssemblyException>> & |
| getSubExceptions() const { |
| return SubExceptions; |
| } |
| std::vector<std::unique_ptr<WebAssemblyException>> &getSubExceptions() { |
| return SubExceptions; |
| } |
| void addSubException(std::unique_ptr<WebAssemblyException> E) { |
| SubExceptions.push_back(std::move(E)); |
| } |
| using iterator = typename decltype(SubExceptions)::const_iterator; |
| iterator begin() const { return SubExceptions.begin(); } |
| iterator end() const { return SubExceptions.end(); } |
| |
| void reserveBlocks(unsigned Size) { Blocks.reserve(Size); } |
| void reverseBlock(unsigned From = 0) { |
| std::reverse(Blocks.begin() + From, Blocks.end()); |
| } |
| |
| // Return the nesting level. An outermost one has depth 1. |
| unsigned getExceptionDepth() const { |
| unsigned D = 1; |
| for (const WebAssemblyException *CurException = ParentException; |
| CurException; CurException = CurException->ParentException) |
| ++D; |
| return D; |
| } |
| |
| void print(raw_ostream &OS, unsigned Depth = 0) const; |
| void dump() const; |
| }; |
| |
| raw_ostream &operator<<(raw_ostream &OS, const WebAssemblyException &WE); |
| |
| class WebAssemblyExceptionInfo final : public MachineFunctionPass { |
| // Mapping of basic blocks to the innermost exception they occur in |
| DenseMap<const MachineBasicBlock *, WebAssemblyException *> BBMap; |
| std::vector<std::unique_ptr<WebAssemblyException>> TopLevelExceptions; |
| |
| void discoverAndMapException(WebAssemblyException *WE, |
| const MachineDominatorTree &MDT, |
| const MachineDominanceFrontier &MDF); |
| WebAssemblyException *getOutermostException(MachineBasicBlock *MBB) const; |
| |
| public: |
| static char ID; |
| WebAssemblyExceptionInfo() : MachineFunctionPass(ID) { |
| initializeWebAssemblyExceptionInfoPass(*PassRegistry::getPassRegistry()); |
| } |
| ~WebAssemblyExceptionInfo() override { releaseMemory(); } |
| WebAssemblyExceptionInfo(const WebAssemblyExceptionInfo &) = delete; |
| WebAssemblyExceptionInfo & |
| operator=(const WebAssemblyExceptionInfo &) = delete; |
| |
| bool runOnMachineFunction(MachineFunction &) override; |
| void releaseMemory() override; |
| void recalculate(MachineFunction &MF, MachineDominatorTree &MDT, |
| const MachineDominanceFrontier &MDF); |
| void getAnalysisUsage(AnalysisUsage &AU) const override; |
| |
| bool empty() const { return TopLevelExceptions.empty(); } |
| |
| // Return the innermost exception that MBB lives in. If the block is not in an |
| // exception, null is returned. |
| WebAssemblyException *getExceptionFor(const MachineBasicBlock *MBB) const { |
| return BBMap.lookup(MBB); |
| } |
| |
| void changeExceptionFor(const MachineBasicBlock *MBB, |
| WebAssemblyException *WE) { |
| if (!WE) { |
| BBMap.erase(MBB); |
| return; |
| } |
| BBMap[MBB] = WE; |
| } |
| |
| void addTopLevelException(std::unique_ptr<WebAssemblyException> WE) { |
| assert(!WE->getParentException() && "Not a top level exception!"); |
| TopLevelExceptions.push_back(std::move(WE)); |
| } |
| |
| void print(raw_ostream &OS, const Module *M = nullptr) const override; |
| }; |
| |
| } // end namespace llvm |
| |
| #endif |