diff options
-rw-r--r-- | clang/lib/CodeGen/CGCall.cpp | 34 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenModule.cpp | 9 |
2 files changed, 37 insertions, 6 deletions
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 891f9071bdc..49b5df0c4f0 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -3058,19 +3058,41 @@ CodeGenFunction::EmitRuntimeCall(llvm::Value *callee, return call; } +// Calls which may throw must have operand bundles indicating which funclet +// they are nested within. +static void +getBundlesForFunclet(llvm::Value *Callee, + llvm::Instruction *CurrentFuncletPad, + SmallVectorImpl<llvm::OperandBundleDef> &BundleList) { + // There is no need for a funclet operand bundle if we aren't inside a funclet. + if (!CurrentFuncletPad) + return; + + // Skip intrinsics which cannot throw. + auto *CalleeFn = dyn_cast<llvm::Function>(Callee->stripPointerCasts()); + if (CalleeFn && CalleeFn->isIntrinsic() && CalleeFn->doesNotThrow()) + return; + + BundleList.emplace_back("funclet", CurrentFuncletPad); +} + /// Emits a call or invoke to the given noreturn runtime function. void CodeGenFunction::EmitNoreturnRuntimeCallOrInvoke(llvm::Value *callee, ArrayRef<llvm::Value*> args) { + SmallVector<llvm::OperandBundleDef, 1> BundleList; + getBundlesForFunclet(callee, CurrentFuncletPad, BundleList); + if (getInvokeDest()) { llvm::InvokeInst *invoke = Builder.CreateInvoke(callee, getUnreachableBlock(), getInvokeDest(), - args); + args, + BundleList); invoke->setDoesNotReturn(); invoke->setCallingConv(getRuntimeCC()); } else { - llvm::CallInst *call = Builder.CreateCall(callee, args); + llvm::CallInst *call = Builder.CreateCall(callee, args, BundleList); call->setDoesNotReturn(); call->setCallingConv(getRuntimeCC()); Builder.CreateUnreachable(); @@ -3489,12 +3511,16 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, } llvm::BasicBlock *InvokeDest = CannotThrow ? nullptr : getInvokeDest(); + SmallVector<llvm::OperandBundleDef, 1> BundleList; + getBundlesForFunclet(Callee, CurrentFuncletPad, BundleList); + llvm::CallSite CS; if (!InvokeDest) { - CS = Builder.CreateCall(Callee, IRCallArgs); + CS = Builder.CreateCall(Callee, IRCallArgs, BundleList); } else { llvm::BasicBlock *Cont = createBasicBlock("invoke.cont"); - CS = Builder.CreateInvoke(Callee, Cont, InvokeDest, IRCallArgs); + CS = Builder.CreateInvoke(Callee, Cont, InvokeDest, IRCallArgs, + BundleList); EmitBlock(Cont); } if (callOrInvoke) diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 29c5f3eed5a..b207bac3dee 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -2495,6 +2495,7 @@ static void replaceUsesOfNonProtoConstant(llvm::Constant *old, llvm::Type *newRetTy = newFn->getReturnType(); SmallVector<llvm::Value*, 4> newArgs; + SmallVector<llvm::OperandBundleDef, 1> newBundles; for (llvm::Value::use_iterator ui = old->use_begin(), ue = old->use_end(); ui != ue; ) { @@ -2562,16 +2563,19 @@ static void replaceUsesOfNonProtoConstant(llvm::Constant *old, // over the required information. newArgs.append(callSite.arg_begin(), callSite.arg_begin() + argNo); + // Copy over any operand bundles. + callSite.getOperandBundlesAsDefs(newBundles); + llvm::CallSite newCall; if (callSite.isCall()) { - newCall = llvm::CallInst::Create(newFn, newArgs, "", + newCall = llvm::CallInst::Create(newFn, newArgs, newBundles, "", callSite.getInstruction()); } else { auto *oldInvoke = cast<llvm::InvokeInst>(callSite.getInstruction()); newCall = llvm::InvokeInst::Create(newFn, oldInvoke->getNormalDest(), oldInvoke->getUnwindDest(), - newArgs, "", + newArgs, newBundles, "", callSite.getInstruction()); } newArgs.clear(); // for the next iteration @@ -2589,6 +2593,7 @@ static void replaceUsesOfNonProtoConstant(llvm::Constant *old, // Copy debug location attached to CI. if (callSite->getDebugLoc()) newCall->setDebugLoc(callSite->getDebugLoc()); + callSite->eraseFromParent(); } } |