// Creates the helper function that will do the setjmp() call and // function call for implementing Invoke. Creates the call to the // helper function. Returns a Value which is zero on the normal // execution path and non-zero if the landingpad block should be // entered. Value *FuncRewriter::createSetjmpWrappedCall(InvokeInst *Invoke) { Type *I32 = Type::getInt32Ty(Func->getContext()); // Allocate space for storing the invoke's result temporarily (so // that the helper function can return multiple values). We don't // need to do this if the result is unused, and we can't if its type // is void. Instruction *ResultAlloca = NULL; if (!Invoke->use_empty()) { ResultAlloca = new AllocaInst(Invoke->getType(), "invoke_result_ptr"); Func->getEntryBlock().getInstList().push_front(ResultAlloca); } // Create type for the helper function. SmallVector<Type *, 10> ArgTypes; for (unsigned I = 0, E = Invoke->getNumArgOperands(); I < E; ++I) ArgTypes.push_back(Invoke->getArgOperand(I)->getType()); ArgTypes.push_back(Invoke->getCalledValue()->getType()); ArgTypes.push_back(FrameJmpBuf->getType()); if (ResultAlloca) ArgTypes.push_back(Invoke->getType()->getPointerTo()); FunctionType *FTy = FunctionType::get(I32, ArgTypes, false); // Create the helper function. Function *HelperFunc = Function::Create( FTy, GlobalValue::InternalLinkage, Func->getName() + "_setjmp_caller"); Func->getParent()->getFunctionList().insertAfter(Func, HelperFunc); BasicBlock *EntryBB = BasicBlock::Create(Func->getContext(), "", HelperFunc); BasicBlock *NormalBB = BasicBlock::Create(Func->getContext(), "normal", HelperFunc); BasicBlock *ExceptionBB = BasicBlock::Create(Func->getContext(), "exception", HelperFunc); // Unpack the helper function's arguments. Function::arg_iterator ArgIter = HelperFunc->arg_begin(); SmallVector<Value *, 10> InnerCallArgs; for (unsigned I = 0, E = Invoke->getNumArgOperands(); I < E; ++I) { ArgIter->setName("arg"); InnerCallArgs.push_back(ArgIter++); } Argument *CalleeArg = ArgIter++; Argument *JmpBufArg = ArgIter++; CalleeArg->setName("func_ptr"); JmpBufArg->setName("jmp_buf"); // Create setjmp() call. Value *SetjmpArgs[] = { JmpBufArg }; CallInst *SetjmpCall = CallInst::Create(SetjmpIntrinsic, SetjmpArgs, "invoke_sj", EntryBB); CopyDebug(SetjmpCall, Invoke); // Setting the "returns_twice" attribute here prevents optimization // passes from inlining HelperFunc into its caller. SetjmpCall->setCanReturnTwice(); // Check setjmp()'s result. Value *IsZero = CopyDebug(new ICmpInst(*EntryBB, CmpInst::ICMP_EQ, SetjmpCall, ConstantInt::get(I32, 0), "invoke_sj_is_zero"), Invoke); CopyDebug(BranchInst::Create(NormalBB, ExceptionBB, IsZero, EntryBB), Invoke); // Handle the normal, non-exceptional code path. CallInst *InnerCall = CallInst::Create(CalleeArg, InnerCallArgs, "", NormalBB); CopyDebug(InnerCall, Invoke); InnerCall->setAttributes(Invoke->getAttributes()); InnerCall->setCallingConv(Invoke->getCallingConv()); if (ResultAlloca) { InnerCall->setName("result"); Argument *ResultArg = ArgIter++; ResultArg->setName("result_ptr"); CopyDebug(new StoreInst(InnerCall, ResultArg, NormalBB), Invoke); } ReturnInst::Create(Func->getContext(), ConstantInt::get(I32, 0), NormalBB); // Handle the exceptional code path. ReturnInst::Create(Func->getContext(), ConstantInt::get(I32, 1), ExceptionBB); // Create the outer call to the helper function. SmallVector<Value *, 10> OuterCallArgs; for (unsigned I = 0, E = Invoke->getNumArgOperands(); I < E; ++I) OuterCallArgs.push_back(Invoke->getArgOperand(I)); OuterCallArgs.push_back(Invoke->getCalledValue()); OuterCallArgs.push_back(FrameJmpBuf); if (ResultAlloca) OuterCallArgs.push_back(ResultAlloca); CallInst *OuterCall = CallInst::Create(HelperFunc, OuterCallArgs, "invoke_is_exc", Invoke); CopyDebug(OuterCall, Invoke); // Retrieve the function return value stored in the alloca. We only // need to do this on the non-exceptional path, but we currently do // it unconditionally because that is simpler. if (ResultAlloca) { Value *Result = new LoadInst(ResultAlloca, "", Invoke); Result->takeName(Invoke); Invoke->replaceAllUsesWith(Result); } return OuterCall; }