diff options
Diffstat (limited to 'llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenExceptions.cpp')
-rw-r--r-- | llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenExceptions.cpp | 125 |
1 files changed, 92 insertions, 33 deletions
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenExceptions.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenExceptions.cpp index 3e3178e7735..c906767458b 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenExceptions.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenExceptions.cpp @@ -24,7 +24,7 @@ /// This pass does following things: /// /// 1) Create three global variables: __THREW__, threwValue, and tempRet0. -/// tempRet0 will be set within ___cxa_find_matching_catch() function in +/// tempRet0 will be set within __cxa_find_matching_catch() function in /// JS library, and __THREW__ and threwValue will be set in invoke wrappers /// in JS glue code. For what invoke wrappers are, refer to 3). /// @@ -77,31 +77,33 @@ /// %val = landingpad catch c1 catch c2 catch c3 ... /// ... use %val ... /// into -/// %fmc = call @___cxa_find_matching_catch_N(c1, c2, c3, ...) +/// %fmc = call @__cxa_find_matching_catch_N(c1, c2, c3, ...) /// %val = {%fmc, tempRet0} /// ... use %val ... /// Here N is a number calculated based on the number of clauses. -/// Global variable tempRet0 is set within ___cxa_find_matching_catch() in +/// Global variable tempRet0 is set within __cxa_find_matching_catch() in /// JS glue code. /// /// 5) Lower /// resume {%a, %b} /// into -/// call @___resumeException(%a) -/// where ___resumeException() is a function in JS glue code. +/// call @__resumeException(%a) +/// where __resumeException() is a function in JS glue code. /// -/// TODO: Handle i64 types +/// 6) Lower +/// call @llvm.eh.typeid.for(type) (intrinsic) +/// into +/// call @llvm_eh_typeid_for(type) +/// llvm_eh_typeid_for function will be generated in JS glue code. /// ///===----------------------------------------------------------------------===// #include "WebAssembly.h" -#include "llvm/ADT/IndexedMap.h" -#include "llvm/IR/Constants.h" +#include "llvm/IR/CallSite.h" #include "llvm/IR/IRBuilder.h" -#include "llvm/IR/Instructions.h" #include "llvm/IR/Module.h" -#include "llvm/Pass.h" #include "llvm/Support/raw_ostream.h" +#include <set> using namespace llvm; @@ -114,9 +116,9 @@ class WebAssemblyLowerEmscriptenExceptions final : public ModulePass { } bool runOnFunction(Function &F); - // Returns ___cxa_find_matching_catch_N function, where N = NumClauses + 2. + // Returns __cxa_find_matching_catch_N function, where N = NumClauses + 2. // This is because a landingpad instruction contains two more arguments, - // a personality function and a cleanup bit, and ___cxa_find_matching_catch_N + // a personality function and a cleanup bit, and __cxa_find_matching_catch_N // functions are named after the number of arguments in the original // landingpad instruction. Function *getFindMatchingCatch(Module &M, unsigned NumClauses); @@ -126,8 +128,9 @@ class WebAssemblyLowerEmscriptenExceptions final : public ModulePass { GlobalVariable *ThrewGV; // __THREW__ GlobalVariable *ThrewValueGV; // threwValue GlobalVariable *TempRet0GV; // tempRet0 - Function *ResumeF; - // ___cxa_find_matching_catch_N functions. + Function *ResumeF; // __resumeException + Function *EHTypeIdF; // llvm_eh_typeid_for + // __cxa_find_matching_catch_N functions. // Indexed by the number of clauses in an original landingpad instruction. DenseMap<int, Function *> FindMatchingCatches; // Map of <function signature string, invoke_ wrappers> @@ -178,9 +181,9 @@ static inline std::string createGlobalValueName(const Module &M, // Simple function name mangler. // This function simply takes LLVM's string representation of parameter types -// concatenate them with '_'. There are non-alphanumeric characters but llc is -// ok with it, and we need to postprocess these names after the lowering phase -// anyway. +// and concatenate them with '_'. There are non-alphanumeric characters but llc +// is ok with it, and we need to postprocess these names after the lowering +// phase anyway. static std::string getSignature(FunctionType *FTy) { std::string Sig; raw_string_ostream OS(Sig); @@ -191,6 +194,9 @@ static std::string getSignature(FunctionType *FTy) { OS << "_..."; Sig = OS.str(); Sig.erase(std::remove_if(Sig.begin(), Sig.end(), isspace), Sig.end()); + // When s2wasm parses .s file, a comma means the end of an argument. So a + // mangled function name can contain any character but a comma. + std::replace(Sig.begin(), Sig.end(), ',', '.'); return Sig; } @@ -203,7 +209,7 @@ Function *WebAssemblyLowerEmscriptenExceptions::getFindMatchingCatch( FunctionType *FTy = FunctionType::get(Int8PtrTy, Args, false); Function *F = Function::Create( FTy, GlobalValue::ExternalLinkage, - "___cxa_find_matching_catch_" + Twine(NumClauses + 2), &M); + "__cxa_find_matching_catch_" + Twine(NumClauses + 2), &M); FindMatchingCatches[NumClauses] = F; return F; } @@ -239,10 +245,12 @@ WebAssemblyLowerEmscriptenExceptions::getInvokeWrapper(Module &M, } bool WebAssemblyLowerEmscriptenExceptions::runOnModule(Module &M) { - IRBuilder<> Builder(M.getContext()); + LLVMContext &C = M.getContext(); + IRBuilder<> Builder(C); IntegerType *Int1Ty = Builder.getInt1Ty(); PointerType *Int8PtrTy = Builder.getInt8PtrTy(); IntegerType *Int32Ty = Builder.getInt32Ty(); + Type *VoidTy = Builder.getVoidTy(); // Create global variables __THREW__, threwValue, and tempRet0 ThrewGV = new GlobalVariable(M, Int1Ty, false, GlobalValue::ExternalLinkage, @@ -255,11 +263,15 @@ bool WebAssemblyLowerEmscriptenExceptions::runOnModule(Module &M) { M, Int32Ty, false, GlobalValue::ExternalLinkage, Builder.getInt32(0), createGlobalValueName(M, "tempRet0")); - // Register ___resumeException function - Type *VoidTy = Type::getVoidTy(M.getContext()); + // Register __resumeException function FunctionType *ResumeFTy = FunctionType::get(VoidTy, Int8PtrTy, false); ResumeF = Function::Create(ResumeFTy, GlobalValue::ExternalLinkage, - "___resumeException", &M); + "__resumeException", &M); + + // Register llvm_eh_typeid_for function + FunctionType *EHTypeIdTy = FunctionType::get(Int32Ty, Int8PtrTy, false); + EHTypeIdF = Function::Create(EHTypeIdTy, GlobalValue::ExternalLinkage, + "llvm_eh_typeid_for", &M); bool Changed = false; for (Function &F : M) { @@ -283,9 +295,9 @@ bool WebAssemblyLowerEmscriptenExceptions::runOnModule(Module &M) { Argument *Arg2 = &*(++F->arg_begin()); Arg1->setName("threw"); Arg2->setName("value"); - BasicBlock *EntryBB = BasicBlock::Create(M.getContext(), "entry", F); - BasicBlock *ThenBB = BasicBlock::Create(M.getContext(), "if.then", F); - BasicBlock *EndBB = BasicBlock::Create(M.getContext(), "if.end", F); + BasicBlock *EntryBB = BasicBlock::Create(C, "entry", F); + BasicBlock *ThenBB = BasicBlock::Create(C, "if.then", F); + BasicBlock *EndBB = BasicBlock::Create(C, "if.end", F); Builder.SetInsertPoint(EntryBB); Value *Threw = Builder.CreateLoad(ThrewGV, ThrewGV->getName() + ".val"); @@ -305,7 +317,7 @@ bool WebAssemblyLowerEmscriptenExceptions::runOnModule(Module &M) { FTy = FunctionType::get(VoidTy, Params, false); F = Function::Create(FTy, GlobalValue::ExternalLinkage, "setTempRet0", &M); F->arg_begin()->setName("value"); - EntryBB = BasicBlock::Create(M.getContext(), "entry", F); + EntryBB = BasicBlock::Create(C, "entry", F); Builder.SetInsertPoint(EntryBB); Builder.CreateStore(&*F->arg_begin(), TempRet0GV); Builder.CreateRetVoid(); @@ -315,10 +327,12 @@ bool WebAssemblyLowerEmscriptenExceptions::runOnModule(Module &M) { bool WebAssemblyLowerEmscriptenExceptions::runOnFunction(Function &F) { Module &M = *F.getParent(); - IRBuilder<> Builder(M.getContext()); + LLVMContext &C = F.getContext(); + IRBuilder<> Builder(C); bool Changed = false; SmallVector<Instruction *, 64> ToErase; SmallPtrSet<LandingPadInst *, 32> LandingPads; + bool AllowExceptions = true; // will later change based on whitelist option for (BasicBlock &BB : F) { auto *II = dyn_cast<InvokeInst>(BB.getTerminator()); @@ -328,7 +342,8 @@ bool WebAssemblyLowerEmscriptenExceptions::runOnFunction(Function &F) { LandingPads.insert(II->getLandingPadInst()); Builder.SetInsertPoint(II); - if (canThrow(II->getCalledValue())) { + bool NeedInvoke = AllowExceptions && canThrow(II->getCalledValue()); + if (NeedInvoke) { // If we are calling a function that is noreturn, we must remove that // attribute. The code we insert here does expect it to return, after we // catch the exception. @@ -336,7 +351,7 @@ bool WebAssemblyLowerEmscriptenExceptions::runOnFunction(Function &F) { if (auto *F = dyn_cast<Function>(II->getCalledValue())) F->removeFnAttr(Attribute::NoReturn); AttributeSet NewAttrs = II->getAttributes(); - NewAttrs.removeAttribute(M.getContext(), AttributeSet::FunctionIndex, + NewAttrs.removeAttribute(C, AttributeSet::FunctionIndex, Attribute::NoReturn); II->setAttributes(NewAttrs); } @@ -354,8 +369,32 @@ bool WebAssemblyLowerEmscriptenExceptions::runOnFunction(Function &F) { CallInst *NewCall = Builder.CreateCall(getInvokeWrapper(M, II), CallArgs); NewCall->takeName(II); NewCall->setCallingConv(II->getCallingConv()); - NewCall->setAttributes(II->getAttributes()); NewCall->setDebugLoc(II->getDebugLoc()); + + // Because we added the pointer to the callee as first argument, all + // argument attribute indices have to be incremented by one. + SmallVector<AttributeSet, 8> AttributesVec; + const AttributeSet &InvokePAL = II->getAttributes(); + CallSite::arg_iterator AI = II->arg_begin(); + unsigned i = 1; // Argument attribute index starts from 1 + for (unsigned e = II->getNumArgOperands(); i <= e; ++AI, ++i) { + if (InvokePAL.hasAttributes(i)) { + AttrBuilder B(InvokePAL, i); + AttributesVec.push_back(AttributeSet::get(C, i + 1, B)); + } + } + // Add any return attributes. + if (InvokePAL.hasAttributes(AttributeSet::ReturnIndex)) + AttributesVec.push_back( + AttributeSet::get(C, InvokePAL.getRetAttributes())); + // Add any function attributes. + if (InvokePAL.hasAttributes(AttributeSet::FunctionIndex)) + AttributesVec.push_back( + AttributeSet::get(C, InvokePAL.getFnAttributes())); + // Reconstruct the AttributesList based on the vector we constructed. + AttributeSet NewCallPAL = AttributeSet::get(C, AttributesVec); + NewCall->setAttributes(NewCallPAL); + II->replaceAllUsesWith(NewCall); ToErase.push_back(II); @@ -374,8 +413,8 @@ bool WebAssemblyLowerEmscriptenExceptions::runOnFunction(Function &F) { CallInst *NewCall = Builder.CreateCall(II->getCalledValue(), CallArgs); NewCall->takeName(II); NewCall->setCallingConv(II->getCallingConv()); - NewCall->setAttributes(II->getAttributes()); NewCall->setDebugLoc(II->getDebugLoc()); + NewCall->setAttributes(II->getAttributes()); II->replaceAllUsesWith(NewCall); ToErase.push_back(II); @@ -399,7 +438,7 @@ bool WebAssemblyLowerEmscriptenExceptions::runOnFunction(Function &F) { Builder.SetInsertPoint(RI); Value *Low = Builder.CreateExtractValue(Input, 0, "low"); - // Create a call to ___resumeException function + // Create a call to __resumeException function Value *Args[] = {Low}; Builder.CreateCall(ResumeF, Args); @@ -409,6 +448,26 @@ bool WebAssemblyLowerEmscriptenExceptions::runOnFunction(Function &F) { } } + // Process llvm.eh.typeid.for intrinsics + for (BasicBlock &BB : F) { + for (Instruction &I : BB) { + auto *CI = dyn_cast<CallInst>(&I); + if (!CI) + continue; + const Function *Callee = CI->getCalledFunction(); + if (!Callee) + continue; + if (Callee->getIntrinsicID() != Intrinsic::eh_typeid_for) + continue; + + Builder.SetInsertPoint(CI); + CallInst *NewCI = + Builder.CreateCall(EHTypeIdF, CI->getArgOperand(0), "typeid"); + CI->replaceAllUsesWith(NewCI); + ToErase.push_back(CI); + } + } + // Look for orphan landingpads, can occur in blocks with no predecesors for (BasicBlock &BB : F) { Instruction *I = BB.getFirstNonPHI(); @@ -437,7 +496,7 @@ bool WebAssemblyLowerEmscriptenExceptions::runOnFunction(Function &F) { FMCArgs.push_back(Clause); } - // Create a call to ___cxa_find_matching_catch_N function + // Create a call to __cxa_find_matching_catch_N function Function *FMCF = getFindMatchingCatch(M, FMCArgs.size()); CallInst *FMCI = Builder.CreateCall(FMCF, FMCArgs, "fmc"); Value *Undef = UndefValue::get(LPI->getType()); |