From: Eli Friedman Date: Sat, 9 Apr 2011 08:18:08 +0000 (+0000) Subject: PR8369: make __attribute((regparm(0))) work correctly. Original patch by X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a49218e17bcbb1acde0245773173e2c0c42f4f19;p=clang PR8369: make __attribute((regparm(0))) work correctly. Original patch by pageexec@freemail.hu, tweaks by me. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@129206 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 97d3d0f35b..1b94a1d83f 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -2271,12 +2271,13 @@ class FunctionType : public Type { // you'll need to adjust both the Bits field below and // Type::FunctionTypeBitfields. - // | CC |noreturn|regparm - // |0 .. 2| 3 |4 .. 6 + // | CC |noreturn|hasregparm|regparm + // |0 .. 2| 3 | 4 |5 .. 7 enum { CallConvMask = 0x7 }; enum { NoReturnMask = 0x8 }; + enum { HasRegParmMask = 0x10 }; enum { RegParmMask = ~(CallConvMask | NoReturnMask), - RegParmOffset = 4 }; + RegParmOffset = 5 }; unsigned char Bits; @@ -2287,9 +2288,10 @@ class FunctionType : public Type { public: // Constructor with no defaults. Use this when you know that you // have all the elements (when reading an AST file for example). - ExtInfo(bool noReturn, unsigned regParm, CallingConv cc) { + ExtInfo(bool noReturn, bool hasRegParm, unsigned regParm, CallingConv cc) { Bits = ((unsigned) cc) | (noReturn ? NoReturnMask : 0) | + (hasRegParm ? HasRegParmMask : 0) | (regParm << RegParmOffset); } @@ -2298,6 +2300,7 @@ class FunctionType : public Type { ExtInfo() : Bits(0) {} bool getNoReturn() const { return Bits & NoReturnMask; } + bool getHasRegParm() const { return Bits & HasRegParmMask; } unsigned getRegParm() const { return Bits >> RegParmOffset; } CallingConv getCC() const { return CallingConv(Bits & CallConvMask); } @@ -2319,7 +2322,7 @@ class FunctionType : public Type { } ExtInfo withRegParm(unsigned RegParm) const { - return ExtInfo((Bits & ~RegParmMask) | (RegParm << RegParmOffset)); + return ExtInfo(HasRegParmMask | (Bits & ~RegParmMask) | (RegParm << RegParmOffset)); } ExtInfo withCallingConv(CallingConv cc) const { @@ -2355,7 +2358,8 @@ protected: public: QualType getResultType() const { return ResultType; } - + + bool getHasRegParm() const { return getExtInfo().getHasRegParm(); } unsigned getRegParmType() const { return getExtInfo().getRegParm(); } bool getNoReturnAttr() const { return getExtInfo().getNoReturn(); } CallingConv getCallConv() const { return getExtInfo().getCC(); } diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 39229a7b73..420fcd398d 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -5175,6 +5175,8 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, return QualType(); // Regparm is part of the calling convention. + if (lbaseInfo.getHasRegParm() != rbaseInfo.getHasRegParm()) + return QualType(); if (lbaseInfo.getRegParm() != rbaseInfo.getRegParm()) return QualType(); @@ -5187,6 +5189,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, allRTypes = false; FunctionType::ExtInfo einfo(NoReturn, + lbaseInfo.getHasRegParm(), lbaseInfo.getRegParm(), lbaseInfo.getCC()); diff --git a/lib/AST/DumpXML.cpp b/lib/AST/DumpXML.cpp index 9a34722aa5..93ae1e37c9 100644 --- a/lib/AST/DumpXML.cpp +++ b/lib/AST/DumpXML.cpp @@ -955,7 +955,7 @@ struct XMLDumper : public XMLDeclVisitor, void visitFunctionTypeAttrs(FunctionType *T) { setFlag("noreturn", T->getNoReturnAttr()); setCallingConv(T->getCallConv()); - if (T->getRegParmType()) setInteger("regparm", T->getRegParmType()); + if (T->getHasRegParm()) setInteger("regparm", T->getRegParmType()); } void visitFunctionTypeChildren(FunctionType *T) { dispatch(T->getResultType()); diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index 7a1600f166..0ba6789367 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -188,6 +188,7 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const ObjCMethodDecl *MD) { ArgTys, FunctionType::ExtInfo( /*NoReturn*/ false, + /*HasRegParm*/ false, /*RegParm*/ 0, getCallingConventionForDecl(MD))); } @@ -255,7 +256,7 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(CanQualType ResTy, return *FI; // Construct the function info. - FI = new CGFunctionInfo(CC, Info.getNoReturn(), Info.getRegParm(), ResTy, + FI = new CGFunctionInfo(CC, Info.getNoReturn(), Info.getHasRegParm(), Info.getRegParm(), ResTy, ArgTys.data(), ArgTys.size()); FunctionInfos.InsertNode(FI, InsertPos); @@ -284,13 +285,13 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(CanQualType ResTy, } CGFunctionInfo::CGFunctionInfo(unsigned _CallingConvention, - bool _NoReturn, unsigned _RegParm, + bool _NoReturn, bool _HasRegParm, unsigned _RegParm, CanQualType ResTy, const CanQualType *ArgTys, unsigned NumArgTys) : CallingConvention(_CallingConvention), EffectiveCallingConvention(_CallingConvention), - NoReturn(_NoReturn), RegParm(_RegParm) + NoReturn(_NoReturn), HasRegParm(_HasRegParm), RegParm(_RegParm) { NumArgs = NumArgTys; @@ -762,8 +763,10 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, PAL.push_back(llvm::AttributeWithIndex::get(0, RetAttrs)); // FIXME: RegParm should be reduced in case of global register variable. - signed RegParm = FI.getRegParm(); - if (!RegParm) + signed RegParm; + if (FI.getHasRegParm()) + RegParm = FI.getRegParm(); + else RegParm = CodeGenOpts.NumRegisterParameters; unsigned PointerWidth = getContext().Target.getPointerWidth(0); diff --git a/lib/CodeGen/CGCall.h b/lib/CodeGen/CGCall.h index fed29a2cf4..f5a84ec99f 100644 --- a/lib/CodeGen/CGCall.h +++ b/lib/CodeGen/CGCall.h @@ -83,6 +83,7 @@ namespace CodeGen { ArgInfo *Args; /// How many arguments to pass inreg. + bool HasRegParm; unsigned RegParm; public: @@ -90,7 +91,7 @@ namespace CodeGen { typedef ArgInfo *arg_iterator; CGFunctionInfo(unsigned CallingConvention, bool NoReturn, - unsigned RegParm, CanQualType ResTy, + bool HasRegParm, unsigned RegParm, CanQualType ResTy, const CanQualType *ArgTys, unsigned NumArgTys); ~CGFunctionInfo() { delete[] Args; } @@ -116,6 +117,7 @@ namespace CodeGen { EffectiveCallingConvention = Value; } + bool getHasRegParm() const { return HasRegParm; } unsigned getRegParm() const { return RegParm; } CanQualType getReturnType() const { return Args[0].type; } @@ -126,6 +128,7 @@ namespace CodeGen { void Profile(llvm::FoldingSetNodeID &ID) { ID.AddInteger(getCallingConvention()); ID.AddBoolean(NoReturn); + ID.AddBoolean(HasRegParm); ID.AddInteger(RegParm); getReturnType().Profile(ID); for (arg_iterator it = arg_begin(), ie = arg_end(); it != ie; ++it) @@ -139,6 +142,7 @@ namespace CodeGen { Iterator end) { ID.AddInteger(Info.getCC()); ID.AddBoolean(Info.getNoReturn()); + ID.AddBoolean(Info.getHasRegParm()); ID.AddInteger(Info.getRegParm()); ResTy.Profile(ID); for (; begin != end; ++begin) { diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 32fd9a1204..a2249c787b 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1270,8 +1270,9 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { } // Merge regparm attribute. - if (OldTypeInfo.getRegParm() != NewTypeInfo.getRegParm()) { - if (NewTypeInfo.getRegParm()) { + if (OldTypeInfo.getHasRegParm() != NewTypeInfo.getHasRegParm() || + OldTypeInfo.getRegParm() != NewTypeInfo.getRegParm()) { + if (NewTypeInfo.getHasRegParm()) { Diag(New->getLocation(), diag::err_regparm_mismatch) << NewType->getRegParmType() << OldType->getRegParmType(); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index e8488f9ac4..fbf0a986d5 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -9367,7 +9367,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, // If we don't have a function type, just build one from nothing. } else { FunctionProtoType::ExtProtoInfo EPI; - EPI.ExtInfo = FunctionType::ExtInfo(NoReturn, 0, CC_Default); + EPI.ExtInfo = FunctionType::ExtInfo(NoReturn, false, 0, CC_Default); BlockTy = Context.getFunctionType(RetTy, 0, 0, EPI); } diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 0ec2986ba5..3a19f2f73a 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -2976,7 +2976,7 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, } // Also diagnose fastcall with regparm. - if (fn->getRegParmType()) { + if (fn->getHasRegParm()) { S.Diag(attr.getLoc(), diag::err_attributes_are_not_compatible) << "regparm" << FunctionType::getNameForCallConv(CC); diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 4cbb81d1ac..0e96770f57 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -3092,12 +3092,12 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) { } case TYPE_FUNCTION_NO_PROTO: { - if (Record.size() != 4) { + if (Record.size() != 5) { Error("incorrect encoding of no-proto function type"); return QualType(); } QualType ResultType = GetType(Record[0]); - FunctionType::ExtInfo Info(Record[1], Record[2], (CallingConv)Record[3]); + FunctionType::ExtInfo Info(Record[1], Record[2], Record[3], (CallingConv)Record[4]); return Context->getFunctionNoProtoType(ResultType, Info); } @@ -3106,10 +3106,11 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) { FunctionProtoType::ExtProtoInfo EPI; EPI.ExtInfo = FunctionType::ExtInfo(/*noreturn*/ Record[1], - /*regparm*/ Record[2], - static_cast(Record[3])); + /*hasregparm*/ Record[2], + /*regparm*/ Record[3], + static_cast(Record[4])); - unsigned Idx = 4; + unsigned Idx = 5; unsigned NumParams = Record[Idx++]; llvm::SmallVector ParamTypes; for (unsigned I = 0; I != NumParams; ++I) diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index 482ce4bec7..f0f5347a16 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -161,6 +161,7 @@ void ASTTypeWriter::VisitFunctionType(const FunctionType *T) { Writer.AddTypeRef(T->getResultType(), Record); FunctionType::ExtInfo C = T->getExtInfo(); Record.push_back(C.getNoReturn()); + Record.push_back(C.getHasRegParm()); Record.push_back(C.getRegParm()); // FIXME: need to stabilize encoding of calling convention... Record.push_back(C.getCC()); diff --git a/test/CodeGen/regparm-flag.c b/test/CodeGen/regparm-flag.c index f37239e473..8ecf539508 100644 --- a/test/CodeGen/regparm-flag.c +++ b/test/CodeGen/regparm-flag.c @@ -4,12 +4,17 @@ void f1(int a, int b, int c, int d, int e, int f, int g, int h); +void f2(int a, int b) __attribute((regparm(0))); + void f0() { // CHECK: call void @f1(i32 inreg 1, i32 inreg 2, i32 inreg 3, i32 inreg 4, // CHECK: i32 5, i32 6, i32 7, i32 8) f1(1, 2, 3, 4, 5, 6, 7, 8); +// CHECK: call void @f2(i32 1, i32 2) + f2(1, 2); } // CHECK: declare void @f1(i32 inreg, i32 inreg, i32 inreg, i32 inreg, // CHECK: i32, i32, i32, i32) +// CHECK: declare void @f2(i32, i32)