]> granicus.if.org Git - clang/commitdiff
Add attributes for preserve_mostcc/preserve_allcc calling conventions to the C/C...
authorRoman Levenstein <rlevenstein@apple.com>
Wed, 16 Mar 2016 18:00:46 +0000 (18:00 +0000)
committerRoman Levenstein <rlevenstein@apple.com>
Wed, 16 Mar 2016 18:00:46 +0000 (18:00 +0000)
Till now, preserve_mostcc/preserve_allcc calling convention attributes were only
available at the LLVM IR level. This patch adds attributes for
preserve_mostcc/preserve_allcc calling conventions to the C/C++ front-end.

The code was mostly written by Juergen Ributzka.
I just added support for the AArch64 target and tests.

Differential Revision: http://reviews.llvm.org/D18025

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

15 files changed:
include/clang-c/Index.h
include/clang/AST/Type.h
include/clang/Basic/Attr.td
include/clang/Basic/AttrDocs.td
include/clang/Basic/Specifiers.h
lib/AST/ItaniumMangle.cpp
lib/AST/Type.cpp
lib/AST/TypePrinter.cpp
lib/Basic/Targets.cpp
lib/CodeGen/CGCall.cpp
lib/Sema/SemaDeclAttr.cpp
lib/Sema/SemaType.cpp
test/CodeGen/preserve-call-conv.c [new file with mode: 0644]
test/Sema/preserve-call-conv.c [new file with mode: 0644]
tools/libclang/CXType.cpp

index 9c5c6807b298aa1226d9e37e48371a775c89fd80..a564af88b28b316cef56713d8a0576e641c1b967 100644 (file)
@@ -2971,6 +2971,8 @@ enum CXCallingConv {
   CXCallingConv_X86_64SysV = 11,
   CXCallingConv_X86VectorCall = 12,
   CXCallingConv_Swift = 13,
+  CXCallingConv_PreserveMost = 14,
+  CXCallingConv_PreserveAll = 15,
 
   CXCallingConv_Invalid = 100,
   CXCallingConv_Unexposed = 200
index 6c3fd805df6859a53b765d61c032a63c7cef5567..2e02ad1ea0fb2d0c6c51189b50e4b8def39c8d92 100644 (file)
@@ -3740,6 +3740,8 @@ public:
     attr_inteloclbicc,
     attr_ms_abi,
     attr_sysv_abi,
+    attr_preserve_most,
+    attr_preserve_all,
     attr_ptr32,
     attr_ptr64,
     attr_sptr,
index f50cb296ada076aaf706cec99a7005e61351476b..f07f30d9960e70e995d1ec3cb6c8a2a209d17d1c 100644 (file)
@@ -1399,6 +1399,16 @@ def Pascal : InheritableAttr {
   let Documentation = [Undocumented];
 }
 
+def PreserveMost : InheritableAttr {
+  let Spellings = [GNU<"preserve_most">];
+  let Documentation = [PreserveMostDocs];
+}
+
+def PreserveAll : InheritableAttr {
+  let Spellings = [GNU<"preserve_all">];
+  let Documentation = [PreserveAllDocs];
+}
+
 def Target : InheritableAttr {
   let Spellings = [GCC<"target">];
   let Args = [StringArgument<"featuresStr">];
index 4e80a8db096c0985e326f64acc20dfb2036ba3a7..4e2df24d4d50526c71a22e365416e83ebb8c810f 100644 (file)
@@ -2172,3 +2172,70 @@ a global variable of the class type. Therefor, the old code could keep using
 the old manged name and the new code will use the new mangled name with tags.
   }];
 }
