diff options
author | Heejin Ahn <aheejin@gmail.com> | 2018-11-08 22:56:26 +0000 |
---|---|---|
committer | Heejin Ahn <aheejin@gmail.com> | 2018-11-08 22:56:26 +0000 |
commit | 0c68a875faf6a8be7d60679fe2fa71768350d464 (patch) | |
tree | 324179e22c46ba23cb46296788a11920676a701d | |
parent | ca591dea1085a173386771fd07a96e5a23d6d2b6 (diff) | |
download | bcm5719-llvm-0c68a875faf6a8be7d60679fe2fa71768350d464.tar.gz bcm5719-llvm-0c68a875faf6a8be7d60679fe2fa71768350d464.zip |
[WebAssembly] Fix LowerEmscriptenEHSjLj when there's only longjmp
Summary:
The pass incorrectly assumed if there's a longjmp declaration in the
module, there is also a setjmp function declaration. Fixed it, and now
the pass only converts longjmp and does not do any other transformation
when there's no setjmp declaration in the module.
Fixes PR39562.
Reviewers: jgravelle-google, sbc100
Subscribers: dschuff, sunfish, llvm-commits
Differential Revision: https://reviews.llvm.org/D54273
llvm-svn: 346445
-rw-r--r-- | llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp | 112 | ||||
-rw-r--r-- | llvm/test/CodeGen/WebAssembly/lower-em-sjlj-longjmp-only.ll | 24 |
2 files changed, 84 insertions, 52 deletions
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp index f0d24075801..68a9b192c4f 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp @@ -140,7 +140,17 @@ /// /// * Setjmp / Longjmp handling /// -/// 7) In the function entry that calls setjmp, initialize setjmpTable and +/// In case calls to longjmp() exists +/// +/// 1) Lower +/// longjmp(buf, value) +/// into +/// emscripten_longjmp_jmpbuf(buf, value) +/// emscripten_longjmp_jmpbuf will be lowered to emscripten_longjmp later. +/// +/// In case calls to setjmp() exists +/// +/// 2) In the function entry that calls setjmp, initialize setjmpTable and /// sejmpTableSize as follows: /// setjmpTableSize = 4; /// setjmpTable = (int *) malloc(40); @@ -148,7 +158,7 @@ /// setjmpTable and setjmpTableSize are used in saveSetjmp() function in JS /// code. /// -/// 8) Lower +/// 3) Lower /// setjmp(buf) /// into /// setjmpTable = saveSetjmp(buf, label, setjmpTable, setjmpTableSize); @@ -162,13 +172,8 @@ /// A BB with setjmp is split into two after setjmp call in order to make the /// post-setjmp BB the possible destination of longjmp BB. /// -/// 9) Lower -/// longjmp(buf, value) -/// into -/// emscripten_longjmp_jmpbuf(buf, value) -/// emscripten_longjmp_jmpbuf will be lowered to emscripten_longjmp later. /// -/// 10) Lower every call that might longjmp into +/// 4) Lower every call that might longjmp into /// __THREW__ = 0; /// call @__invoke_SIG(func, arg1, arg2) /// %__THREW__.val = __THREW__; @@ -189,21 +194,21 @@ /// ... /// default: goto splitted next BB /// } -/// testSetjmp examines setjmpTable to see if there is a matching setjmp -/// call. After calling an invoke wrapper, if a longjmp occurred, __THREW__ -/// will be the address of matching jmp_buf buffer and __threwValue be the -/// second argument to longjmp. mem[__THREW__.val] is a setjmp ID that is -/// stored in saveSetjmp. testSetjmp returns a setjmp label, a unique ID to -/// each setjmp callsite. Label 0 means this longjmp buffer does not -/// correspond to one of the setjmp callsites in this function, so in this -/// case we just chain the longjmp to the caller. (Here we call -/// emscripten_longjmp, which is different from emscripten_longjmp_jmpbuf. -/// emscripten_longjmp_jmpbuf takes jmp_buf as its first argument, while -/// emscripten_longjmp takes an int. Both of them will eventually be lowered -/// to emscripten_longjmp in s2wasm, but here we need two signatures - we -/// can't translate an int value to a jmp_buf.) -/// Label -1 means no longjmp occurred. Otherwise we jump to the right -/// post-setjmp BB based on the label. +/// testSetjmp examines setjmpTable to see if there is a matching setjmp +/// call. After calling an invoke wrapper, if a longjmp occurred, __THREW__ +/// will be the address of matching jmp_buf buffer and __threwValue be the +/// second argument to longjmp. mem[__THREW__.val] is a setjmp ID that is +/// stored in saveSetjmp. testSetjmp returns a setjmp label, a unique ID to +/// each setjmp callsite. Label 0 means this longjmp buffer does not +/// correspond to one of the setjmp callsites in this function, so in this +/// case we just chain the longjmp to the caller. (Here we call +/// emscripten_longjmp, which is different from emscripten_longjmp_jmpbuf. +/// emscripten_longjmp_jmpbuf takes jmp_buf as its first argument, while +/// emscripten_longjmp takes an int. Both of them will eventually be lowered +/// to emscripten_longjmp in s2wasm, but here we need two signatures - we +/// can't translate an int value to a jmp_buf.) +/// Label -1 means no longjmp occurred. Otherwise we jump to the right +/// post-setjmp BB based on the label. /// ///===----------------------------------------------------------------------===// @@ -662,22 +667,6 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(Module &M) { if (DoSjLj) { Changed = true; // We have setjmp or longjmp somewhere - // Register saveSetjmp function - FunctionType *SetjmpFTy = SetjmpF->getFunctionType(); - SmallVector<Type *, 4> Params = {SetjmpFTy->getParamType(0), - IRB.getInt32Ty(), Type::getInt32PtrTy(C), - IRB.getInt32Ty()}; - FunctionType *FTy = - FunctionType::get(Type::getInt32PtrTy(C), Params, false); - SaveSetjmpF = Function::Create(FTy, GlobalValue::ExternalLinkage, - SaveSetjmpFName, &M); - - // Register testSetjmp function - Params = {IRB.getInt32Ty(), Type::getInt32PtrTy(C), IRB.getInt32Ty()}; - FTy = FunctionType::get(IRB.getInt32Ty(), Params, false); - TestSetjmpF = Function::Create(FTy, GlobalValue::ExternalLinkage, - TestSetjmpFName, &M); - if (LongjmpF) { // Replace all uses of longjmp with emscripten_longjmp_jmpbuf, which is // defined in JS code @@ -687,20 +676,39 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(Module &M) { LongjmpF->replaceAllUsesWith(EmLongjmpJmpbufF); } - FTy = FunctionType::get(IRB.getVoidTy(), - {IRB.getInt32Ty(), IRB.getInt32Ty()}, false); - EmLongjmpF = - Function::Create(FTy, GlobalValue::ExternalLinkage, EmLongjmpFName, &M); - - // Only traverse functions that uses setjmp in order not to insert - // unnecessary prep / cleanup code in every function - SmallPtrSet<Function *, 8> SetjmpUsers; - for (User *U : SetjmpF->users()) { - auto *UI = cast<Instruction>(U); - SetjmpUsers.insert(UI->getFunction()); + + if (SetjmpF) { + // Register saveSetjmp function + FunctionType *SetjmpFTy = SetjmpF->getFunctionType(); + SmallVector<Type *, 4> Params = {SetjmpFTy->getParamType(0), + IRB.getInt32Ty(), Type::getInt32PtrTy(C), + IRB.getInt32Ty()}; + FunctionType *FTy = + FunctionType::get(Type::getInt32PtrTy(C), Params, false); + SaveSetjmpF = Function::Create(FTy, GlobalValue::ExternalLinkage, + SaveSetjmpFName, &M); + + // Register testSetjmp function + Params = {IRB.getInt32Ty(), Type::getInt32PtrTy(C), IRB.getInt32Ty()}; + FTy = FunctionType::get(IRB.getInt32Ty(), Params, false); + TestSetjmpF = Function::Create(FTy, GlobalValue::ExternalLinkage, + TestSetjmpFName, &M); + + FTy = FunctionType::get(IRB.getVoidTy(), + {IRB.getInt32Ty(), IRB.getInt32Ty()}, false); + EmLongjmpF = Function::Create(FTy, GlobalValue::ExternalLinkage, + EmLongjmpFName, &M); + + // Only traverse functions that uses setjmp in order not to insert + // unnecessary prep / cleanup code in every function + SmallPtrSet<Function *, 8> SetjmpUsers; + for (User *U : SetjmpF->users()) { + auto *UI = cast<Instruction>(U); + SetjmpUsers.insert(UI->getFunction()); + } + for (Function *F : SetjmpUsers) + runSjLjOnFunction(*F); } - for (Function *F : SetjmpUsers) - runSjLjOnFunction(*F); } if (!Changed) { diff --git a/llvm/test/CodeGen/WebAssembly/lower-em-sjlj-longjmp-only.ll b/llvm/test/CodeGen/WebAssembly/lower-em-sjlj-longjmp-only.ll new file mode 100644 index 00000000000..7d31c8ced3f --- /dev/null +++ b/llvm/test/CodeGen/WebAssembly/lower-em-sjlj-longjmp-only.ll @@ -0,0 +1,24 @@ +; RUN: opt < %s -wasm-lower-em-ehsjlj -S | FileCheck %s + +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, %struct.__sigset_t } +%struct.__sigset_t = type { [32 x i32] } + +@buffer = global [1 x %struct.__jmp_buf_tag] zeroinitializer, align 16 + +; Tests if program does not crash when there's no setjmp function calls in the +; module. + +; CHECK: call void @emscripten_longjmp_jmpbuf +define void @longjmp_only() { +entry: + call void @longjmp(%struct.__jmp_buf_tag* getelementptr inbounds ([1 x %struct.__jmp_buf_tag], [1 x %struct.__jmp_buf_tag]* @buffer, i32 0, i32 0), i32 1) #1 + unreachable +} + +; Function Attrs: noreturn nounwind +declare void @longjmp(%struct.__jmp_buf_tag*, i32) #1 + +attributes #1 = { noreturn nounwind } |