[WebAssembly] Add -emscripten-cxx-exceptions-whitelist option
authorDerek Schuff <dschuff@google.com>
Tue, 9 Aug 2016 22:37:00 +0000 (22:37 +0000)
committerDerek Schuff <dschuff@google.com>
Tue, 9 Aug 2016 22:37:00 +0000 (22:37 +0000)
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

llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenExceptions.cpp
llvm/test/CodeGen/WebAssembly/lower-em-exceptions-whitelist.ll [new file with mode: 0644]

index c906767..7a7587b 100644 (file)
@@ -109,6 +109,13 @@ using namespace llvm;
 
 #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 {
 class WebAssemblyLowerEmscriptenExceptions final : public ModulePass {
   const char *getPassName() const override {
@@ -124,6 +131,7 @@ 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
@@ -135,13 +143,17 @@ class WebAssemblyLowerEmscriptenExceptions final : public ModulePass {
   DenseMap<int, Function *> FindMatchingCatches;
   // Map of <function signature string, invoke_ wrappers>
   StringMap<Function *> InvokeWrappers;
+  // Set of whitelisted function names
+  std::set<std::string> WhitelistSet;
 
 public:
   static char ID;
 
   WebAssemblyLowerEmscriptenExceptions()
       : ModulePass(ID), ThrewGV(nullptr), ThrewValueGV(nullptr),
-        TempRet0GV(nullptr) {}
+        TempRet0GV(nullptr) {
+    WhitelistSet.insert(Whitelist.begin(), Whitelist.end());
+  }
   bool runOnModule(Module &M) override;
 };
 } // End anonymous namespace
@@ -332,7 +344,8 @@ bool WebAssemblyLowerEmscriptenExceptions::runOnFunction(Function &F) {
   bool Changed = false;
   SmallVector<Instruction *, 64> ToErase;
   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) {
     auto *II = dyn_cast<InvokeInst>(BB.getTerminator());
diff --git a/llvm/test/CodeGen/WebAssembly/lower-em-exceptions-whitelist.ll b/llvm/test/CodeGen/WebAssembly/lower-em-exceptions-whitelist.ll
new file mode 100644 (file)
index 0000000..ad8cfa2
--- /dev/null
@@ -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()