+
+def PreserveMostDocs : Documentation {
+  let Category = DocCatCallingConvs;
+  let Content = [{
+On X86-64 and AArch64 targets, this attribute changes the calling convention of
+a function. The ``preserve_most`` calling convention attempts to make the code
+in the caller as unintrusive as possible. This convention behaves identically
+to the ``C`` calling convention on how arguments and return values are passed,
+but it uses a different set of caller/callee-saved registers. This alleviates
+the burden of saving and recovering a large register set before and after the
+call in the caller. If the arguments are passed in callee-saved registers,
+then they will be preserved by the callee across the call. This doesn't
+apply for values returned in callee-saved registers.
+
+- On X86-64 the callee preserves all general purpose registers, except for
+  R11. R11 can be used as a scratch register. Floating-point registers
+  (XMMs/YMMs) are not preserved and need to be saved by the caller.
+
+The idea behind this convention is to support calls to runtime functions
+that have a hot path and a cold path. The hot path is usually a small piece
+of code that doesn't use many registers. The cold path might need to call out to
+another function and therefore only needs to preserve the caller-saved
+registers, which haven't already been saved by the caller. The
+`preserve_most` calling convention is very similar to the ``cold`` calling
+convention in terms of caller/callee-saved registers, but they are used for
+different types of function calls. ``coldcc`` is for function calls that are
+rarely executed, whereas `preserve_most` function calls are intended to be
+on the hot path and definitely executed a lot. Furthermore ``preserve_most``
+doesn't prevent the inliner from inlining the function call.
+
+This calling convention will be used by a future version of the Objective-C
+runtime and should therefore still be considered experimental at this time.
+Although this convention was created to optimize certain runtime calls to
+the Objective-C runtime, it is not limited to this runtime and might be used
+by other runtimes in the future too. The current implementation only
+supports X86-64 and AArch64, but the intention is to support more architectures
+in the future.
+  }];
+}
+
+def PreserveAllDocs : Documentation {
+  let Category = DocCatCallingConvs;
+  let Content = [{
+On X86-64 and AArch64 targets, this attribute changes the calling convention of
+a function. The ``preserve_all`` calling convention attempts to make the code
+in the caller even less intrusive than the ``preserve_most`` calling convention.
+This calling convention also behaves identical to the ``C`` calling convention
+on how arguments and return values are passed, but it uses a different set of
+caller/callee-saved registers. This removes the burden of saving and
+recovering a large register set before and after the call in the caller. If
+the arguments are passed in callee-saved registers, then they will be
+preserved by the callee across the call. This doesn't apply for values
+returned in callee-saved registers.
+
+- On X86-64 the callee preserves all general purpose registers, except for
+  R11. R11 can be used as a scratch register. Furthermore it also preserves
+  all floating-point registers (XMMs/YMMs).
+
+The idea behind this convention is to support calls to runtime functions
+that don't need to call out to any other functions.
+
+This calling convention, like the ``preserve_most`` calling convention, will be
+used by a future version of the Objective-C runtime and should be considered
+experimental at this time.
+  }];
+}
+
index 9be0d5aaafd347d9d5891fbfc98064dc59ab90b2..8857e0df5658d38e8b66e5c2ded3c62297a1dc25 100644 (file)
@@ -239,7 +239,9 @@ namespace clang {
     CC_IntelOclBicc, // __attribute__((intel_ocl_bicc))
     CC_SpirFunction, // default for OpenCL functions on SPIR target
     CC_SpirKernel,   // inferred for OpenCL kernels on SPIR target
-    CC_Swift         // __attribute__((swiftcall))
+    CC_Swift,        // __attribute__((swiftcall))
+    CC_PreserveMost, // __attribute__((preserve_most))
+    CC_PreserveAll,  // __attribute__((preserve_all))
   };
 
   /// \brief Checks whether the given calling convention supports variadic
