From: Rafael Espindola Date: Tue, 30 Mar 2010 22:15:11 +0000 (+0000) Subject: Remember the regparm attribute in FunctionType::ExtInfo. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=425ef72306d4ff6b3698b744353e5f0e56b4b884;p=clang 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/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index ae8125511b..1633dbd311 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -447,6 +447,11 @@ public: /// allowable type. QualType getCallConvType(QualType T, CallingConv CallConv); + /// getRegParmType - Sets the specified regparm attribute to + /// the given type, which must be a FunctionType or a pointer to an + /// allowable type. + QualType getRegParmType(QualType T, unsigned RegParm); + /// getComplexType - Return the uniqued reference to the type for a complex /// number with the specified element type. QualType getComplexType(QualType T); diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index c0bc54a06a..85020653df 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -1740,6 +1740,9 @@ class FunctionType : public Type { /// NoReturn - Indicates if the function type is attribute noreturn. unsigned NoReturn : 1; + /// RegParm - How many arguments to pass inreg. + unsigned RegParm : 3; + /// CallConv - The calling convention used by the function. unsigned CallConv : 2; @@ -1750,22 +1753,38 @@ class FunctionType : public Type { // This class is used for passing arround the information needed to // construct a call. It is not actually used for storage, just for // factoring together common arguments. + // If you add a field (say Foo), other than the obvious places (both, constructors, + // compile failures), what you need to update is + // * Operetor== + // * getFoo + // * withFoo + // * functionType. Add Foo, getFoo. + // * ASTContext::getFooType + // * ASTContext::mergeFunctionTypes + // * FunctionNoProtoType::Profile + // * FunctionProtoType::Profile + // * TypePrinter::PrintFunctionProto + // * PCH read and write + // * Codegen + class ExtInfo { public: // Constructor with no defaults. Use this when you know that you // have all the elements (when reading a PCH file for example). - ExtInfo(bool noReturn, CallingConv cc) : - NoReturn(noReturn), CC(cc) {} + ExtInfo(bool noReturn, unsigned regParm, CallingConv cc) : + NoReturn(noReturn), RegParm(regParm), CC(cc) {} // Constructor with all defaults. Use when for example creating a // function know to use defaults. - ExtInfo() : NoReturn(false), CC(CC_Default) {} + ExtInfo() : NoReturn(false), RegParm(0), CC(CC_Default) {} bool getNoReturn() const { return NoReturn; } + unsigned getRegParm() const { return RegParm; } CallingConv getCC() const { return CC; } bool operator==(const ExtInfo &Other) const { return getNoReturn() == Other.getNoReturn() && + getRegParm() == Other.getRegParm() && getCC() == Other.getCC(); } bool operator!=(const ExtInfo &Other) const { @@ -1776,16 +1795,22 @@ class FunctionType : public Type { // the following with methods instead of mutating these objects. ExtInfo withNoReturn(bool noReturn) const { - return ExtInfo(noReturn, getCC()); + return ExtInfo(noReturn, getRegParm(), getCC()); + } + + ExtInfo withRegParm(unsigned RegParm) const { + return ExtInfo(getNoReturn(), RegParm, getCC()); } ExtInfo withCallingConv(CallingConv cc) const { - return ExtInfo(getNoReturn(), cc); + return ExtInfo(getNoReturn(), getRegParm(), cc); } private: // True if we have __attribute__((noreturn)) bool NoReturn; + // The value passed to __attribute__((regparm(x))) + unsigned RegParm; // The calling convention as specified via // __attribute__((cdecl|stdcall||fastcall)) CallingConv CC; @@ -1798,16 +1823,17 @@ protected: : Type(tc, Canonical, Dependent), SubClassData(SubclassInfo), TypeQuals(typeQuals), NoReturn(Info.getNoReturn()), - CallConv(Info.getCC()), ResultType(res) {} + RegParm(Info.getRegParm()), CallConv(Info.getCC()), ResultType(res) {} bool getSubClassData() const { return SubClassData; } unsigned getTypeQuals() const { return TypeQuals; } public: QualType getResultType() const { return ResultType; } + unsigned getRegParmType() const { return RegParm; } bool getNoReturnAttr() const { return NoReturn; } CallingConv getCallConv() const { return (CallingConv)CallConv; } ExtInfo getExtInfo() const { - return ExtInfo(NoReturn, (CallingConv)CallConv); + return ExtInfo(NoReturn, RegParm, (CallingConv)CallConv); } static llvm::StringRef getNameForCallConv(CallingConv CC); @@ -1839,6 +1865,7 @@ public: static void Profile(llvm::FoldingSetNodeID &ID, QualType ResultType, const ExtInfo &Info) { ID.AddInteger(Info.getCC()); + ID.AddInteger(Info.getRegParm()); ID.AddInteger(Info.getNoReturn()); ID.AddPointer(ResultType.getAsOpaquePtr()); } diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 00a7987a2b..2b88a6cd9f 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -1141,17 +1141,23 @@ static QualType getExtFunctionType(ASTContext& Context, QualType T, } 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 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, 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 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, 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 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, 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 b3675203d7..4e24de1922 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -841,6 +841,7 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result, 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 d1893cc611..85e23d60ba 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -298,7 +298,9 @@ void TypePrinter::PrintFunctionProto(const FunctionProtoType *T, } 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 d861348ce8..cb1ecc1aa6 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -175,6 +175,7 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const ObjCMethodDecl *MD) { ArgTys, FunctionType::ExtInfo( /*NoReturn*/ false, + /*RegParm*/ 0, getCallingConventionForDecl(MD))); } @@ -216,16 +217,13 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy, const CGFunctionInfo &CodeGenTypes::getFunctionInfo(CanQualType ResTy, const llvm::SmallVectorImpl &ArgTys, const FunctionType::ExtInfo &Info) { - const CallingConv CallConv = Info.getCC(); - const bool NoReturn = Info.getNoReturn(); - #ifndef NDEBUG for (llvm::SmallVectorImpl::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 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(CanQualType ResTy, 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 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(CanQualType ResTy, CGFunctionInfo::CGFunctionInfo(unsigned _CallingConvention, bool _NoReturn, + unsigned _RegParm, CanQualType ResTy, const llvm::SmallVectorImpl &ArgTys) : CallingConvention(_CallingConvention), EffectiveCallingConvention(_CallingConvention), - NoReturn(_NoReturn) + NoReturn(_NoReturn), RegParm(_RegParm) { NumArgs = ArgTys.size(); Args = new ArgInfo[1 + NumArgs]; @@ -609,11 +608,7 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, // 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()) - 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 235ff9c674..31c8aac3f2 100644 --- a/lib/CodeGen/CGCall.h +++ b/lib/CodeGen/CGCall.h @@ -76,12 +76,16 @@ namespace CodeGen { 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 &ArgTys); ~CGFunctionInfo() { delete[] Args; } @@ -108,6 +112,8 @@ namespace CodeGen { EffectiveCallingConvention = Value; } + unsigned getRegParm() const { return RegParm; } + CanQualType getReturnType() const { return Args[0].type; } ABIArgInfo &getReturnInfo() { return Args[0].info; } @@ -116,6 +122,7 @@ namespace CodeGen { 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 @@ namespace CodeGen { 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 ceb7a6bf57..579f827e16 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -2075,20 +2075,21 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) { } 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 ParamTypes; for (unsigned I = 0; I != NumParams; ++I) @@ -2105,7 +2106,8 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) { 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 b4fbd17bd6..5086b488f6 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -143,6 +143,7 @@ void PCHTypeWriter::VisitFunctionType(const FunctionType *T) { 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 406b8201a3..e232230db7 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -7037,11 +7037,11 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, 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 ce410a7605..2c6cc7fc9d 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -1739,6 +1739,30 @@ bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) { 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(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 @@ void ProcessTypeAttributeList(Sema &S, QualType &Result, 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)) diff --git a/test/CodeGen/regparm.c b/test/CodeGen/regparm.c index 2b5bbfc1a3..2dd796489c 100644 --- a/test/CodeGen/regparm.c +++ b/test/CodeGen/regparm.c @@ -8,12 +8,16 @@ typedef struct { int ccc[200]; } foo; +typedef void (*FType)(int, int) __attribute ((regparm (3), stdcall)); +FType bar; + static void FASTCALL -reduced(char b, double c, foo* d, double e, int f) { -} +reduced(char b, double c, foo* d, double e, int f); int main(void) { // CHECK: call void @reduced(i8 signext inreg 0, {{.*}} %struct.anon* inreg null reduced(0, 0.0, 0, 0.0, 0); + // CHECK: call x86_stdcallcc void %tmp(i32 inreg 1, i32 inreg 2) + bar(1,2); }