Index: include/llvm/CodeGen/MachineFunction.h =================================================================== --- include/llvm/CodeGen/MachineFunction.h +++ include/llvm/CodeGen/MachineFunction.h @@ -73,6 +73,7 @@ class TargetMachine; class TargetRegisterClass; class TargetSubtargetInfo; +struct WasmEHFuncInfo; struct WinEHFuncInfo; template <> struct ilist_alloc_traits { @@ -245,6 +246,10 @@ // Keep track of jump tables for switch instructions MachineJumpTableInfo *JumpTableInfo; + // Keeps track of Wasm exception handling related data. This will be null for + // functions that aren't using a wasm EH personality. + WasmEHFuncInfo *WasmEHInfo = nullptr; + // Keeps track of Windows exception handling related data. This will be null // for functions that aren't using a funclet-based EH personality. WinEHFuncInfo *WinEHInfo = nullptr; @@ -432,6 +437,12 @@ MachineConstantPool *getConstantPool() { return ConstantPool; } const MachineConstantPool *getConstantPool() const { return ConstantPool; } + /// getWasmEHFuncInfo - Return information about how the current function uses + /// Wasm exception handling. Returns null for functions that don't use wasm + /// exception handling. + const WasmEHFuncInfo *getWasmEHFuncInfo() const { return WasmEHInfo; } + WasmEHFuncInfo *getWasmEHFuncInfo() { return WasmEHInfo; } + /// getWinEHFuncInfo - Return information about how the current function uses /// Windows exception handling. Returns null for functions that don't use /// funclets for exception handling. Index: include/llvm/CodeGen/WasmEHFuncInfo.h =================================================================== --- /dev/null +++ include/llvm/CodeGen/WasmEHFuncInfo.h @@ -0,0 +1,75 @@ +//===--- llvm/CodeGen/WasmEHFuncInfo.h --------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Data structures for Wasm exception handling schemes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_WASMEHFUNCINFO_H +#define LLVM_CODEGEN_WASMEHFUNCINFO_H + +namespace llvm { + +using BBOrMBB = PointerUnion; + +struct WasmEHFuncInfo { + // When there is an entry , if an exception is not caught by A, it + // should next unwind to the EH pad B. + DenseMap EHPadUnwindMap; + // For entry , A is a BB with an instruction that may throw + // (invoke/cleanupret in LLVM IR, call/rethrow in the backend) and B is an EH + // pad that A unwinds to. + DenseMap ThrowUnwindMap; + + // Helper functions + const BasicBlock *getEHPadUnwindDest(const BasicBlock *BB) const { + return EHPadUnwindMap.lookup(BB).get(); + } + void setEHPadUnwindDest(const BasicBlock *BB, const BasicBlock *Dest) { + EHPadUnwindMap[BB] = Dest; + } + const BasicBlock *getThrowUnwindDest(BasicBlock *BB) const { + return ThrowUnwindMap.lookup(BB).get(); + } + void setThrowUnwindDest(const BasicBlock *BB, const BasicBlock *Dest) { + ThrowUnwindMap[BB] = Dest; + } + bool hasEHPadUnwindDest(const BasicBlock *BB) const { + return EHPadUnwindMap.count(BB); + } + bool hasThrowUnwindDest(const BasicBlock *BB) const { + return ThrowUnwindMap.count(BB); + } + + MachineBasicBlock *getEHPadUnwindDest(MachineBasicBlock *MBB) const { + return EHPadUnwindMap.lookup(MBB).get(); + } + void setEHPadUnwindDest(MachineBasicBlock *MBB, MachineBasicBlock *Dest) { + EHPadUnwindMap[MBB] = Dest; + } + MachineBasicBlock *getThrowUnwindDest(MachineBasicBlock *MBB) const { + return ThrowUnwindMap.lookup(MBB).get(); + } + void setThrowUnwindDest(MachineBasicBlock *MBB, MachineBasicBlock *Dest) { + ThrowUnwindMap[MBB] = Dest; + } + bool hasEHPadUnwindDest(MachineBasicBlock *MBB) const { + return EHPadUnwindMap.count(MBB); + } + bool hasThrowUnwindDest(MachineBasicBlock *MBB) const { + return ThrowUnwindMap.count(MBB); + } +}; + +// Analyze the IR in the given function to build WasmEHFuncInfo. +void calculateWasmEHInfo(const Function *F, WasmEHFuncInfo &FuncInfo); + +}; // namespace llvm + +#endif // LLVM_CODEGEN_WASMEHFUNCINFO_H Index: lib/CodeGen/MachineFunction.cpp =================================================================== --- lib/CodeGen/MachineFunction.cpp +++ lib/CodeGen/MachineFunction.cpp @@ -37,6 +37,7 @@ #include "llvm/CodeGen/TargetLowering.h" #include "llvm/CodeGen/TargetRegisterInfo.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" +#include "llvm/CodeGen/WasmEHFuncInfo.h" #include "llvm/CodeGen/WinEHFuncInfo.h" #include "llvm/Config/llvm-config.h" #include "llvm/IR/Attributes.h" @@ -175,6 +176,11 @@ WinEHInfo = new (Allocator) WinEHFuncInfo(); } + if (isScopedEHPersonality(classifyEHPersonality( + F.hasPersonalityFn() ? F.getPersonalityFn() : nullptr))) { + WasmEHInfo = new (Allocator) WasmEHFuncInfo(); + } + assert(Target.isCompatibleDataLayout(getDataLayout()) && "Can't create a MachineFunction using a Module with a " "Target-incompatible DataLayout attached\n"); Index: lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp =================================================================== --- lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp +++ lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp @@ -23,6 +23,7 @@ #include "llvm/CodeGen/TargetLowering.h" #include "llvm/CodeGen/TargetRegisterInfo.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" +#include "llvm/CodeGen/WasmEHFuncInfo.h" #include "llvm/CodeGen/WinEHFuncInfo.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DerivedTypes.h" @@ -118,6 +119,10 @@ } } } + if (Personality == EHPersonality::Wasm_CXX) { + WasmEHFuncInfo &EHInfo = *MF->getWasmEHFuncInfo(); + calculateWasmEHInfo(&fn, EHInfo); + } // Initialize the mapping of values to registers. This is only set up for // instruction values that are used outside of the block that defines @@ -282,28 +287,46 @@ } } - if (!isFuncletEHPersonality(Personality)) - return; - - WinEHFuncInfo &EHInfo = *MF->getWinEHFuncInfo(); + if (isFuncletEHPersonality(Personality)) { + WinEHFuncInfo &EHInfo = *MF->getWinEHFuncInfo(); - // Map all BB references in the WinEH data to MBBs. - for (WinEHTryBlockMapEntry &TBME : EHInfo.TryBlockMap) { - for (WinEHHandlerType &H : TBME.HandlerArray) { - if (H.Handler) - H.Handler = MBBMap[H.Handler.get()]; + // Map all BB references in the WinEH data to MBBs. + for (WinEHTryBlockMapEntry &TBME : EHInfo.TryBlockMap) { + for (WinEHHandlerType &H : TBME.HandlerArray) { + if (H.Handler) + H.Handler = MBBMap[H.Handler.get()]; + } + } + for (CxxUnwindMapEntry &UME : EHInfo.CxxUnwindMap) + if (UME.Cleanup) + UME.Cleanup = MBBMap[UME.Cleanup.get()]; + for (SEHUnwindMapEntry &UME : EHInfo.SEHUnwindMap) { + const auto *BB = UME.Handler.get(); + UME.Handler = MBBMap[BB]; + } + for (ClrEHUnwindMapEntry &CME : EHInfo.ClrEHUnwindMap) { + const auto *BB = CME.Handler.get(); + CME.Handler = MBBMap[BB]; } } - for (CxxUnwindMapEntry &UME : EHInfo.CxxUnwindMap) - if (UME.Cleanup) - UME.Cleanup = MBBMap[UME.Cleanup.get()]; - for (SEHUnwindMapEntry &UME : EHInfo.SEHUnwindMap) { - const BasicBlock *BB = UME.Handler.get(); - UME.Handler = MBBMap[BB]; - } - for (ClrEHUnwindMapEntry &CME : EHInfo.ClrEHUnwindMap) { - const BasicBlock *BB = CME.Handler.get(); - CME.Handler = MBBMap[BB]; + + else if (Personality == EHPersonality::Wasm_CXX) { + WasmEHFuncInfo &EHInfo = *MF->getWasmEHFuncInfo(); + // Map all BB references in the WinEH data to MBBs. + DenseMap NewMap; + for (auto &KV : EHInfo.EHPadUnwindMap) { + const auto *Src = KV.first.get(); + const auto *Dst = KV.second.get(); + NewMap[MBBMap[Src]] = MBBMap[Dst]; + } + EHInfo.EHPadUnwindMap = std::move(NewMap); + NewMap.clear(); + for (auto &KV : EHInfo.ThrowUnwindMap) { + const auto *Src = KV.first.get(); + const auto *Dst = KV.second.get(); + NewMap[MBBMap[Src]] = MBBMap[Dst]; + } + EHInfo.ThrowUnwindMap = std::move(NewMap); } } Index: lib/CodeGen/WasmEHPrepare.cpp =================================================================== --- lib/CodeGen/WasmEHPrepare.cpp +++ lib/CodeGen/WasmEHPrepare.cpp @@ -116,6 +116,7 @@ #include "llvm/CodeGen/Passes.h" #include "llvm/CodeGen/TargetLowering.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" +#include "llvm/CodeGen/WasmEHFuncInfo.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Intrinsics.h" @@ -329,3 +330,45 @@ GetSelectorCI->replaceAllUsesWith(Selector); GetSelectorCI->eraseFromParent(); } + +void llvm::calculateWasmEHInfo(const Function *F, WasmEHFuncInfo &EHInfo) { + for (const auto &BB : *F) { + if (!BB.isEHPad()) + continue; + const Instruction *Pad = BB.getFirstNonPHI(); + + // If an exception is not caught by a catchpad (i.e., it is a foreign + // exception), it will unwind to its parent catchswitch's unwind + // destination. We don't record an unwind destination for cleanuppads + // because every exception should be caught by it. + if (const auto *CatchPad = dyn_cast(Pad)) { + const auto *UnwindBB = CatchPad->getCatchSwitch()->getUnwindDest(); + if (!UnwindBB) + continue; + const Instruction *UnwindPad = UnwindBB->getFirstNonPHI(); + if (const auto *CatchSwitch = dyn_cast(UnwindPad)) + // Currently there should be only one handler per a catchswitch. + EHInfo.setEHPadUnwindDest(&BB, *CatchSwitch->handlers().begin()); + else // cleanuppad + EHInfo.setEHPadUnwindDest(&BB, UnwindBB); + } + } + + // Record the unwind destination for invoke and cleanupret instructions. + for (const auto &BB : *F) { + const Instruction *TI = BB.getTerminator(); + BasicBlock *UnwindBB = nullptr; + if (const auto *Invoke = dyn_cast(TI)) + UnwindBB = Invoke->getUnwindDest(); + else if (const auto *CleanupRet = dyn_cast(TI)) + UnwindBB = CleanupRet->getUnwindDest(); + if (!UnwindBB) + continue; + const Instruction *UnwindPad = UnwindBB->getFirstNonPHI(); + if (const auto *CatchSwitch = dyn_cast(UnwindPad)) + // Currently there should be only one handler per a catchswitch. + EHInfo.setThrowUnwindDest(&BB, *CatchSwitch->handlers().begin()); + else // cleanuppad + EHInfo.setThrowUnwindDest(&BB, UnwindBB); + } +}