85#include "llvm/IR/IntrinsicsWebAssembly.h"
91#define DEBUG_TYPE "wasmehprepare"
95 Type *LPadContextTy =
nullptr;
99 Value *LPadIndexField =
nullptr;
100 Value *LSDAField =
nullptr;
101 Value *SelectorField =
nullptr;
114 void prepareEHPad(
BasicBlock *BB,
bool NeedPersonality,
unsigned Index = 0);
124 return "WebAssembly Exception handling preparation";
129char WasmEHPrepare::ID = 0;
131 "Prepare WebAssembly exceptions",
false,
false)
137bool WasmEHPrepare::doInitialization(
Module &M) {
148template <
typename Container>
151 while (!WL.
empty()) {
160bool WasmEHPrepare::runOnFunction(
Function &
F) {
161 bool Changed =
false;
162 Changed |= prepareThrows(
F);
163 Changed |= prepareEHPads(
F);
167bool WasmEHPrepare::prepareThrows(
Function &
F) {
170 bool Changed =
false;
180 auto *ThrowI = cast<CallInst>(U);
181 if (ThrowI->getFunction() != &
F)
184 auto *BB = ThrowI->getParent();
187 IRB.SetInsertPoint(BB);
188 IRB.CreateUnreachable();
195bool WasmEHPrepare::prepareEHPads(
Function &
F) {
204 auto *Pad = BB.getFirstNonPHI();
205 if (isa<CatchPadInst>(Pad))
207 else if (isa<CleanupPadInst>(Pad))
213 if (!
F.hasPersonalityFn() ||
216 "' does not have a correct Wasm personality function "
217 "'__gxx_wasm_personality_v0'");
219 assert(
F.hasPersonalityFn() &&
"Personality function not found");
226 LPadContextGV = cast<GlobalVariable>(
227 M.getOrInsertGlobal(
"__wasm_lpad_context", LPadContextTy));
230 LPadIndexField = IRB.CreateConstGEP2_32(LPadContextTy, LPadContextGV, 0, 0,
233 IRB.CreateConstGEP2_32(LPadContextTy, LPadContextGV, 0, 1,
"lsda_gep");
234 SelectorField = IRB.CreateConstGEP2_32(LPadContextTy, LPadContextGV, 0, 2,
252 CallPersonalityF =
M.getOrInsertFunction(
253 "_Unwind_CallPersonality", IRB.getInt32Ty(), IRB.getInt8PtrTy());
254 if (
Function *
F = dyn_cast<Function>(CallPersonalityF.getCallee()))
255 F->setDoesNotThrow();
258 for (
auto *BB : CatchPads) {
259 auto *CPI = cast<CatchPadInst>(BB->getFirstNonPHI());
262 if (CPI->arg_size() == 1 &&
263 cast<Constant>(CPI->getArgOperand(0))->isNullValue())
264 prepareEHPad(BB,
false);
266 prepareEHPad(BB,
true,
Index++);
270 for (
auto *BB : CleanupPads)
271 prepareEHPad(BB,
false);
278void WasmEHPrepare::prepareEHPad(
BasicBlock *BB,
bool NeedPersonality,
285 Instruction *GetExnCI =
nullptr, *GetSelectorCI =
nullptr;
286 for (
auto &U : FPI->uses()) {
287 if (
auto *CI = dyn_cast<CallInst>(
U.getUser())) {
288 if (CI->getCalledOperand() == GetExnF)
290 if (CI->getCalledOperand() == GetSelectorF)
299 "wasm.get.ehselector() cannot exist w/o wasm.get.exception()");
314 if (!NeedPersonality) {
316 assert(GetSelectorCI->use_empty() &&
317 "wasm.get.ehselector() still has uses!");
318 GetSelectorCI->eraseFromParent();
327 IRB.CreateCall(LPadIndexF, {FPI, IRB.getInt32(
Index)});
330 IRB.CreateStore(IRB.getInt32(
Index), LPadIndexField);
332 auto *CPI = cast<CatchPadInst>(FPI);
337 IRB.CreateStore(IRB.CreateCall(LSDAF), LSDAField);
340 CallInst *PersCI = IRB.CreateCall(CallPersonalityF, CatchCI,
346 IRB.CreateLoad(IRB.getInt32Ty(), SelectorField,
"selector");
350 assert(GetSelectorCI &&
"wasm.get.ehselector() call does not exist");
351 GetSelectorCI->replaceAllUsesWith(Selector);
352 GetSelectorCI->eraseFromParent();
360 for (
const auto &BB : *
F) {
365 if (
const auto *CatchPad = dyn_cast<CatchPadInst>(Pad)) {
366 const auto *UnwindBB = CatchPad->getCatchSwitch()->getUnwindDest();
369 const Instruction *UnwindPad = UnwindBB->getFirstNonPHI();
370 if (
const auto *CatchSwitch = dyn_cast<CatchSwitchInst>(UnwindPad))
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
Prepare WebAssembly exceptions
static void eraseDeadBBsAndChildren(const Container &BBs)
LLVM Basic Block Representation.
iterator begin()
Instruction iterator methods.
const_iterator getFirstInsertionPt() const
Returns an iterator to the first instruction in this block that is suitable for inserting a non-PHI i...
const Instruction * getFirstNonPHI() const
Returns a pointer to the first instruction in this block that is not a PHINode instruction.
InstListType::iterator iterator
Instruction iterators...
LLVMContext & getContext() const
Get the context in which this basic block lives.
bool isEHPad() const
Return true if this basic block is an exception handling block.
This class represents a function call, abstracting a target machine's calling convention.
A handy container for a FunctionType+Callee-pointer pair, which can be passed around as a single enti...
FunctionPass class - This class is used to implement most global optimizations.
virtual bool runOnFunction(Function &F)=0
runOnFunction - Virtual method overriden by subclasses to do the per-function processing of the pass.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
SymbolTableList< Instruction >::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
A Module instance is used to store all the information related to an LLVM module.
virtual bool doInitialization(Module &)
doInitialization - Virtual method overridden by subclasses to do any necessary initialization before ...
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
void append(ItTy in_start, ItTy in_end)
Add the specified range to the end of the SmallVector.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
static StructType * get(LLVMContext &Context, ArrayRef< Type * > Elements, bool isPacked=false)
This static method is the primary way to create a literal StructType.
The instances of the Type class are immutable: once they are created, they are never changed.
LLVM Value Representation.
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
iterator_range< user_iterator > users()
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Function * getDeclaration(Module *M, ID id, ArrayRef< Type * > Tys=std::nullopt)
Create or insert an LLVM Function declaration for an intrinsic, and return it.
This is an optimization pass for GlobalISel generic memory operations.
Interval::succ_iterator succ_end(Interval *I)
auto successors(const MachineBasicBlock *BB)
FunctionPass * createWasmEHPass()
createWasmEHPass - This pass adapts exception handling code to use WebAssembly's exception handling s...
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...
void DeleteDeadBlock(BasicBlock *BB, DomTreeUpdater *DTU=nullptr, bool KeepOneInputPHIs=false)
Delete the specified block, which must have no predecessors.
bool isScopedEHPersonality(EHPersonality Pers)
Returns true if this personality uses scope-style EH IR instructions: catchswitch,...
OperandBundleDefT< Value * > OperandBundleDef
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
EHPersonality classifyEHPersonality(const Value *Pers)
See if the given exception handling personality function is one that we understand.
void calculateWasmEHInfo(const Function *F, WasmEHFuncInfo &EHInfo)
bool pred_empty(const BasicBlock *BB)
void setUnwindDest(const BasicBlock *BB, const BasicBlock *Dest)