[llvm] 20c1d9c - [WebAssembly] Handle cleanuppad with no parent in Wasm SjLj

Heejin Ahn via llvm-commits llvm-commits at lists.llvm.org
Thu Jan 27 21:10:48 PST 2022


Author: Heejin Ahn
Date: 2022-01-27T21:10:23-08:00
New Revision: 20c1d9ce5ece40ec779f3e5898a369fce9c7ba0b

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

LOG: [WebAssembly] Handle cleanuppad with no parent in Wasm SjLj

Wasm SjLj converts longjmpable calls into `invoke`s that unwind to
`%catch.longjmp.dispatch` BB, from where we check if the thrown
exception is a `longjmp`. But in case a call already has a `funclet`
attribute, i.e., it is within a catch scope, we have to unwind to its
unwind destination first to preserve the scoping structure. That will
eventually unwind to `%catch.longjmp.dispatch`, because all
`catchswitch` and `cleanupret` that unwind to caller are redirected to
`%catch.dispatch.longjmp` during Wasm SjLj transformation.

But the prevous code assumed `cleanuppad`'s parent pad was always an
instruction, and didn't handle when a `cleanuppad`'s parent is `none`.
This CL handles this case, and makes the `while` loop more intuitive by
removing `FromPad` condition and explicitly inserting `break`s.

Reviewed By: dschuff

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

Added: 
    

Modified: 
    llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
    llvm/test/CodeGen/WebAssembly/lower-wasm-ehsjlj.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
index 6751b11fb793..7dbb53a2bcd5 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
@@ -1823,10 +1823,10 @@ void WebAssemblyLowerEmscriptenEHSjLj::handleLongjmpableCallsForWasmSjLj(
     BasicBlock *UnwindDest = nullptr;
     if (auto Bundle = CI->getOperandBundle(LLVMContext::OB_funclet)) {
       Instruction *FromPad = cast<Instruction>(Bundle->Inputs[0]);
-      while (!UnwindDest && FromPad) {
+      while (!UnwindDest) {
         if (auto *CPI = dyn_cast<CatchPadInst>(FromPad)) {
           UnwindDest = CPI->getCatchSwitch()->getUnwindDest();
-          FromPad = nullptr; // stop searching
+          break;
         } else if (auto *CPI = dyn_cast<CleanupPadInst>(FromPad)) {
           // getCleanupRetUnwindDest() can return nullptr when
           // 1. This cleanuppad's matching cleanupret uwninds to caller
@@ -1834,7 +1834,10 @@ void WebAssemblyLowerEmscriptenEHSjLj::handleLongjmpableCallsForWasmSjLj(
           //    unreachable.
           // In case of 2, we need to traverse the parent pad chain.
           UnwindDest = getCleanupRetUnwindDest(CPI);
-          FromPad = cast<Instruction>(CPI->getParentPad());
+          Value *ParentPad = CPI->getParentPad();
+          if (isa<ConstantTokenNone>(ParentPad))
+            break;
+          FromPad = cast<Instruction>(ParentPad);
         }
       }
     }

diff  --git a/llvm/test/CodeGen/WebAssembly/lower-wasm-ehsjlj.ll b/llvm/test/CodeGen/WebAssembly/lower-wasm-ehsjlj.ll
index ac18a683f67d..ae5cb68ff835 100644
--- a/llvm/test/CodeGen/WebAssembly/lower-wasm-ehsjlj.ll
+++ b/llvm/test/CodeGen/WebAssembly/lower-wasm-ehsjlj.ll
@@ -5,6 +5,7 @@ target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
 target triple = "wasm32-unknown-unknown"
 
 %struct.__jmp_buf_tag = type { [6 x i32], i32, [32 x i32] }
+%struct.Temp = type { i8 }
 @_ZL3buf = internal global [1 x %struct.__jmp_buf_tag] zeroinitializer, align 16
 
 ; void test() {
@@ -17,8 +18,7 @@ target triple = "wasm32-unknown-unknown"
 ;   }
 ; }
 define void @setjmp_and_try() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
-; CHECK-LABEL: @setjmp_and_try(
-
+; CHECK-LABEL: @setjmp_and_try
 entry:
   %call = call i32 @setjmp(%struct.__jmp_buf_tag* getelementptr inbounds ([1 x %struct.__jmp_buf_tag], [1 x %struct.__jmp_buf_tag]* @_ZL3buf, i32 0, i32 0)) #0
   %cmp = icmp ne i32 %call, 0
@@ -66,7 +66,7 @@ return:                                           ; preds = %catch.start, %if.en
 ;   }
 ; }
 define void @setjmp_within_try() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
-; CHECK-LABEL: @setjmp_within_try(
+; CHECK-LABEL: @setjmp_within_try
 entry:
   %jmpval = alloca i32, align 4
   %exn.slot = alloca i8*, align 4
@@ -141,7 +141,7 @@ invoke.cont2:                                     ; preds = %if.end
 ;   }
 ; }
 define void @setjmp_and_nested_try() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
