Please use GitHub pull requests for new patches. Avoid migrating existing patches. Phabricator shutdown timeline
Changeset View
Changeset View
Standalone View
Standalone View
clang/lib/CodeGen/CGCall.cpp
Show First 20 Lines • Show All 4,548 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
/// Emits a call or invoke to the given noreturn runtime function. | /// Emits a call or invoke to the given noreturn runtime function. | ||||
void CodeGenFunction::EmitNoreturnRuntimeCallOrInvoke( | void CodeGenFunction::EmitNoreturnRuntimeCallOrInvoke( | ||||
llvm::FunctionCallee callee, ArrayRef<llvm::Value *> args) { | llvm::FunctionCallee callee, ArrayRef<llvm::Value *> args) { | ||||
SmallVector<llvm::OperandBundleDef, 1> BundleList = | SmallVector<llvm::OperandBundleDef, 1> BundleList = | ||||
getBundlesForFunclet(callee.getCallee()); | getBundlesForFunclet(callee.getCallee()); | ||||
if (getInvokeDest()) { | bool UseUnwindAbort = shouldUseUnwindAbort(); | ||||
if (!UseUnwindAbort && getInvokeDest()) { | |||||
llvm::InvokeInst *invoke = | llvm::InvokeInst *invoke = | ||||
Builder.CreateInvoke(callee, | Builder.CreateInvoke(callee, | ||||
getUnreachableBlock(), | getUnreachableBlock(), | ||||
getInvokeDest(), | getInvokeDest(), | ||||
args, | args, | ||||
BundleList); | BundleList); | ||||
invoke->setDoesNotReturn(); | invoke->setDoesNotReturn(); | ||||
invoke->setCallingConv(getRuntimeCC()); | invoke->setCallingConv(getRuntimeCC()); | ||||
} else { | } else { | ||||
llvm::CallInst *call = Builder.CreateCall(callee, args, BundleList); | llvm::CallInst *call = Builder.CreateCall(callee, args, BundleList); | ||||
call->setDoesNotReturn(); | call->setDoesNotReturn(); | ||||
call->setCallingConv(getRuntimeCC()); | call->setCallingConv(getRuntimeCC()); | ||||
if (UseUnwindAbort) { | |||||
call->setUnwindAbort(); | |||||
setupPersonalityFn(); | |||||
} | |||||
Builder.CreateUnreachable(); | Builder.CreateUnreachable(); | ||||
} | } | ||||
} | } | ||||
/// Emits a call or invoke instruction to the given nullary runtime function. | /// Emits a call or invoke instruction to the given nullary runtime function. | ||||
llvm::CallBase * | llvm::CallBase * | ||||
CodeGenFunction::EmitRuntimeCallOrInvoke(llvm::FunctionCallee callee, | CodeGenFunction::EmitRuntimeCallOrInvoke(llvm::FunctionCallee callee, | ||||
const Twine &name) { | const Twine &name) { | ||||
Show All 10 Lines | CodeGenFunction::EmitRuntimeCallOrInvoke(llvm::FunctionCallee callee, | ||||
return call; | return call; | ||||
} | } | ||||
/// Emits a call or invoke instruction to the given function, depending | /// Emits a call or invoke instruction to the given function, depending | ||||
/// on the current state of the EH stack. | /// on the current state of the EH stack. | ||||
llvm::CallBase *CodeGenFunction::EmitCallOrInvoke(llvm::FunctionCallee Callee, | llvm::CallBase *CodeGenFunction::EmitCallOrInvoke(llvm::FunctionCallee Callee, | ||||
ArrayRef<llvm::Value *> Args, | ArrayRef<llvm::Value *> Args, | ||||
const Twine &Name) { | const Twine &Name) { | ||||
llvm::BasicBlock *InvokeDest = getInvokeDest(); | bool UseUnwindAbort = shouldUseUnwindAbort(); | ||||
llvm::BasicBlock *InvokeDest = UseUnwindAbort ? nullptr : getInvokeDest(); | |||||
SmallVector<llvm::OperandBundleDef, 1> BundleList = | SmallVector<llvm::OperandBundleDef, 1> BundleList = | ||||
getBundlesForFunclet(Callee.getCallee()); | getBundlesForFunclet(Callee.getCallee()); | ||||
llvm::CallBase *Inst; | llvm::CallBase *Inst; | ||||
if (!InvokeDest) | if (!InvokeDest) { | ||||
Inst = Builder.CreateCall(Callee, Args, BundleList, Name); | llvm::CallInst *CI = Builder.CreateCall(Callee, Args, BundleList, Name); | ||||
else { | if (UseUnwindAbort) { | ||||
CI->setUnwindAbort(); | |||||
setupPersonalityFn(); | |||||
} | |||||
Inst = CI; | |||||
} else { | |||||
llvm::BasicBlock *ContBB = createBasicBlock("invoke.cont"); | llvm::BasicBlock *ContBB = createBasicBlock("invoke.cont"); | ||||
Inst = Builder.CreateInvoke(Callee, ContBB, InvokeDest, Args, BundleList, | Inst = Builder.CreateInvoke(Callee, ContBB, InvokeDest, Args, BundleList, | ||||
Name); | Name); | ||||
EmitBlock(ContBB); | EmitBlock(ContBB); | ||||
} | } | ||||
// In ObjC ARC mode with no ObjC ARC exception safety, tell the ARC | // In ObjC ARC mode with no ObjC ARC exception safety, tell the ARC | ||||
// optimizer it can aggressively ignore unwind edges. | // optimizer it can aggressively ignore unwind edges. | ||||
▲ Show 20 Lines • Show All 743 Lines • ▼ Show 20 Lines | #endif | ||||
// Disable inlining inside SEH __try blocks. | // Disable inlining inside SEH __try blocks. | ||||
if (isSEHTryScope()) { | if (isSEHTryScope()) { | ||||
Attrs = Attrs.addFnAttribute(getLLVMContext(), llvm::Attribute::NoInline); | Attrs = Attrs.addFnAttribute(getLLVMContext(), llvm::Attribute::NoInline); | ||||
} | } | ||||
// Decide whether to use a call or an invoke. | // Decide whether to use a call or an invoke. | ||||
bool CannotThrow; | bool CannotThrow; | ||||
bool UseUnwindAbort = false; | |||||
if (currentFunctionUsesSEHTry()) { | if (currentFunctionUsesSEHTry()) { | ||||
// SEH cares about asynchronous exceptions, so everything can "throw." | // SEH cares about asynchronous exceptions, so everything can "throw." | ||||
CannotThrow = false; | CannotThrow = false; | ||||
} else if (isCleanupPadScope() && | } else if (isCleanupPadScope() && | ||||
EHPersonality::get(*this).isMSVCXXPersonality()) { | EHPersonality::get(*this).isMSVCXXPersonality()) { | ||||
// The MSVC++ personality will implicitly terminate the program if an | // The MSVC++ personality will implicitly terminate the program if an | ||||
// exception is thrown during a cleanup outside of a try/catch. | // exception is thrown during a cleanup outside of a try/catch. | ||||
// We don't need to model anything in IR to get this behavior. | // We don't need to model anything in IR to get this behavior. | ||||
CannotThrow = true; | CannotThrow = true; | ||||
} else { | } else { | ||||
// Otherwise, nounwind call sites will never throw. | // Otherwise, nounwind call sites will never throw. | ||||
CannotThrow = Attrs.hasFnAttr(llvm::Attribute::NoUnwind); | CannotThrow = Attrs.hasFnAttr(llvm::Attribute::NoUnwind); | ||||
if (auto *FPtr = dyn_cast<llvm::Function>(CalleePtr)) | if (auto *FPtr = dyn_cast<llvm::Function>(CalleePtr)) | ||||
if (FPtr->hasFnAttribute(llvm::Attribute::NoUnwind)) | if (FPtr->hasFnAttribute(llvm::Attribute::NoUnwind)) | ||||
CannotThrow = true; | CannotThrow = true; | ||||
jroelofs: Is there coverage for a nounwind callee + an unwindabort call? | |||||
if (!CannotThrow && shouldUseUnwindAbort()) { | |||||
// If we can use unwindabort, don't use a landingpad. | |||||
UseUnwindAbort = true; | |||||
CannotThrow = true; | |||||
} | |||||
} | } | ||||
// If we made a temporary, be sure to clean up after ourselves. Note that we | // If we made a temporary, be sure to clean up after ourselves. Note that we | ||||
// can't depend on being inside of an ExprWithCleanups, so we need to manually | // can't depend on being inside of an ExprWithCleanups, so we need to manually | ||||
// pop this cleanup later on. Being eager about this is OK, since this | // pop this cleanup later on. Being eager about this is OK, since this | ||||
// temporary is 'invisible' outside of the callee. | // temporary is 'invisible' outside of the callee. | ||||
if (UnusedReturnSizePtr) | if (UnusedReturnSizePtr) | ||||
pushFullExprCleanup<CallLifetimeEnd>(NormalEHLifetimeMarker, SRetAlloca, | pushFullExprCleanup<CallLifetimeEnd>(NormalEHLifetimeMarker, SRetAlloca, | ||||
Show All 17 Lines | #endif | ||||
Attrs = AssumeAlignedAttrEmitter.TryEmitAsCallSiteAttribute(Attrs); | Attrs = AssumeAlignedAttrEmitter.TryEmitAsCallSiteAttribute(Attrs); | ||||
AllocAlignAttrEmitter AllocAlignAttrEmitter(*this, TargetDecl, CallArgs); | AllocAlignAttrEmitter AllocAlignAttrEmitter(*this, TargetDecl, CallArgs); | ||||
Attrs = AllocAlignAttrEmitter.TryEmitAsCallSiteAttribute(Attrs); | Attrs = AllocAlignAttrEmitter.TryEmitAsCallSiteAttribute(Attrs); | ||||
// Emit the actual call/invoke instruction. | // Emit the actual call/invoke instruction. | ||||
llvm::CallBase *CI; | llvm::CallBase *CI; | ||||
if (!InvokeDest) { | if (!InvokeDest) { | ||||
CI = Builder.CreateCall(IRFuncTy, CalleePtr, IRCallArgs, BundleList); | llvm::CallInst *Call = | ||||
Builder.CreateCall(IRFuncTy, CalleePtr, IRCallArgs, BundleList); | |||||
if (UseUnwindAbort) { | |||||
Call->setUnwindAbort(); | |||||
setupPersonalityFn(); | |||||
} | |||||
CI = Call; | |||||
} else { | } else { | ||||
llvm::BasicBlock *Cont = createBasicBlock("invoke.cont"); | llvm::BasicBlock *Cont = createBasicBlock("invoke.cont"); | ||||
CI = Builder.CreateInvoke(IRFuncTy, CalleePtr, Cont, InvokeDest, IRCallArgs, | CI = Builder.CreateInvoke(IRFuncTy, CalleePtr, Cont, InvokeDest, IRCallArgs, | ||||
BundleList); | BundleList); | ||||
EmitBlock(Cont); | EmitBlock(Cont); | ||||
} | } | ||||
if (callOrInvoke) | if (callOrInvoke) | ||||
*callOrInvoke = CI; | *callOrInvoke = CI; | ||||
▲ Show 20 Lines • Show All 272 Lines • Show Last 20 Lines |
Is there coverage for a nounwind callee + an unwindabort call?