diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp index 7dbb53a2bcd557..8a63c7c893dc75 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp @@ -874,15 +874,17 @@ static void nullifySetjmp(Function *F) { Function *SetjmpF = M.getFunction("setjmp"); SmallVector ToErase; - for (User *U : SetjmpF->users()) { - auto *CI = dyn_cast(U); - // FIXME 'invoke' to setjmp can happen when we use Wasm EH + Wasm SjLj, but - // we don't support two being used together yet. - if (!CI) - report_fatal_error("Wasm EH + Wasm SjLj is not fully supported yet"); - BasicBlock *BB = CI->getParent(); + for (User *U : make_early_inc_range(SetjmpF->users())) { + auto *CB = dyn_cast(U); + BasicBlock *BB = CB->getParent(); if (BB->getParent() != F) // in other function continue; + CallInst *CI = nullptr; + // setjmp cannot throw. So if it is an invoke, lower it to a call + if (auto *II = dyn_cast(CB)) + CI = llvm::changeToCall(II); + else + CI = cast(CB); ToErase.push_back(CI); CI->replaceAllUsesWith(IRB.getInt32(0)); } diff --git a/llvm/test/CodeGen/WebAssembly/lower-em-sjlj.ll b/llvm/test/CodeGen/WebAssembly/lower-em-sjlj.ll index 77dcff2e0799e8..57612f687afdfc 100644 --- a/llvm/test/CodeGen/WebAssembly/lower-em-sjlj.ll +++ b/llvm/test/CodeGen/WebAssembly/lower-em-sjlj.ll @@ -140,10 +140,13 @@ entry: ; free cannot longjmp call void @free(i8* %ptr) ret i32 %call +; CHECK: entry: ; CHECK-NOT: @malloc ; CHECK-NOT: %setjmpTable ; CHECK-NOT: @saveSetjmp ; CHECK-NOT: @testSetjmp +; The remaining setjmp call is converted to constant 0, because setjmp returns 0 +; when called directly. ; CHECK: ret i32 0 } diff --git a/llvm/test/CodeGen/WebAssembly/lower-wasm-ehsjlj.ll b/llvm/test/CodeGen/WebAssembly/lower-wasm-ehsjlj.ll index ae5cb68ff835c5..446c298865ade1 100644 --- a/llvm/test/CodeGen/WebAssembly/lower-wasm-ehsjlj.ll +++ b/llvm/test/CodeGen/WebAssembly/lower-wasm-ehsjlj.ll @@ -271,6 +271,29 @@ ehcleanup: ; preds = %entry cleanupret from %0 unwind to caller } +; This case was adapted from @cleanuppad_no_parent by removing allocas and +; destructor calls, to generate a situation that there's only 'invoke @setjmp' +; and no other longjmpable calls. +define i32 @setjmp_only() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { +; CHECK-LABEL: @setjmp_only +entry: + %buf = alloca [1 x %struct.__jmp_buf_tag], align 16 + %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 + ret i32 %call +; CHECK: invoke.cont: +; The remaining setjmp call is converted to constant 0, because setjmp returns 0 +; when called directly. +; CHECK: ret i32 0 + +ehcleanup: ; preds = %entry + %0 = cleanuppad within none [] + cleanupret from %0 unwind to caller +} + declare void @foo() ; Function Attrs: nounwind declare %struct.Temp* @_ZN4TempD2Ev(%struct.Temp* %this) #2