index 5e079960ae1162b59f2ed361e29926fcb1373691..2a517a5ccf9241900944c71c87573a8c0c3b022b 100644 (file)
@@ -2165,6 +2165,8 @@ StringRef CXXNameMangler::getCallingConvQualifierName(CallingConv CC) {
   case CC_IntelOclBicc:
   case CC_SpirFunction:
   case CC_SpirKernel:
+  case CC_PreserveMost:
+  case CC_PreserveAll:
     // FIXME: we should be mangling all of the above.
     return "";
 
index efa2595f6d26b06fbecb6627f6166784149163c1..74aa323dbc8b538aaa65f9204590ef91cc9ad09d 100644 (file)
@@ -2656,6 +2656,8 @@ StringRef FunctionType::getNameForCallConv(CallingConv CC) {
   case CC_SpirFunction: return "spir_function";
   case CC_SpirKernel: return "spir_kernel";
   case CC_Swift: return "swiftcall";
+  case CC_PreserveMost: return "preserve_most";
+  case CC_PreserveAll: return "preserve_all";
   }
 
   llvm_unreachable("Invalid calling convention.");
@@ -2999,6 +3001,8 @@ bool AttributedType::isQualifier() const {
   case AttributedType::attr_swiftcall:
   case AttributedType::attr_vectorcall:
   case AttributedType::attr_inteloclbicc:
+  case AttributedType::attr_preserve_most:
+  case AttributedType::attr_preserve_all:
   case AttributedType::attr_ms_abi:
   case AttributedType::attr_sysv_abi:
   case AttributedType::attr_ptr32:
@@ -3056,6 +3060,8 @@ bool AttributedType::isCallingConv() const {
   case attr_ms_abi:
   case attr_sysv_abi:
   case attr_inteloclbicc:
+  case attr_preserve_most:
+  case attr_preserve_all:
     return true;
   }
   llvm_unreachable("invalid attr kind");
index 47f60acb1d13f892be7fcc8eff921f760e1c73c1..7c519fc6381f1c457271f71864e142cb75c32941 100644 (file)
@@ -726,6 +726,13 @@ void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T,
       break;
     case CC_Swift:
       OS << " __attribute__((swiftcall))";
+      break;
+    case CC_PreserveMost:
+      OS << " __attribute__((preserve_most))";
+      break;
+    case CC_PreserveAll:
+      OS << " __attribute__((preserve_all))";
+      break;
     }
   }
 
@@ -1345,6 +1352,12 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
    break;
   }
   case AttributedType::attr_inteloclbicc: OS << "inteloclbicc"; break;
+  case AttributedType::attr_preserve_most:
+    OS << "preserve_most";
+    break;
+  case AttributedType::attr_preserve_all:
+    OS << "preserve_all";
+    break;
   }
   OS << "))";
 }
index 797d052d0c15cdee5c1bcc713e237732009e02f5..a151c5947833e1f9a0006f9fc7b2325ff891c98f 100644 (file)
@@ -4095,6 +4095,8 @@ public:
     case CC_X86VectorCall:
     case CC_IntelOclBicc:
     case CC_X86_64Win64:
+    case CC_PreserveMost:
+    case CC_PreserveAll:
       return CCCR_OK;
     default:
       return CCCR_Warning;
@@ -5545,6 +5547,8 @@ public:
     switch (CC) {
     case CC_C:
     case CC_Swift:
+    case CC_PreserveMost:
+    case CC_PreserveAll:
       return CCCR_OK;
     default:
       return CCCR_Warning;
index 7fb301c8c3680ee7d3884083d34775ae6e610fc4..5e10f26ceb6923211d44f0674a7a873f696bf49c 100644 (file)
@@ -57,6 +57,8 @@ static unsigned ClangCallConvToLLVMCallConv(CallingConv CC) {
   case CC_X86VectorCall: return llvm::CallingConv::X86_VectorCall;
   case CC_SpirFunction: return llvm::CallingConv::SPIR_FUNC;
   case CC_SpirKernel: return llvm::CallingConv::SPIR_KERNEL;
+  case CC_PreserveMost: return llvm::CallingConv::PreserveMost;
+  case CC_PreserveAll: return llvm::CallingConv::PreserveAll;
   }
 }
 
