diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp index 0427fe473f8e1..027ee1086bf4e 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp @@ -129,27 +129,23 @@ /// /// If there are calls to setjmp() /// -/// 2) In the function entry that calls setjmp, initialize setjmpTable and -/// sejmpTableSize as follows: -/// setjmpTableSize = 4; -/// setjmpTable = (int *) malloc(40); -/// setjmpTable[0] = 0; -/// setjmpTable and setjmpTableSize are used to call saveSetjmp() function in -/// Emscripten compiler-rt. +/// 2) In the function entry that calls setjmp, initialize +/// functionInvocationId as follows: +/// +/// functionInvocationId = alloca(4) +/// +/// Note: the alloca size is not important as this pointer is +/// merely used for pointer comparisions. /// /// 3) Lower /// setjmp(env) /// into -/// setjmpTable = saveSetjmp(env, label, setjmpTable, setjmpTableSize); -/// setjmpTableSize = getTempRet0(); -/// For each dynamic setjmp call, setjmpTable stores its ID (a number which -/// is incrementally assigned from 0) and its label (a unique number that -/// represents each callsite of setjmp). When we need more entries in -/// setjmpTable, it is reallocated in saveSetjmp() in Emscripten's -/// compiler-rt and it will return the new table address, and assign the new -/// table size in setTempRet0(). saveSetjmp also stores the setjmp's ID into -/// the buffer 'env'. 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. +/// __wasm_setjmp(env, label, functionInvocationId) +/// +/// __wasm_setjmp records the necessary info (the label and +/// functionInvocationId) to the "env". +/// 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. /// /// 4) Lower every call that might longjmp into /// __THREW__ = 0; @@ -158,8 +154,7 @@ /// __THREW__ = 0; /// %__threwValue.val = __threwValue; /// if (%__THREW__.val != 0 & %__threwValue.val != 0) { -/// %label = testSetjmp(mem[%__THREW__.val], setjmpTable, -/// setjmpTableSize); +/// %label = __wasm_setjmp_test(%__THREW__.val, functionInvocationId); /// if (%label == 0) /// emscripten_longjmp(%__THREW__.val, %__threwValue.val); /// setTempRet0(%__threwValue.val); @@ -173,16 +168,16 @@ /// ... /// 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. Label -1 means no longjmp -/// occurred. Otherwise we jump to the right post-setjmp BB based on the -/// label. +/// +/// __wasm_setjmp_test examines the jmp buf to see if it was for 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. +/// __wasm_setjmp_test 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. Label -1 means no longjmp occurred. +/// Otherwise we jump to the right post-setjmp BB based on the label. /// /// * Wasm setjmp / longjmp handling /// This mode still uses some Emscripten library functions but not JavaScript's @@ -199,45 +194,44 @@ /// If there are calls to setjmp() /// /// 2) and 3): The same as 2) and 3) in Emscripten SjLj. -/// (setjmpTable/setjmpTableSize initialization + setjmp callsite -/// transformation) +/// (functionInvocationId initialization + setjmp callsite transformation) /// /// 4) Create a catchpad with a wasm.catch() intrinsic, which returns the value -/// thrown by __wasm_longjmp function. In Emscripten library, we have this -/// struct: +/// thrown by __wasm_longjmp function. In the runtime library, we have an +/// equivalent of the following struct: /// /// struct __WasmLongjmpArgs { /// void *env; /// int val; /// }; -/// struct __WasmLongjmpArgs __wasm_longjmp_args; /// -/// The thrown value here is a pointer to __wasm_longjmp_args struct object. We -/// use this struct to transfer two values by throwing a single value. Wasm -/// throw and catch instructions are capable of throwing and catching multiple -/// values, but it also requires multivalue support that is currently not very -/// reliable. +/// The thrown value here is a pointer to the struct. We use this struct to +/// transfer two values by throwing a single value. Wasm throw and catch +/// instructions are capable of throwing and catching multiple values, but +/// it also requires multivalue support that is currently not very reliable. /// TODO Switch to throwing and catching two values without using the struct /// /// All longjmpable function calls will be converted to an invoke that will /// unwind to this catchpad in case a longjmp occurs. Within the catchpad, we -/// test the thrown values using testSetjmp function as we do for Emscripten -/// SjLj. The main difference is, in Emscripten SjLj, we need to transform every -/// longjmpable callsite into a sequence of code including testSetjmp() call; in -/// Wasm SjLj we do the testing in only one place, in this catchpad. +/// test the thrown values using __wasm_setjmp_test function as we do for +/// Emscripten SjLj. The main difference is, in Emscripten SjLj, we need to +/// transform every longjmpable callsite into a sequence of code including +/// __wasm_setjmp_test() call; in Wasm SjLj we do the testing in only one +/// place, in this catchpad. /// -/// After testing calling testSetjmp(), if the longjmp does not correspond to -/// one of the setjmps within the current function, it rethrows the longjmp -/// by calling __wasm_longjmp(). If it corresponds to one of setjmps in the -/// function, we jump to the beginning of the function, which contains a switch -/// to each post-setjmp BB. Again, in Emscripten SjLj, this switch is added for -/// every longjmpable callsite; in Wasm SjLj we do this only once at the top of -/// the function. (after setjmpTable/setjmpTableSize initialization) +/// After testing calling __wasm_setjmp_test(), if the longjmp does not +/// correspond to one of the setjmps within the current function, it rethrows +/// the longjmp by calling __wasm_longjmp(). If it corresponds to one of +/// setjmps in the function, we jump to the beginning of the function, which +/// contains a switch to each post-setjmp BB. Again, in Emscripten SjLj, this +/// switch is added for every longjmpable callsite; in Wasm SjLj we do this +/// only once at the top of the function. (after functionInvocationId +/// initialization) /// /// The below is the pseudocode for what we have described /// /// entry: -/// Initialize setjmpTable and setjmpTableSize +/// Initialize functionInvocationId /// /// setjmp.dispatch: /// switch %label { @@ -260,7 +254,7 @@ /// %longjmp.args = wasm.catch() ;; struct __WasmLongjmpArgs /// %env = load 'env' field from __WasmLongjmpArgs /// %val = load 'val' field from __WasmLongjmpArgs -/// %label = testSetjmp(mem[%env], setjmpTable, setjmpTableSize); +/// %label = __wasm_setjmp_test(%env, functionInvocationId); /// if (%label == 0) /// __wasm_longjmp(%env, %val) /// catchret to %setjmp.dispatch @@ -309,8 +303,8 @@ class WebAssemblyLowerEmscriptenEHSjLj final : public ModulePass { Function *ResumeF = nullptr; // __resumeException() (Emscripten) Function *EHTypeIDF = nullptr; // llvm.eh.typeid.for() (intrinsic) Function *EmLongjmpF = nullptr; // emscripten_longjmp() (Emscripten) - Function *SaveSetjmpF = nullptr; // saveSetjmp() (Emscripten) - Function *TestSetjmpF = nullptr; // testSetjmp() (Emscripten) + Function *WasmSetjmpF = nullptr; // __wasm_setjmp() (Emscripten) + Function *WasmSetjmpTestF = nullptr; // __wasm_setjmp_test() (Emscripten) Function *WasmLongjmpF = nullptr; // __wasm_longjmp() (Emscripten) Function *CatchF = nullptr; // wasm.catch() (intrinsic) @@ -335,18 +329,17 @@ class WebAssemblyLowerEmscriptenEHSjLj final : public ModulePass { bool runEHOnFunction(Function &F); bool runSjLjOnFunction(Function &F); void handleLongjmpableCallsForEmscriptenSjLj( - Function &F, InstVector &SetjmpTableInsts, - InstVector &SetjmpTableSizeInsts, + Function &F, Instruction *FunctionInvocationId, SmallVectorImpl &SetjmpRetPHIs); void - handleLongjmpableCallsForWasmSjLj(Function &F, InstVector &SetjmpTableInsts, - InstVector &SetjmpTableSizeInsts, + handleLongjmpableCallsForWasmSjLj(Function &F, + Instruction *FunctionInvocationId, SmallVectorImpl &SetjmpRetPHIs); Function *getFindMatchingCatch(Module &M, unsigned NumClauses); Value *wrapInvoke(CallBase *CI); void wrapTestSetjmp(BasicBlock *BB, DebugLoc DL, Value *Threw, - Value *SetjmpTable, Value *SetjmpTableSize, Value *&Label, + Value *FunctionInvocationId, Value *&Label, Value *&LongjmpResult, BasicBlock *&CallEmLongjmpBB, PHINode *&CallEmLongjmpBBThrewPHI, PHINode *&CallEmLongjmpBBThrewValuePHI, @@ -618,7 +611,7 @@ static bool canLongjmp(const Value *Callee) { // There are functions in Emscripten's JS glue code or compiler-rt if (CalleeName == "__resumeException" || CalleeName == "llvm_eh_typeid_for" || - CalleeName == "saveSetjmp" || CalleeName == "testSetjmp" || + CalleeName == "__wasm_setjmp" || CalleeName == "__wasm_setjmp_test" || CalleeName == "getTempRet0" || CalleeName == "setTempRet0") return false; @@ -687,11 +680,12 @@ static bool isEmAsmCall(const Value *Callee) { CalleeName == "emscripten_asm_const_async_on_main_thread"; } -// Generate testSetjmp function call seqence with preamble and postamble. -// The code this generates is equivalent to the following JavaScript code: +// Generate __wasm_setjmp_test function call seqence with preamble and +// postamble. The code this generates is equivalent to the following +// JavaScript code: // %__threwValue.val = __threwValue; // if (%__THREW__.val != 0 & %__threwValue.val != 0) { -// %label = testSetjmp(mem[%__THREW__.val], setjmpTable, setjmpTableSize); +// %label = __wasm_setjmp_test(%__THREW__.val, functionInvocationId); // if (%label == 0) // emscripten_longjmp(%__THREW__.val, %__threwValue.val); // setTempRet0(%__threwValue.val); @@ -703,10 +697,10 @@ static bool isEmAsmCall(const Value *Callee) { // As output parameters. returns %label, %longjmp_result, and the BB the last // instruction (%longjmp_result = ...) is in. void WebAssemblyLowerEmscriptenEHSjLj::wrapTestSetjmp( - BasicBlock *BB, DebugLoc DL, Value *Threw, Value *SetjmpTable, - Value *SetjmpTableSize, Value *&Label, Value *&LongjmpResult, - BasicBlock *&CallEmLongjmpBB, PHINode *&CallEmLongjmpBBThrewPHI, - PHINode *&CallEmLongjmpBBThrewValuePHI, BasicBlock *&EndBB) { + BasicBlock *BB, DebugLoc DL, Value *Threw, Value *FunctionInvocationId, + Value *&Label, Value *&LongjmpResult, BasicBlock *&CallEmLongjmpBB, + PHINode *&CallEmLongjmpBBThrewPHI, PHINode *&CallEmLongjmpBBThrewValuePHI, + BasicBlock *&EndBB) { Function *F = BB->getParent(); Module *M = F->getParent(); LLVMContext &C = M->getContext(); @@ -743,16 +737,14 @@ void WebAssemblyLowerEmscriptenEHSjLj::wrapTestSetjmp( CallEmLongjmpBBThrewValuePHI->addIncoming(ThrewValue, ThenBB1); } - // %label = testSetjmp(mem[%__THREW__.val], setjmpTable, setjmpTableSize); + // %label = __wasm_setjmp_test(%__THREW__.val, functionInvocationId); // if (%label == 0) IRB.SetInsertPoint(ThenBB1); BasicBlock *EndBB2 = BasicBlock::Create(C, "if.end2", F); Value *ThrewPtr = IRB.CreateIntToPtr(Threw, getAddrPtrType(M), Threw->getName() + ".p"); - Value *LoadedThrew = IRB.CreateLoad(getAddrIntType(M), ThrewPtr, - ThrewPtr->getName() + ".loaded"); - Value *ThenLabel = IRB.CreateCall( - TestSetjmpF, {LoadedThrew, SetjmpTable, SetjmpTableSize}, "label"); + Value *ThenLabel = IRB.CreateCall(WasmSetjmpTestF, + {ThrewPtr, FunctionInvocationId}, "label"); Value *Cmp2 = IRB.CreateICmpEQ(ThenLabel, IRB.getInt32(0)); IRB.CreateCondBr(Cmp2, CallEmLongjmpBB, EndBB2); @@ -1007,17 +999,17 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(Module &M) { Type *Int8PtrTy = IRB.getPtrTy(); Type *Int32PtrTy = IRB.getPtrTy(); Type *Int32Ty = IRB.getInt32Ty(); - // Register saveSetjmp function + + // Register __wasm_setjmp function FunctionType *SetjmpFTy = SetjmpF->getFunctionType(); FunctionType *FTy = FunctionType::get( - Int32PtrTy, - {SetjmpFTy->getParamType(0), Int32Ty, Int32PtrTy, Int32Ty}, false); - SaveSetjmpF = getEmscriptenFunction(FTy, "saveSetjmp", &M); + IRB.getVoidTy(), {SetjmpFTy->getParamType(0), Int32Ty, Int32PtrTy}, + false); + WasmSetjmpF = getEmscriptenFunction(FTy, "__wasm_setjmp", &M); - // Register testSetjmp function - FTy = FunctionType::get(Int32Ty, - {getAddrIntType(&M), Int32PtrTy, Int32Ty}, false); - TestSetjmpF = getEmscriptenFunction(FTy, "testSetjmp", &M); + // Register __wasm_setjmp_test function + FTy = FunctionType::get(Int32Ty, {Int32PtrTy, Int32PtrTy}, false); + WasmSetjmpTestF = getEmscriptenFunction(FTy, "__wasm_setjmp_test", &M); // wasm.catch() will be lowered down to wasm 'catch' instruction in // instruction selection. @@ -1063,7 +1055,7 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(Module &M) { if (V && V->use_empty()) V->eraseFromParent(); for (auto *V : {GetTempRet0F, SetTempRet0F, ResumeF, EHTypeIDF, EmLongjmpF, - SaveSetjmpF, TestSetjmpF, WasmLongjmpF, CatchF}) + WasmSetjmpF, WasmSetjmpTestF, WasmLongjmpF, CatchF}) if (V && V->use_empty()) V->eraseFromParent(); @@ -1268,42 +1260,20 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runSjLjOnFunction(Function &F) { LLVMContext &C = F.getContext(); IRBuilder<> IRB(C); SmallVector ToErase; - // Vector of %setjmpTable values - SmallVector SetjmpTableInsts; - // Vector of %setjmpTableSize values - SmallVector SetjmpTableSizeInsts; // Setjmp preparation - // This instruction effectively means %setjmpTableSize = 4. - // We create this as an instruction intentionally, and we don't want to fold - // this instruction to a constant 4, because this value will be used in - // SSAUpdater.AddAvailableValue(...) later. BasicBlock *Entry = &F.getEntryBlock(); DebugLoc FirstDL = getOrCreateDebugLoc(&*Entry->begin(), F.getSubprogram()); SplitBlock(Entry, &*Entry->getFirstInsertionPt()); - BinaryOperator *SetjmpTableSize = BinaryOperator::Create( - Instruction::Add, IRB.getInt32(4), IRB.getInt32(0), "setjmpTableSize", - Entry->getTerminator()->getIterator()); - SetjmpTableSize->setDebugLoc(FirstDL); - // setjmpTable = (int *) malloc(40); - Type *IntPtrTy = getAddrIntType(&M); - Constant *size = ConstantInt::get(IntPtrTy, 40); - IRB.SetInsertPoint(SetjmpTableSize); - auto *SetjmpTable = IRB.CreateMalloc(IntPtrTy, IRB.getInt32Ty(), size, - nullptr, nullptr, "setjmpTable"); - SetjmpTable->setDebugLoc(FirstDL); - // CallInst::CreateMalloc may return a bitcast instruction if the result types - // mismatch. We need to set the debug loc for the original call too. - auto *MallocCall = SetjmpTable->stripPointerCasts(); - if (auto *MallocCallI = dyn_cast(MallocCall)) { - MallocCallI->setDebugLoc(FirstDL); - } - // setjmpTable[0] = 0; - IRB.CreateStore(IRB.getInt32(0), SetjmpTable); - SetjmpTableInsts.push_back(SetjmpTable); - SetjmpTableSizeInsts.push_back(SetjmpTableSize); + IRB.SetInsertPoint(Entry->getTerminator()->getIterator()); + // This alloca'ed pointer is used by the runtime to identify function + // invocations. It's just for pointer comparisons. It will never be + // dereferenced. + Instruction *FunctionInvocationId = + IRB.CreateAlloca(IRB.getInt32Ty(), nullptr, "functionInvocationId"); + FunctionInvocationId->setDebugLoc(FirstDL); // Setjmp transformation SmallVector SetjmpRetPHIs; @@ -1350,92 +1320,22 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runSjLjOnFunction(Function &F) { // 0, because index 0 means the longjmp is not ours to handle. IRB.SetInsertPoint(CI); Value *Args[] = {CI->getArgOperand(0), IRB.getInt32(SetjmpRetPHIs.size()), - SetjmpTable, SetjmpTableSize}; - Instruction *NewSetjmpTable = - IRB.CreateCall(SaveSetjmpF, Args, "setjmpTable"); - Instruction *NewSetjmpTableSize = - IRB.CreateCall(GetTempRet0F, std::nullopt, "setjmpTableSize"); - SetjmpTableInsts.push_back(NewSetjmpTable); - SetjmpTableSizeInsts.push_back(NewSetjmpTableSize); + FunctionInvocationId}; + IRB.CreateCall(WasmSetjmpF, Args); ToErase.push_back(CI); } // Handle longjmpable calls. if (EnableEmSjLj) - handleLongjmpableCallsForEmscriptenSjLj( - F, SetjmpTableInsts, SetjmpTableSizeInsts, SetjmpRetPHIs); + handleLongjmpableCallsForEmscriptenSjLj(F, FunctionInvocationId, + SetjmpRetPHIs); else // EnableWasmSjLj - handleLongjmpableCallsForWasmSjLj(F, SetjmpTableInsts, SetjmpTableSizeInsts, - SetjmpRetPHIs); + handleLongjmpableCallsForWasmSjLj(F, FunctionInvocationId, SetjmpRetPHIs); // Erase everything we no longer need in this function for (Instruction *I : ToErase) I->eraseFromParent(); - // Free setjmpTable buffer before each return instruction + function-exiting - // call - SmallVector ExitingInsts; - for (BasicBlock &BB : F) { - Instruction *TI = BB.getTerminator(); - if (isa(TI)) - ExitingInsts.push_back(TI); - // Any 'call' instruction with 'noreturn' attribute exits the function at - // this point. If this throws but unwinds to another EH pad within this - // function instead of exiting, this would have been an 'invoke', which - // happens if we use Wasm EH or Wasm SjLJ. - for (auto &I : BB) { - if (auto *CI = dyn_cast(&I)) { - bool IsNoReturn = CI->hasFnAttr(Attribute::NoReturn); - if (Function *CalleeF = CI->getCalledFunction()) - IsNoReturn |= CalleeF->hasFnAttribute(Attribute::NoReturn); - if (IsNoReturn) - ExitingInsts.push_back(&I); - } - } - } - for (auto *I : ExitingInsts) { - DebugLoc DL = getOrCreateDebugLoc(I, F.getSubprogram()); - // If this existing instruction is a call within a catchpad, we should add - // it as "funclet" to the operand bundle of 'free' call - SmallVector Bundles; - if (auto *CB = dyn_cast(I)) - if (auto Bundle = CB->getOperandBundle(LLVMContext::OB_funclet)) - Bundles.push_back(OperandBundleDef(*Bundle)); - IRB.SetInsertPoint(I); - auto *Free = IRB.CreateFree(SetjmpTable, Bundles); - Free->setDebugLoc(DL); - } - - // Every call to saveSetjmp can change setjmpTable and setjmpTableSize - // (when buffer reallocation occurs) - // entry: - // setjmpTableSize = 4; - // setjmpTable = (int *) malloc(40); - // setjmpTable[0] = 0; - // ... - // somebb: - // setjmpTable = saveSetjmp(env, label, setjmpTable, setjmpTableSize); - // setjmpTableSize = getTempRet0(); - // So we need to make sure the SSA for these variables is valid so that every - // saveSetjmp and testSetjmp calls have the correct arguments. - SSAUpdater SetjmpTableSSA; - SSAUpdater SetjmpTableSizeSSA; - SetjmpTableSSA.Initialize(PointerType::get(C, 0), "setjmpTable"); - SetjmpTableSizeSSA.Initialize(Type::getInt32Ty(C), "setjmpTableSize"); - for (Instruction *I : SetjmpTableInsts) - SetjmpTableSSA.AddAvailableValue(I->getParent(), I); - for (Instruction *I : SetjmpTableSizeInsts) - SetjmpTableSizeSSA.AddAvailableValue(I->getParent(), I); - - for (auto &U : make_early_inc_range(SetjmpTable->uses())) - if (auto *I = dyn_cast(U.getUser())) - if (I->getParent() != Entry) - SetjmpTableSSA.RewriteUse(U); - for (auto &U : make_early_inc_range(SetjmpTableSize->uses())) - if (auto *I = dyn_cast(U.getUser())) - if (I->getParent() != Entry) - SetjmpTableSizeSSA.RewriteUse(U); - // Finally, our modifications to the cfg can break dominance of SSA variables. // For example, in this code, // if (x()) { .. setjmp() .. } @@ -1454,21 +1354,13 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runSjLjOnFunction(Function &F) { // setjmp. Refer to 4) of "Emscripten setjmp/longjmp handling" section in the // comments at top of the file for details. void WebAssemblyLowerEmscriptenEHSjLj::handleLongjmpableCallsForEmscriptenSjLj( - Function &F, InstVector &SetjmpTableInsts, InstVector &SetjmpTableSizeInsts, + Function &F, Instruction *FunctionInvocationId, SmallVectorImpl &SetjmpRetPHIs) { Module &M = *F.getParent(); LLVMContext &C = F.getContext(); IRBuilder<> IRB(C); SmallVector ToErase; - // We need to pass setjmpTable and setjmpTableSize to testSetjmp function. - // These values are defined in the beginning of the function and also in each - // setjmp callsite, but we don't know which values we should use at this - // point. So here we arbitraily use the ones defined in the beginning of the - // function, and SSAUpdater will later update them to the correct values. - Instruction *SetjmpTable = *SetjmpTableInsts.begin(); - Instruction *SetjmpTableSize = *SetjmpTableSizeInsts.begin(); - // call.em.longjmp BB that will be shared within the function. BasicBlock *CallEmLongjmpBB = nullptr; // PHI node for the loaded value of __THREW__ global variable in @@ -1601,7 +1493,7 @@ void WebAssemblyLowerEmscriptenEHSjLj::handleLongjmpableCallsForEmscriptenSjLj( IRB.SetInsertPoint(NormalBB); IRB.CreateBr(Tail); - BB = NormalBB; // New insertion point to insert testSetjmp() + BB = NormalBB; // New insertion point to insert __wasm_setjmp_test() } } @@ -1610,16 +1502,15 @@ void WebAssemblyLowerEmscriptenEHSjLj::handleLongjmpableCallsForEmscriptenSjLj( // right setjmp-tail if so ToErase.push_back(BB->getTerminator()); - // Generate a function call to testSetjmp function and preamble/postamble - // code to figure out (1) whether longjmp occurred (2) if longjmp - // occurred, which setjmp it corresponds to + // Generate a function call to __wasm_setjmp_test function and + // preamble/postamble code to figure out (1) whether longjmp + // occurred (2) if longjmp occurred, which setjmp it corresponds to Value *Label = nullptr; Value *LongjmpResult = nullptr; BasicBlock *EndBB = nullptr; - wrapTestSetjmp(BB, CI->getDebugLoc(), Threw, SetjmpTable, SetjmpTableSize, - Label, LongjmpResult, CallEmLongjmpBB, - CallEmLongjmpBBThrewPHI, CallEmLongjmpBBThrewValuePHI, - EndBB); + wrapTestSetjmp(BB, CI->getDebugLoc(), Threw, FunctionInvocationId, Label, + LongjmpResult, CallEmLongjmpBB, CallEmLongjmpBBThrewPHI, + CallEmLongjmpBBThrewValuePHI, EndBB); assert(Label && LongjmpResult && EndBB); // Create switch instruction @@ -1658,7 +1549,7 @@ static BasicBlock *getCleanupRetUnwindDest(const CleanupPadInst *CPI) { // BBs. Refer to 4) of "Wasm setjmp/longjmp handling" section in the comments at // top of the file for details. void WebAssemblyLowerEmscriptenEHSjLj::handleLongjmpableCallsForWasmSjLj( - Function &F, InstVector &SetjmpTableInsts, InstVector &SetjmpTableSizeInsts, + Function &F, Instruction *FunctionInvocationId, SmallVectorImpl &SetjmpRetPHIs) { Module &M = *F.getParent(); LLVMContext &C = F.getContext(); @@ -1682,18 +1573,13 @@ void WebAssemblyLowerEmscriptenEHSjLj::handleLongjmpableCallsForWasmSjLj( DebugLoc FirstDL = getOrCreateDebugLoc(&*Entry->begin(), F.getSubprogram()); IRB.SetCurrentDebugLocation(FirstDL); - // Arbitrarily use the ones defined in the beginning of the function. - // SSAUpdater will later update them to the correct values. - Instruction *SetjmpTable = *SetjmpTableInsts.begin(); - Instruction *SetjmpTableSize = *SetjmpTableSizeInsts.begin(); - // Add setjmp.dispatch BB right after the entry block. Because we have - // initialized setjmpTable/setjmpTableSize in the entry block and split the + // initialized functionInvocationId in the entry block and split the // rest into another BB, here 'OrigEntry' is the function's original entry // block before the transformation. // // entry: - // setjmpTable / setjmpTableSize initialization + // functionInvocationId initialization // setjmp.dispatch: // switch will be inserted here later // entry.split: (OrigEntry) @@ -1731,17 +1617,15 @@ void WebAssemblyLowerEmscriptenEHSjLj::handleLongjmpableCallsForWasmSjLj( // int val = __wasm_longjmp_args.val; Instruction *Val = IRB.CreateLoad(IRB.getInt32Ty(), ValField, "val"); - // %label = testSetjmp(mem[%env], setjmpTable, setjmpTableSize); + // %label = __wasm_setjmp_test(%env, functionInvocatinoId); // if (%label == 0) // __wasm_longjmp(%env, %val) // catchret to %setjmp.dispatch BasicBlock *ThenBB = BasicBlock::Create(C, "if.then", &F); BasicBlock *EndBB = BasicBlock::Create(C, "if.end", &F); Value *EnvP = IRB.CreateBitCast(Env, getAddrPtrType(&M), "env.p"); - Value *SetjmpID = IRB.CreateLoad(getAddrIntType(&M), EnvP, "setjmp.id"); - Value *Label = - IRB.CreateCall(TestSetjmpF, {SetjmpID, SetjmpTable, SetjmpTableSize}, - OperandBundleDef("funclet", CatchPad), "label"); + Value *Label = IRB.CreateCall(WasmSetjmpTestF, {EnvP, FunctionInvocationId}, + OperandBundleDef("funclet", CatchPad), "label"); Value *Cmp = IRB.CreateICmpEQ(Label, IRB.getInt32(0)); IRB.CreateCondBr(Cmp, ThenBB, EndBB); diff --git a/llvm/test/CodeGen/WebAssembly/lower-em-ehsjlj-options.ll b/llvm/test/CodeGen/WebAssembly/lower-em-ehsjlj-options.ll index aa4d87756c87d..4a63c812d6ae9 100644 --- a/llvm/test/CodeGen/WebAssembly/lower-em-ehsjlj-options.ll +++ b/llvm/test/CodeGen/WebAssembly/lower-em-ehsjlj-options.ll @@ -59,12 +59,12 @@ entry: %call = call i32 @setjmp(ptr %buf) #0 call void @longjmp(ptr %buf, i32 1) #1 unreachable -; SJLJ: call saveSetjmp +; SJLJ: call __wasm_setjmp ; SJLJ: i32.const emscripten_longjmp ; SJLJ-NOT: i32.const emscripten_longjmp_jmpbuf ; SJLJ: call invoke_vii ; SJLJ-NOT: call "__invoke_void_ptr_i32" -; SJLJ: call testSetjmp +; SJLJ: call __wasm_setjmp_test ; NONE: call setjmp ; NONE: call longjmp diff --git a/llvm/test/CodeGen/WebAssembly/lower-em-ehsjlj.ll b/llvm/test/CodeGen/WebAssembly/lower-em-ehsjlj.ll index 7cf05cc922cd3..32942cd92e684 100644 --- a/llvm/test/CodeGen/WebAssembly/lower-em-ehsjlj.ll +++ b/llvm/test/CodeGen/WebAssembly/lower-em-ehsjlj.ll @@ -49,7 +49,7 @@ try.cont: ; preds = %lpad, %entry ; longjmp checking part ; CHECK: if.then1: -; CHECK: call i32 @testSetjmp +; CHECK: call i32 @__wasm_setjmp_test } ; @foo can either throw an exception or longjmp. Because this function doesn't @@ -117,7 +117,6 @@ if.end: ; preds = %entry ; CHECK: rethrow.exn: ; CHECK-NEXT: %exn = call ptr @__cxa_find_matching_catch_2() -; CHECK-NEXT: call void @free(ptr %setjmpTable{{.*}}) ; CHECK-NEXT: call void @__resumeException(ptr %exn) ; CHECK-NEXT: unreachable @@ -147,7 +146,6 @@ throw: ; preds = %if.end, %entry unreachable ; CHECK: throw: -; CHECK-NEXT: call void @free(ptr %setjmpTable{{.*}}) ; CHECK-NEXT: call void @__cxa_throw(ptr null, ptr null, ptr null) ; CHECK-NEXT: unreachable } @@ -208,7 +206,6 @@ return: ; preds = %entry, %if.end ; CHECK: rethrow.exn: ; CHECK-NEXT: %exn = call ptr @__cxa_find_matching_catch_2() -; CHECK-NEXT: tail call void @free(ptr %setjmpTable{{.*}}) ; CHECK-NEXT: call void @__resumeException(ptr %exn) ; CHECK-NEXT: unreachable } diff --git a/llvm/test/CodeGen/WebAssembly/lower-em-sjlj-alias.ll b/llvm/test/CodeGen/WebAssembly/lower-em-sjlj-alias.ll index 1a85a63e44ad4..79ae16191d6b3 100644 --- a/llvm/test/CodeGen/WebAssembly/lower-em-sjlj-alias.ll +++ b/llvm/test/CodeGen/WebAssembly/lower-em-sjlj-alias.ll @@ -12,7 +12,7 @@ target triple = "wasm32-unknown-emscripten" ; CHECK-LABEL: @malloc_test define void @malloc_test() { entry: - ; CHECK: call ptr @malloc + ; CHECK: alloca i32 %retval = alloca i32, align 4 %jmp = alloca [1 x %struct.__jmp_buf_tag], align 16 store i32 0, ptr %retval, align 4 diff --git a/llvm/test/CodeGen/WebAssembly/lower-em-sjlj-debuginfo.ll b/llvm/test/CodeGen/WebAssembly/lower-em-sjlj-debuginfo.ll index 4f694151c7613..fec9836a1607c 100644 --- a/llvm/test/CodeGen/WebAssembly/lower-em-sjlj-debuginfo.ll +++ b/llvm/test/CodeGen/WebAssembly/lower-em-sjlj-debuginfo.ll @@ -16,25 +16,22 @@ entry: call void @foo(), !dbg !7 ret void, !dbg !8 ; CHECK: entry: - ; CHECK-NEXT: call ptr @malloc(i32 40), !dbg ![[DL0:.*]] + ; CHECK-NEXT: %functionInvocationId = alloca i32, align 4, !dbg ![[DL0:.*]] ; CHECK: entry.split: ; CHECK: alloca {{.*}}, !dbg ![[DL0]] - ; CHECK: call ptr @saveSetjmp{{.*}}, !dbg ![[DL1:.*]] - ; CHECK-NEXT: call i32 @getTempRet0{{.*}}, !dbg ![[DL1]] + ; CHECK: call void @__wasm_setjmp{{.*}}, !dbg ![[DL1:.*]] ; CHECK-NEXT: br {{.*}}, !dbg ![[DL2:.*]] ; CHECK: entry.split.split: ; CHECK: call {{.*}} void @__invoke_void{{.*}}, !dbg ![[DL2]] ; CHECK: entry.split.split.split: - ; CHECK-NEXT: call void @free{{.*}}, !dbg ![[DL3:.*]] ; CHECK: if.then1: - ; CHECK: call i32 @testSetjmp{{.*}}, !dbg ![[DL2]] + ; CHECK: call i32 @__wasm_setjmp_test{{.*}}, !dbg ![[DL2]] ; CHECK: if.end: - ; CHECK: call i32 @getTempRet0{{.*}}, !dbg ![[DL2]] ; CHECK: call.em.longjmp: ; CHECK: call void @emscripten_longjmp{{.*}}, !dbg ![[DL2]] @@ -43,26 +40,6 @@ entry: ; CHECK: call void @setTempRet0{{.*}}, !dbg ![[DL2]] } -; No instruction has debug info but the current function (setjmp_debug_info2) -; and the called function (malloc / free) have DISubprograms, so the newly -; generated calls should have debug info attached. We don't have an instruction -; to take debug info from, so we create dummy debug info. -define void @setjmp_debug_info1() !dbg !9 { -; CHECK-LABEL: @setjmp_debug_info1 -entry: - %buf = alloca [1 x %struct.__jmp_buf_tag], align 16 - %arraydecay = getelementptr inbounds [1 x %struct.__jmp_buf_tag], ptr %buf, i32 0, i32 0 - %call = call i32 @setjmp(ptr %arraydecay) #0 - call void @foo() - ret void - ; CHECK: call ptr @malloc(i32 40), !dbg ![[DL_DUMMY:.*]] - ; CHECK: call void @free{{.*}}, !dbg ![[DL_DUMMY]] -} - -; Note that these functions have DISubprograms. -declare !dbg !10 ptr @malloc(i32) -declare !dbg !11 void @free(ptr) - declare void @foo() ; Function Attrs: returns_twice declare i32 @setjmp(ptr) #0 @@ -79,9 +56,3 @@ declare i32 @setjmp(ptr) #0 !6 = !DILocation(line:4, scope: !3) !7 = !DILocation(line:5, scope: !3) !8 = !DILocation(line:6, scope: !3) -!9 = distinct !DISubprogram(name: "setjmp_debug_info1", unit:!2, file: !1, line: 50) -!10 = !DISubprogram(name: "malloc", file: !1, line: 10, isDefinition: false) -!11 = !DISubprogram(name: "free", file: !1, line: 20, isDefinition: false) - -; Dummy debug info generated -; CHECK: ![[DL_DUMMY]] = !DILocation(line: 50, column: 1, scope: !9) diff --git a/llvm/test/CodeGen/WebAssembly/lower-em-sjlj.ll b/llvm/test/CodeGen/WebAssembly/lower-em-sjlj.ll index 7115b01ed1618..27ec95a2c462a 100644 --- a/llvm/test/CodeGen/WebAssembly/lower-em-sjlj.ll +++ b/llvm/test/CodeGen/WebAssembly/lower-em-sjlj.ll @@ -22,15 +22,12 @@ entry: call void @longjmp(ptr %buf, i32 1) #1 unreachable ; CHECK: entry: -; CHECK-NEXT: %[[MALLOCCALL:.*]] = tail call ptr @malloc([[PTR]] 40) -; CHECK-NEXT: store i32 0, ptr %[[MALLOCCALL]] -; CHECK-NEXT: %[[SETJMP_TABLE_SIZE:.*]] = add i32 4, 0 +; CHECK-NEXT: %functionInvocationId = alloca i32, align 4 ; CHECK-NEXT: br label %entry.split ; CHECK: entry.split ; CHECK-NEXT: %[[BUF:.*]] = alloca [1 x %struct.__jmp_buf_tag] -; CHECK-NEXT: %[[SETJMP_TABLE1:.*]] = call ptr @saveSetjmp(ptr %[[BUF]], i32 1, ptr %[[MALLOCCALL]], i32 %[[SETJMP_TABLE_SIZE]]) -; CHECK-NEXT: %[[SETJMP_TABLE_SIZE1:.*]] = call i32 @getTempRet0() +; CHECK-NEXT: call void @__wasm_setjmp(ptr %[[BUF]], i32 1, ptr %functionInvocationId) ; CHECK-NEXT: br label %entry.split.split ; CHECK: entry.split.split: @@ -51,8 +48,7 @@ entry: ; CHECK: if.then1: ; CHECK-NEXT: %[[__THREW__VAL_P:.*]] = inttoptr [[PTR]] %[[__THREW__VAL]] to ptr -; CHECK-NEXT: %[[__THREW__VAL_P_LOADED:.*]] = load [[PTR]], ptr %[[__THREW__VAL_P]] -; CHECK-NEXT: %[[LABEL:.*]] = call i32 @testSetjmp([[PTR]] %[[__THREW__VAL_P_LOADED]], ptr %[[SETJMP_TABLE1]], i32 %[[SETJMP_TABLE_SIZE1]]) +; CHECK-NEXT: %[[LABEL:.*]] = call i32 @__wasm_setjmp_test(ptr %[[__THREW__VAL_P]], ptr %functionInvocationId) ; CHECK-NEXT: %[[CMP:.*]] = icmp eq i32 %[[LABEL]], 0 ; CHECK-NEXT: br i1 %[[CMP]], label %call.em.longjmp, label %if.end2 @@ -69,7 +65,6 @@ entry: ; CHECK: call.em.longjmp: ; CHECK-NEXT: %threw.phi = phi [[PTR]] [ %[[__THREW__VAL]], %if.then1 ] ; CHECK-NEXT: %threwvalue.phi = phi i32 [ %[[THREWVALUE_VAL]], %if.then1 ] -; CHECK-NEXT: tail call void @free(ptr %[[SETJMP_TABLE1]]) ; CHECK-NEXT: call void @emscripten_longjmp([[PTR]] %threw.phi, i32 %threwvalue.phi) ; CHECK-NEXT: unreachable @@ -87,13 +82,12 @@ entry: call void @foo() ret void ; CHECK: entry: -; CHECK: %[[SETJMP_TABLE:.*]] = call ptr @saveSetjmp( +; CHECK: call void @__wasm_setjmp( ; CHECK: entry.split.split: ; CHECK: @__invoke_void(ptr @foo) ; CHECK: entry.split.split.split: -; CHECK-NEXT: tail call void @free(ptr %[[SETJMP_TABLE]]) ; CHECK-NEXT: ret void } @@ -110,9 +104,8 @@ entry: call void @foo() ret void ; CHECK: call.em.longjmp: -; CHECK-NEXT: %threw.phi = phi [[PTR]] [ %__THREW__.val, %if.then1 ], [ %__THREW__.val4, %if.then15 ] -; CHECK-NEXT: %threwvalue.phi = phi i32 [ %__threwValue.val, %if.then1 ], [ %__threwValue.val8, %if.then15 ] -; CHECK-NEXT: tail call void @free(ptr %[[SETJMP_TABLE1]]) +; CHECK-NEXT: %threw.phi = phi [[PTR]] [ %__THREW__.val, %if.then1 ], [ %__THREW__.val2, %if.then13 ] +; CHECK-NEXT: %threwvalue.phi = phi i32 [ %__threwValue.val, %if.then1 ], [ %__threwValue.val6, %if.then13 ] ; CHECK-NEXT: call void @emscripten_longjmp([[PTR]] %threw.phi, i32 %threwvalue.phi) ; CHECK-NEXT: unreachable } @@ -145,7 +138,6 @@ entry: %cmp = icmp sgt i32 %n, 5 br i1 %cmp, label %if.then, label %if.end ; CHECK: entry: -; CHECK: %[[SETJMP_TABLE_SIZE0:.*]] = add i32 4, 0 if.then: ; preds = %entry %0 = load i32, ptr @global_var, align 4 @@ -154,13 +146,10 @@ if.then: ; preds = %entry br label %if.end ; CHECK: if.then: ; CHECK: %[[VAR0:.*]] = load i32, ptr @global_var, align 4 -; CHECK: %[[SETJMP_TABLE1:.*]] = call ptr @saveSetjmp( -; CHECK-NEXT: %[[SETJMP_TABLE_SIZE1:.*]] = call i32 @getTempRet0() +; CHECK: call void @__wasm_setjmp( ; CHECK: if.then.split: -; CHECK: %[[VAR1:.*]] = phi i32 [ %[[VAR2:.*]], %if.end3 ], [ %[[VAR0]], %if.then ] -; CHECK: %[[SETJMP_TABLE_SIZE2:.*]] = phi i32 [ %[[SETJMP_TABLE_SIZE1]], %if.then ], [ %[[SETJMP_TABLE_SIZE3:.*]], %if.end3 ] -; CHECK: %[[SETJMP_TABLE2:.*]] = phi ptr [ %[[SETJMP_TABLE1]], %if.then ], [ %[[SETJMP_TABLE3:.*]], %if.end3 ] +; CHECK: %[[VAR1:.*]] = phi i32 [ %[[VAR2:.*]], %if.end1 ], [ %[[VAR0]], %if.then ] ; CHECK: store i32 %[[VAR1]], ptr @global_var, align 4 if.end: ; preds = %if.then, %entry @@ -168,8 +157,6 @@ if.end: ; preds = %if.then, %entry unreachable ; CHECK: if.end: ; CHECK: %[[VAR2]] = phi i32 [ %[[VAR1]], %if.then.split ], [ undef, %entry.split ] -; CHECK: %[[SETJMP_TABLE_SIZE3]] = phi i32 [ %[[SETJMP_TABLE_SIZE2]], %if.then.split ], [ %[[SETJMP_TABLE_SIZE0]], %entry.split ] -; CHECK: %[[SETJMP_TABLE3]] = phi ptr [ %[[SETJMP_TABLE2]], %if.then.split ], [ %setjmpTable, %entry.split ] } ; Test a case when a function only calls other functions that are neither setjmp nor longjmp @@ -296,8 +283,8 @@ declare void @free(ptr) ; JS glue functions and invoke wrappers declaration ; CHECK-DAG: declare i32 @getTempRet0() ; CHECK-DAG: declare void @setTempRet0(i32) -; CHECK-DAG: declare ptr @saveSetjmp(ptr, i32, ptr, i32) -; CHECK-DAG: declare i32 @testSetjmp([[PTR]], ptr, i32) +; CHECK-DAG: declare void @__wasm_setjmp(ptr, i32, ptr) +; CHECK-DAG: declare i32 @__wasm_setjmp_test(ptr, ptr) ; CHECK-DAG: declare void @emscripten_longjmp([[PTR]], i32) ; CHECK-DAG: declare void @__invoke_void(ptr) @@ -308,8 +295,8 @@ attributes #3 = { allocsize(0) } ; CHECK-DAG: attributes #{{[0-9]+}} = { nounwind "wasm-import-module"="env" "wasm-import-name"="getTempRet0" } ; CHECK-DAG: attributes #{{[0-9]+}} = { nounwind "wasm-import-module"="env" "wasm-import-name"="setTempRet0" } ; CHECK-DAG: attributes #{{[0-9]+}} = { "wasm-import-module"="env" "wasm-import-name"="__invoke_void" } -; CHECK-DAG: attributes #{{[0-9]+}} = { "wasm-import-module"="env" "wasm-import-name"="saveSetjmp" } -; CHECK-DAG: attributes #{{[0-9]+}} = { "wasm-import-module"="env" "wasm-import-name"="testSetjmp" } +; CHECK-DAG: attributes #{{[0-9]+}} = { "wasm-import-module"="env" "wasm-import-name"="__wasm_setjmp" } +; CHECK-DAG: attributes #{{[0-9]+}} = { "wasm-import-module"="env" "wasm-import-name"="__wasm_setjmp_test" } ; CHECK-DAG: attributes #{{[0-9]+}} = { noreturn "wasm-import-module"="env" "wasm-import-name"="emscripten_longjmp" } ; CHECK-DAG: attributes #{{[0-9]+}} = { "wasm-import-module"="env" "wasm-import-name"="__invoke_ptr_i32_ptr" } ; CHECK-DAG: attributes #[[ALLOCSIZE_ATTR]] = { allocsize(1) } diff --git a/llvm/test/CodeGen/WebAssembly/lower-wasm-ehsjlj.ll b/llvm/test/CodeGen/WebAssembly/lower-wasm-ehsjlj.ll index 25471eb50081b..bd8db83a0e57e 100644 --- a/llvm/test/CodeGen/WebAssembly/lower-wasm-ehsjlj.ll +++ b/llvm/test/CodeGen/WebAssembly/lower-wasm-ehsjlj.ll @@ -108,8 +108,8 @@ catch: ; preds = %catch.start call void @__cxa_end_catch() [ "funclet"(token %2) ] catchret from %2 to label %catchret.dest ; CHECK: catch: ; preds = %catch.start -; CHECK-NEXT: %exn = load ptr, ptr %exn.slot15, align 4 -; CHECK-NEXT: %5 = call ptr @__cxa_begin_catch(ptr %exn) #7 [ "funclet"(token %2) ] +; CHECK-NEXT: %exn = load ptr, ptr %exn.slot6, align 4 +; CHECK-NEXT: %5 = call ptr @__cxa_begin_catch(ptr %exn) #6 [ "funclet"(token %2) ] ; CHECK-NEXT: invoke void @__cxa_end_catch() [ "funclet"(token %2) ] ; CHECK-NEXT: to label %.noexc unwind label %catch.dispatch.longjmp @@ -265,7 +265,7 @@ ehcleanup: ; preds = %entry ; (cleanuppad), whose parent is 'none', so we should unwind directly to ; %catch.dispatch.longjmp. %call2 = call noundef ptr @_ZN4TempD2Ev(ptr noundef %t) #2 [ "funclet"(token %0) ] -; CHECK: %call13 = invoke {{.*}} ptr @_ZN4TempD2Ev(ptr +; CHECK: %call11 = invoke {{.*}} ptr @_ZN4TempD2Ev(ptr ; CHECK-NEXT: to label {{.*}} unwind label %catch.dispatch.longjmp cleanupret from %0 unwind to caller } diff --git a/llvm/test/CodeGen/WebAssembly/lower-wasm-sjlj.ll b/llvm/test/CodeGen/WebAssembly/lower-wasm-sjlj.ll index b8d2230fac9f5..82c04e24b72f1 100644 --- a/llvm/test/CodeGen/WebAssembly/lower-wasm-sjlj.ll +++ b/llvm/test/CodeGen/WebAssembly/lower-wasm-sjlj.ll @@ -25,16 +25,12 @@ entry: unreachable ; CHECK: entry: -; CHECK-NEXT: %setjmpTable = tail call ptr @malloc([[PTR]] 40) -; CHECK-NEXT: store i32 0, ptr %setjmpTable, align 4 -; CHECK-NEXT: %setjmpTableSize = add i32 4, 0 +; CHECK-NEXT: %functionInvocationId = alloca i32, align 4 ; CHECK-NEXT: br label %setjmp.dispatch ; CHECK: setjmp.dispatch: ; CHECK-NEXT: %[[VAL2:.*]] = phi i32 [ %val, %if.end ], [ undef, %entry ] ; CHECK-NEXT: %[[BUF:.*]] = phi ptr [ %[[BUF2:.*]], %if.end ], [ undef, %entry ] -; CHECK-NEXT: %[[SETJMPTABLESIZE2:.*]] = phi i32 [ %[[SETJMPTABLESIZE3:.*]], %if.end ], [ %setjmpTableSize, %entry ] -; CHECK-NEXT: %[[SETJMPTABLE2:.*]] = phi ptr [ %[[SETJMPTABLE3:.*]], %if.end ], [ %setjmpTable, %entry ] ; CHECK-NEXT: %label.phi = phi i32 [ %label, %if.end ], [ -1, %entry ] ; CHECK-NEXT: switch i32 %label.phi, label %entry.split [ ; CHECK-NEXT: i32 1, label %entry.split.split @@ -42,14 +38,11 @@ entry: ; CHECK: entry.split: ; CHECK-NEXT: %buf = alloca [1 x %struct.__jmp_buf_tag], align 16 -; CHECK-NEXT: %[[SETJMPTABLE4:.*]] = call ptr @saveSetjmp(ptr %buf, i32 1, ptr %[[SETJMPTABLE2]], i32 %[[SETJMPTABLESIZE2]]) -; CHECK-NEXT: %[[SETJMPTABLESIZE4:.*]] = call i32 @getTempRet0() +; CHECK-NEXT: call void @__wasm_setjmp(ptr %buf, i32 1, ptr %functionInvocationId) ; CHECK-NEXT: br label %entry.split.split ; CHECK: entry.split.split: ; CHECK-NEXT: %[[BUF2]] = phi ptr [ %[[BUF]], %setjmp.dispatch ], [ %buf, %entry.split ] -; CHECK-NEXT: %[[SETJMPTABLESIZE3]] = phi i32 [ %[[SETJMPTABLESIZE4]], %entry.split ], [ %[[SETJMPTABLESIZE2]], %setjmp.dispatch ] -; CHECK-NEXT: %[[SETJMPTABLE3]] = phi ptr [ %[[SETJMPTABLE4]], %entry.split ], [ %[[SETJMPTABLE2]], %setjmp.dispatch ] ; CHECK-NEXT: %setjmp.ret = phi i32 [ 0, %entry.split ], [ %[[VAL2]], %setjmp.dispatch ] ; CHECK-NEXT: invoke void @__wasm_longjmp(ptr %[[BUF2]], i32 1) ; CHECK-NEXT: to label %.noexc unwind label %catch.dispatch.longjmp @@ -67,13 +60,11 @@ entry: ; CHECK-NEXT: %val_gep = getelementptr { ptr, i32 }, ptr %thrown, i32 0, i32 1 ; CHECK-NEXT: %env = load ptr, ptr %env_gep, align {{.*}} ; CHECK-NEXT: %val = load i32, ptr %val_gep, align 4 -; CHECK-NEXT: %setjmp.id = load [[PTR]], ptr %env, align {{.*}} -; CHECK-NEXT: %label = call i32 @testSetjmp([[PTR]] %setjmp.id, ptr %[[SETJMPTABLE3]], i32 %[[SETJMPTABLESIZE3]]) [ "funclet"(token %1) ] +; CHECK-NEXT: %label = call i32 @__wasm_setjmp_test(ptr %env, ptr %functionInvocationId) [ "funclet"(token %1) ] ; CHECK-NEXT: %2 = icmp eq i32 %label, 0 ; CHECK-NEXT: br i1 %2, label %if.then, label %if.end ; CHECK: if.then: -; CHECK-NEXT: tail call void @free(ptr %[[SETJMPTABLE3]]) [ "funclet"(token %1) ] ; CHECK-NEXT: call void @__wasm_longjmp(ptr %env, i32 %val) [ "funclet"(token %1) ] ; CHECK-NEXT: unreachable @@ -142,10 +133,9 @@ declare ptr @__cxa_begin_catch(ptr) declare void @__cxa_end_catch() declare void @free(ptr) -; JS glue function declarations -; CHECK-DAG: declare i32 @getTempRet0() -; CHECK-DAG: declare ptr @saveSetjmp(ptr, i32, ptr, i32) -; CHECK-DAG: declare i32 @testSetjmp([[PTR]], ptr, i32) +; Runtime glue function declarations +; CHECK-DAG: declare void @__wasm_setjmp(ptr, i32, ptr) +; CHECK-DAG: declare i32 @__wasm_setjmp_test(ptr, ptr) ; CHECK-DAG: declare void @__wasm_longjmp(ptr, i32) attributes #0 = { returns_twice }