aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2014-01-09 15:56:56 -0800
committerAlon Zakai <alonzakai@gmail.com>2014-01-09 16:04:25 -0800
commit245715440fb27520b37e27ad1c62c90acc1abc20 (patch)
tree4d18aee6379753a994bbcf14be642485405c80ec
parenta78b08fd3d9f5ad0adaa5336411fec34a34c3bf0 (diff)
exception handling support
-rw-r--r--include/llvm/InitializePasses.h3
-rw-r--r--include/llvm/Transforms/NaCl.h3
-rw-r--r--lib/Target/JSBackend/CallHandlers.h96
-rw-r--r--lib/Target/JSBackend/JSBackend.cpp33
-rw-r--r--lib/Transforms/NaCl/CMakeLists.txt1
-rw-r--r--lib/Transforms/NaCl/LowerEmExceptionsPass.cpp118
-rw-r--r--lib/Transforms/NaCl/PNaClABISimplify.cpp7
7 files changed, 227 insertions, 34 deletions
diff --git a/include/llvm/InitializePasses.h b/include/llvm/InitializePasses.h
index 1e2d6203fb..3e0107944d 100644
--- a/include/llvm/InitializePasses.h
+++ b/include/llvm/InitializePasses.h
@@ -305,7 +305,8 @@ void initializeRewriteLLVMIntrinsicsPass(PassRegistry&);
void initializeRewritePNaClLibraryCallsPass(PassRegistry&);
void initializeStripAttributesPass(PassRegistry&);
void initializeStripMetadataPass(PassRegistry&);
-void initializeExpandI64Pass(PassRegistry&); // EMSCRIPTEN
+void initializeExpandI64Pass(PassRegistry&); // XXX EMSCRIPTEN
+void initializeLowerEmExceptionsPass(PassRegistry&); // XXX EMSCRIPTEN
// @LOCALMOD-END
}
diff --git a/include/llvm/Transforms/NaCl.h b/include/llvm/Transforms/NaCl.h
index 429f5a1fe1..03d22c994d 100644
--- a/include/llvm/Transforms/NaCl.h
+++ b/include/llvm/Transforms/NaCl.h
@@ -50,7 +50,8 @@ ModulePass *createRewritePNaClLibraryCallsPass();
ModulePass *createStripAttributesPass();
ModulePass *createStripMetadataPass();
-ModulePass *createExpandI64Pass(); // EMSCRIPTEN
+ModulePass *createExpandI64Pass(); // XXX EMSCRIPTEN
+ModulePass *createLowerEmExceptionsPass(); // XXX EMSCRIPTEN
void PNaClABISimplifyAddPreOptPasses(PassManager &PM);
void PNaClABISimplifyAddPostOptPasses(PassManager &PM);
diff --git a/lib/Target/JSBackend/CallHandlers.h b/lib/Target/JSBackend/CallHandlers.h
index 221421a80a..aa4a1a7c93 100644
--- a/lib/Target/JSBackend/CallHandlers.h
+++ b/lib/Target/JSBackend/CallHandlers.h
@@ -2,14 +2,27 @@
//
// Each handler needs DEF_CALL_HANDLER and SETUP_CALL_HANDLER
-typedef std::string (JSWriter::*CallHandler)(const CallInst*, std::string Name, int NumArgs);
+typedef std::string (JSWriter::*CallHandler)(const Instruction*, std::string Name, int NumArgs);
typedef std::map<std::string, CallHandler> CallHandlerMap;
CallHandlerMap *CallHandlers;
// Definitions
-const Value *getActuallyCalledValue(const CallInst *CI) {
- const Value *CV = CI->getCalledValue();
+unsigned getNumArgOperands(const Instruction *I) {
+ if (const CallInst *CI = dyn_cast<const CallInst>(I)) {
+ return CI->getNumArgOperands();
+ } else {
+ return cast<const InvokeInst>(I)->getNumArgOperands();
+ }
+}
+
+const Value *getActuallyCalledValue(const Instruction *I) {
+ const Value *CV = NULL;
+ if (const CallInst *CI = dyn_cast<const CallInst>(I)) {
+ CV = CI->getCalledValue();
+ } else {
+ CV = cast<const InvokeInst>(I)->getCalledValue();
+ }
if (const BitCastInst *B = dyn_cast<const BitCastInst>(CV)) {
// if the called value is a bitcast of a function, then we just call it directly, properly
// for example, extern void x() in C will turn into void x(...) in LLVM IR, then the IR bitcasts
@@ -23,32 +36,55 @@ const Value *getActuallyCalledValue(const CallInst *CI) {
}
#define DEF_CALL_HANDLER(Ident, Code) \
- std::string CH_##Ident(const CallInst *CI, std::string Name, int NumArgs=-1) { Code }
+ std::string CH_##Ident(const Instruction *CI, std::string Name, int NumArgs=-1) { Code }
DEF_CALL_HANDLER(__default__, {
const Value *CV = getActuallyCalledValue(CI);
bool NeedCasts;
FunctionType *FT;
- if (const Function *F = dyn_cast<const Function>(CV)) {
+ bool Invoke = false;
+ if (isa<const InvokeInst>(CI)) {
+ // invoke of f(a, b) turns into invoke_sig(index-of-f, a, b)
+ Invoke = true;
+ }
+ std::string Sig;
+ const Function *F = dyn_cast<const Function>(CV);
+ if (F) {
NeedCasts = F->isDeclaration(); // if ffi call, need casts
FT = F->getFunctionType();
} else {
// function pointer call
FT = dyn_cast<FunctionType>(dyn_cast<PointerType>(CV->getType())->getElementType());
- std::string Sig = getFunctionSignature(FT);
- Name = std::string("FUNCTION_TABLE_") + Sig + "[" + Name + " & #FM_" + Sig + "#]";
ensureFunctionTable(FT);
- NeedCasts = false; // function table call, so stays in asm module
+ if (!Invoke) {
+ Sig = getFunctionSignature(FT);
+ Name = std::string("FUNCTION_TABLE_") + Sig + "[" + Name + " & #FM_" + Sig + "#]";
+ NeedCasts = false; // function table call, so stays in asm module
+ }
+ }
+ if (Invoke) {
+ Sig = getFunctionSignature(FT);
+ Name = "invoke_" + Sig;
+ NeedCasts = true;
}
std::string text = Name + "(";
- if (NumArgs == -1) NumArgs = CI->getNumOperands()-1; // last operand is the function itself
+ if (NumArgs == -1) NumArgs = getNumArgOperands(CI);
+ if (Invoke) {
+ // add first param
+ if (F) {
+ text += utostr(getFunctionIndex(F)); // convert to function pointer
+ } else {
+ text += getValueAsStr(CV); // already a function pointer
+ }
+ if (NumArgs > 0) text += ",";
+ }
for (int i = 0; i < NumArgs; i++) {
if (!NeedCasts) {
- text += getValueAsStr(CI->getArgOperand(i));
+ text += getValueAsStr(CI->getOperand(i));
} else {
- text += getValueAsCastStr(CI->getArgOperand(i), ASM_NONSPECIFIC);
+ text += getValueAsCastStr(CI->getOperand(i), ASM_NONSPECIFIC);
}
- if (i < NumArgs - 1) text += ", ";
+ if (i < NumArgs - 1) text += ",";
}
text += ")";
// handle return value
@@ -70,20 +106,20 @@ DEF_CALL_HANDLER(getHigh32, {
})
DEF_CALL_HANDLER(setHigh32, {
- return "tempRet0 = " + getValueAsStr(CI->getArgOperand(0));
+ return "tempRet0 = " + getValueAsStr(CI->getOperand(0));
})
DEF_CALL_HANDLER(FPtoILow, {
- return getAssign(getJSName(CI), CI->getType()) + "(~~" + getValueAsStr(CI->getArgOperand(0)) + ")>>>0";
+ return getAssign(getJSName(CI), CI->getType()) + "(~~" + getValueAsStr(CI->getOperand(0)) + ")>>>0";
})
DEF_CALL_HANDLER(FPtoIHigh, {
- std::string Input = getValueAsStr(CI->getArgOperand(0));
+ std::string Input = getValueAsStr(CI->getOperand(0));
return getAssign(getJSName(CI), CI->getType()) + "+Math_abs(" + Input + ") >= +1 ? " + Input + " > +0 ? (Math_min(+Math_floor(" + Input + " / +4294967296), +4294967295) | 0) >>> 0 : ~~+Math_ceil((" + Input + " - +(~~" + Input + " >>> 0)) / +4294967296) >>> 0 : 0";
})
DEF_CALL_HANDLER(BDtoILow, {
- return "HEAPF64[tempDoublePtr>>3] = " + getValueAsStr(CI->getArgOperand(0)) + ";" + getAssign(getJSName(CI), CI->getType()) + "HEAP32[tempDoublePtr>>2]|0";
+ return "HEAPF64[tempDoublePtr>>3] = " + getValueAsStr(CI->getOperand(0)) + ";" + getAssign(getJSName(CI), CI->getType()) + "HEAP32[tempDoublePtr>>2]|0";
})
DEF_CALL_HANDLER(BDtoIHigh, {
@@ -92,34 +128,34 @@ DEF_CALL_HANDLER(BDtoIHigh, {
DEF_CALL_HANDLER(SItoF, {
// TODO: fround
- return getAssign(getJSName(CI), CI->getType()) + "(+" + getValueAsCastParenStr(CI->getArgOperand(0), ASM_UNSIGNED) + ") + " +
- "(+4294967296*(+" + getValueAsCastParenStr(CI->getArgOperand(1), ASM_SIGNED) + "))";
+ return getAssign(getJSName(CI), CI->getType()) + "(+" + getValueAsCastParenStr(CI->getOperand(0), ASM_UNSIGNED) + ") + " +
+ "(+4294967296*(+" + getValueAsCastParenStr(CI->getOperand(1), ASM_SIGNED) + "))";
})
DEF_CALL_HANDLER(UItoF, {
// TODO: fround
- return getAssign(getJSName(CI), CI->getType()) + "(+" + getValueAsCastParenStr(CI->getArgOperand(0), ASM_UNSIGNED) + ") + " +
- "(+4294967296*(+" + getValueAsCastParenStr(CI->getArgOperand(1), ASM_UNSIGNED) + "))";
+ return getAssign(getJSName(CI), CI->getType()) + "(+" + getValueAsCastParenStr(CI->getOperand(0), ASM_UNSIGNED) + ") + " +
+ "(+4294967296*(+" + getValueAsCastParenStr(CI->getOperand(1), ASM_UNSIGNED) + "))";
})
DEF_CALL_HANDLER(SItoD, {
- return getAssign(getJSName(CI), CI->getType()) + "(+" + getValueAsCastParenStr(CI->getArgOperand(0), ASM_UNSIGNED) + ") + " +
- "(+4294967296*(+" + getValueAsCastParenStr(CI->getArgOperand(1), ASM_SIGNED) + "))";
+ return getAssign(getJSName(CI), CI->getType()) + "(+" + getValueAsCastParenStr(CI->getOperand(0), ASM_UNSIGNED) + ") + " +
+ "(+4294967296*(+" + getValueAsCastParenStr(CI->getOperand(1), ASM_SIGNED) + "))";
})
DEF_CALL_HANDLER(UItoD, {
- return getAssign(getJSName(CI), CI->getType()) + "(+" + getValueAsCastParenStr(CI->getArgOperand(0), ASM_UNSIGNED) + ") + " +
- "(+4294967296*(+" + getValueAsCastParenStr(CI->getArgOperand(1), ASM_UNSIGNED) + "))";
+ return getAssign(getJSName(CI), CI->getType()) + "(+" + getValueAsCastParenStr(CI->getOperand(0), ASM_UNSIGNED) + ") + " +
+ "(+4294967296*(+" + getValueAsCastParenStr(CI->getOperand(1), ASM_UNSIGNED) + "))";
})
DEF_CALL_HANDLER(BItoD, {
- return "HEAP32[tempDoublePtr>>2] = " + getValueAsStr(CI->getArgOperand(0)) + ";" +
- "HEAP32[tempDoublePtr+4>>2] = " + getValueAsStr(CI->getArgOperand(1)) + ";" +
+ return "HEAP32[tempDoublePtr>>2] = " + getValueAsStr(CI->getOperand(0)) + ";" +
+ "HEAP32[tempDoublePtr+4>>2] = " + getValueAsStr(CI->getOperand(1)) + ";" +
getAssign(getJSName(CI), CI->getType()) + "+HEAPF64[tempDoublePtr>>3]";
})
DEF_CALL_HANDLER(llvm_nacl_atomic_store_i32, {
- return "HEAP32[" + getValueAsStr(CI->getArgOperand(0)) + ">>2]=" + getValueAsStr(CI->getArgOperand(1));
+ return "HEAP32[" + getValueAsStr(CI->getOperand(0)) + ">>2]=" + getValueAsStr(CI->getOperand(1));
})
DEF_CALL_HANDLER(llvm_memcpy_p0i8_p0i8_i32, {
@@ -138,7 +174,7 @@ DEF_CALL_HANDLER(llvm_memmove_p0i8_p0i8_i32, {
})
DEF_CALL_HANDLER(llvm_expect_i32, {
- return getAssign(getJSName(CI), CI->getType()) + getValueAsStr(CI->getArgOperand(0));
+ return getAssign(getJSName(CI), CI->getType()) + getValueAsStr(CI->getOperand(0));
})
DEF_CALL_HANDLER(llvm_dbg_declare, {
@@ -817,12 +853,12 @@ void setupCallHandlers() {
SETUP_CALL_HANDLER(SDL_RWFromMem);
}
-std::string handleCall(const CallInst *CI) {
+std::string handleCall(const Instruction *CI) {
const Value *CV = getActuallyCalledValue(CI);
assert(!isa<InlineAsm>(CV) && "asm() not supported, use EM_ASM() (see emscripten.h)");
std::string Name = getJSName(CV);
if (strcmp(Name.c_str(), "_llvm_dbg_value") == 0) return ""; // ignore this
- unsigned NumArgs = CI->getNumArgOperands();
+ unsigned NumArgs = getNumArgOperands(CI);
CallHandlerMap::iterator CH = CallHandlers->find("___default__");
if (isa<Function>(CV)) {
CallHandlerMap::iterator Custom = CallHandlers->find(Name);
diff --git a/lib/Target/JSBackend/JSBackend.cpp b/lib/Target/JSBackend/JSBackend.cpp
index 7fb4208744..2cc66c3a4b 100644
--- a/lib/Target/JSBackend/JSBackend.cpp
+++ b/lib/Target/JSBackend/JSBackend.cpp
@@ -237,6 +237,7 @@ namespace {
}
}
std::string getPtrAsStr(const Value* Ptr) {
+ if (isa<const ConstantPointerNull>(Ptr)) return "0";
if (const Function *F = dyn_cast<Function>(Ptr)) {
return utostr(getFunctionIndex(F));
} else if (const Constant *CV = dyn_cast<Constant>(Ptr)) {
@@ -941,8 +942,8 @@ void JSWriter::generateInstruction(const Instruction *I, raw_string_ostream& Cod
case Instruction::Br:
case Instruction::Switch: break; // handled while relooping
case Instruction::Unreachable: {
- // No need to emit anything, as there should be an abort right before these
- // Code << "abort();";
+ // Typically there should be an abort right before these, so we don't emit any code // TODO: when ASSERTIONS are on, emit abort(0)
+ Code << "// unreachable";
break;
}
case Instruction::Add:
@@ -1237,6 +1238,24 @@ void JSWriter::generateInstruction(const Instruction *I, raw_string_ostream& Cod
Code << ";";
break;
}
+ case Instruction::Invoke: {
+ Code << "__THREW__ = 0;";
+ const InvokeInst *II = cast<InvokeInst>(I);
+ Code << handleCall(II) + ';';
+ // the check and branch and done in the relooper setup code
+ break;
+ }
+ case Instruction::LandingPad: {
+ const LandingPadInst *LP = cast<const LandingPadInst>(I);
+ Code << getAssign(iName, I->getType());
+ Code << "___cxa_find_matching_catch(-1,-1";
+ unsigned n = LP->getNumClauses();
+ for (unsigned i = 0; i < n; i++) {
+ Code << "," + getValueAsStr(LP->getClause(i));
+ }
+ Code << ")|0;";
+ break;
+ }
}
// append debug info
if (MDNode *N = I->getMetadata("dbg")) {
@@ -1357,6 +1376,16 @@ void JSWriter::printFunctionBody(const Function *F) {
}
break;
}
+ case Instruction::Invoke: {
+ const InvokeInst* II = cast<InvokeInst>(TI);
+ BasicBlock *S0 = II->getNormalDest();
+ BasicBlock *S1 = II->getUnwindDest();
+ std::string P0 = getPhiCode(&*BI, S0);
+ std::string P1 = getPhiCode(&*BI, S1);
+ LLVMToRelooper[&*BI]->AddBranchTo(LLVMToRelooper[&*S0], "!__THREW__", P0.size() > 0 ? P0.c_str() : NULL);
+ LLVMToRelooper[&*BI]->AddBranchTo(LLVMToRelooper[&*S1], NULL, P1.size() > 0 ? P1.c_str() : NULL);
+ break;
+ }
case Instruction::Ret:
case Instruction::Unreachable: break;
}
diff --git a/lib/Transforms/NaCl/CMakeLists.txt b/lib/Transforms/NaCl/CMakeLists.txt
index a344a163b7..9d97378638 100644
--- a/lib/Transforms/NaCl/CMakeLists.txt
+++ b/lib/Transforms/NaCl/CMakeLists.txt
@@ -29,6 +29,7 @@ add_llvm_library(LLVMNaClTransforms
StripAttributes.cpp
StripMetadata.cpp
ExpandI64.cpp
+ LowerEmExceptions.cpp
)
add_dependencies(LLVMNaClTransforms intrinsics_gen)
diff --git a/lib/Transforms/NaCl/LowerEmExceptionsPass.cpp b/lib/Transforms/NaCl/LowerEmExceptionsPass.cpp
new file mode 100644
index 0000000000..3690537c4e
--- /dev/null
+++ b/lib/Transforms/NaCl/LowerEmExceptionsPass.cpp
@@ -0,0 +1,118 @@
+//===- LowerEmExceptions - Lower exceptions for Emscripten/JS -----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This is based off the 'cheap' version of LowerInvoke. It does two things:
+//
+// 1) Lower
+// invoke() to l1 unwind l2
+// into
+// preinvoke(); // (will clear __THREW__)
+// call();
+// threw = postinvoke(); (check __THREW__)
+// br threw, l1, l2
+//
+// 2) Lower landingpads to return a single i8*, avoid the structural type
+// which is unneeded anyhow.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Transforms/Scalar.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Target/TargetLowering.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+#include "llvm/Transforms/Utils/Local.h"
+#include "llvm/Transforms/NaCl.h"
+
+using namespace llvm;
+
+namespace {
+ class LowerEmExceptions : public ModulePass {
+ Function *PreInvoke, *PostInvoke;
+ Module *TheModule;
+
+ public:
+ static char ID; // Pass identification, replacement for typeid
+ explicit LowerEmExceptions() : ModulePass(ID), PreInvoke(NULL), PostInvoke(NULL), TheModule(NULL) {
+ initializeLowerEmExceptionsPass(*PassRegistry::getPassRegistry());
+ }
+ bool runOnModule(Module &M);
+ };
+}
+
+char LowerEmExceptions::ID = 0;
+INITIALIZE_PASS(LowerEmExceptions, "loweremexceptions",
+ "Lower invoke and unwind for js/emscripten",
+ false, false)
+
+Instruction *getSingleUse(Instruction *I) {
+ Instruction *Ret = NULL;
+ for (Instruction::use_iterator UI = I->use_begin(), UE = I->use_end(); UI != UE; ++UI) {
+ assert(Ret == NULL);
+ Ret = cast<ExtractElementInst>(*UI);
+ }
+ assert(Ret != NULL);
+ return Ret;
+}
+
+bool LowerEmExceptions::runOnModule(Module &M) {
+ TheModule = &M;
+
+ Type *Void = Type::getVoidTy(M.getContext());
+ Type *i32 = Type::getInt32Ty(M.getContext());
+
+ SmallVector<Type*, 0> ArgTypes;
+ FunctionType *VoidFunc = FunctionType::get(Void, ArgTypes, false);
+ FunctionType *IntFunc = FunctionType::get(i32, ArgTypes, false);
+
+ PreInvoke = Function::Create(VoidFunc, GlobalValue::ExternalLinkage, "preInvoke", TheModule);
+ PostInvoke = Function::Create(IntFunc, GlobalValue::ExternalLinkage, "postInvoke", TheModule);
+
+ bool Changed = false;
+
+ for (Module::iterator Iter = M.begin(), E = M.end(); Iter != E; ) {
+ Function *F = Iter++;
+ for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) {
+ if (InvokeInst *II = dyn_cast<InvokeInst>(BB->getTerminator())) {
+ // Fix up the landingpad. First, make a copy returning just an integer
+ LandingPadInst *LP = II->getLandingPadInst();
+ unsigned Num = LP->getNumClauses();
+ LandingPadInst *NewLP = LandingPadInst::Create(i32, LP->getPersonalityFn(), Num, "", LP);
+ NewLP->setCleanup(LP->isCleanup());
+ for (unsigned i = 0; i < Num; i++) NewLP->addClause(LP->getClause(i));
+
+ // Next, replace the old LP's single use, which is an extractelement, to eliminate the ee's and use the value directly
+ ExtractElementInst *EE = cast<ExtractElementInst>(getSingleUse(LP));
+ EE->replaceAllUsesWith(NewLP);
+ EE->eraseFromParent();
+
+ // Finish the LP by replacing it
+ LP->replaceAllUsesWith(NewLP);
+ LP->eraseFromParent();
+
+ Changed = true;
+ }
+ }
+ }
+
+ return Changed;
+}
+
+ModulePass *llvm::createLowerEmExceptionsPass() {
+ return new LowerEmExceptions();
+}
+
diff --git a/lib/Transforms/NaCl/PNaClABISimplify.cpp b/lib/Transforms/NaCl/PNaClABISimplify.cpp
index 38d8ae0a40..ab88be133c 100644
--- a/lib/Transforms/NaCl/PNaClABISimplify.cpp
+++ b/lib/Transforms/NaCl/PNaClABISimplify.cpp
@@ -27,6 +27,11 @@ EnableSjLjEH("enable-pnacl-sjlj-eh",
"as part of the pnacl-abi-simplify passes"),
cl::init(false));
+static cl::opt<bool> // XXX EMSCRIPTEN
+EnableEmCxxExceptions("enable-emscripten-cxx-exceptions",
+ cl::desc("Enables C++ exceptions in emscripten"),
+ cl::init(false));
+
void llvm::PNaClABISimplifyAddPreOptPasses(PassManager &PM) {
if (EnableSjLjEH) {
// This comes before ExpandTls because it introduces references to
@@ -34,6 +39,8 @@ void llvm::PNaClABISimplifyAddPreOptPasses(PassManager &PM) {
// InternalizePass because it assumes various variables (including
// __pnacl_eh_stack) have not been internalized yet.
PM.add(createPNaClSjLjEHPass());
+ } else if (EnableEmCxxExceptions) { // XXX EMSCRIPTEN
+ PM.add(createLowerEmExceptionsPass());
} else {
// LowerInvoke prevents use of C++ exception handling by removing
// references to BasicBlocks which handle exceptions.