-; CHECK-LABEL: @setjmp_and_nested_try(
+; CHECK-LABEL: @setjmp_and_nested_try
 entry:
   %call = call i32 @setjmp(%struct.__jmp_buf_tag* getelementptr inbounds ([1 x %struct.__jmp_buf_tag], [1 x %struct.__jmp_buf_tag]* @_ZL3buf, i32 0, i32 0)) #0
   %cmp = icmp ne i32 %call, 0
@@ -239,7 +239,41 @@ terminate:                                        ; preds = %ehcleanup
 ; CHECK-NEXT:    catchswitch within none [label %catch.longjmp] unwind to caller
 }
 
+; void @cleanuppad_no_parent {
+;   jmp_buf buf;
+;   Temp t;
+;   setjmp(buf);
+; }
+define void @cleanuppad_no_parent() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
+; CHECK-LABEL: @cleanuppad_no_parent
+entry:
+  %buf = alloca [1 x %struct.__jmp_buf_tag], align 16
+  %t = alloca %struct.Temp, align 1
+  %arraydecay = getelementptr inbounds [1 x %struct.__jmp_buf_tag], [1 x %struct.__jmp_buf_tag]* %buf, i32 0, i32 0
+  %call = invoke i32 @setjmp(%struct.__jmp_buf_tag* noundef %arraydecay) #0
+          to label %invoke.cont unwind label %ehcleanup
+
+invoke.cont:                                      ; preds = %entry
+  %call1 = call noundef %struct.Temp* @_ZN4TempD2Ev(%struct.Temp* noundef %t) #2
+  ret void
+
+ehcleanup:                                        ; preds = %entry
+  %0 = cleanuppad within none []
+  ; After SjLj transformation, this will be converted to an invoke that
+  ; eventually unwinds to %catch.dispatch.longjmp. But in case a call has a
+  ; "funclet" attribute, we should unwind to the funclet's unwind destination
+  ; first to preserve the scoping structure. But this call's parent is %0
+  ; (cleanuppad), whose parent is 'none', so we should unwind directly to
+  ; %catch.dispatch.longjmp.
+  %call2 = call noundef %struct.Temp* @_ZN4TempD2Ev(%struct.Temp* noundef %t) #2 [ "funclet"(token %0) ]
+; CHECK: %call13 = invoke {{.*}} %struct.Temp* @_ZN4TempD2Ev(%struct.Temp*
+; CHECK-NEXT:    to label {{.*}} unwind label %catch.dispatch.longjmp
+  cleanupret from %0 unwind to caller
+}
+
 declare void @foo()
+; Function Attrs: nounwind
+declare %struct.Temp* @_ZN4TempD2Ev(%struct.Temp* %this) #2
 ; Function Attrs: returns_twice
 declare i32 @setjmp(%struct.__jmp_buf_tag*) #0
 ; Function Attrs: noreturn


        


More information about the llvm-commits mailing list