summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenExceptions.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenExceptions.cpp')
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenExceptions.cpp125
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());
OpenPOWER on IntegriCloud