Index: include/clang/CodeGen/CGFunctionInfo.h =================================================================== --- include/clang/CodeGen/CGFunctionInfo.h +++ include/clang/CodeGen/CGFunctionInfo.h @@ -381,6 +381,11 @@ return reinterpret_cast(this + 1); } + /// Function prototype of the current function. This is useful to get more + /// information about the specifications associated with function being + /// generated. Not part of the profile. + const FunctionProtoType *FuncProtoTy; + CGFunctionInfo() : Required(RequiredArgs::All) {} public: @@ -473,6 +478,11 @@ ArgStructAlign = Align.getQuantity(); } + /// \brief Return the function prototype of the current function, or null if + /// it is not available. + const FunctionProtoType *getFunctionProtoType() const { return FuncProtoTy; } + void setFunctionProtoType(const FunctionProtoType *FTP) { FuncProtoTy = FTP; } + void Profile(llvm::FoldingSetNodeID &ID) { ID.AddInteger(getASTCallingConvention()); ID.AddBoolean(InstanceMethod); Index: lib/CodeGen/CGCall.cpp =================================================================== --- lib/CodeGen/CGCall.cpp +++ lib/CodeGen/CGCall.cpp @@ -88,8 +88,8 @@ // variadic type. return arrangeLLVMFunctionInfo(FTNP->getReturnType().getUnqualifiedType(), /*instanceMethod=*/false, - /*chainCall=*/false, None, - FTNP->getExtInfo(), RequiredArgs(0)); + /*chainCall=*/false, None, FTNP->getTypePtr(), + RequiredArgs(0)); } /// Arrange the LLVM function layout for a value of the given function @@ -104,7 +104,7 @@ CanQualType resultType = FTP->getReturnType().getUnqualifiedType(); return CGT.arrangeLLVMFunctionInfo(resultType, instanceMethod, /*chainCall=*/false, prefix, - FTP->getExtInfo(), required); + FTP->getTypePtr(), required); } /// Arrange the argument and result information for a value of the @@ -215,15 +215,14 @@ RequiredArgs required = (MD->isVariadic() ? RequiredArgs(argTypes.size()) : RequiredArgs::All); - FunctionType::ExtInfo extInfo = FTP->getExtInfo(); CanQualType resultType = TheCXXABI.HasThisReturn(GD) ? argTypes.front() : TheCXXABI.hasMostDerivedReturn(GD) ? CGM.getContext().VoidPtrTy : Context.VoidTy; return arrangeLLVMFunctionInfo(resultType, /*instanceMethod=*/true, - /*chainCall=*/false, argTypes, extInfo, - required); + /*chainCall=*/false, argTypes, + FTP->getTypePtr(), required); } /// Arrange a call to a C++ method, passing the given arguments. @@ -246,10 +245,9 @@ ? CGM.getContext().VoidPtrTy : Context.VoidTy; - FunctionType::ExtInfo Info = FPT->getExtInfo(); return arrangeLLVMFunctionInfo(ResultType, /*instanceMethod=*/true, - /*chainCall=*/false, ArgTypes, Info, - Required); + /*chainCall=*/false, ArgTypes, + FPT->getTypePtr(), Required); } /// Arrange the argument and result information for the declaration or @@ -270,7 +268,7 @@ CanQual noProto = FTy.getAs(); return arrangeLLVMFunctionInfo( noProto->getReturnType(), /*instanceMethod=*/false, - /*chainCall=*/false, None, noProto->getExtInfo(), RequiredArgs::All); + /*chainCall=*/false, None, noProto->getTypePtr(), RequiredArgs::All); } assert(isa(FTy)); @@ -344,8 +342,8 @@ CanQual FTP = GetFormalType(MD); CanQualType ArgTys[] = { GetThisType(Context, MD->getParent()) }; return arrangeLLVMFunctionInfo(Context.VoidTy, /*instanceMethod=*/false, - /*chainCall=*/false, ArgTys, - FTP->getExtInfo(), RequiredArgs(1)); + /*chainCall=*/false, ArgTys, FTP->getTypePtr(), + RequiredArgs(1)); } const CGFunctionInfo & @@ -404,7 +402,7 @@ argTypes.push_back(CGT.getContext().getCanonicalParamType(arg.Ty)); return CGT.arrangeLLVMFunctionInfo(GetReturnType(fnType->getReturnType()), /*instanceMethod=*/false, chainCall, - argTypes, fnType->getExtInfo(), required); + argTypes, fnType, required); } /// Figure out the rules for calling a function with the given formal @@ -452,10 +450,9 @@ for (const auto &Arg : args) argTypes.push_back(Context.getCanonicalParamType(Arg.Ty)); - FunctionType::ExtInfo info = FPT->getExtInfo(); - return arrangeLLVMFunctionInfo( - GetReturnType(FPT->getReturnType()), /*instanceMethod=*/true, - /*chainCall=*/false, argTypes, info, required); + return arrangeLLVMFunctionInfo(GetReturnType(FPT->getReturnType()), + /*instanceMethod=*/true, + /*chainCall=*/false, argTypes, FPT, required); } const CGFunctionInfo &CodeGenTypes::arrangeFreeFunctionDeclaration( @@ -482,13 +479,10 @@ /// Arrange the argument and result information for an abstract value /// of a given function type. This is the method which all of the /// above functions ultimately defer to. -const CGFunctionInfo & -CodeGenTypes::arrangeLLVMFunctionInfo(CanQualType resultType, - bool instanceMethod, - bool chainCall, - ArrayRef argTypes, - FunctionType::ExtInfo info, - RequiredArgs required) { +CGFunctionInfo &CodeGenTypes::commonArrangeLLVMFunctionInfo( + CanQualType resultType, bool instanceMethod, bool chainCall, + ArrayRef argTypes, FunctionType::ExtInfo info, + RequiredArgs required) { assert(std::all_of(argTypes.begin(), argTypes.end(), std::mem_fun_ref(&CanQualType::isCanonicalAsParam))); @@ -533,6 +527,32 @@ return *FI; } +/// Entry point for the common generation of LLVM function info that uses no +/// function type. +const CGFunctionInfo &CodeGenTypes::arrangeLLVMFunctionInfo( + CanQualType returnType, bool instanceMethod, bool chainCall, + ArrayRef argTypes, FunctionType::ExtInfo info, + RequiredArgs args) { + auto &FI = commonArrangeLLVMFunctionInfo(returnType, instanceMethod, + chainCall, argTypes, info, args); + return FI; +} + +/// Entry point for the common generation of LLVM function info that uses +/// function type. +const CGFunctionInfo &CodeGenTypes::arrangeLLVMFunctionInfo( + CanQualType returnType, bool instanceMethod, bool chainCall, + ArrayRef argTypes, const FunctionType *funcTy, + RequiredArgs args) { + assert(funcTy && "Invalid function type."); + auto &FI = + commonArrangeLLVMFunctionInfo(returnType, instanceMethod, chainCall, + argTypes, funcTy->getExtInfo(), args); + if (const auto *FTP = dyn_cast_or_null(funcTy)) + FI.setFunctionProtoType(FTP); + return FI; +} + CGFunctionInfo *CGFunctionInfo::create(unsigned llvmCC, bool instanceMethod, bool chainCall, @@ -559,6 +579,7 @@ FI->getArgsBuffer()[0].type = resultType; for (unsigned i = 0, e = argTypes.size(); i != e; ++i) FI->getArgsBuffer()[i + 1].type = argTypes[i]; + FI->FuncProtoTy = nullptr; return FI; } @@ -1391,6 +1412,17 @@ 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, AttributeListType &PAL, @@ -1405,6 +1437,11 @@ if (FI.isNoReturn()) FuncAttrs.addAttribute(llvm::Attribute::NoReturn); + // If we have information about the function proto type, we can learn + // attributes form there. + AddAttributesFromFunctionProtoType(getContext(), FuncAttrs, + FI.getFunctionProtoType()); + // FIXME: handle sseregparm someday... if (TargetDecl) { if (TargetDecl->hasAttr()) @@ -1417,10 +1454,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); Index: lib/CodeGen/CGExpr.cpp =================================================================== --- lib/CodeGen/CGExpr.cpp +++ lib/CodeGen/CGExpr.cpp @@ -3747,6 +3747,12 @@ assert(CalleeType->isFunctionPointerType() && "Call must have function pointer type!"); + // Preserve the function proto type because it contains useful information + // that we may be interested in using later on in the code generation. + const FunctionProtoType *InitalFTP = CalleeType->getAs() + ->getPointeeType() + ->getAs(); + CalleeType = getContext().getCanonicalType(CalleeType); const auto *FnType = @@ -3828,7 +3834,7 @@ E->getDirectCallee(), /*ParamsToSkip*/ 0); const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeFreeFunctionCall( - Args, FnType, /*isChainCall=*/Chain); + Args, InitalFTP ? InitalFTP : FnType, /*isChainCall=*/Chain); // C99 6.5.2.2p6: // If the expression that denotes the called function has a type Index: lib/CodeGen/CGExprComplex.cpp =================================================================== --- lib/CodeGen/CGExprComplex.cpp +++ lib/CodeGen/CGExprComplex.cpp @@ -585,10 +585,18 @@ // 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; @@ -596,8 +604,6 @@ RValue Res = CGF.EmitCall(FuncInfo, Func, ReturnValueSlot(), Args, nullptr, &Call); cast(Call)->setCallingConv(CGF.CGM.getBuiltinCC()); - cast(Call)->setDoesNotThrow(); - return Res.getComplexVal(); } Index: lib/CodeGen/CodeGenTypes.h =================================================================== --- lib/CodeGen/CodeGenTypes.h +++ lib/CodeGen/CodeGenTypes.h @@ -270,18 +270,41 @@ const CGFunctionInfo &arrangeCXXMethodType(const CXXRecordDecl *RD, const FunctionProtoType *FTP); +private: + /// Common generation of LLVM information for a call or type with the given + /// signature. + /// + /// \param argTypes - must all actually be canonical as params. + CGFunctionInfo & + commonArrangeLLVMFunctionInfo(CanQualType returnType, bool instanceMethod, + bool chainCall, ArrayRef argTypes, + FunctionType::ExtInfo info, RequiredArgs args); + +public: /// "Arrange" the LLVM information for a call or type with the given /// signature. This is largely an internal method; other clients /// should use one of the above routines, which ultimately defer to /// this. /// - /// \param argTypes - must all actually be canonical as params + /// \param argTypes - must all actually be canonical as params. const CGFunctionInfo &arrangeLLVMFunctionInfo(CanQualType returnType, bool instanceMethod, bool chainCall, ArrayRef argTypes, FunctionType::ExtInfo info, RequiredArgs args); + /// "Arrange" the LLVM information for a call or type with the given + /// signature and include the function type in the resulting information. + /// Using this version should preferred given that the code generation is more + /// accurate if it has access to the function type. + /// + /// \param argTypes - must all actually be canonical as params. + /// \param funcTy - the type of the function being generated. Useful to get + /// extra information about the function to be called. + const CGFunctionInfo & + arrangeLLVMFunctionInfo(CanQualType returnType, bool instanceMethod, + bool chainCall, ArrayRef argTypes, + const FunctionType *funcTy, RequiredArgs args); /// \brief Compute a new LLVM record layout object for the given record. CGRecordLayout *ComputeRecordLayout(const RecordDecl *D, 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