forked from OSchip/llvm-project
Implement ARM pcs attribute. Basically it's another way of calling convention selection (AAPCS or
AAPCS+VFP), similar to fastcall / stdcall / whatevercall seen on x86. In particular, all library functions should always be AAPCS regardless of floating point ABI used. llvm-svn: 129534
This commit is contained in:
parent
fdc33cbecd
commit
231e875b5c
|
@ -360,7 +360,9 @@ enum CallingConv {
|
|||
CC_X86StdCall, // __attribute__((stdcall))
|
||||
CC_X86FastCall, // __attribute__((fastcall))
|
||||
CC_X86ThisCall, // __attribute__((thiscall))
|
||||
CC_X86Pascal // __attribute__((pascal))
|
||||
CC_X86Pascal, // __attribute__((pascal))
|
||||
CC_AAPCS, // __attribute__((pcs("aapcs")))
|
||||
CC_AAPCS_VFP // __attribute__((pcs("aapcs-vfp")))
|
||||
};
|
||||
|
||||
typedef std::pair<const Type*, Qualifiers> SplitQualType;
|
||||
|
@ -2864,9 +2866,10 @@ public:
|
|||
|
||||
// Enumerated operand (string or keyword).
|
||||
attr_objc_gc,
|
||||
attr_pcs,
|
||||
|
||||
FirstEnumOperandKind = attr_objc_gc,
|
||||
LastEnumOperandKind = attr_objc_gc,
|
||||
LastEnumOperandKind = attr_pcs,
|
||||
|
||||
// No operand.
|
||||
attr_noreturn,
|
||||
|
|
|
@ -416,6 +416,13 @@ def Packed : InheritableAttr {
|
|||
let Spellings = ["packed"];
|
||||
}
|
||||
|
||||
def Pcs : InheritableAttr {
|
||||
let Spellings = ["pcs"];
|
||||
let Args = [EnumArgument<"PCS", "PCSType",
|
||||
["aapcs", "aapcs-vfp"],
|
||||
["AAPCS", "AAPCS_VFP"]>];
|
||||
}
|
||||
|
||||
def Pure : InheritableAttr {
|
||||
let Spellings = ["pure"];
|
||||
}
|
||||
|
|
|
@ -1151,6 +1151,7 @@ def err_cconv_varargs : Error<
|
|||
def err_regparm_mismatch : Error<"function declared with with regparm(%0) "
|
||||
"attribute was previously declared "
|
||||
"%plural{0:without the regparm|:with the regparm(%1)}1 attribute">;
|
||||
def err_invalid_pcs : Error<"Invalid PCS type">;
|
||||
|
||||
// Availability attribute
|
||||
def warn_availability_unknown_platform : Warning<
|
||||
|
|
|
@ -213,6 +213,7 @@ public:
|
|||
AT_ownership_takes, // Clang-specific.
|
||||
AT_packed,
|
||||
AT_pascal,
|
||||
AT_pcs, // ARM specific
|
||||
AT_pure,
|
||||
AT_regparm,
|
||||
AT_section,
|
||||
|
|
|
@ -911,6 +911,8 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
|
|||
case CC_X86StdCall: return set("cc", "x86_stdcall");
|
||||
case CC_X86ThisCall: return set("cc", "x86_thiscall");
|
||||
case CC_X86Pascal: return set("cc", "x86_pascal");
|
||||
case CC_AAPCS: return set("cc", "aapcs");
|
||||
case CC_AAPCS_VFP: return set("cc", "aapcs_vfp");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -874,6 +874,8 @@ void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T,
|
|||
if (CC == CC_Default)
|
||||
CC = IsInstMethod ? getASTContext().getDefaultMethodCallConv() : CC_C;
|
||||
switch (CC) {
|
||||
default:
|
||||
assert(0 && "Unsupported CC for mangling");
|
||||
case CC_Default:
|
||||
case CC_C: Out << 'A'; break;
|
||||
case CC_X86Pascal: Out << 'C'; break;
|
||||
|
|
|
@ -1169,6 +1169,8 @@ llvm::StringRef FunctionType::getNameForCallConv(CallingConv CC) {
|
|||
case CC_X86FastCall: return "fastcall";
|
||||
case CC_X86ThisCall: return "thiscall";
|
||||
case CC_X86Pascal: return "pascal";
|
||||
case CC_AAPCS: return "aapcs";
|
||||
case CC_AAPCS_VFP: return "aapcs-vfp";
|
||||
}
|
||||
|
||||
llvm_unreachable("Invalid calling convention.");
|
||||
|
|
|
@ -400,6 +400,12 @@ void TypePrinter::printFunctionProto(const FunctionProtoType *T,
|
|||
case CC_X86Pascal:
|
||||
S += " __attribute__((pascal))";
|
||||
break;
|
||||
case CC_AAPCS:
|
||||
S += " __attribute__((pcs(\"aapcs\")))";
|
||||
break;
|
||||
case CC_AAPCS_VFP:
|
||||
S += " __attribute__((pcs(\"aapcs-vfp\")))";
|
||||
break;
|
||||
}
|
||||
if (Info.getNoReturn())
|
||||
S += " __attribute__((noreturn))";
|
||||
|
@ -851,6 +857,16 @@ void TypePrinter::printAttributed(const AttributedType *T,
|
|||
case AttributedType::attr_stdcall: S += "stdcall"; break;
|
||||
case AttributedType::attr_thiscall: S += "thiscall"; break;
|
||||
case AttributedType::attr_pascal: S += "pascal"; break;
|
||||
case AttributedType::attr_pcs: {
|
||||
S += "pcs(";
|
||||
QualType t = T->getEquivalentType();
|
||||
while (!t->isFunctionType())
|
||||
t = t->getPointeeType();
|
||||
S += (t->getAs<FunctionType>()->getCallConv() == CC_AAPCS ?
|
||||
"\"aapcs\"" : "\"aapcs-vfp\"");
|
||||
S += ")";
|
||||
break;
|
||||
}
|
||||
}
|
||||
S += "))";
|
||||
}
|
||||
|
|
|
@ -36,6 +36,8 @@ static unsigned ClangCallConvToLLVMCallConv(CallingConv CC) {
|
|||
case CC_X86StdCall: return llvm::CallingConv::X86_StdCall;
|
||||
case CC_X86FastCall: return llvm::CallingConv::X86_FastCall;
|
||||
case CC_X86ThisCall: return llvm::CallingConv::X86_ThisCall;
|
||||
case CC_AAPCS: return llvm::CallingConv::ARM_AAPCS;
|
||||
case CC_AAPCS_VFP: return llvm::CallingConv::ARM_AAPCS_VFP;
|
||||
// TODO: add support for CC_X86Pascal to llvm
|
||||
}
|
||||
}
|
||||
|
@ -104,6 +106,9 @@ static CallingConv getCallingConventionForDecl(const Decl *D) {
|
|||
if (D->hasAttr<PascalAttr>())
|
||||
return CC_X86Pascal;
|
||||
|
||||
if (PcsAttr *PCS = D->getAttr<PcsAttr>())
|
||||
return (PCS->getPCS() == PcsAttr::AAPCS ? CC_AAPCS : CC_AAPCS_VFP);
|
||||
|
||||
return CC_C;
|
||||
}
|
||||
|
||||
|
|
|
@ -2271,27 +2271,33 @@ void ARMABIInfo::computeInfo(CGFunctionInfo &FI) const {
|
|||
it != ie; ++it)
|
||||
it->info = classifyArgumentType(it->type);
|
||||
|
||||
const llvm::Triple &Triple(getContext().Target.getTriple());
|
||||
// Always honor user-specified calling convention.
|
||||
if (FI.getCallingConvention() != llvm::CallingConv::C)
|
||||
return;
|
||||
|
||||
// Calling convention as default by an ABI.
|
||||
llvm::CallingConv::ID DefaultCC;
|
||||
if (Triple.getEnvironmentName() == "gnueabi" ||
|
||||
Triple.getEnvironmentName() == "eabi")
|
||||
llvm::StringRef Env = getContext().Target.getTriple().getEnvironmentName();
|
||||
if (Env == "gnueabi" || Env == "eabi")
|
||||
DefaultCC = llvm::CallingConv::ARM_AAPCS;
|
||||
else
|
||||
DefaultCC = llvm::CallingConv::ARM_APCS;
|
||||
|
||||
// If user did not ask for specific calling convention explicitly (e.g. via
|
||||
// pcs attribute), set effective calling convention if it's different than ABI
|
||||
// default.
|
||||
switch (getABIKind()) {
|
||||
case APCS:
|
||||
if (DefaultCC != llvm::CallingConv::ARM_APCS)
|
||||
FI.setEffectiveCallingConvention(llvm::CallingConv::ARM_APCS);
|
||||
break;
|
||||
|
||||
case AAPCS:
|
||||
if (DefaultCC != llvm::CallingConv::ARM_AAPCS)
|
||||
FI.setEffectiveCallingConvention(llvm::CallingConv::ARM_AAPCS);
|
||||
break;
|
||||
|
||||
case AAPCS_VFP:
|
||||
FI.setEffectiveCallingConvention(llvm::CallingConv::ARM_AAPCS_VFP);
|
||||
if (DefaultCC != llvm::CallingConv::ARM_AAPCS_VFP)
|
||||
FI.setEffectiveCallingConvention(llvm::CallingConv::ARM_AAPCS_VFP);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -201,5 +201,6 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
|
|||
.Case("nocommon", AT_nocommon)
|
||||
.Case("opencl_kernel_function", AT_opencl_kernel_function)
|
||||
.Case("uuid", AT_uuid)
|
||||
.Case("pcs", AT_pcs)
|
||||
.Default(UnknownAttribute);
|
||||
}
|
||||
|
|
|
@ -2427,6 +2427,30 @@ static void HandleCallConvAttr(Decl *d, const AttributeList &attr, Sema &S) {
|
|||
case AttributeList::AT_pascal:
|
||||
d->addAttr(::new (S.Context) PascalAttr(attr.getLoc(), S.Context));
|
||||
return;
|
||||
case AttributeList::AT_pcs: {
|
||||
Expr *Arg = attr.getArg(0);
|
||||
StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
|
||||
if (Str == 0 || Str->isWide()) {
|
||||
S.Diag(attr.getLoc(), diag::err_attribute_argument_n_not_string)
|
||||
<< "pcs" << 1;
|
||||
attr.setInvalid();
|
||||
return;
|
||||
}
|
||||
|
||||
llvm::StringRef StrRef = Str->getString();
|
||||
PcsAttr::PCSType PCS;
|
||||
if (StrRef == "aapcs")
|
||||
PCS = PcsAttr::AAPCS;
|
||||
else if (StrRef == "aapcs-vfp")
|
||||
PCS = PcsAttr::AAPCS_VFP;
|
||||
else {
|
||||
S.Diag(attr.getLoc(), diag::err_invalid_pcs);
|
||||
attr.setInvalid();
|
||||
return;
|
||||
}
|
||||
|
||||
d->addAttr(::new (S.Context) PcsAttr(attr.getLoc(), S.Context, PCS));
|
||||
}
|
||||
default:
|
||||
llvm_unreachable("unexpected attribute kind");
|
||||
return;
|
||||
|
@ -2442,19 +2466,41 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC) {
|
|||
if (attr.isInvalid())
|
||||
return true;
|
||||
|
||||
if (attr.getNumArgs() != 0) {
|
||||
if (attr.getNumArgs() != 0 &&
|
||||
!(attr.getKind() == AttributeList::AT_pcs && attr.getNumArgs() == 1)) {
|
||||
Diag(attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
|
||||
attr.setInvalid();
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: diagnose uses of these conventions on the wrong target.
|
||||
// TODO: diagnose uses of these conventions on the wrong target. Or, better
|
||||
// move to TargetAttributesSema one day.
|
||||
switch (attr.getKind()) {
|
||||
case AttributeList::AT_cdecl: CC = CC_C; break;
|
||||
case AttributeList::AT_fastcall: CC = CC_X86FastCall; break;
|
||||
case AttributeList::AT_stdcall: CC = CC_X86StdCall; break;
|
||||
case AttributeList::AT_thiscall: CC = CC_X86ThisCall; break;
|
||||
case AttributeList::AT_pascal: CC = CC_X86Pascal; break;
|
||||
case AttributeList::AT_pcs: {
|
||||
Expr *Arg = attr.getArg(0);
|
||||
StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
|
||||
if (Str == 0 || Str->isWide()) {
|
||||
Diag(attr.getLoc(), diag::err_attribute_argument_n_not_string)
|
||||
<< "pcs" << 1;
|
||||
attr.setInvalid();
|
||||
return true;
|
||||
}
|
||||
|
||||
llvm::StringRef StrRef = Str->getString();
|
||||
if (StrRef == "aapcs") {
|
||||
CC = CC_AAPCS;
|
||||
break;
|
||||
} else if (StrRef == "aapcs-vfp") {
|
||||
CC = CC_AAPCS_VFP;
|
||||
break;
|
||||
}
|
||||
// FALLS THROUGH
|
||||
}
|
||||
default: llvm_unreachable("unexpected attribute kind"); return true;
|
||||
}
|
||||
|
||||
|
@ -2882,6 +2928,7 @@ static void ProcessInheritableDeclAttr(Scope *scope, Decl *D,
|
|||
case AttributeList::AT_fastcall:
|
||||
case AttributeList::AT_thiscall:
|
||||
case AttributeList::AT_pascal:
|
||||
case AttributeList::AT_pcs:
|
||||
HandleCallConvAttr(D, Attr, S);
|
||||
break;
|
||||
case AttributeList::AT_opencl_kernel_function:
|
||||
|
|
|
@ -119,7 +119,8 @@ static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr,
|
|||
case AttributeList::AT_stdcall: \
|
||||
case AttributeList::AT_thiscall: \
|
||||
case AttributeList::AT_pascal: \
|
||||
case AttributeList::AT_regparm
|
||||
case AttributeList::AT_regparm: \
|
||||
case AttributeList::AT_pcs \
|
||||
|
||||
namespace {
|
||||
/// An object which stores processing state for the entire
|
||||
|
@ -2244,6 +2245,8 @@ static AttributeList::Kind getAttrListKind(AttributedType::Kind kind) {
|
|||
return AttributeList::AT_thiscall;
|
||||
case AttributedType::attr_pascal:
|
||||
return AttributeList::AT_pascal;
|
||||
case AttributedType::attr_pcs:
|
||||
return AttributeList::AT_pcs;
|
||||
}
|
||||
llvm_unreachable("unexpected attribute kind!");
|
||||
return AttributeList::Kind();
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
// RUN: %clang_cc1 -triple arm-none-linux-gnueabi -emit-llvm -w -o - < %s | FileCheck %s
|
||||
typedef int __attribute__((pcs("aapcs"))) (*aapcs_fn)(void);
|
||||
typedef int __attribute__((pcs("aapcs-vfp"))) (*aapcs_vfp_fn)(void);
|
||||
|
||||
aapcs_fn bar;
|
||||
|
||||
int foo(aapcs_vfp_fn baz) {
|
||||
// CHECK: define i32 @foo
|
||||
// CHECK: call arm_aapcscc
|
||||
// CHECK: call arm_aapcs_vfpcc
|
||||
return bar() + baz();
|
||||
}
|
Loading…
Reference in New Issue