diff options
author | Heejin Ahn <aheejin@gmail.com> | 2021-09-12 17:05:50 -0700 |
---|---|---|
committer | Heejin Ahn <aheejin@gmail.com> | 2021-09-13 14:20:04 -0700 |
commit | c55b6c593b32c45947bd44fc5c38b4b5e01f4d66 (patch) | |
tree | 2d4037a29117d3b085020009b805b0339b3ff400 | |
parent | b7b4ebbcfa463a7fae61dca7cec30c5b747bdec8 (diff) | |
download | llvm-c55b6c593b32c45947bd44fc5c38b4b5e01f4d66.zip llvm-c55b6c593b32c45947bd44fc5c38b4b5e01f4d66.tar.gz llvm-c55b6c593b32c45947bd44fc5c38b4b5e01f4d66.tar.bz2 |
[WebAssembly] Handle _setjmp and _longjmp in SjLj
In some platforms `_setjmp` and `_longjmp` are used instead of `setjmp`
and `longjmp`. This CL adds support for them.
Fixes https://github.com/emscripten-core/emscripten/issues/14999.
Reviewed By: dschuff
Differential Revision: https://reviews.llvm.org/D109669
-rw-r--r-- | llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp | 27 | ||||
-rw-r--r-- | llvm/test/CodeGen/WebAssembly/lower-em-sjlj.ll | 18 |
2 files changed, 45 insertions, 0 deletions
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp index dd8909b..33a9c60 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp @@ -831,6 +831,33 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(Module &M) { Function *SetjmpF = M.getFunction("setjmp"); Function *LongjmpF = M.getFunction("longjmp"); + // In some platforms _setjmp and _longjmp are used instead. Change these to + // use setjmp/longjmp instead, because we laster detect these functions by + // their names. + Function *SetjmpF2 = M.getFunction("_setjmp"); + Function *LongjmpF2 = M.getFunction("_longjmp"); + if (SetjmpF2) { + if (SetjmpF) { + if (SetjmpF->getFunctionType() != SetjmpF2->getFunctionType()) + report_fatal_error("setjmp and _setjmp have different function types"); + } else { + SetjmpF = Function::Create(SetjmpF2->getFunctionType(), + GlobalValue::ExternalLinkage, "setjmp", M); + } + SetjmpF2->replaceAllUsesWith(SetjmpF); + } + if (LongjmpF2) { + if (LongjmpF) { + if (LongjmpF->getFunctionType() != LongjmpF2->getFunctionType()) + report_fatal_error( + "longjmp and _longjmp have different function types"); + } else { + LongjmpF = Function::Create(LongjmpF2->getFunctionType(), + GlobalValue::ExternalLinkage, "setjmp", M); + } + LongjmpF2->replaceAllUsesWith(LongjmpF); + } + auto *TPC = getAnalysisIfAvailable<TargetPassConfig>(); assert(TPC && "Expected a TargetPassConfig"); auto &TM = TPC->getTM<WebAssemblyTargetMachine>(); diff --git a/llvm/test/CodeGen/WebAssembly/lower-em-sjlj.ll b/llvm/test/CodeGen/WebAssembly/lower-em-sjlj.ll index 1186b58..fcfd503 100644 --- a/llvm/test/CodeGen/WebAssembly/lower-em-sjlj.ll +++ b/llvm/test/CodeGen/WebAssembly/lower-em-sjlj.ll @@ -282,12 +282,30 @@ entry: ret void } +; Test if _setjmp and _longjmp calls are treated in the same way as setjmp and +; longjmp +define void @_setjmp__longjmp() { +; CHECK-LABEL: @_setjmp__longjmp +; These calls should have been transformed away +; CHECK-NOT: call i32 @_setjmp +; CHECK-NOT: call void @_longjmp +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 + %arraydecay1 = getelementptr inbounds [1 x %struct.__jmp_buf_tag], [1 x %struct.__jmp_buf_tag]* %buf, i32 0, i32 0 + call void @_longjmp(%struct.__jmp_buf_tag* %arraydecay1, i32 1) #1 + unreachable +} + ; Function Attrs: nounwind declare void @foo() #2 ; Function Attrs: returns_twice declare i32 @setjmp(%struct.__jmp_buf_tag*) #0 +declare i32 @_setjmp(%struct.__jmp_buf_tag*) #0 ; Function Attrs: noreturn declare void @longjmp(%struct.__jmp_buf_tag*, i32) #1 +declare void @_longjmp(%struct.__jmp_buf_tag*, i32) #1 declare i32 @__gxx_personality_v0(...) declare i8* @__cxa_begin_catch(i8*) declare void @__cxa_end_catch() |