Remember the regparm attribute in FunctionType::ExtInfo.
Fixes PR3782.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@99940 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 00a7987..2b88a6c 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -1141,17 +1141,23 @@
 }
 
 QualType ASTContext::getNoReturnType(QualType T, bool AddNoReturn) {
-  FunctionType::ExtInfo Info = getFunctionExtInfo(*T);
+  FunctionType::ExtInfo Info = getFunctionExtInfo(T);
   return getExtFunctionType(*this, T,
                                  Info.withNoReturn(AddNoReturn));
 }
 
 QualType ASTContext::getCallConvType(QualType T, CallingConv CallConv) {
-  FunctionType::ExtInfo Info = getFunctionExtInfo(*T);
+  FunctionType::ExtInfo Info = getFunctionExtInfo(T);
   return getExtFunctionType(*this, T,
                             Info.withCallingConv(CallConv));
 }
 
+QualType ASTContext::getRegParmType(QualType T, unsigned RegParm) {
+  FunctionType::ExtInfo Info = getFunctionExtInfo(T);
+  return getExtFunctionType(*this, T,
+                                 Info.withRegParm(RegParm));
+}
+
 /// getComplexType - Return the uniqued reference to the type for a complex
 /// number with the specified element type.
 QualType ASTContext::getComplexType(QualType T) {
@@ -4308,12 +4314,19 @@
   if (getCanonicalType(retType) != getCanonicalType(rbase->getResultType()))
     allRTypes = false;
   // FIXME: double check this
+  // FIXME: should we error if lbase->getRegParmAttr() != 0 &&
+  //                           rbase->getRegParmAttr() != 0 &&
+  //                           lbase->getRegParmAttr() != rbase->getRegParmAttr()?
   FunctionType::ExtInfo lbaseInfo = lbase->getExtInfo();
   FunctionType::ExtInfo rbaseInfo = rbase->getExtInfo();
+  unsigned RegParm = lbaseInfo.getRegParm() == 0 ? rbaseInfo.getRegParm() :
+      lbaseInfo.getRegParm();
   bool NoReturn = lbaseInfo.getNoReturn() || rbaseInfo.getNoReturn();
-  if (NoReturn != lbaseInfo.getNoReturn())
+  if (NoReturn != lbaseInfo.getNoReturn() ||
+      RegParm != lbaseInfo.getRegParm())
     allLTypes = false;
-  if (NoReturn != rbaseInfo.getNoReturn())
+  if (NoReturn != rbaseInfo.getNoReturn() ||
+      RegParm != rbaseInfo.getRegParm())
     allRTypes = false;
   CallingConv lcc = lbaseInfo.getCC();
   CallingConv rcc = rbaseInfo.getCC();
@@ -4356,7 +4369,7 @@
     return getFunctionType(retType, types.begin(), types.size(),
                            lproto->isVariadic(), lproto->getTypeQuals(),
                            false, false, 0, 0,
-                           FunctionType::ExtInfo(NoReturn, lcc));
+                           FunctionType::ExtInfo(NoReturn, RegParm, lcc));
   }
 
   if (lproto) allRTypes = false;
@@ -4391,12 +4404,12 @@
                            proto->getNumArgs(), proto->isVariadic(),
                            proto->getTypeQuals(),
                            false, false, 0, 0,
-                           FunctionType::ExtInfo(NoReturn, lcc));
+                           FunctionType::ExtInfo(NoReturn, RegParm, lcc));
   }
 
   if (allLTypes) return lhs;
   if (allRTypes) return rhs;
-  FunctionType::ExtInfo Info(NoReturn, lcc);
+  FunctionType::ExtInfo Info(NoReturn, RegParm, lcc);
   return getFunctionNoProtoType(retType, Info);
 }
 
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index b367520..4e24de1 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -841,6 +841,7 @@
       ID.AddPointer(Exs[i].getAsOpaquePtr());
   }
   ID.AddInteger(Info.getNoReturn());
+  ID.AddInteger(Info.getRegParm());
   ID.AddInteger(Info.getCC());
 }
 
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index d1893cc..85e23d6 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -298,7 +298,9 @@
   }
   if (Info.getNoReturn())
     S += " __attribute__((noreturn))";
-
+  if (Info.getRegParm())
+    S += " __attribute__((regparm (" +
+        llvm::utostr_32(Info.getRegParm()) + ")))";
   
   if (T->hasExceptionSpec()) {
     S += " throw(";
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index d861348..cb1ecc1 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -175,6 +175,7 @@
                          ArgTys,
                          FunctionType::ExtInfo(
                              /*NoReturn*/ false,
+                             /*RegParm*/ 0,
                              getCallingConventionForDecl(MD)));
 }
 
