static CallInst *ReplaceCallWith(const char *NewFn, CallInst *CI, ArgIt ArgBegin, ArgIt ArgEnd, Type *RetTy) { // If we haven't already looked up this function, check to see if the // program already contains a function with this name. Module *M = CI->getParent()->getParent()->getParent(); // Get or insert the definition now. std::vector<Type *> ParamTys; for (ArgIt I = ArgBegin; I != ArgEnd; ++I) ParamTys.push_back((*I)->getType()); Constant* FCache = M->getOrInsertFunction(NewFn, FunctionType::get(RetTy, ParamTys, false)); IRBuilder<> Builder(CI->getParent(), CI); SmallVector<Value *, 8> Args(ArgBegin, ArgEnd); CallInst *NewCI = Builder.CreateCall(FCache, Args); NewCI->setName(CI->getName()); if (!CI->use_empty()) CI->replaceAllUsesWith(NewCI); return NewCI; }
void AtomicVisitor::replaceInstructionWithIntrinsicCall( Instruction &I, const NaCl::AtomicIntrinsics::AtomicIntrinsic *Intrinsic, Type *DstType, Type *OverloadedType, ArrayRef<Value *> Args) { std::string Name(I.getName()); Function *F = Intrinsic->getDeclaration(&M); CallInst *Call = CallInst::Create(F, Args, "", &I); Call->setDebugLoc(I.getDebugLoc()); Instruction *Res = Call; assert((I.getType()->isStructTy() == isa<AtomicCmpXchgInst>(&I)) && "cmpxchg returns a struct, and other instructions don't"); if (auto S = dyn_cast<StructType>(I.getType())) { assert(S->getNumElements() == 2 && "cmpxchg returns a struct with two elements"); assert(S->getElementType(0) == DstType && "cmpxchg struct's first member should be the value type"); assert(S->getElementType(1) == Type::getInt1Ty(C) && "cmpxchg struct's second member should be the success flag"); // Recreate struct { T value, i1 success } after the call. auto Success = CmpInst::Create( Instruction::ICmp, CmpInst::ICMP_EQ, Res, cast<AtomicCmpXchgInst>(&I)->getCompareOperand(), "success", &I); Res = InsertValueInst::Create( InsertValueInst::Create(UndefValue::get(S), Res, 0, Name + ".insert.value", &I), Success, 1, Name + ".insert.success", &I); } else if (!Call->getType()->isVoidTy() && DstType != OverloadedType) { // The call returns a value which needs to be cast to a non-integer. Res = createCast(I, Call, DstType, Name + ".cast"); Res->setDebugLoc(I.getDebugLoc()); } I.replaceAllUsesWith(Res); I.eraseFromParent(); Call->setName(Name); ModifiedModule = true; }
// 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; }