[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