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
This commit is contained in:
Rafael Espindola 2010-03-30 22:15:11 +00:00
Родитель 7fd3a6456a
Коммит 425ef72306
12 изменённых файлов: 118 добавлений и 35 удалений

Просмотреть файл

@ -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);

Просмотреть файл

@ -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());
}

Просмотреть файл

@ -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);
}

Просмотреть файл

@ -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());
}

Просмотреть файл

@ -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(";

Просмотреть файл

@ -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<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 @@ 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<CanQualType> &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<RegparmAttr>())
RegParm = RegParmAttr->getNumParams();
signed RegParm = FI.getRegParm();
unsigned PointerWidth = getContext().Target.getPointerWidth(0);
for (CGFunctionInfo::const_arg_iterator it = FI.arg_begin(),

Просмотреть файл

@ -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<CanQualType> &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

Просмотреть файл

@ -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<QualType, 16> 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:

Просмотреть файл

@ -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());
}

Просмотреть файл

@ -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());

Просмотреть файл

@ -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<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 @@ 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))

Просмотреть файл

@ -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);
}