зеркало из https://github.com/microsoft/clang-1.git
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:
Родитель
7fd3a6456a
Коммит
425ef72306
|
@ -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);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче