126 using namespace llvm;
128 #define DEBUG_TYPE "wasmehprepare" 132 Type *LPadContextTy =
nullptr;
136 Value *LPadIndexField =
nullptr;
137 Value *LSDAField =
nullptr;
138 Value *SelectorField =
nullptr;
146 Function *CallPersonalityF =
nullptr;
153 void prepareTerminateCleanupPad(
BasicBlock *BB);
160 bool doInitialization(
Module &M)
override;
164 return "WebAssembly Exception handling preparation";
175 bool WasmEHPrepare::doInitialization(
Module &M) {
186 template <
typename Container>
189 while (!WL.empty()) {
199 bool Changed =
false;
200 Changed |= prepareThrows(F);
201 Changed |= prepareEHPads(F);
205 bool WasmEHPrepare::prepareThrows(
Function &F) {
208 bool Changed =
false;
220 auto *ThrowI = cast<CallInst>(U);
221 if (ThrowI->getFunction() != &
F)
224 auto *BB = ThrowI->getParent();
226 auto &InstList = BB->getInstList();
228 IRB.SetInsertPoint(BB);
229 IRB.CreateUnreachable();
236 bool WasmEHPrepare::prepareEHPads(
Function &F) {
245 auto *Pad = BB.getFirstNonPHI();
246 if (isa<CatchPadInst>(Pad))
247 CatchPads.push_back(&BB);
248 else if (isa<CleanupPadInst>(Pad))
252 if (CatchPads.empty() && CleanupPads.
empty())
254 assert(F.hasPersonalityFn() &&
"Personality function not found");
257 LPadContextGV = cast<GlobalVariable>(
259 LPadIndexField = IRB.CreateConstGEP2_32(LPadContextTy, LPadContextGV, 0, 0,
262 IRB.CreateConstGEP2_32(LPadContextTy, LPadContextGV, 0, 1,
"lsda_gep");
263 SelectorField = IRB.CreateConstGEP2_32(LPadContextTy, LPadContextGV, 0, 2,
280 "_Unwind_CallPersonality", IRB.getInt32Ty(), IRB.getInt8PtrTy()));
281 CallPersonalityF->setDoesNotThrow();
285 ClangCallTermF = M.
getFunction(
"__clang_call_terminate");
288 for (
auto *BB : CatchPads) {
289 auto *CPI = cast<CatchPadInst>(BB->getFirstNonPHI());
291 if (CPI->getNumArgOperands() == 1 &&
292 cast<Constant>(CPI->getArgOperand(0))->isNullValue())
293 prepareEHPad(BB, -1);
295 prepareEHPad(BB, Index++);
299 return !CatchPads.empty();
307 for (
auto *BB : CleanupPads)
309 if (
auto *CI = dyn_cast<CallInst>(&
I))
310 if (CI->getCalledValue() == ClangCallTermF)
311 prepareEHPad(BB, -1);
324 Instruction *Exn = IRB.CreateCall(CatchF, IRB.getInt32(0),
"exn");
328 Instruction *GetExnCI =
nullptr, *GetSelectorCI =
nullptr;
329 for (
auto &U : FPI->uses()) {
330 if (
auto *CI = dyn_cast<CallInst>(U.getUser())) {
331 if (CI->getCalledValue() == GetExnF)
333 else if (CI->getCalledValue() == GetSelectorF)
338 assert(GetExnCI &&
"wasm.get.exception() call does not exist");
339 GetExnCI->replaceAllUsesWith(Exn);
340 GetExnCI->eraseFromParent();
344 if (FPI->getNumArgOperands() == 0 ||
345 (FPI->getNumArgOperands() == 1 &&
346 cast<Constant>(FPI->getArgOperand(0))->isNullValue())) {
348 assert(GetSelectorCI->use_empty() &&
349 "wasm.get.ehselector() still has uses!");
350 GetSelectorCI->eraseFromParent();
359 IRB.CreateCall(LPadIndexF, {FPI, IRB.getInt32(Index)});
362 IRB.CreateStore(IRB.getInt32(Index), LPadIndexField);
370 auto *CPI = cast<CatchPadInst>(FPI);
371 if (isa<ConstantTokenNone>(CPI->getCatchSwitch()->getParentPad()))
373 IRB.CreateStore(IRB.CreateCall(LSDAF), LSDAField);
381 Instruction *Selector = IRB.CreateLoad(SelectorField,
"selector");
385 assert(GetSelectorCI &&
"wasm.get.ehselector() call does not exist");
386 GetSelectorCI->replaceAllUsesWith(Selector);
387 GetSelectorCI->eraseFromParent();
391 for (
const auto &BB : *F) {
400 if (
const auto *CatchPad = dyn_cast<CatchPadInst>(Pad)) {
401 const auto *UnwindBB = CatchPad->getCatchSwitch()->getUnwindDest();
404 const Instruction *UnwindPad = UnwindBB->getFirstNonPHI();
405 if (
const auto *CatchSwitch = dyn_cast<CatchSwitchInst>(UnwindPad))
414 for (
const auto &BB : *F) {
417 if (
const auto *Invoke = dyn_cast<InvokeInst>(TI))
418 UnwindBB = Invoke->getUnwindDest();
419 else if (
const auto *CleanupRet = dyn_cast<CleanupReturnInst>(TI))
420 UnwindBB = CleanupRet->getUnwindDest();
424 if (
const auto *CatchSwitch = dyn_cast<CatchSwitchInst>(UnwindPad))
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
This class represents lattice values for constants.
Constant * getOrInsertFunction(StringRef Name, FunctionType *T, AttributeList AttributeList)
Look up the specified function in the module symbol table.
A Module instance is used to store all the information related to an LLVM module. ...
void push_back(const T &Elt)
This class represents a function call, abstracting a target machine's calling convention.
void DeleteDeadBlock(BasicBlock *BB, DomTreeUpdater *DTU=nullptr)
Delete the specified block, which must have no predecessors.
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction if the block is well formed or null if the block is not well forme...
LLVMContext & getContext() const
Get the context in which this basic block lives.
iterator begin()
Instruction iterator methods.
LLVMContext & getContext() const
Get the global data context.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
static StructType * get(LLVMContext &Context, ArrayRef< Type *> Elements, bool isPacked=false)
This static method is the primary way to create a literal StructType.
Interval::succ_iterator succ_begin(Interval *I)
succ_begin/succ_end - define methods so that Intervals may be used just like BasicBlocks can with the...
static void eraseDeadBBsAndChildren(const Container &BBs)
FunctionPass * createWasmEHPass()
createWasmEHPass - This pass adapts exception handling code to use WebAssembly's exception handling s...
Function * getDeclaration(Module *M, ID id, ArrayRef< Type *> Tys=None)
Create or insert an LLVM Function declaration for an intrinsic, and return it.
void SetInsertPoint(BasicBlock *TheBB)
This specifies that created instructions should be appended to the end of the specified block...
Interval::succ_iterator succ_end(Interval *I)
static bool runOnFunction(Function &F, bool PostInlining)
const Instruction * getFirstNonPHI() const
Returns a pointer to the first instruction in this block that is not a PHINode instruction.
const_iterator getFirstInsertionPt() const
Returns an iterator to the first instruction in this block that is suitable for inserting a non-PHI i...
LLVM Basic Block Representation.
void setEHPadUnwindDest(const BasicBlock *BB, const BasicBlock *Dest)
The instances of the Type class are immutable: once they are created, they are never changed...
Interval::pred_iterator pred_begin(Interval *I)
pred_begin/pred_end - define methods so that Intervals may be used just like BasicBlocks can with the...
FunctionPass class - This class is used to implement most global optimizations.
Interval::pred_iterator pred_end(Interval *I)
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function. ...
Iterator for intrusive lists based on ilist_node.
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small...
LLVM_NODISCARD T pop_back_val()
OperandBundleDefT< Value * > OperandBundleDef
INITIALIZE_PASS(WasmEHPrepare, DEBUG_TYPE, "Prepare WebAssembly exceptions", false, false) FunctionPass *llvm
Function * getFunction(StringRef Name) const
Look up the specified function in the module symbol table.
iterator_range< user_iterator > users()
Constant * getOrInsertGlobal(StringRef Name, Type *Ty, function_ref< GlobalVariable *()> CreateGlobalCallback)
Look up the specified global in the module symbol table.
LLVM_NODISCARD bool empty() const
void calculateWasmEHInfo(const Function *F, WasmEHFuncInfo &EHInfo)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
bool isEHPad() const
Return true if this basic block is an exception handling block.
Module * getParent()
Get the module that this global value is contained inside of...
LLVM Value Representation.
void setThrowUnwindDest(const BasicBlock *BB, const BasicBlock *Dest)
StringRef - Represent a constant reference to a string, i.e.
This file describes how to lower LLVM code to machine code.