/// 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);
/// 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;
// 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 {
// 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;
: 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);
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());
}
}
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) {
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();
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;
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);
}
ID.AddPointer(Exs[i].getAsOpaquePtr());
}
ID.AddInteger(Info.getNoReturn());
+ ID.AddInteger(Info.getRegParm());
ID.AddInteger(Info.getCC());
}
}
if (Info.getNoReturn())
S += " __attribute__((noreturn))";
-
+ if (Info.getRegParm())
+ S += " __attribute__((regparm (" +
+ llvm::utostr_32(Info.getRegParm()) + ")))";
if (T->hasExceptionSpec()) {
S += " throw(";
ArgTys,
FunctionType::ExtInfo(
/*NoReturn*/ false,
+ /*RegParm*/ 0,
getCallingConventionForDecl(MD)));
}
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;
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.
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];
// 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(),
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; }
EffectiveCallingConvention = Value;
}
+ unsigned getRegParm() const { return RegParm; }
+
CanQualType getReturnType() const { return Args[0].type; }
ABIArgInfo &getReturnInfo() { return Args[0].info; }
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);
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
}
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)
isVariadic, Quals, hasExceptionSpec,
hasAnyExceptionSpec, NumExceptions,
Exceptions.data(),
- FunctionType::ExtInfo(NoReturn, CallConv));
+ FunctionType::ExtInfo(NoReturn, RegParm,
+ CallConv));
}
case pch::TYPE_UNRESOLVED_USING:
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());
}
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());
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;
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))
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);
}