]> granicus.if.org Git - clang/commitdiff
Implement ARM pcs attribute. Basically it's another way of calling convention selecti...
authorAnton Korobeynikov <asl@math.spbu.ru>
Thu, 14 Apr 2011 20:06:49 +0000 (20:06 +0000)
committerAnton Korobeynikov <asl@math.spbu.ru>
Thu, 14 Apr 2011 20:06:49 +0000 (20:06 +0000)
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.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@129534 91177308-0d34-0410-b5e6-96231b3b80d8

14 files changed:
include/clang/AST/Type.h
include/clang/Basic/Attr.td
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/AttributeList.h
lib/AST/DumpXML.cpp
lib/AST/MicrosoftMangle.cpp
lib/AST/Type.cpp
lib/AST/TypePrinter.cpp
lib/CodeGen/CGCall.cpp
lib/CodeGen/TargetInfo.cpp
lib/Sema/AttributeList.cpp
lib/Sema/SemaDeclAttr.cpp
lib/Sema/SemaType.cpp
test/CodeGen/arm-pcs.c [new file with mode: 0644]

index 1b94a1d83fe06361c3efc12d49b63a51c1e16c88..6154f0e624a8dc7be07ecaff4816eab240a498f3 100644 (file)
@@ -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,
index 308315cb32fec35b51883d5f8a4af72033a0ba56..51ef7df47dc817022f25c4d00512129a84f63a2b 100644 (file)
@@ -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"];
 }
index 9d0c2c4f2484480622accef721666167831c9357..90945d7bd40e81641f382a338b6e6a2f9eda39b3 100644 (file)
@@ -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<
index fa2f94379eb3a9a2a408263d249b8a02f307ab89..ed2295554e35217c2f91b3f188454c4e945ef4d9 100644 (file)
@@ -213,6 +213,7 @@ public:
     AT_ownership_takes,    // Clang-specific.
     AT_packed,
     AT_pascal,
+    AT_pcs,  // ARM specific
     AT_pure,
     AT_regparm,
     AT_section,
index 93ae1e37c9ced4b0a926f5ba29994cdd86886b2d..8355b2d901c3d5a10bbd518f16b155175694b8b5 100644 (file)
@@ -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");
     }
   }
 
index 5b4dc5a1913d6bc4bc22a5d2fbf9c94da971c493..445d975625ba54e44a0c64b220203de12d4f2a4f 100644 (file)
@@ -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;
index b0726e427564741abdcffd320af9dff62b72414c..62e17f044887e902bc779789e633cce16fa30c5b 100644 (file)
@@ -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.");
index e287c46fa974f0b7da554f9c2bbb9c4c6a7ab9a7..79fbcaa434e70f7be76da98a146ca292b3c44324 100644 (file)
@@ -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 += "))";
 }
index 0ba6789367f49e746ccdc86998db8453e0fa644a..dfe9049add1197c9650436f67ad13daaa1af6602 100644 (file)
@@ -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;
 }
 
index 5db9a8e640badd86a5c594e1f518d58bee0f4cc4..cab60ee5b58ae93c1968d641328279b87eb8bb2d 100644 (file)
@@ -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;
   }
 }
index 792ab4ee8be1b99dcec473fc1554ffd67fab73e0..983c0e0c289cf99f1bd48a15075efb85b91a41f2 100644 (file)
@@ -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);
 }
index 6d1a4c86f282e61276368c4cbe67cc40fa2c4fee..4c72c8390c5ad19f8761f25eae7559d41f129e57 100644 (file)
@@ -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:
index 9c70d250ddc352f6293dbe3e0417abcdf0367850..d3408fc6acddcf673e9e5dfe74860868e980abdd 100644 (file)
@@ -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();
diff --git a/test/CodeGen/arm-pcs.c b/test/CodeGen/arm-pcs.c
new file mode 100644 (file)
index 0000000..d722f84
--- /dev/null
@@ -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();
+}