From 0bc76c777e2bd1136ffa914544afba197d3ec582 Mon Sep 17 00:00:00 2001 From: Derek Schuff Date: Thu, 18 Aug 2016 15:27:25 +0000 Subject: [PATCH] [WebAssembly] Refactor WebAssemblyLowerEmscriptenException pass for setjmp/longjmp This patch changes the code structure of WebAssemblyLowerEmscriptenException pass to support both exception handling and setjmp/longjmp. It also changes the name of the pass and the source file. 1. Change the file/pass name to WebAssemblyLowerEmscriptenExceptions -> WebAssemblyLowerEmscriptenEHSjLj to make it clear that it supports both EH and SjLj 2. List function / global variable names at the top so they can be changed easily 3. Some cosmetic changes Patch by Heejin Ahn Differential Revision: https://reviews.llvm.org/D23588 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@279075 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/WebAssembly/CMakeLists.txt | 2 +- lib/Target/WebAssembly/WebAssembly.h | 4 +- ...p => WebAssemblyLowerEmscriptenEHSjLj.cpp} | 285 +++++++++++------- .../WebAssembly/WebAssemblyTargetMachine.cpp | 15 +- .../lower-em-exceptions-whitelist.ll | 2 +- .../WebAssembly/lower-em-exceptions.ll | 16 +- 6 files changed, 191 insertions(+), 133 deletions(-) rename lib/Target/WebAssembly/{WebAssemblyLowerEmscriptenExceptions.cpp => WebAssemblyLowerEmscriptenEHSjLj.cpp} (66%) diff --git a/lib/Target/WebAssembly/CMakeLists.txt b/lib/Target/WebAssembly/CMakeLists.txt index 2ce8364b844e..61c1d38f8823 100644 --- a/lib/Target/WebAssembly/CMakeLists.txt +++ b/lib/Target/WebAssembly/CMakeLists.txt @@ -20,7 +20,7 @@ add_llvm_target(WebAssemblyCodeGen WebAssemblyISelLowering.cpp WebAssemblyInstrInfo.cpp WebAssemblyLowerBrUnless.cpp - WebAssemblyLowerEmscriptenExceptions.cpp + WebAssemblyLowerEmscriptenEHSjLj.cpp WebAssemblyMachineFunctionInfo.cpp WebAssemblyMCInstLower.cpp WebAssemblyOptimizeLiveIntervals.cpp diff --git a/lib/Target/WebAssembly/WebAssembly.h b/lib/Target/WebAssembly/WebAssembly.h index e3c7b42b19dd..c40e6c41e40d 100644 --- a/lib/Target/WebAssembly/WebAssembly.h +++ b/lib/Target/WebAssembly/WebAssembly.h @@ -26,8 +26,8 @@ class ModulePass; class FunctionPass; // LLVM IR passes. -ModulePass *createWebAssemblyLowerEmscriptenExceptions(); -void initializeWebAssemblyLowerEmscriptenExceptionsPass(PassRegistry &); +ModulePass *createWebAssemblyLowerEmscriptenEHSjLj(bool DoEH, bool DoSjLj); +void initializeWebAssemblyLowerEmscriptenEHSjLjPass(PassRegistry &); FunctionPass *createWebAssemblyOptimizeReturned(); // ISel and immediate followup passes. diff --git a/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenExceptions.cpp b/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp similarity index 66% rename from lib/Target/WebAssembly/WebAssemblyLowerEmscriptenExceptions.cpp rename to lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp index a6a8cc5fe4a7..8512b20770bb 100644 --- a/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenExceptions.cpp +++ b/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp @@ -1,4 +1,4 @@ -// WebAssemblyLowerEmscriptenExceptions.cpp - Lower exceptions for Emscripten // +//=== WebAssemblyLowerEmscriptenEHSjLj.cpp - Lower exceptions for Emscripten =// // // The LLVM Compiler Infrastructure // @@ -23,9 +23,9 @@ /// /// This pass does following things: /// -/// 1) Create three global variables: __THREW__, threwValue, and tempRet0. +/// 1) Create three global variables: __THREW__, __threwValue, and tempRet0. /// tempRet0 will be set within __cxa_find_matching_catch() function in -/// JS library, and __THREW__ and threwValue will be set in invoke wrappers +/// JS library, and __THREW__ and __threwValue will be set in invoke wrappers /// in JS glue code. For what invoke wrappers are, refer to 3). /// /// 2) Create setThrew and setTempRet0 functions. @@ -38,7 +38,7 @@ /// function setThrew(threw, value) { /// if (__THREW__ == 0) { /// __THREW__ = threw; -/// threwValue = value; +/// __threwValue = value; /// } /// } /// @@ -107,22 +107,49 @@ using namespace llvm; -#define DEBUG_TYPE "wasm-lower-em-exceptions" +#define DEBUG_TYPE "wasm-lower-em-ehsjlj" static cl::list - Whitelist("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); + 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); namespace { -class WebAssemblyLowerEmscriptenExceptions final : public ModulePass { +class WebAssemblyLowerEmscriptenEHSjLj final : public ModulePass { + static const char *ThrewGVName; + static const char *ThrewValueGVName; + static const char *TempRet0GVName; + static const char *ResumeFName; + static const char *EHTypeIDFName; + static const char *SetThrewFName; + static const char *SetTempRet0FName; + static const char *FindMatchingCatchPrefix; + static const char *InvokePrefix; + + bool DoEH; // Enable exception handling + bool DoSjLj; // Enable setjmp/longjmp handling + + GlobalVariable *ThrewGV; + GlobalVariable *ThrewValueGV; + GlobalVariable *TempRet0GV; + Function *ResumeF; + Function *EHTypeIDF; + // __cxa_find_matching_catch_N functions. + // Indexed by the number of clauses in an original landingpad instruction. + DenseMap FindMatchingCatches; + // Map of + StringMap InvokeWrappers; + // Set of whitelisted function names for exception handling + std::set EHWhitelistSet; + const char *getPassName() const override { return "WebAssembly Lower Emscripten Exceptions"; } - bool runOnFunction(Function &F); + bool runEHOnFunction(Function &F); + bool runSjLjOnFunction(Function &F); // 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 @@ -131,39 +158,41 @@ class WebAssemblyLowerEmscriptenExceptions final : public ModulePass { Function *getFindMatchingCatch(Module &M, unsigned NumClauses); Function *getInvokeWrapper(Module &M, InvokeInst *II); - bool areAllExceptionsAllowed() const { return WhitelistSet.empty(); } - - GlobalVariable *ThrewGV; // __THREW__ - GlobalVariable *ThrewValueGV; // threwValue - GlobalVariable *TempRet0GV; // tempRet0 - 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 FindMatchingCatches; - // Map of - StringMap InvokeWrappers; - // Set of whitelisted function names - std::set WhitelistSet; + bool areAllExceptionsAllowed() const { return EHWhitelistSet.empty(); } public: static char ID; - WebAssemblyLowerEmscriptenExceptions() - : ModulePass(ID), ThrewGV(nullptr), ThrewValueGV(nullptr), - TempRet0GV(nullptr) { - WhitelistSet.insert(Whitelist.begin(), Whitelist.end()); + WebAssemblyLowerEmscriptenEHSjLj(bool DoEH = true, bool DoSjLj = true) + : ModulePass(ID), DoEH(DoEH), DoSjLj(DoSjLj), ThrewGV(nullptr), + ThrewValueGV(nullptr), TempRet0GV(nullptr), ResumeF(nullptr), + EHTypeIDF(nullptr) { + EHWhitelistSet.insert(EHWhitelist.begin(), EHWhitelist.end()); } bool runOnModule(Module &M) override; }; } // End anonymous namespace -char WebAssemblyLowerEmscriptenExceptions::ID = 0; -INITIALIZE_PASS(WebAssemblyLowerEmscriptenExceptions, DEBUG_TYPE, - "WebAssembly Lower Emscripten Exceptions", false, false) - -ModulePass *llvm::createWebAssemblyLowerEmscriptenExceptions() { - return new WebAssemblyLowerEmscriptenExceptions(); +const char *WebAssemblyLowerEmscriptenEHSjLj::ThrewGVName = "__THREW__"; +const char *WebAssemblyLowerEmscriptenEHSjLj::ThrewValueGVName = "__threwValue"; +const char *WebAssemblyLowerEmscriptenEHSjLj::TempRet0GVName = "__tempRet0"; +const char *WebAssemblyLowerEmscriptenEHSjLj::ResumeFName = "__resumeException"; +const char *WebAssemblyLowerEmscriptenEHSjLj::EHTypeIDFName = + "llvm_eh_typeid_for"; +const char *WebAssemblyLowerEmscriptenEHSjLj::SetThrewFName = "setThrew"; +const char *WebAssemblyLowerEmscriptenEHSjLj::SetTempRet0FName = "setTempRet0"; +const char *WebAssemblyLowerEmscriptenEHSjLj::FindMatchingCatchPrefix = + "__cxa_find_matching_catch_"; +const char *WebAssemblyLowerEmscriptenEHSjLj::InvokePrefix = "__invoke_"; + +char WebAssemblyLowerEmscriptenEHSjLj::ID = 0; +INITIALIZE_PASS(WebAssemblyLowerEmscriptenEHSjLj, DEBUG_TYPE, + "WebAssembly Lower Emscripten Exceptions / Setjmp / Longjmp", + false, false) + +ModulePass *llvm::createWebAssemblyLowerEmscriptenEHSjLj(bool DoEH, + bool DoSjLj) { + return new WebAssemblyLowerEmscriptenEHSjLj(DoEH, DoSjLj); } static bool canThrow(const Value *V) { @@ -212,23 +241,23 @@ static std::string getSignature(FunctionType *FTy) { return Sig; } -Function *WebAssemblyLowerEmscriptenExceptions::getFindMatchingCatch( - Module &M, unsigned NumClauses) { +Function * +WebAssemblyLowerEmscriptenEHSjLj::getFindMatchingCatch(Module &M, + unsigned NumClauses) { if (FindMatchingCatches.count(NumClauses)) return FindMatchingCatches[NumClauses]; PointerType *Int8PtrTy = Type::getInt8PtrTy(M.getContext()); SmallVector Args(NumClauses, Int8PtrTy); FunctionType *FTy = FunctionType::get(Int8PtrTy, Args, false); - Function *F = Function::Create( - FTy, GlobalValue::ExternalLinkage, - "__cxa_find_matching_catch_" + Twine(NumClauses + 2), &M); + Function *F = + Function::Create(FTy, GlobalValue::ExternalLinkage, + FindMatchingCatchPrefix + Twine(NumClauses + 2), &M); FindMatchingCatches[NumClauses] = F; return F; } -Function * -WebAssemblyLowerEmscriptenExceptions::getInvokeWrapper(Module &M, - InvokeInst *II) { +Function *WebAssemblyLowerEmscriptenEHSjLj::getInvokeWrapper(Module &M, + InvokeInst *II) { SmallVector ArgTys; Value *Callee = II->getCalledValue(); FunctionType *CalleeFTy; @@ -251,58 +280,77 @@ WebAssemblyLowerEmscriptenExceptions::getInvokeWrapper(Module &M, FunctionType *FTy = FunctionType::get(CalleeFTy->getReturnType(), ArgTys, CalleeFTy->isVarArg()); Function *F = Function::Create(FTy, GlobalValue::ExternalLinkage, - "__invoke_" + Sig, &M); + InvokePrefix + Sig, &M); InvokeWrappers[Sig] = F; return F; } -bool WebAssemblyLowerEmscriptenExceptions::runOnModule(Module &M) { +bool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(Module &M) { 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, - Builder.getFalse(), - createGlobalValueName(M, "__THREW__")); + IRBuilder<> IRB(C); + IntegerType *Int1Ty = IRB.getInt1Ty(); + PointerType *Int8PtrTy = IRB.getInt8PtrTy(); + IntegerType *Int32Ty = IRB.getInt32Ty(); + Type *VoidTy = IRB.getVoidTy(); + + // Create global variables __THREW__, threwValue, and tempRet0, which are + // used in common for both exception handling and setjmp/longjmp handling + ThrewGV = + new GlobalVariable(M, Int1Ty, false, GlobalValue::ExternalLinkage, + IRB.getFalse(), createGlobalValueName(M, ThrewGVName)); ThrewValueGV = new GlobalVariable( - M, Int32Ty, false, GlobalValue::ExternalLinkage, Builder.getInt32(0), - createGlobalValueName(M, "threwValue")); - TempRet0GV = new GlobalVariable( - M, Int32Ty, false, GlobalValue::ExternalLinkage, Builder.getInt32(0), - createGlobalValueName(M, "tempRet0")); - - // Register __resumeException function - FunctionType *ResumeFTy = FunctionType::get(VoidTy, Int8PtrTy, false); - ResumeF = Function::Create(ResumeFTy, GlobalValue::ExternalLinkage, - "__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); + M, Int32Ty, false, GlobalValue::ExternalLinkage, IRB.getInt32(0), + createGlobalValueName(M, ThrewValueGVName)); + TempRet0GV = new GlobalVariable(M, Int32Ty, false, + GlobalValue::ExternalLinkage, IRB.getInt32(0), + createGlobalValueName(M, TempRet0GVName)); bool Changed = false; - for (Function &F : M) { - if (F.isDeclaration()) - continue; - Changed |= runOnFunction(F); + + // Exception handling + if (DoEH) { + // Register __resumeException function + FunctionType *ResumeFTy = FunctionType::get(VoidTy, Int8PtrTy, false); + ResumeF = Function::Create(ResumeFTy, GlobalValue::ExternalLinkage, + ResumeFName, &M); + + // Register llvm_eh_typeid_for function + FunctionType *EHTypeIDTy = FunctionType::get(Int32Ty, Int8PtrTy, false); + EHTypeIDF = Function::Create(EHTypeIDTy, GlobalValue::ExternalLinkage, + EHTypeIDFName, &M); + + for (Function &F : M) { + if (F.isDeclaration()) + continue; + Changed |= runEHOnFunction(F); + } + } + + // TODO: Run CFGSimplify like the emscripten JSBackend? + + // Setjmp/longjmp handling + if (DoSjLj) { + for (Function &F : M) { + if (F.isDeclaration()) + continue; + Changed |= runSjLjOnFunction(F); + } } if (!Changed) return false; - assert(!M.getNamedGlobal("setThrew") && "setThrew already exists"); - assert(!M.getNamedGlobal("setTempRet0") && "setTempRet0 already exists"); + // If we have made any changes while doing exception handling or + // setjmp/longjmp handling, we have to create these functions for JavaScript + // to call. + assert(!M.getNamedGlobal(SetThrewFName) && "setThrew already exists"); + assert(!M.getNamedGlobal(SetTempRet0FName) && "setTempRet0 already exists"); // Create setThrew function SmallVector Params = {Int1Ty, Int32Ty}; FunctionType *FTy = FunctionType::get(VoidTy, Params, false); Function *F = - Function::Create(FTy, GlobalValue::ExternalLinkage, "setThrew", &M); + Function::Create(FTy, GlobalValue::ExternalLinkage, SetThrewFName, &M); Argument *Arg1 = &*(F->arg_begin()); Argument *Arg2 = &*(++F->arg_begin()); Arg1->setName("threw"); @@ -311,41 +359,41 @@ bool WebAssemblyLowerEmscriptenExceptions::runOnModule(Module &M) { 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"); - Value *Cmp = Builder.CreateICmpEQ(Threw, Builder.getFalse(), "cmp"); - Builder.CreateCondBr(Cmp, ThenBB, EndBB); + IRB.SetInsertPoint(EntryBB); + Value *Threw = IRB.CreateLoad(ThrewGV, ThrewGV->getName() + ".val"); + Value *Cmp = IRB.CreateICmpEQ(Threw, IRB.getFalse(), "cmp"); + IRB.CreateCondBr(Cmp, ThenBB, EndBB); - Builder.SetInsertPoint(ThenBB); - Builder.CreateStore(Arg1, ThrewGV); - Builder.CreateStore(Arg2, ThrewValueGV); - Builder.CreateBr(EndBB); + IRB.SetInsertPoint(ThenBB); + IRB.CreateStore(Arg1, ThrewGV); + IRB.CreateStore(Arg2, ThrewValueGV); + IRB.CreateBr(EndBB); - Builder.SetInsertPoint(EndBB); - Builder.CreateRetVoid(); + IRB.SetInsertPoint(EndBB); + IRB.CreateRetVoid(); // Create setTempRet0 function Params = {Int32Ty}; FTy = FunctionType::get(VoidTy, Params, false); - F = Function::Create(FTy, GlobalValue::ExternalLinkage, "setTempRet0", &M); + F = Function::Create(FTy, GlobalValue::ExternalLinkage, SetTempRet0FName, &M); F->arg_begin()->setName("value"); EntryBB = BasicBlock::Create(C, "entry", F); - Builder.SetInsertPoint(EntryBB); - Builder.CreateStore(&*F->arg_begin(), TempRet0GV); - Builder.CreateRetVoid(); + IRB.SetInsertPoint(EntryBB); + IRB.CreateStore(&*F->arg_begin(), TempRet0GV); + IRB.CreateRetVoid(); return true; } -bool WebAssemblyLowerEmscriptenExceptions::runOnFunction(Function &F) { +bool WebAssemblyLowerEmscriptenEHSjLj::runEHOnFunction(Function &F) { Module &M = *F.getParent(); LLVMContext &C = F.getContext(); - IRBuilder<> Builder(C); + IRBuilder<> IRB(C); bool Changed = false; SmallVector ToErase; SmallPtrSet LandingPads; bool AllowExceptions = - areAllExceptionsAllowed() || WhitelistSet.count(F.getName()); + areAllExceptionsAllowed() || EHWhitelistSet.count(F.getName()); for (BasicBlock &BB : F) { auto *II = dyn_cast(BB.getTerminator()); @@ -353,7 +401,7 @@ bool WebAssemblyLowerEmscriptenExceptions::runOnFunction(Function &F) { continue; Changed = true; LandingPads.insert(II->getLandingPadInst()); - Builder.SetInsertPoint(II); + IRB.SetInsertPoint(II); bool NeedInvoke = AllowExceptions && canThrow(II->getCalledValue()); if (NeedInvoke) { @@ -371,7 +419,7 @@ bool WebAssemblyLowerEmscriptenExceptions::runOnFunction(Function &F) { // Pre-invoke // __THREW__ = 0; - Builder.CreateStore(Builder.getFalse(), ThrewGV); + IRB.CreateStore(IRB.getFalse(), ThrewGV); // Invoke function wrapper in JavaScript SmallVector CallArgs; @@ -379,7 +427,7 @@ bool WebAssemblyLowerEmscriptenExceptions::runOnFunction(Function &F) { // within the invoke wrapper later CallArgs.push_back(II->getCalledValue()); CallArgs.append(II->arg_begin(), II->arg_end()); - CallInst *NewCall = Builder.CreateCall(getInvokeWrapper(M, II), CallArgs); + CallInst *NewCall = IRB.CreateCall(getInvokeWrapper(M, II), CallArgs); NewCall->takeName(II); NewCall->setCallingConv(II->getCallingConv()); NewCall->setDebugLoc(II->getDebugLoc()); @@ -413,17 +461,17 @@ bool WebAssemblyLowerEmscriptenExceptions::runOnFunction(Function &F) { // Post-invoke // %__THREW__.val = __THREW__; __THREW__ = 0; - Value *Threw = Builder.CreateLoad(ThrewGV, ThrewGV->getName() + ".val"); - Builder.CreateStore(Builder.getFalse(), ThrewGV); + Value *Threw = IRB.CreateLoad(ThrewGV, ThrewGV->getName() + ".val"); + IRB.CreateStore(IRB.getFalse(), ThrewGV); // Insert a branch based on __THREW__ variable - Builder.CreateCondBr(Threw, II->getUnwindDest(), II->getNormalDest()); + IRB.CreateCondBr(Threw, II->getUnwindDest(), II->getNormalDest()); } else { // This can't throw, and we don't need this invoke, just replace it with a // call+branch SmallVector CallArgs(II->arg_begin(), II->arg_end()); - CallInst *NewCall = Builder.CreateCall(II->getCalledValue(), CallArgs); + CallInst *NewCall = IRB.CreateCall(II->getCalledValue(), CallArgs); NewCall->takeName(II); NewCall->setCallingConv(II->getCallingConv()); NewCall->setDebugLoc(II->getDebugLoc()); @@ -431,7 +479,7 @@ bool WebAssemblyLowerEmscriptenExceptions::runOnFunction(Function &F) { II->replaceAllUsesWith(NewCall); ToErase.push_back(II); - Builder.CreateBr(II->getNormalDest()); + IRB.CreateBr(II->getNormalDest()); // Remove any PHI node entries from the exception destination II->getUnwindDest()->removePredecessor(&BB); @@ -448,15 +496,15 @@ bool WebAssemblyLowerEmscriptenExceptions::runOnFunction(Function &F) { // Split the input into legal values Value *Input = RI->getValue(); - Builder.SetInsertPoint(RI); - Value *Low = Builder.CreateExtractValue(Input, 0, "low"); + IRB.SetInsertPoint(RI); + Value *Low = IRB.CreateExtractValue(Input, 0, "low"); // Create a call to __resumeException function Value *Args[] = {Low}; - Builder.CreateCall(ResumeF, Args); + IRB.CreateCall(ResumeF, Args); // Add a terminator to the block - Builder.CreateUnreachable(); + IRB.CreateUnreachable(); ToErase.push_back(RI); } } @@ -473,9 +521,9 @@ bool WebAssemblyLowerEmscriptenExceptions::runOnFunction(Function &F) { if (Callee->getIntrinsicID() != Intrinsic::eh_typeid_for) continue; - Builder.SetInsertPoint(CI); + IRB.SetInsertPoint(CI); CallInst *NewCI = - Builder.CreateCall(EHTypeIdF, CI->getArgOperand(0), "typeid"); + IRB.CreateCall(EHTypeIDF, CI->getArgOperand(0), "typeid"); CI->replaceAllUsesWith(NewCI); ToErase.push_back(CI); } @@ -491,7 +539,7 @@ bool WebAssemblyLowerEmscriptenExceptions::runOnFunction(Function &F) { // Handle all the landingpad for this function together, as multiple invokes // may share a single lp for (LandingPadInst *LPI : LandingPads) { - Builder.SetInsertPoint(LPI); + IRB.SetInsertPoint(LPI); SmallVector FMCArgs; for (unsigned i = 0, e = LPI->getNumClauses(); i < e; ++i) { Constant *Clause = LPI->getClause(i); @@ -501,8 +549,7 @@ bool WebAssemblyLowerEmscriptenExceptions::runOnFunction(Function &F) { if (LPI->isFilter(i)) { ArrayType *ATy = cast(Clause->getType()); for (unsigned j = 0, e = ATy->getNumElements(); j < e; ++j) { - Value *EV = - Builder.CreateExtractValue(Clause, makeArrayRef(j), "filter"); + Value *EV = IRB.CreateExtractValue(Clause, makeArrayRef(j), "filter"); FMCArgs.push_back(EV); } } else @@ -511,12 +558,11 @@ bool WebAssemblyLowerEmscriptenExceptions::runOnFunction(Function &F) { // Create a call to __cxa_find_matching_catch_N function Function *FMCF = getFindMatchingCatch(M, FMCArgs.size()); - CallInst *FMCI = Builder.CreateCall(FMCF, FMCArgs, "fmc"); + CallInst *FMCI = IRB.CreateCall(FMCF, FMCArgs, "fmc"); Value *Undef = UndefValue::get(LPI->getType()); - Value *Pair0 = Builder.CreateInsertValue(Undef, FMCI, 0, "pair0"); - Value *TempRet0 = - Builder.CreateLoad(TempRet0GV, TempRet0GV->getName() + "val"); - Value *Pair1 = Builder.CreateInsertValue(Pair0, TempRet0, 1, "pair1"); + Value *Pair0 = IRB.CreateInsertValue(Undef, FMCI, 0, "pair0"); + Value *TempRet0 = IRB.CreateLoad(TempRet0GV, TempRet0GV->getName() + "val"); + Value *Pair1 = IRB.CreateInsertValue(Pair0, TempRet0, 1, "pair1"); LPI->replaceAllUsesWith(Pair1); ToErase.push_back(LPI); @@ -528,3 +574,8 @@ bool WebAssemblyLowerEmscriptenExceptions::runOnFunction(Function &F) { return Changed; } + +bool WebAssemblyLowerEmscriptenEHSjLj::runSjLjOnFunction(Function &F) { + // TODO + return false; +} diff --git a/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp b/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp index e442cb1cdeda..1d21f2b33fd9 100644 --- a/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp +++ b/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp @@ -30,18 +30,24 @@ using namespace llvm; #define DEBUG_TYPE "wasm" // Emscripten's asm.js-style exception handling -static cl::opt EnableEmExceptionHandling( +static cl::opt EnableEmException( "enable-emscripten-cxx-exceptions", cl::desc("WebAssembly Emscripten-style exception handling"), cl::init(false)); +// Emscripten's asm.js-style setjmp/longjmp handling +static cl::opt EnableEmSjLj( + "enable-emscripten-sjlj", + cl::desc("WebAssembly Emscripten-style setjmp/longjmp handling"), + cl::init(false)); + extern "C" void LLVMInitializeWebAssemblyTarget() { // Register the target. RegisterTargetMachine X(TheWebAssemblyTarget32); RegisterTargetMachine Y(TheWebAssemblyTarget64); // Register exception handling pass to opt - initializeWebAssemblyLowerEmscriptenExceptionsPass( + initializeWebAssemblyLowerEmscriptenEHSjLjPass( *PassRegistry::getPassRegistry()); } @@ -160,8 +166,9 @@ void WebAssemblyPassConfig::addIRPasses() { addPass(createWebAssemblyOptimizeReturned()); // Handle exceptions. - if (EnableEmExceptionHandling) - addPass(createWebAssemblyLowerEmscriptenExceptions()); + if (EnableEmException || EnableEmSjLj) + addPass(createWebAssemblyLowerEmscriptenEHSjLj(EnableEmException, + EnableEmSjLj)); TargetPassConfig::addIRPasses(); } diff --git a/test/CodeGen/WebAssembly/lower-em-exceptions-whitelist.ll b/test/CodeGen/WebAssembly/lower-em-exceptions-whitelist.ll index ad8cfa28e154..e510bc9fca78 100644 --- a/test/CodeGen/WebAssembly/lower-em-exceptions-whitelist.ll +++ b/test/CodeGen/WebAssembly/lower-em-exceptions-whitelist.ll @@ -1,4 +1,4 @@ -; RUN: opt < %s -wasm-lower-em-exceptions -emscripten-cxx-exceptions-whitelist=do_catch -S | FileCheck %s +; RUN: opt < %s -wasm-lower-em-ehsjlj -emscripten-cxx-exceptions-whitelist=do_catch -S | FileCheck %s define void @dont_catch() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { ; CHECK-LABEL: @dont_catch( diff --git a/test/CodeGen/WebAssembly/lower-em-exceptions.ll b/test/CodeGen/WebAssembly/lower-em-exceptions.ll index 5e9431d3cca9..e9eb2540ccc3 100644 --- a/test/CodeGen/WebAssembly/lower-em-exceptions.ll +++ b/test/CodeGen/WebAssembly/lower-em-exceptions.ll @@ -1,10 +1,10 @@ -; RUN: opt < %s -wasm-lower-em-exceptions -S | FileCheck %s +; RUN: opt < %s -wasm-lower-em-ehsjlj -S | FileCheck %s @_ZTIi = external constant i8* @_ZTIc = external constant i8* ; CHECK: @[[__THREW__:__THREW__.*]] = global i1 false -; CHECK: @[[THREWVALUE:threwValue.*]] = global i32 0 -; CHECK: @[[TEMPRET0:tempRet0.*]] = global i32 0 +; CHECK: @[[THREWVALUE:__threwValue.*]] = global i32 0 +; CHECK: @[[TEMPRET0:__tempRet0.*]] = global i32 0 ; Test invoke instruction with clauses (try-catch block) define void @clause() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { @@ -170,12 +170,12 @@ declare void @__cxa_call_unexpected(i8*) ; setThrew function creation ; CHECK-LABEL: define void @setThrew(i1 %threw, i32 %value) { ; CHECK: entry: -; CHECK-NEXT: %__THREW__.val = load i1, i1* @__THREW__ -; CHECK-NEXT: %cmp = icmp eq i1 %__THREW__.val, false +; CHECK-NEXT: %[[__THREW__]].val = load i1, i1* @[[__THREW__]] +; CHECK-NEXT: %cmp = icmp eq i1 %[[__THREW__]].val, false ; CHECK-NEXT: br i1 %cmp, label %if.then, label %if.end ; CHECK: if.then: -; CHECK-NEXT: store i1 %threw, i1* @__THREW__ -; CHECK-NEXT: store i32 %value, i32* @threwValue +; CHECK-NEXT: store i1 %threw, i1* @[[__THREW__]] +; CHECK-NEXT: store i32 %value, i32* @[[THREWVALUE]] ; CHECK-NEXT: br label %if.end ; CHECK: if.end: ; CHECK-NEXT: ret void @@ -184,6 +184,6 @@ declare void @__cxa_call_unexpected(i8*) ; setTempRet0 function creation ; CHECK-LABEL: define void @setTempRet0(i32 %value) { ; CHECK: entry: -; CHECK-NEXT: store i32 %value, i32* @tempRet0 +; CHECK-NEXT: store i32 %value, i32* @[[TEMPRET0]] ; CHECK-NEXT: ret void ; CHECK: }