sfantao created this revision.
sfantao added reviewers: rjmccall, rnk, ABataev, hfinkel.
sfantao added a subscriber: cfe-commits.

This patch changes the generation of `CGFunctionInfo` to contain the 
`FunctionProtoType` if it is available. This enables the code generation for 
call instructions to look into this type for exception information and 
therefore generate better quality IR - it will not create invoke instructions 
for functions that are know not to throw.

The emission code had to be changed in a few places to keep the 
`FunctionProtoType` and, namely for the complex arithmetic library calls, 
create new `FunctionProtoType`s with the right exception information.

This patch is just a first step to have more accurate IR, as there may be other 
patterns that could take advantage of extra information. I'm just covering some 
cases I am aware of.

Thanks!
Samuel 

http://reviews.llvm.org/D14796

Files:
  include/clang/CodeGen/CGFunctionInfo.h
  lib/CodeGen/CGCall.cpp
  lib/CodeGen/CGExpr.cpp
  lib/CodeGen/CGExprComplex.cpp
  lib/CodeGen/CodeGenTypes.h
  test/CodeGenCXX/observe-noexcept.cpp

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
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<CanQualType> 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<CanQualType> 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<CanQualType> argTypes,
+                          const FunctionType *funcTy, RequiredArgs args);
 
   /// \brief Compute a new LLVM record layout object for the given record.
   CGRecordLayout *ComputeRecordLayout(const RecordDecl *D,
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<QualType, 4> ArgsQTys(
+      4, Op.Ty->castAs<ComplexType>()->getElementType());
+  QualType FQTy = CGF.getContext().getFunctionType(Op.Ty, ArgsQTys, EPI);
+  const CGFunctionInfo &FuncInfo = CGF.CGM.getTypes().arrangeFreeFunctionCall(
+      Args, cast<FunctionType>(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);
   cast<llvm::CallInst>(Call)->setCallingConv(CGF.CGM.getBuiltinCC());
-  cast<llvm::CallInst>(Call)->setDoesNotThrow();
-
   return Res.getComplexVal();
 }
 
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<PointerType>()
+                                           ->getPointeeType()
+                                           ->getAs<FunctionProtoType>();
+
   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/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<FunctionNoProtoType> noProto = FTy.getAs<FunctionNoProtoType>();
     return arrangeLLVMFunctionInfo(
         noProto->getReturnType(), /*instanceMethod=*/false,
-        /*chainCall=*/false, None, noProto->getExtInfo(), RequiredArgs::All);
+        /*chainCall=*/false, None, noProto->getTypePtr(), RequiredArgs::All);
   }
 
   assert(isa<FunctionProtoType>(FTy));
@@ -344,8 +342,8 @@
   CanQual<FunctionProtoType> 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<CanQualType> argTypes,
-                                      FunctionType::ExtInfo info,
-                                      RequiredArgs required) {
+CGFunctionInfo &CodeGenTypes::commonArrangeLLVMFunctionInfo(
+    CanQualType resultType, bool instanceMethod, bool chainCall,
+    ArrayRef<CanQualType> 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<CanQualType> 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<CanQualType> 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<FunctionProtoType>(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<ReturnsTwiceAttr>())
@@ -1417,10 +1454,8 @@
       FuncAttrs.addAttribute(llvm::Attribute::NoDuplicate);
 
     if (const FunctionDecl *Fn = dyn_cast<FunctionDecl>(TargetDecl)) {
-      const FunctionProtoType *FPT = Fn->getType()->getAs<FunctionProtoType>();
-      if (FPT && !isUnresolvedExceptionSpec(FPT->getExceptionSpecType()) &&
-          FPT->isNothrow(getContext()))
-        FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
+      AddAttributesFromFunctionProtoType(
+          getContext(), FuncAttrs, Fn->getType()->getAs<FunctionProtoType>());
       // 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<CXXMethodDecl>(Fn);
Index: include/clang/CodeGen/CGFunctionInfo.h
===================================================================
--- include/clang/CodeGen/CGFunctionInfo.h
+++ include/clang/CodeGen/CGFunctionInfo.h
@@ -381,6 +381,11 @@
     return reinterpret_cast<const ArgInfo*>(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);
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to