diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp @@ -1244,21 +1244,33 @@ for (Instruction *I : ToErase) I->eraseFromParent(); - // Free setjmpTable buffer before each return instruction + // Free setjmpTable buffer before each return instruction + function-exiting + // call + SmallVector ExitingInsts; for (BasicBlock &BB : F) { Instruction *TI = BB.getTerminator(); - if (isa(TI)) { - DebugLoc DL = getOrCreateDebugLoc(TI, F.getSubprogram()); - auto *Free = CallInst::CreateFree(SetjmpTable, TI); - Free->setDebugLoc(DL); - // CallInst::CreateFree may create a bitcast instruction if its argument - // types mismatch. We need to set the debug loc for the bitcast too. - if (auto *FreeCallI = dyn_cast(Free)) { - if (auto *BitCastI = dyn_cast(FreeCallI->getArgOperand(0))) - BitCastI->setDebugLoc(DL); + if (isa(TI)) + ExitingInsts.push_back(TI); + for (auto &I : BB) { + if (auto *CB = dyn_cast(&I)) { + StringRef CalleeName = CB->getCalledOperand()->getName(); + if (CalleeName == "__resumeException" || + CalleeName == "emscripten_longjmp" || CalleeName == "__cxa_throw") + ExitingInsts.push_back(&I); } } } + for (auto *I : ExitingInsts) { + DebugLoc DL = getOrCreateDebugLoc(I, F.getSubprogram()); + auto *Free = CallInst::CreateFree(SetjmpTable, I); + Free->setDebugLoc(DL); + // CallInst::CreateFree may create a bitcast instruction if its argument + // types mismatch. We need to set the debug loc for the bitcast too. + if (auto *FreeCallI = dyn_cast(Free)) { + if (auto *BitCastI = dyn_cast(FreeCallI->getArgOperand(0))) + BitCastI->setDebugLoc(DL); + } + } // Every call to saveSetjmp can change setjmpTable and setjmpTableSize // (when buffer reallocation occurs) diff --git a/llvm/test/CodeGen/WebAssembly/lower-em-ehsjlj.ll b/llvm/test/CodeGen/WebAssembly/lower-em-ehsjlj.ll --- a/llvm/test/CodeGen/WebAssembly/lower-em-ehsjlj.ll +++ b/llvm/test/CodeGen/WebAssembly/lower-em-ehsjlj.ll @@ -89,7 +89,8 @@ ; This function contains a setjmp call and no invoke, so we only handle longjmp ; here. But @foo can also throw an exception, so we check if an exception is -; thrown and if so rethrow it by calling @__resumeException. +; thrown and if so rethrow it by calling @__resumeException. Also we have to +; free the setjmpTable buffer before calling @__resumeException. define void @rethrow_exception() { ; CHECK-LABEL: @rethrow_exception entry: @@ -112,6 +113,8 @@ ; CHECK: eh.rethrow: ; CHECK-NEXT: %exn = call i8* @__cxa_find_matching_catch_2() +; CHECK-NEXT: %[[BUF:.*]] = bitcast i32* %setjmpTable1 to i8* +; CHECK-NEXT: call void @free(i8* %[[BUF]]) ; CHECK-NEXT: call void @__resumeException(i8* %exn) ; CHECK-NEXT: unreachable @@ -119,6 +122,32 @@ ret void } +; The same as 'rethrow_exception' but contains a __cxa_throw call. We have to +; free the setjmpTable buffer before calling __cxa_throw. +define void @rethrow_exception2() { +; CHECK-LABEL: @rethrow_exception2 +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 = call i32 @setjmp(%struct.__jmp_buf_tag* %arraydecay) #0 + %cmp = icmp ne i32 %call, 0 + br i1 %cmp, label %throw, label %if.end + +if.end: ; preds = %entry + call void @foo() + br label %throw + +throw: ; preds = %entry, %if.end + call void @__cxa_throw(i8* null, i8* null, i8* null) #1 + unreachable + +; CHECK: throw: +; CHECK: %[[BUF:.*]] = bitcast i32* %setjmpTable5 to i8* +; CHECK-NEXT: call void @free(i8* %[[BUF]]) +; CHECK-NEXT: call void @__cxa_throw(i8* null, i8* null, i8* null) +; CHECK-NEXT: unreachable +} + declare void @foo() ; Function Attrs: returns_twice declare i32 @setjmp(%struct.__jmp_buf_tag*) @@ -127,6 +156,7 @@ declare i32 @__gxx_personality_v0(...) declare i8* @__cxa_begin_catch(i8*) declare void @__cxa_end_catch() +declare void @__cxa_throw(i8*, i8*, i8*) attributes #0 = { returns_twice } attributes #1 = { noreturn } diff --git a/llvm/test/CodeGen/WebAssembly/lower-em-sjlj.ll b/llvm/test/CodeGen/WebAssembly/lower-em-sjlj.ll --- a/llvm/test/CodeGen/WebAssembly/lower-em-sjlj.ll +++ b/llvm/test/CodeGen/WebAssembly/lower-em-sjlj.ll @@ -71,6 +71,8 @@ ; CHECK-NEXT: ] ; CHECK: if.then2: +; CHECK-NEXT: %[[BUF:.*]] = bitcast i32* %[[SETJMP_TABLE1]] to i8* +; CHECK-NEXT: call void @free(i8* %[[BUF]]) ; CHECK-NEXT: call void @emscripten_longjmp([[PTR]] %[[__THREW__VAL]], i32 %[[THREWVALUE_VAL]]) ; CHECK-NEXT: unreachable