218 using namespace llvm;
220 #define DEBUG_TYPE "wasm-lower-em-ehsjlj" 224 cl::desc(
"The list of function names in which Emscripten-style " 225 "exception handling is enabled (see emscripten " 226 "EMSCRIPTEN_CATCHING_WHITELIST options)"),
230 class WebAssemblyLowerEmscriptenEHSjLj final :
public ModulePass {
231 static const char *ResumeFName;
232 static const char *EHTypeIDFName;
233 static const char *EmLongjmpFName;
234 static const char *EmLongjmpJmpbufFName;
235 static const char *SaveSetjmpFName;
236 static const char *TestSetjmpFName;
237 static const char *FindMatchingCatchPrefix;
238 static const char *InvokePrefix;
260 std::set<std::string> EHWhitelistSet;
263 return "WebAssembly Lower Emscripten Exceptions";
270 template <
typename CallOrInvoke>
Value *wrapInvoke(CallOrInvoke *CI);
274 template <
typename CallOrInvoke>
Function *getInvokeWrapper(CallOrInvoke *CI);
276 bool areAllExceptionsAllowed()
const {
return EHWhitelistSet.empty(); }
277 bool canLongjmp(
Module &M,
const Value *Callee)
const;
284 WebAssemblyLowerEmscriptenEHSjLj(
bool EnableEH =
true,
bool EnableSjLj =
true)
285 :
ModulePass(ID), EnableEH(EnableEH), EnableSjLj(EnableSjLj),
286 ThrewGV(nullptr), ThrewValueGV(nullptr), GetTempRet0Func(nullptr),
287 SetTempRet0Func(nullptr), ResumeF(nullptr), EHTypeIDF(nullptr),
288 EmLongjmpF(nullptr), EmLongjmpJmpbufF(nullptr), SaveSetjmpF(nullptr),
289 TestSetjmpF(nullptr) {
292 bool runOnModule(
Module &M)
override;
300 const char *WebAssemblyLowerEmscriptenEHSjLj::ResumeFName =
"__resumeException";
301 const char *WebAssemblyLowerEmscriptenEHSjLj::EHTypeIDFName =
302 "llvm_eh_typeid_for";
303 const char *WebAssemblyLowerEmscriptenEHSjLj::EmLongjmpFName =
304 "emscripten_longjmp";
305 const char *WebAssemblyLowerEmscriptenEHSjLj::EmLongjmpJmpbufFName =
306 "emscripten_longjmp_jmpbuf";
307 const char *WebAssemblyLowerEmscriptenEHSjLj::SaveSetjmpFName =
"saveSetjmp";
308 const char *WebAssemblyLowerEmscriptenEHSjLj::TestSetjmpFName =
"testSetjmp";
309 const char *WebAssemblyLowerEmscriptenEHSjLj::FindMatchingCatchPrefix =
310 "__cxa_find_matching_catch_";
311 const char *WebAssemblyLowerEmscriptenEHSjLj::InvokePrefix =
"__invoke_";
315 "WebAssembly Lower Emscripten Exceptions / Setjmp / Longjmp",
320 return new WebAssemblyLowerEmscriptenEHSjLj(EnableEH, EnableSjLj);
324 if (
const auto *
F = dyn_cast<const Function>(V)) {
326 if (
F->isIntrinsic())
330 if (Name ==
"setjmp" || Name ==
"longjmp")
332 return !
F->doesNotThrow();
359 OS <<
"_" << *ParamTy;
363 Sig.erase(
remove_if(Sig, isspace), Sig.end());
376 WebAssemblyLowerEmscriptenEHSjLj::getFindMatchingCatch(
Module &M,
377 unsigned NumClauses) {
378 if (FindMatchingCatches.
count(NumClauses))
379 return FindMatchingCatches[NumClauses];
385 FindMatchingCatchPrefix +
Twine(NumClauses + 2), &M);
386 FindMatchingCatches[NumClauses] =
F;
397 template <
typename CallOrInvoke>
398 Value *WebAssemblyLowerEmscriptenEHSjLj::wrapInvoke(CallOrInvoke *CI) {
404 if (CI->doesNotReturn()) {
405 if (
auto *
F = dyn_cast<Function>(CI->getCalledValue()))
422 Args.
append(CI->arg_begin(), CI->arg_end());
436 for (
unsigned i = 0, e = CI->getNumArgOperands(); i < e; ++i)
445 CI->replaceAllUsesWith(NewCall);
455 template <
typename CallOrInvoke>
456 Function *WebAssemblyLowerEmscriptenEHSjLj::getInvokeWrapper(CallOrInvoke *CI) {
457 Module *M = CI->getModule();
461 if (
auto *
F = dyn_cast<Function>(Callee))
462 CalleeFTy =
F->getFunctionType();
464 auto *CalleeTy = cast<PointerType>(Callee->
getType())->getElementType();
469 if (InvokeWrappers.
find(Sig) != InvokeWrappers.
end())
470 return InvokeWrappers[Sig];
480 InvokePrefix + Sig, M);
481 InvokeWrappers[Sig] =
F;
485 bool WebAssemblyLowerEmscriptenEHSjLj::canLongjmp(
Module &M,
487 if (
auto *CalleeF = dyn_cast<Function>(Callee))
488 if (CalleeF->isIntrinsic())
496 if (Callee == SetjmpF || Callee == MallocF || Callee == FreeF)
500 if (Callee == ResumeF || Callee == EHTypeIDF || Callee == SaveSetjmpF ||
501 Callee == TestSetjmpF)
514 if (Callee == BeginCatchF || Callee == EndCatchF ||
515 Callee == AllocExceptionF || Callee == ThrowF || Callee == TerminateF ||
516 Callee == GetTempRet0Func || Callee == SetTempRet0Func)
537 void WebAssemblyLowerEmscriptenEHSjLj::wrapTestSetjmp(
568 TestSetjmpF, {LoadedThrew, SetjmpTable, SetjmpTableSize},
"label");
574 IRB.
CreateCall(EmLongjmpF, {Threw, ThrewValue});
595 LongjmpResult = IRB.
CreateCall(GetTempRet0Func,
None,
"longjmp_result");
598 void WebAssemblyLowerEmscriptenEHSjLj::rebuildSSA(
Function &
F) {
599 DominatorTree &DT = getAnalysis<DominatorTreeWrapperPass>(
F).getDomTree();
604 for (
auto UI =
I.use_begin(), UE =
I.use_end(); UI != UE;) {
613 if (
PHINode *UserPN = dyn_cast<PHINode>(User))
614 if (UserPN->getIncomingBlock(U) == &BB)
625 bool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(
Module &M) {
626 LLVM_DEBUG(
dbgs() <<
"********** Lower Emscripten EH & SjLj **********\n");
633 bool SetjmpUsed = SetjmpF && !SetjmpF->
use_empty();
634 bool LongjmpUsed = LongjmpF && !LongjmpF->
use_empty();
635 bool DoSjLj = EnableSjLj && (SetjmpUsed || LongjmpUsed);
651 bool Changed =
false;
670 Changed |= runEHOnFunction(F);
683 EmLongjmpJmpbufFName, &M);
697 SaveSetjmpFName, &M);
703 TestSetjmpFName, &M);
714 auto *UI = cast<Instruction>(U);
715 SetjmpUsers.
insert(UI->getFunction());
718 runSjLjOnFunction(*F);
740 bool WebAssemblyLowerEmscriptenEHSjLj::runEHOnFunction(
Function &F) {
744 bool Changed =
false;
747 bool AllowExceptions =
748 areAllExceptionsAllowed() || EHWhitelistSet.
count(F.
getName());
755 LandingPads.
insert(II->getLandingPadInst());
758 bool NeedInvoke = AllowExceptions &&
canThrow(II->getCalledValue());
761 Value *Threw = wrapInvoke(II);
766 IRB.
CreateCondBr(Cmp, II->getUnwindDest(), II->getNormalDest());
773 NewCall->takeName(II);
774 NewCall->setCallingConv(II->getCallingConv());
775 NewCall->setDebugLoc(II->getDebugLoc());
776 NewCall->setAttributes(II->getAttributes());
777 II->replaceAllUsesWith(NewCall);
783 II->getUnwindDest()->removePredecessor(&BB);
796 Value *Input = RI->getValue();
813 const Function *Callee = CI->getCalledFunction();
821 IRB.
CreateCall(EHTypeIDF, CI->getArgOperand(0),
"typeid");
830 if (
auto *LPI = dyn_cast<LandingPadInst>(I))
839 for (
unsigned i = 0, e = LPI->getNumClauses(); i < e; ++i) {
840 Constant *Clause = LPI->getClause(i);
844 if (LPI->isFilter(i)) {
845 auto *ATy = cast<ArrayType>(Clause->
getType());
846 for (
unsigned j = 0, e = ATy->getNumElements(); j < e; ++j) {
855 Function *FMCF = getFindMatchingCatch(M, FMCArgs.
size());
868 I->eraseFromParent();
873 bool WebAssemblyLowerEmscriptenEHSjLj::runSjLjOnFunction(
Function &F) {
879 std::vector<Instruction *> SetjmpTableInsts;
881 std::vector<Instruction *> SetjmpTableSizeInsts;
896 nullptr,
nullptr,
"setjmpTable");
900 SetjmpTableInsts.push_back(SetjmpTable);
901 SetjmpTableSizeInsts.push_back(SetjmpTableSize);
904 std::vector<PHINode *> SetjmpRetPHIs;
927 CI->replaceAllUsesWith(SetjmpRet);
929 SetjmpRetPHIs.push_back(SetjmpRet);
936 SetjmpTable, SetjmpTableSize};
938 IRB.
CreateCall(SaveSetjmpF, Args,
"setjmpTable");
941 SetjmpTableInsts.push_back(NewSetjmpTable);
942 SetjmpTableSizeInsts.push_back(NewSetjmpTableSize);
952 std::vector<BasicBlock *> BBs;
957 for (
unsigned i = 0; i < BBs.size(); i++) {
965 const Value *Callee = CI->getCalledValue();
966 if (!canLongjmp(M, Callee))
969 Value *Threw =
nullptr;
980 if (
auto *LI = dyn_cast<LoadInst>(
I))
981 if (
auto *GV = dyn_cast<GlobalVariable>(LI->getPointerOperand()))
983 Threw = ThrewLI = LI;
991 if (
auto *
SI = dyn_cast<StoreInst>(
I))
992 if (
auto *GV = dyn_cast<GlobalVariable>(
SI->getPointerOperand()))
993 if (GV == ThrewGV &&
SI->getValueOperand() == IRB.
getInt32(0)) {
998 assert(Threw && ThrewLI &&
"Cannot find __THREW__ load after invoke");
999 assert(ThrewResetSI &&
"Cannot find __THREW__ store after invoke");
1004 Threw = wrapInvoke(CI);
1017 Value *Label =
nullptr;
1018 Value *LongjmpResult =
nullptr;
1020 wrapTestSetjmp(BB, CI, Threw, SetjmpTable, SetjmpTableSize, Label,
1021 LongjmpResult, EndBB);
1022 assert(Label && LongjmpResult && EndBB);
1031 for (
unsigned i = 0; i < SetjmpRetPHIs.size(); i++) {
1033 SetjmpRetPHIs[i]->addIncoming(LongjmpResult, EndBB);
1038 BBs.push_back(Tail);
1044 I->eraseFromParent();
1049 if (isa<ReturnInst>(TI))
1074 for (
auto UI = SetjmpTable->use_begin(), UE = SetjmpTable->use_end();
1081 if (
I->getParent() != &EntryBB)
1084 for (
auto UI = SetjmpTableSize->
use_begin(), UE = SetjmpTableSize->
use_end();
1089 if (
I->getParent() != &EntryBB)
BranchInst * CreateCondBr(Value *Cond, BasicBlock *True, BasicBlock *False, MDNode *BranchWeights=nullptr, MDNode *Unpredictable=nullptr)
Create a conditional 'br Cond, TrueDest, FalseDest' instruction.
Helper class for SSA formation on a set of values defined in multiple blocks.
void addIncoming(Value *V, BasicBlock *BB)
Add an incoming value to the end of the PHI list.
ModulePass * createWebAssemblyLowerEmscriptenEHSjLj(bool DoEH, bool DoSjLj)
Value * CreateICmpNE(Value *LHS, Value *RHS, const Twine &Name="")
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
LLVM_ATTRIBUTE_NORETURN void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
This class represents lattice values for constants.
static GlobalVariable * getGlobalVariableI32(Module &M, IRBuilder<> &IRB, const char *Name)
Type * getParamType(unsigned i) const
Parameter type accessors.
void Initialize(Type *Ty, StringRef Name)
Reset this object to get ready for a new set of SSA updates with type 'Ty'.
LoadInst * CreateLoad(Type *Ty, Value *Ptr, const char *Name)
Provided to resolve 'CreateLoad(Ty, Ptr, "...")' correctly, instead of converting the string to 'bool...
A Module instance is used to store all the information related to an LLVM module. ...
void push_back(const T &Elt)
void AddAvailableValue(BasicBlock *BB, Value *V)
Indicate that a rewritten value is available in the specified block with the specified value...
void addCase(ConstantInt *OnVal, BasicBlock *Dest)
Add an entry to the switch instruction.
void recalculate(ParentType &Func)
recalculate - compute a dominator tree for the given function
This class represents a function call, abstracting a target machine's calling convention.
static PointerType * getInt32PtrTy(LLVMContext &C, unsigned AS=0)
const GlobalVariable * getNamedGlobal(StringRef Name) const
Return the global variable in the module with the specified name, of arbitrary type.
iterator find(StringRef Key)
Externally visible function.
param_iterator param_end() const
An instruction for reading from memory.
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...
static Instruction * CreateFree(Value *Source, Instruction *InsertBefore)
Generate the IR for a call to the builtin free function.
This file contains the entry points for global functions defined in the LLVM WebAssembly back-end...
static bool canThrow(const Value *V)
IntegerType * getInt32Ty()
Fetch the type representing a 32-bit integer.
AnalysisUsage & addRequired()
const Module * getModule() const
Return the module owning the function this basic block belongs to, or nullptr if the function does no...
amdgpu Simplify well known AMD library false Value Value const Twine & Name
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
ArrayRef< T > makeArrayRef(const T &OneElt)
Construct an ArrayRef from a single element.
LLVMContext & getContext() const
Get the global data context.
A Use represents the edge between a Value definition and its users.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
AttributeSet getRetAttributes() const
The attributes for the ret value are returned.
Type * getVoidTy()
Fetch the type representing void.
StoreInst * CreateStore(Value *Val, Value *Ptr, bool isVolatile=false)
Value * CreateIntToPtr(Value *V, Type *DestTy, const Twine &Name="")
LLVM_NODISCARD LLVM_ATTRIBUTE_ALWAYS_INLINE bool startswith(StringRef Prefix) const
Check if this string starts with the given Prefix.
User * getUser() const LLVM_READONLY
Returns the User that contains this Use.
Class to represent function types.
Type * getType() const
All values are typed, get the type of this value.
AttributeSet getParamAttributes(unsigned ArgNo) const
The attributes for the argument or parameter at the given index are returned.
An instruction for storing to memory.
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
void takeName(Value *V)
Transfer the name from V to this value.
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree...
amdgpu Simplify well known AMD library false Value * Callee
void SetInsertPoint(BasicBlock *TheBB)
This specifies that created instructions should be appended to the end of the specified block...
Class to represent pointers.
AttributeSet getAttributes(unsigned Index) const
The attributes for the specified index are returned.
const BasicBlock & getEntryBlock() const
static Function * Create(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, const Twine &N="", Module *M=nullptr)
The landingpad instruction holds all of the information necessary to generate correct exception handl...
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...
void setDebugLoc(DebugLoc Loc)
Set the debug location information for this instruction.
LLVM Basic Block Representation.
The instances of the Type class are immutable: once they are created, they are never changed...
This is an important class for using LLVM in a threaded context.
void RewriteUseAfterInsertions(Use &U)
Rewrite a use like RewriteUse but handling in-block definitions.
UnreachableInst * CreateUnreachable()
This is an important base class in LLVM.
Resume the propagation of an exception.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
ArrayRef< Type * > params() const
param_iterator param_begin() const
Represent the analysis usage information of a pass.
static void replace(Module &M, GlobalVariable *Old, GlobalVariable *New)
void setCallingConv(CallingConv::ID CC)
static FunctionType * get(Type *Result, ArrayRef< Type *> Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
Value * CreateICmpEQ(Value *LHS, Value *RHS, const Twine &Name="")
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
auto remove_if(R &&Range, UnaryPredicate P) -> decltype(adl_begin(Range))
Provide wrappers to std::remove_if which take ranges instead of having to pass begin/end explicitly...
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function. ...
static UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
Value * CreateExtractValue(Value *Agg, ArrayRef< unsigned > Idxs, const Twine &Name="")
PointerType * getInt8PtrTy(unsigned AddrSpace=0)
Fetch the type representing a pointer to an 8-bit integer value.
static PointerType * getInt8PtrTy(LLVMContext &C, unsigned AS=0)
std::string & str()
Flushes the stream contents to the target string and returns the string's reference.
PHINode * CreatePHI(Type *Ty, unsigned NumReservedValues, const Twine &Name="")
Iterator for intrusive lists based on ilist_node.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements...
static PointerType * getUnqual(Type *ElementType)
This constructs a pointer to an object of the specified type in the generic address space (address sp...
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small...
bool dominates(const Instruction *Def, const Use &U) const
Return true if Def dominates a use in User.
Type * getReturnType() const
ConstantInt * getInt32(uint32_t C)
Get a constant 32-bit value.
Intrinsic::ID getIntrinsicID() const LLVM_READONLY
getIntrinsicID - This method returns the ID number of the specified function, or Intrinsic::not_intri...
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Function * getFunction(StringRef Name) const
Look up the specified function in the module symbol table.
FunctionType * getFunctionType() const
Returns the FunctionType for me.
StringMap - This is an unconventional map that is specialized for handling keys that are "strings"...
const Module * getModule() const
Return the module owning the function this instruction belongs to or nullptr it the function does not...
static BinaryOperator * Create(BinaryOps Op, Value *S1, Value *S2, const Twine &Name=Twine(), Instruction *InsertBefore=nullptr)
Construct a binary instruction, given the opcode and the two operands.
iterator_range< user_iterator > users()
void append(in_iter in_start, in_iter in_end)
Add the specified range to the end of the SmallVector.
static Instruction * CreateMalloc(Instruction *InsertBefore, Type *IntPtrTy, Type *AllocTy, Value *AllocSize, Value *ArraySize=nullptr, Function *MallocF=nullptr, const Twine &Name="")
Generate the IR for a call to malloc:
SwitchInst * CreateSwitch(Value *V, BasicBlock *Dest, unsigned NumCases=10, MDNode *BranchWeights=nullptr, MDNode *Unpredictable=nullptr)
Create a switch instruction with the specified value, default dest, and with a hint for the number of...
static IntegerType * getInt32Ty(LLVMContext &C)
StringRef getName() const
Return a constant reference to the value's name.
const Function * getParent() const
Return the enclosing method, or null if none.
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
void setAttributes(AttributeList A)
Set the parameter attributes for this call.
LLVM_NODISCARD std::enable_if<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type >::type dyn_cast(const Y &Val)
CallInst * CreateCall(FunctionType *FTy, Value *Callee, ArrayRef< Value *> Args=None, const Twine &Name="", MDNode *FPMathTag=nullptr)
void eraseFromParent()
eraseFromParent - This method unlinks 'this' from the containing module and deletes it...
size_type count(const_arg_type_t< KeyT > Val) const
Return 1 if the specified key is in the map, 0 otherwise.
Value * CreateAnd(Value *LHS, Value *RHS, const Twine &Name="")
bool isDeclaration() const
Return true if the primary definition of this global value is outside of the current translation unit...
INITIALIZE_PASS(WebAssemblyLowerEmscriptenEHSjLj, DEBUG_TYPE, "WebAssembly Lower Emscripten Exceptions / Setjmp / Longjmp", false, false) ModulePass *llvm
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
A raw_ostream that writes to an std::string.
Module * getParent()
Get the module that this global value is contained inside of...
LLVM Value Representation.
static cl::list< std::string > EHWhitelist("emscripten-cxx-exceptions-whitelist", cl::desc("The list of function names in which Emscripten-style " "exception handling is enabled (see emscripten " "EMSCRIPTEN_CATCHING_WHITELIST options)"), cl::CommaSeparated)
BranchInst * CreateBr(BasicBlock *Dest)
Create an unconditional 'br label X' instruction.
AttributeSet getFnAttributes() const
The function attributes are returned.
BasicBlock * SplitBlock(BasicBlock *Old, Instruction *SplitPt, DominatorTree *DT=nullptr, LoopInfo *LI=nullptr, MemorySSAUpdater *MSSAU=nullptr)
Split the specified block at the specified instruction - everything before SplitPt stays in Old and e...
StringRef - Represent a constant reference to a string, i.e.
Legacy analysis pass which computes a DominatorTree.
Value * CreateInsertValue(Value *Agg, Value *Val, ArrayRef< unsigned > Idxs, const Twine &Name="")
void RewriteUse(Use &U)
Rewrite a use of the symbolic value.
static std::string getSignature(FunctionType *FTy)
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
static AttributeList get(LLVMContext &C, ArrayRef< std::pair< unsigned, Attribute >> Attrs)
Create an AttributeList with the specified parameters in it.
const BasicBlock * getParent() const