mirror of
https://github.com/intel/llvm.git
synced 2026-01-25 01:07:04 +08:00
Add attributes for preserve_mostcc/preserve_allcc calling conventions to the C/C++ front-end
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 llvm-svn: 263647
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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">];
|
||||
|
||||
@@ -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.
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 "";
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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 << "))";
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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!");
|
||||
}
|
||||
|
||||
17
clang/test/CodeGen/preserve-call-conv.c
Normal file
17
clang/test/CodeGen/preserve-call-conv.c
Normal file
@@ -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()
|
||||
}
|
||||
|
||||
35
clang/test/Sema/preserve-call-conv.c
Normal file
35
clang/test/Sema/preserve-call-conv.c
Normal file
@@ -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}}
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user