@@ -216,16 +217,13 @@
 const CGFunctionInfo &CodeGenTypes::getFunctionInfo(CanQualType ResTy,
                            const llvm::SmallVectorImpl<CanQualType> &ArgTys,
                                             const FunctionType::ExtInfo &Info) {
-  const CallingConv CallConv = Info.getCC();
-  const bool NoReturn = Info.getNoReturn();
-
 #ifndef NDEBUG
   for (llvm::SmallVectorImpl<CanQualType>::const_iterator
          I = ArgTys.begin(), E = ArgTys.end(); I != E; ++I)
     assert(I->isCanonicalAsParam());
 #endif
 
-  unsigned CC = ClangCallConvToLLVMCallConv(CallConv);
+  unsigned CC = ClangCallConvToLLVMCallConv(Info.getCC());
 
   // Lookup or create unique function info.
   llvm::FoldingSetNodeID ID;
@@ -238,7 +236,7 @@
     return *FI;
 
   // Construct the function info.
-  FI = new CGFunctionInfo(CC, NoReturn, ResTy, ArgTys);
+  FI = new CGFunctionInfo(CC, Info.getNoReturn(), Info.getRegParm(), ResTy, ArgTys);
   FunctionInfos.InsertNode(FI, InsertPos);
 
   // Compute ABI information.
@@ -249,11 +247,12 @@
 
 CGFunctionInfo::CGFunctionInfo(unsigned _CallingConvention,
                                bool _NoReturn,
+                               unsigned _RegParm,
                                CanQualType ResTy,
                                const llvm::SmallVectorImpl<CanQualType> &ArgTys)
   : CallingConvention(_CallingConvention),
     EffectiveCallingConvention(_CallingConvention),
-    NoReturn(_NoReturn)
+    NoReturn(_NoReturn), RegParm(_RegParm)
 {
   NumArgs = ArgTys.size();
   Args = new ArgInfo[1 + NumArgs];
@@ -609,11 +608,7 @@
   // FIXME: we need to honour command line settings also...
   // FIXME: RegParm should be reduced in case of nested functions and/or global
   // register variable.
-  signed RegParm = 0;
-  if (TargetDecl)
-    if (const RegparmAttr *RegParmAttr
-          = TargetDecl->getAttr<RegparmAttr>())
-      RegParm = RegParmAttr->getNumParams();
+  signed RegParm = FI.getRegParm();
 
   unsigned PointerWidth = getContext().Target.getPointerWidth(0);
   for (CGFunctionInfo::const_arg_iterator it = FI.arg_begin(),
diff --git a/lib/CodeGen/CGCall.h b/lib/CodeGen/CGCall.h
index 235ff9c..31c8aac 100644
--- a/lib/CodeGen/CGCall.h
+++ b/lib/CodeGen/CGCall.h
@@ -76,12 +76,16 @@
     unsigned NumArgs;
     ArgInfo *Args;
 
+    /// How many arguments to pass inreg.
+    unsigned RegParm;
+
   public:
     typedef const ArgInfo *const_arg_iterator;
     typedef ArgInfo *arg_iterator;
 
     CGFunctionInfo(unsigned CallingConvention,
                    bool NoReturn,
+                   unsigned RegParm,
                    CanQualType ResTy,
                    const llvm::SmallVectorImpl<CanQualType> &ArgTys);
     ~CGFunctionInfo() { delete[] Args; }
@@ -108,6 +112,8 @@
       EffectiveCallingConvention = Value;
     }
 
+    unsigned getRegParm() const { return RegParm; }
+
     CanQualType getReturnType() const { return Args[0].type; }
 
     ABIArgInfo &getReturnInfo() { return Args[0].info; }
@@ -116,6 +122,7 @@
     void Profile(llvm::FoldingSetNodeID &ID) {
       ID.AddInteger(getCallingConvention());
       ID.AddBoolean(NoReturn);
+      ID.AddInteger(RegParm);
       getReturnType().Profile(ID);
       for (arg_iterator it = arg_begin(), ie = arg_end(); it != ie; ++it)
         it->type.Profile(ID);
@@ -128,6 +135,7 @@
                         Iterator end) {
       ID.AddInteger(Info.getCC());
       ID.AddBoolean(Info.getNoReturn());
+      ID.AddInteger(Info.getRegParm());
       ResTy.Profile(ID);
       for (; begin != end; ++begin) {
         CanQualType T = *begin; // force iterator to be over canonical types
diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp
index ceb7a6b..579f827 100644
--- a/lib/Frontend/PCHReader.cpp
+++ b/lib/Frontend/PCHReader.cpp
@@ -2075,20 +2075,21 @@
   }
 
   case pch::TYPE_FUNCTION_NO_PROTO: {
-    if (Record.size() != 3) {
+    if (Record.size() != 4) {
       Error("incorrect encoding of no-proto function type");
       return QualType();
     }
     QualType ResultType = GetType(Record[0]);
-    FunctionType::ExtInfo Info(Record[1], (CallingConv)Record[2]);
+    FunctionType::ExtInfo Info(Record[1], Record[2], (CallingConv)Record[3]);
     return Context->getFunctionNoProtoType(ResultType, Info);
   }
 
   case pch::TYPE_FUNCTION_PROTO: {
     QualType ResultType = GetType(Record[0]);
     bool NoReturn = Record[1];
-    CallingConv CallConv = (CallingConv)Record[2];
-    unsigned Idx = 3;
+    unsigned RegParm = Record[2];
+    CallingConv CallConv = (CallingConv)Record[3];
+    unsigned Idx = 4;
     unsigned NumParams = Record[Idx++];
     llvm::SmallVector<QualType, 16> ParamTypes;
     for (unsigned I = 0; I != NumParams; ++I)
@@ -2105,7 +2106,8 @@
                                     isVariadic, Quals, hasExceptionSpec,
                                     hasAnyExceptionSpec, NumExceptions,
                                     Exceptions.data(),
-                                    FunctionType::ExtInfo(NoReturn, CallConv));
+                                    FunctionType::ExtInfo(NoReturn, RegParm,
+                                                          CallConv));
   }
 
   case pch::TYPE_UNRESOLVED_USING:
diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp
index b4fbd17..5086b48 100644
--- a/lib/Frontend/PCHWriter.cpp
+++ b/lib/Frontend/PCHWriter.cpp
@@ -143,6 +143,7 @@
   Writer.AddTypeRef(T->getResultType(), Record);
   FunctionType::ExtInfo C = T->getExtInfo();
   Record.push_back(C.getNoReturn());
+  Record.push_back(C.getRegParm());
   // FIXME: need to stabilize encoding of calling convention...
   Record.push_back(C.getCC());
 }
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 406b820..e232230 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -7037,11 +7037,11 @@
   QualType BlockTy;
   if (!BSI->hasPrototype)
     BlockTy = Context.getFunctionType(RetTy, 0, 0, false, 0, false, false, 0, 0,
-                                  FunctionType::ExtInfo(NoReturn, CC_Default));
+                                FunctionType::ExtInfo(NoReturn, 0, CC_Default));
   else
     BlockTy = Context.getFunctionType(RetTy, ArgTypes.data(), ArgTypes.size(),
                                       BSI->isVariadic, 0, false, false, 0, 0,
-                                   FunctionType::ExtInfo(NoReturn, CC_Default));
+                                FunctionType::ExtInfo(NoReturn, 0, CC_Default));
 
   // FIXME: Check that return/parameter types are complete/non-abstract
   DiagnoseUnusedParameters(BSI->Params.begin(), BSI->Params.end());
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index ce410a7..2c6cc7f 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -1739,6 +1739,30 @@
     return false;
   }
 
+  if (Attr.getKind() == AttributeList::AT_regparm) {
+    // The warning is emitted elsewhere
+    if (Attr.getNumArgs() != 1) {
+      return false;
+    }
+
+    // Delay if this is not a function or pointer to block.
+    if (!Type->isFunctionPointerType()
+        && !Type->isBlockPointerType()
+        && !Type->isFunctionType())
+      return true;
+
+    // Otherwise we can process right away.
+    Expr *NumParamsExpr = static_cast<Expr *>(Attr.getArg(0));
+    llvm::APSInt NumParams(32);
+
+    // The warning is emitted elsewhere
+    if (!NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context))
+      return false;
+
+    Type = S.Context.getRegParmType(Type, NumParams.getZExtValue());
+    return false;
+  }
+
   // Otherwise, a calling convention.
   if (Attr.getNumArgs() != 0) {
     S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
@@ -1868,6 +1892,7 @@
     case AttributeList::AT_cdecl:
     case AttributeList::AT_fastcall:
     case AttributeList::AT_stdcall:
+    case AttributeList::AT_regparm:
       // Don't process these on the DeclSpec.
       if (IsDeclSpec ||
           ProcessFnAttr(S, Result, *AL))