[llvm] b7b4ebb - [WebAssembly] Rethrow longjmp in EH handling if EmSjLj is enabled

Heejin Ahn via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 13 14:16:14 PDT 2021


Author: Heejin Ahn
Date: 2021-09-13T14:15:25-07:00
New Revision: b7b4ebbcfa463a7fae61dca7cec30c5b747bdec8

URL: https://github.com/llvm/llvm-project/commit/b7b4ebbcfa463a7fae61dca7cec30c5b747bdec8
DIFF: https://github.com/llvm/llvm-project/commit/b7b4ebbcfa463a7fae61dca7cec30c5b747bdec8.diff

LOG: [WebAssembly] Rethrow longjmp in EH handling if EmSjLj is enabled

This is a fix on top of D106525's Case 2. In D106525, in
`runEHOnFunction` which handles Emscripten EH, We rethrow `longjmp` only
when the module has any usage of `setjmp` or `longjmp`. But now Wasm
object files are linked using wasm-ld, the module this pass sees is not
the whole program, and even if this module does not contain any
`longjmp`, another file can contain it and can be linked with the
current module. This enables the rethrowing of longjmp whenever
Emscripten SjLj is enabled, regardless of whether it is used in this
module or not.

Reviewed By: dschuff

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

Added: 
    llvm/test/CodeGen/WebAssembly/lower-em-ehsjlj-sjlj-not-used.ll

Modified: 
    llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
index 979a17bf8e680..dd8909bc416bf 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
@@ -932,6 +932,18 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(Module &M) {
     }
   }
 
+  // Above, we registered emscripten_longjmp function only when it SjLj is
+  // actually used. But there is a case we need emscripten_longjmp when we
+  // rethrow longjmps after checking for an Emscripten exception. Refer to
+  // runEHOnFunction for details.
+  if (EnableEmEH && EnableEmSjLj && !EmLongjmpF) {
+    // Register emscripten_longjmp function
+    FunctionType *FTy = FunctionType::get(
+        IRB.getVoidTy(), {getAddrIntType(&M), IRB.getInt32Ty()}, false);
+    EmLongjmpF = getEmscriptenFunction(FTy, "emscripten_longjmp", &M);
+    EmLongjmpF->addFnAttr(Attribute::NoReturn);
+  }
+
   // Exception handling transformation
   if (EnableEmEH) {
     for (Function &F : M) {
@@ -1009,6 +1021,11 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runEHOnFunction(Function &F) {
       // value is 0 when nothing happened, 1 when an exception is thrown, and
       // other values when longjmp is thrown.
       //
+      // Note that we do this whenever -enable-emscripten-sjlj is on, regardless
+      // of whether there is actual usage of setjmp/longjmp within the module.
+      // Because we use wasm-ld to link files, what we see here is not the whole
+      // program, and there can be a longjmp call in another file.
+      //
       // if (%__THREW__.val == 0 || %__THREW__.val == 1)
       //   goto %tail
       // else
@@ -1020,8 +1037,7 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runEHOnFunction(Function &F) {
       //
       // tail: ;; Nothing happened or an exception is thrown
       //   ... Continue exception handling ...
-      if (DoSjLj && EnableEmSjLj && !SetjmpUsers.count(&F) &&
-          canLongjmp(Callee)) {
+      if (EnableEmSjLj && !SetjmpUsers.count(&F) && canLongjmp(Callee)) {
         // Create longjmp.rethrow BB once and share it within the function
         if (!RethrowLongjmpBB) {
           RethrowLongjmpBB = BasicBlock::Create(C, "rethrow.longjmp", &F);

diff  --git a/llvm/test/CodeGen/WebAssembly/lower-em-ehsjlj-sjlj-not-used.ll b/llvm/test/CodeGen/WebAssembly/lower-em-ehsjlj-sjlj-not-used.ll
new file mode 100644
index 0000000000000..4d82d04652da8
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/lower-em-ehsjlj-sjlj-not-used.ll
@@ -0,0 +1,59 @@
+; RUN: opt < %s -wasm-lower-em-ehsjlj -enable-emscripten-cxx-exceptions -enable-emscripten-sjlj -S | FileCheck %s
+; RUN: llc < %s -enable-emscripten-cxx-exceptions -enable-emscripten-sjlj -verify-machineinstrs
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+; The same test with the same function in lower-em-ehsjlj.ll, both the
+; Emscripten EH and Emscripten SjLj are enabled in the same way, and this
+; function only does exception handling. The 
diff erence is that this module does
+; not contain any calls to setjmp or longjmp.
+;
+; But we still have to check if the thrown value is longjmp and and if so
+; rethrow it by calling @emscripten_longjmp, because we link object files using
+; wasm-ld, so the module we see in LowerEmscriptenEHSjLj pass is not the whole
+; program and there can be a longjmp call within another file.
+define void @rethrow_longjmp() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
+; CHECK-LABEL: @rethrow_longjmp
+entry:
+  invoke void @foo()
+          to label %try.cont unwind label %lpad
+; CHECK:    entry:
+; CHECK:      %cmp.eq.one = icmp eq i32 %__THREW__.val, 1
+; CHECK-NEXT: %cmp.eq.zero = icmp eq i32 %__THREW__.val, 0
+; CHECK-NEXT: %or = or i1 %cmp.eq.zero, %cmp.eq.one
+; CHECK-NEXT: br i1 %or, label %tail, label %rethrow.longjmp
+
+; CHECK: try.cont:
+; CHECK-NEXT:  %phi = phi i32 [ undef, %tail ], [ undef, %lpad ]
+; CHECK-NEXT:  ret void
+
+; CHECK:    rethrow.longjmp:
+; CHECK-NEXT: %threw.phi = phi i32 [ %__THREW__.val, %entry ]
+; CHECK-NEXT: %__threwValue.val = load i32, i32* @__threwValue, align 4
+; CHECK-NEXT: call void @emscripten_longjmp(i32 %threw.phi, i32 %__threwValue.val
+; CHECK-NEXT: unreachable
+
+; CHECK:    tail:
+; CHECK-NEXT: %cmp = icmp eq i32 %__THREW__.val, 1
+; CHECK-NEXT: br i1 %cmp, label %lpad, 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
+  %3 = call i8* @__cxa_begin_catch(i8* %1) #5
+  call void @__cxa_end_catch()
+  br label %try.cont
+
+try.cont:                                         ; preds = %lpad, %entry
+ %phi = phi i32 [ undef, %entry ], [ undef, %lpad ]
+  ret void
+}
+
+declare void @foo()
+declare i32 @__gxx_personality_v0(...)
+declare i8* @__cxa_begin_catch(i8*)
+declare void @__cxa_end_catch()
+declare void @__cxa_throw(i8*, i8*, i8*)


        


More information about the llvm-commits mailing list