@@ -187,6 +189,12 @@ static CallingConv getCallingConventionForDecl(const Decl *D, bool IsWindows) {
   if (D->hasAttr<SysVABIAttr>())
     return IsWindows ? CC_X86_64SysV : CC_C;
 
+  if (D->hasAttr<PreserveMostAttr>())
+    return CC_PreserveMost;
+
+  if (D->hasAttr<PreserveAllAttr>())
+    return CC_PreserveAll;
+
   return CC_C;
 }
 
index 0cae52a299fc8f371644446fcdb1f28059c7b4e6..725b08a422a09fa1b54cfbcd1cc2d9987192304e 100644 (file)
@@ -3799,7 +3799,14 @@ static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) {
                IntelOclBiccAttr(Attr.getRange(), S.Context,
                                 Attr.getAttributeSpellingListIndex()));
     return;
-
+  case AttributeList::AT_PreserveMost:
+    D->addAttr(::new (S.Context) PreserveMostAttr(
+        Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex()));
+    return;
+  case AttributeList::AT_PreserveAll:
+    D->addAttr(::new (S.Context) PreserveAllAttr(
+        Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex()));
+    return;
   default:
     llvm_unreachable("unexpected attribute kind");
   }
@@ -3857,6 +3864,8 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC,
     return true;
   }
   case AttributeList::AT_IntelOclBicc: CC = CC_IntelOclBicc; break;
+  case AttributeList::AT_PreserveMost: CC = CC_PreserveMost; break;
+  case AttributeList::AT_PreserveAll: CC = CC_PreserveAll; break;
   default: llvm_unreachable("unexpected attribute kind");
   }
 
@@ -5655,6 +5664,8 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
   case AttributeList::AT_SysVABI:
   case AttributeList::AT_Pcs:
   case AttributeList::AT_IntelOclBicc:
+  case AttributeList::AT_PreserveMost:
+  case AttributeList::AT_PreserveAll:
     handleCallConvAttr(S, D, Attr);
     break;
   case AttributeList::AT_OpenCLKernel:
index 73c5bcc0067c99d3c6dc98085474357b27e3e7f8..924cd07e0214310683fcc0f6b1097e2d520df54b 100644 (file)
@@ -112,7 +112,9 @@ static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr,
     case AttributeList::AT_MSABI: \
     case AttributeList::AT_SysVABI: \
     case AttributeList::AT_Pcs: \
-    case AttributeList::AT_IntelOclBicc
+    case AttributeList::AT_IntelOclBicc: \
+    case AttributeList::AT_PreserveMost: \
+    case AttributeList::AT_PreserveAll
 
 // Function type attributes.
 #define FUNCTION_TYPE_ATTRS_CASELIST \
@@ -4639,6 +4641,10 @@ static AttributeList::Kind getAttrListKind(AttributedType::Kind kind) {
     return AttributeList::AT_MSABI;
   case AttributedType::attr_sysv_abi:
     return AttributeList::AT_SysVABI;
+  case AttributedType::attr_preserve_most:
+    return AttributeList::AT_PreserveMost;
+  case AttributedType::attr_preserve_all:
+    return AttributeList::AT_PreserveAll;
   case AttributedType::attr_ptr32:
     return AttributeList::AT_Ptr32;
   case AttributedType::attr_ptr64:
@@ -5974,6 +5980,10 @@ static AttributedType::Kind getCCTypeAttrKind(AttributeList &Attr) {
     return AttributedType::attr_ms_abi;
   case AttributeList::AT_SysVABI:
     return AttributedType::attr_sysv_abi;
+  case AttributeList::AT_PreserveMost:
+    return AttributedType::attr_preserve_most;
+  case AttributeList::AT_PreserveAll:
+    return AttributedType::attr_preserve_all;
   }
   llvm_unreachable("unexpected attribute kind!");
 }
