Index: include/clang/CodeGen/CGFunctionInfo.h =================================================================== --- include/clang/CodeGen/CGFunctionInfo.h +++ include/clang/CodeGen/CGFunctionInfo.h @@ -509,6 +509,29 @@ } }; +/// CGCalleeInfo - Class to encapsulate the information about a callee to be +/// used during the generation of call/invoke instructions. +class CGCalleeInfo { + /// \brief The function proto type of the callee. + const FunctionProtoType *CalleeProtoTy; + /// \brief The function declaration of the callee. + const Decl *CalleeDecl; + +public: + explicit CGCalleeInfo() : CalleeProtoTy(nullptr), CalleeDecl(nullptr) {} + CGCalleeInfo(const FunctionProtoType *calleeProtoTy, const Decl *calleeDecl) + : CalleeProtoTy(calleeProtoTy), CalleeDecl(calleeDecl) {} + CGCalleeInfo(const FunctionProtoType *calleeProtoTy) + : CalleeProtoTy(calleeProtoTy), CalleeDecl(nullptr) {} + CGCalleeInfo(const Decl *calleeDecl) + : CalleeProtoTy(nullptr), CalleeDecl(calleeDecl) {} + + const FunctionProtoType *getCalleeFunctionProtoType() { + return CalleeProtoTy; + } + const Decl *getCalleeDecl() { return CalleeDecl; } +}; + } // end namespace CodeGen } // end namespace clang Index: lib/CodeGen/CGCall.cpp =================================================================== --- lib/CodeGen/CGCall.cpp +++ lib/CodeGen/CGCall.cpp @@ -1391,8 +1391,19 @@ return GetFunctionType(*Info); } +static void AddAttributesFromFunctionProtoType(ASTContext &Ctx, + llvm::AttrBuilder &FuncAttrs, + const FunctionProtoType *FPT) { + if (!FPT) + return; + + if (!isUnresolvedExceptionSpec(FPT->getExceptionSpecType()) && + FPT->isNothrow(Ctx)) + FuncAttrs.addAttribute(llvm::Attribute::NoUnwind); +} + void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, - const Decl *TargetDecl, + CGCalleeInfo CalleeInfo, AttributeListType &PAL, unsigned &CallingConv, bool AttrOnCallSite) { @@ -1405,6 +1416,13 @@ if (FI.isNoReturn()) FuncAttrs.addAttribute(llvm::Attribute::NoReturn); + // If we have information about the function prototype, we can learn + // attributes form there. + AddAttributesFromFunctionProtoType(getContext(), FuncAttrs, + CalleeInfo.getCalleeFunctionProtoType()); + + const Decl *TargetDecl = CalleeInfo.getCalleeDecl(); + // FIXME: handle sseregparm someday... if (TargetDecl) { if (TargetDecl->hasAttr()) @@ -1417,10 +1435,8 @@ FuncAttrs.addAttribute(llvm::Attribute::NoDuplicate); if (const FunctionDecl *Fn = dyn_cast(TargetDecl)) { - const FunctionProtoType *FPT = Fn->getType()->getAs(); - if (FPT && !isUnresolvedExceptionSpec(FPT->getExceptionSpecType()) && - FPT->isNothrow(getContext())) - FuncAttrs.addAttribute(llvm::Attribute::NoUnwind); + AddAttributesFromFunctionProtoType( + getContext(), FuncAttrs, Fn->getType()->getAs()); // Don't use [[noreturn]] or _Noreturn for a call to a virtual function. // These attributes are not inherited by overloads. const CXXMethodDecl *MD = dyn_cast(Fn); @@ -3077,7 +3093,7 @@ llvm::Value *Callee, ReturnValueSlot ReturnValue, const CallArgList &CallArgs, - const Decl *TargetDecl, + CGCalleeInfo CalleeInfo, llvm::Instruction **callOrInvoke) { // FIXME: We no longer need the types from CallArgs; lift up and simplify. @@ -3406,8 +3422,8 @@ unsigned CallingConv; CodeGen::AttributeListType AttributeList; - CGM.ConstructAttributeList(CallInfo, TargetDecl, AttributeList, - CallingConv, true); + CGM.ConstructAttributeList(CallInfo, CalleeInfo, AttributeList, CallingConv, + true); llvm::AttributeSet Attrs = llvm::AttributeSet::get(getLLVMContext(), AttributeList); @@ -3487,9 +3503,11 @@ // lexical order, so deactivate it and run it manually here. CallArgs.freeArgumentMemory(*this); - if (llvm::CallInst *Call = dyn_cast(CI)) + if (llvm::CallInst *Call = dyn_cast(CI)) { + const Decl *TargetDecl = CalleeInfo.getCalleeDecl(); if (TargetDecl && TargetDecl->hasAttr()) Call->setTailCallKind(llvm::CallInst::TCK_NoTail); + } RValue Ret = [&] { switch (RetAI.getKind()) { @@ -3562,6 +3580,8 @@ llvm_unreachable("Unhandled ABIArgInfo::Kind"); } (); + const Decl *TargetDecl = CalleeInfo.getCalleeDecl(); + if (Ret.isScalar() && TargetDecl) { if (const auto *AA = TargetDecl->getAttr()) { llvm::Value *OffsetValue = nullptr; Index: lib/CodeGen/CGExpr.cpp =================================================================== --- lib/CodeGen/CGExpr.cpp +++ lib/CodeGen/CGExpr.cpp @@ -3741,12 +3741,21 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee, const CallExpr *E, ReturnValueSlot ReturnValue, - const Decl *TargetDecl, llvm::Value *Chain) { + CGCalleeInfo CalleeInfo, llvm::Value *Chain) { // Get the actual function type. The callee type will always be a pointer to // function type or a block pointer type. assert(CalleeType->isFunctionPointerType() && "Call must have function pointer type!"); + // Preserve the non-canonical function type because things like exception + // specifications disappear in the canonical type. That information is useful + // to drive the generation of more accurate code for this call later on. + const FunctionProtoType *NonCanonicalFTP = CalleeType->getAs() + ->getPointeeType() + ->getAs(); + + const Decl *TargetDecl = CalleeInfo.getCalleeDecl(); + if (const FunctionDecl *FD = dyn_cast_or_null(TargetDecl)) // We can only guarantee that a function is called from the correct // context/function based on the appropriate target attributes, @@ -3867,7 +3876,8 @@ Callee = Builder.CreateBitCast(Callee, CalleeTy, "callee.knr.cast"); } - return EmitCall(FnInfo, Callee, ReturnValue, Args, TargetDecl); + return EmitCall(FnInfo, Callee, ReturnValue, Args, + CGCalleeInfo(NonCanonicalFTP, TargetDecl)); } LValue CodeGenFunction:: Index: lib/CodeGen/CGExprComplex.cpp =================================================================== --- lib/CodeGen/CGExprComplex.cpp +++ lib/CodeGen/CGExprComplex.cpp @@ -585,19 +585,25 @@ // We *must* use the full CG function call building logic here because the // complex type has special ABI handling. We also should not forget about // special calling convention which may be used for compiler builtins. - const CGFunctionInfo &FuncInfo = - CGF.CGM.getTypes().arrangeFreeFunctionCall( - Op.Ty, Args, FunctionType::ExtInfo(/* No CC here - will be added later */), - RequiredArgs::All); + + // We create a function qualified type to state that this call does not have + // any exceptions. + FunctionProtoType::ExtProtoInfo EPI; + EPI = EPI.withExceptionSpec( + FunctionProtoType::ExceptionSpecInfo(EST_BasicNoexcept)); + SmallVector ArgsQTys( + 4, Op.Ty->castAs()->getElementType()); + QualType FQTy = CGF.getContext().getFunctionType(Op.Ty, ArgsQTys, EPI); + const CGFunctionInfo &FuncInfo = CGF.CGM.getTypes().arrangeFreeFunctionCall( + Args, cast(FQTy.getTypePtr()), false); + llvm::FunctionType *FTy = CGF.CGM.getTypes().GetFunctionType(FuncInfo); llvm::Constant *Func = CGF.CGM.CreateBuiltinFunction(FTy, LibCallName); llvm::Instruction *Call; RValue Res = CGF.EmitCall(FuncInfo, Func, ReturnValueSlot(), Args, - nullptr, &Call); + FQTy->getAs(), &Call); cast(Call)->setCallingConv(CGF.CGM.getBuiltinCC()); - cast(Call)->setDoesNotThrow(); - return Res.getComplexVal(); } Index: lib/CodeGen/CGObjC.cpp =================================================================== --- lib/CodeGen/CGObjC.cpp +++ lib/CodeGen/CGObjC.cpp @@ -949,11 +949,11 @@ // FIXME: We shouldn't need to get the function info here, the // runtime already should have computed it to build the function. llvm::Instruction *CallInstruction; - RValue RV = EmitCall(getTypes().arrangeFreeFunctionCall(propType, args, - FunctionType::ExtInfo(), - RequiredArgs::All), - getPropertyFn, ReturnValueSlot(), args, nullptr, - &CallInstruction); + RValue RV = EmitCall( + getTypes().arrangeFreeFunctionCall( + propType, args, FunctionType::ExtInfo(), RequiredArgs::All), + getPropertyFn, ReturnValueSlot(), args, CGCalleeInfo(), + &CallInstruction); if (llvm::CallInst *call = dyn_cast(CallInstruction)) call->setTailCall(); Index: lib/CodeGen/CGObjCGNU.cpp =================================================================== --- lib/CodeGen/CGObjCGNU.cpp +++ lib/CodeGen/CGObjCGNU.cpp @@ -1327,8 +1327,8 @@ llvm::MDNode *node = llvm::MDNode::get(VMContext, impMD); llvm::Instruction *call; - RValue msgRet = CGF.EmitCall(MSI.CallInfo, imp, Return, ActualArgs, nullptr, - &call); + RValue msgRet = CGF.EmitCall(MSI.CallInfo, imp, Return, ActualArgs, + CGCalleeInfo(), &call); call->setMetadata(msgSendMDKind, node); return msgRet; } @@ -1440,8 +1440,8 @@ imp = EnforceType(Builder, imp, MSI.MessengerType); llvm::Instruction *call; - RValue msgRet = CGF.EmitCall(MSI.CallInfo, imp, Return, ActualArgs, nullptr, - &call); + RValue msgRet = CGF.EmitCall(MSI.CallInfo, imp, Return, ActualArgs, + CGCalleeInfo(), &call); call->setMetadata(msgSendMDKind, node); Index: lib/CodeGen/CGObjCMac.cpp =================================================================== --- lib/CodeGen/CGObjCMac.cpp +++ lib/CodeGen/CGObjCMac.cpp @@ -1947,7 +1947,7 @@ llvm::Instruction *CallSite; Fn = llvm::ConstantExpr::getBitCast(Fn, MSI.MessengerType); RValue rvalue = CGF.EmitCall(MSI.CallInfo, Fn, Return, ActualArgs, - nullptr, &CallSite); + CGCalleeInfo(), &CallSite); // Mark the call as noreturn if the method is marked noreturn and the // receiver cannot be null. Index: lib/CodeGen/CodeGenFunction.h =================================================================== --- lib/CodeGen/CodeGenFunction.h +++ lib/CodeGen/CodeGenFunction.h @@ -2624,16 +2624,14 @@ /// /// \param TargetDecl - If given, the decl of the function in a direct call; /// used to set attributes on the call (noreturn, etc.). - RValue EmitCall(const CGFunctionInfo &FnInfo, - llvm::Value *Callee, - ReturnValueSlot ReturnValue, - const CallArgList &Args, - const Decl *TargetDecl = nullptr, + RValue EmitCall(const CGFunctionInfo &FnInfo, llvm::Value *Callee, + ReturnValueSlot ReturnValue, const CallArgList &Args, + CGCalleeInfo CalleeInfo = CGCalleeInfo(), llvm::Instruction **callOrInvoke = nullptr); RValue EmitCall(QualType FnType, llvm::Value *Callee, const CallExpr *E, ReturnValueSlot ReturnValue, - const Decl *TargetDecl = nullptr, + CGCalleeInfo CalleeInfo = CGCalleeInfo(), llvm::Value *Chain = nullptr); RValue EmitCallExpr(const CallExpr *E, ReturnValueSlot ReturnValue = ReturnValueSlot()); Index: lib/CodeGen/CodeGenModule.h =================================================================== --- lib/CodeGen/CodeGenModule.h +++ lib/CodeGen/CodeGenModule.h @@ -968,16 +968,14 @@ /// function type. /// /// \param Info - The function type information. - /// \param TargetDecl - The decl these attributes are being constructed - /// for. If supplied the attributes applied to this decl may contribute to the - /// function attributes and calling convention. + /// \param CalleeInfo - The callee information these attributes are being + /// constructed for. If valid, the attributes applied to this decl may + /// contribute to the function attributes and calling convention. /// \param PAL [out] - On return, the attribute list to use. /// \param CallingConv [out] - On return, the LLVM calling convention to use. void ConstructAttributeList(const CGFunctionInfo &Info, - const Decl *TargetDecl, - AttributeListType &PAL, - unsigned &CallingConv, - bool AttrOnCallSite); + CGCalleeInfo CalleeInfo, AttributeListType &PAL, + unsigned &CallingConv, bool AttrOnCallSite); // Fills in the supplied string map with the set of target features for the // passed in function. Index: test/CodeGenCXX/observe-noexcept.cpp =================================================================== --- /dev/null +++ test/CodeGenCXX/observe-noexcept.cpp @@ -0,0 +1,47 @@ +// RUN: %clang_cc1 -triple powerpc64le-unknown-unknown -std=c++11 -fopenmp -fexceptions -fcxx-exceptions -O0 -emit-llvm %s -o - | FileCheck %s + +// Check that regions that install a terminate scope in the exception stack can +// correctly generate complex arithmetic. + +// CHECK-LABEL: ffcomplex +void ffcomplex (int a) { + double _Complex dc = (double)a; + + // CHECK: call { double, double } @__muldc3(double %{{.+}}, double %{{.+}}, double %{{.+}}, double %{{.+}}) + dc *= dc; + // CHECK: call {{.+}} @__kmpc_fork_call({{.+}} [[REGNAME1:@.*]] to void (i32*, i32*, ...)*), { double, double }* %{{.+}}) + #pragma omp parallel + { + dc *= dc; + } + // CHECK: ret void +} + +// CHECK: define internal {{.+}}[[REGNAME1]]( +// CHECK-NOT: invoke +// CHECK: call { double, double } @__muldc3(double %{{.+}}, double %{{.+}}, double %{{.+}}, double %{{.+}}) +// CHECK-NOT: invoke +// CHECK: ret void + +// Check if we are observing the function pointer attribute regardless what is +// in the exception specification of the callees. +void fnoexcp(void) noexcept; + +// CHECK-LABEL: foo +void foo(int a, int b) { + + void (*fptr)(void) noexcept = fnoexcp; + + // CHECK: call {{.+}} @__kmpc_fork_call({{.+}} [[REGNAME2:@.*]] to void (i32*, i32*, ...)*), void ()** %{{.+}}) + #pragma omp parallel + { + fptr(); + } + // CHECK: ret void +} + +// CHECK: define internal {{.+}}[[REGNAME2]]( +// CHECK-NOT: invoke +// CHECK: call void %{{[0-9]+}}() +// CHECK-NOT: invoke +// CHECK: ret void