[WebAssembly] Add -emscripten-cxx-exceptions-whitelist option

This patch adds -emscripten-cxx-exceptions-whitelist option to
WebAssemblyLowerEmscriptenExceptions pass. This options is the list of
function names in which Emscripten-style exception handling is enabled.
This is to support emscripten's EXCEPTION_CATCHING_WHITELIST which
exists because of the performance impact of emscripten's non-zero-cost
EH method.

Patch by Heejin Ahn

Differential Revision: https://reviews.llvm.org/D23292

llvm-svn: 278171
This commit is contained in:
Derek Schuff 2016-08-09 22:37:00 +00:00
parent e7c2875dc3
commit 66641322ce
2 changed files with 77 additions and 2 deletions

View File

@ -109,6 +109,13 @@ using namespace llvm;
#define DEBUG_TYPE "wasm-lower-em-exceptions" #define DEBUG_TYPE "wasm-lower-em-exceptions"
static cl::list<std::string>
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);
namespace { namespace {
class WebAssemblyLowerEmscriptenExceptions final : public ModulePass { class WebAssemblyLowerEmscriptenExceptions final : public ModulePass {
const char *getPassName() const override { const char *getPassName() const override {
@ -124,6 +131,7 @@ class WebAssemblyLowerEmscriptenExceptions final : public ModulePass {
Function *getFindMatchingCatch(Module &M, unsigned NumClauses); Function *getFindMatchingCatch(Module &M, unsigned NumClauses);
Function *getInvokeWrapper(Module &M, InvokeInst *II); Function *getInvokeWrapper(Module &M, InvokeInst *II);
bool areAllExceptionsAllowed() const { return WhitelistSet.empty(); }
GlobalVariable *ThrewGV; // __THREW__ GlobalVariable *ThrewGV; // __THREW__
GlobalVariable *ThrewValueGV; // threwValue GlobalVariable *ThrewValueGV; // threwValue
@ -135,13 +143,17 @@ class WebAssemblyLowerEmscriptenExceptions final : public ModulePass {
DenseMap<int, Function *> FindMatchingCatches; DenseMap<int, Function *> FindMatchingCatches;
// Map of <function signature string, invoke_ wrappers> // Map of <function signature string, invoke_ wrappers>
StringMap<Function *> InvokeWrappers; StringMap<Function *> InvokeWrappers;
// Set of whitelisted function names
std::set<std::string> WhitelistSet;
public: public:
static char ID; static char ID;
WebAssemblyLowerEmscriptenExceptions() WebAssemblyLowerEmscriptenExceptions()
: ModulePass(ID), ThrewGV(nullptr), ThrewValueGV(nullptr), : ModulePass(ID), ThrewGV(nullptr), ThrewValueGV(nullptr),
TempRet0GV(nullptr) {} TempRet0GV(nullptr) {
WhitelistSet.insert(Whitelist.begin(), Whitelist.end());
}
bool runOnModule(Module &M) override; bool runOnModule(Module &M) override;
}; };
} // End anonymous namespace } // End anonymous namespace
@ -332,7 +344,8 @@ bool WebAssemblyLowerEmscriptenExceptions::runOnFunction(Function &F) {
bool Changed = false; bool Changed = false;
SmallVector<Instruction *, 64> ToErase; SmallVector<Instruction *, 64> ToErase;
SmallPtrSet<LandingPadInst *, 32> LandingPads; SmallPtrSet<LandingPadInst *, 32> LandingPads;
bool AllowExceptions = true; // will later change based on whitelist option bool AllowExceptions =
areAllExceptionsAllowed() || WhitelistSet.count(F.getName());
for (BasicBlock &BB : F) { for (BasicBlock &BB : F) {
auto *II = dyn_cast<InvokeInst>(BB.getTerminator()); auto *II = dyn_cast<InvokeInst>(BB.getTerminator());

View File

@ -0,0 +1,62 @@
; RUN: opt < %s -wasm-lower-em-exceptions -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(
entry:
invoke void @foo()
to label %invoke.cont unwind label %lpad
; CHECK: entry:
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: br label %invoke.cont
invoke.cont: ; preds = %entry
br label %try.cont
lpad: ; preds = %entry
%0 = landingpad { i8*, i32 }
catch i8* null
%1 = extractvalue { i8*, i32 } %0, 0
%2 = extractvalue { i8*, i32 } %0, 1
br label %catch
catch: ; preds = %lpad
%3 = call i8* @__cxa_begin_catch(i8* %1)
call void @__cxa_end_catch()
br label %try.cont
try.cont: ; preds = %catch, %invoke.cont
ret void
}
define void @do_catch() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
; CHECK-LABEL: @do_catch(
entry:
invoke void @foo()
to label %invoke.cont unwind label %lpad
; CHECK: entry:
; CHECK-NEXT: store i1 false, i1*
; CHECK-NEXT: call void @__invoke_void(void ()* @foo)
invoke.cont: ; preds = %entry
br label %try.cont
lpad: ; preds = %entry
%0 = landingpad { i8*, i32 }
catch i8* null
%1 = extractvalue { i8*, i32 } %0, 0
%2 = extractvalue { i8*, i32 } %0, 1
br label %catch
catch: ; preds = %lpad
%3 = call i8* @__cxa_begin_catch(i8* %1)
call void @__cxa_end_catch()
br label %try.cont
try.cont: ; preds = %catch, %invoke.cont
ret void
}
declare void @foo()
declare i32 @__gxx_personality_v0(...)
declare i8* @__cxa_begin_catch(i8*)
declare void @__cxa_end_catch()