diff --git a/test/CodeGen/preserve-call-conv.c b/test/CodeGen/preserve-call-conv.c
new file mode 100644 (file)
index 0000000..6e91a84
--- /dev/null
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm < %s | FileCheck %s
+// RUN: %clang_cc1 -triple arm64-unknown-unknown -emit-llvm < %s | FileCheck %s
+
+// Check that the preserve_most calling convention attribute at the source level
+// is lowered to the corresponding calling convention attrribute at the LLVM IR
+// level.
+void foo() __attribute__((preserve_most)) {
+  // CHECK-LABEL: define preserve_mostcc void @foo()
+}
+
+// Check that the preserve_most calling convention attribute at the source level
+// is lowered to the corresponding calling convention attrribute at the LLVM IR
+// level.
+void boo() __attribute__((preserve_all)) {
+  // CHECK-LABEL: define preserve_allcc void @boo()
+}
+
diff --git a/test/Sema/preserve-call-conv.c b/test/Sema/preserve-call-conv.c
new file mode 100644 (file)
index 0000000..f258f45
--- /dev/null
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 %s -fsyntax-only -triple x86_64-unknown-unknown -verify
+// RUN: %clang_cc1 %s -fsyntax-only -triple arm64-unknown-unknown -verify
+typedef void typedef_fun_t(int);
+
+void __attribute__((preserve_most)) foo(void *ptr) {
+}
+
+void __attribute__((preserve_most(1))) foo1(void *ptr) { // expected-error {{'preserve_most' attribute takes no arguments}}
+}
+
+void (__attribute__((preserve_most)) *pfoo1)(void *) = foo;
+
+void (__attribute__((cdecl)) *pfoo2)(void *) = foo; // expected-warning {{incompatible pointer types initializing 'void (*)(void *) __attribute__((cdecl))' with an expression of type 'void (void *) __attribute__((preserve_most))'}}
+void (*pfoo3)(void *) = foo; // expected-warning {{incompatible pointer types initializing 'void (*)(void *)' with an expression of type 'void (void *) __attribute__((preserve_most))'}}
+
+typedef_fun_t typedef_fun_foo; // expected-note {{previous declaration is here}}
+void __attribute__((preserve_most)) typedef_fun_foo(int x) { } // expected-error {{function declared 'preserve_most' here was previously declared without calling convention}}
+
+struct type_test_foo {} __attribute__((preserve_most));  // expected-warning {{'preserve_most' attribute only applies to functions and methods}}
+
+void __attribute__((preserve_all)) boo(void *ptr) {
+}
+
+void __attribute__((preserve_all(1))) boo1(void *ptr) { // expected-error {{'preserve_all' attribute takes no arguments}}
+}
+
+void (__attribute__((preserve_all)) *pboo1)(void *) = boo;
+
+void (__attribute__((cdecl)) *pboo2)(void *) = boo; // expected-warning {{incompatible pointer types initializing 'void (*)(void *) __attribute__((cdecl))' with an expression of type 'void (void *) __attribute__((preserve_all))'}}
+void (*pboo3)(void *) = boo; // expected-warning {{incompatible pointer types initializing 'void (*)(void *)' with an expression of type 'void (void *) __attribute__((preserve_all))'}}
+
+typedef_fun_t typedef_fun_boo; // expected-note {{previous declaration is here}}
+void __attribute__((preserve_all)) typedef_fun_boo(int x) { } // expected-error {{function declared 'preserve_all' here was previously declared without calling convention}}
+
+struct type_test_boo {} __attribute__((preserve_all));  // expected-warning {{'preserve_all' attribute only applies to functions and methods}}
index fce749c1e136145e052bfbc71c1c052a59056dec..5cde236055291e1892eb8ba993406bc3cb7e1d7c 100644 (file)
@@ -534,6 +534,8 @@ CXCallingConv clang_getFunctionTypeCallingConv(CXType X) {
       TCALLINGCONV(AAPCS_VFP);
       TCALLINGCONV(IntelOclBicc);
       TCALLINGCONV(Swift);
+      TCALLINGCONV(PreserveMost);
+      TCALLINGCONV(PreserveAll);
     case CC_SpirFunction: return CXCallingConv_Unexposed;
     case CC_SpirKernel: return CXCallingConv_Unexposed;
       break;