Index: include/clang-c/Index.h =================================================================== --- include/clang-c/Index.h +++ include/clang-c/Index.h @@ -2971,6 +2971,8 @@ CXCallingConv_X86_64SysV = 11, CXCallingConv_X86VectorCall = 12, CXCallingConv_Swift = 13, + CXCallingConv_PreserveMost = 14, + CXCallingConv_PreserveAll = 15, CXCallingConv_Invalid = 100, CXCallingConv_Unexposed = 200 Index: include/clang/AST/Type.h =================================================================== --- include/clang/AST/Type.h +++ include/clang/AST/Type.h @@ -3740,6 +3740,8 @@ attr_inteloclbicc, attr_ms_abi, attr_sysv_abi, + attr_preserve_most, + attr_preserve_all, attr_ptr32, attr_ptr64, attr_sptr, Index: include/clang/Basic/Attr.td =================================================================== --- include/clang/Basic/Attr.td +++ include/clang/Basic/Attr.td @@ -1391,6 +1391,16 @@ 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: include/clang/Basic/AttrDocs.td =================================================================== --- include/clang/Basic/AttrDocs.td +++ include/clang/Basic/AttrDocs.td @@ -2132,3 +2132,70 @@ optimizations like C++'s named return value optimization (NRVO). }]; } + +def PreserveMostDocs : Documentation { + let Category = DocCatVariable; + 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 ObjectiveC +runtime and should therefore still be considered experimental at this time. +Although this convention was created to optimize certain runtime calls to +the ObjectiveC 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 = DocCatVariable; + 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 ObjectiveC runtime and should be considered +experimental at this time. + }]; +} + Index: include/clang/Basic/Specifiers.h =================================================================== --- include/clang/Basic/Specifiers.h +++ include/clang/Basic/Specifiers.h @@ -239,7 +239,9 @@ 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: lib/AST/ItaniumMangle.cpp =================================================================== --- lib/AST/ItaniumMangle.cpp +++ lib/AST/ItaniumMangle.cpp @@ -2165,6 +2165,8 @@ 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: lib/AST/Type.cpp =================================================================== --- lib/AST/Type.cpp +++ lib/AST/Type.cpp @@ -2656,6 +2656,8 @@ 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 @@ 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 @@ 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: lib/AST/TypePrinter.cpp =================================================================== --- lib/AST/TypePrinter.cpp +++ lib/AST/TypePrinter.cpp @@ -726,6 +726,13 @@ 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 @@ 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: lib/Basic/Targets.cpp =================================================================== --- lib/Basic/Targets.cpp +++ lib/Basic/Targets.cpp @@ -4095,6 +4095,8 @@ 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 @@ switch (CC) { case CC_C: case CC_Swift: + case CC_PreserveMost: + case CC_PreserveAll: return CCCR_OK; default: return CCCR_Warning; Index: lib/CodeGen/CGCall.cpp =================================================================== --- lib/CodeGen/CGCall.cpp +++ lib/CodeGen/CGCall.cpp @@ -57,6 +57,10 @@ 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; } } @@ -174,6 +178,12 @@ if (D->hasAttr()) return IsWindows ? CC_X86_64SysV : CC_C; + if (D->hasAttr()) + return CC_PreserveMost; + + if (D->hasAttr()) + return CC_PreserveAll; + return CC_C; } Index: lib/Sema/SemaDeclAttr.cpp =================================================================== --- lib/Sema/SemaDeclAttr.cpp +++ lib/Sema/SemaDeclAttr.cpp @@ -3777,7 +3777,14 @@ 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"); } @@ -3835,6 +3842,12 @@ 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"); } @@ -5597,6 +5610,8 @@ 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: lib/Sema/SemaType.cpp =================================================================== --- lib/Sema/SemaType.cpp +++ lib/Sema/SemaType.cpp @@ -112,7 +112,9 @@ 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 @@ 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 @@ 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!"); } Index: test/CodeGen/preserve_all.c =================================================================== --- test/CodeGen/preserve_all.c +++ test/CodeGen/preserve_all.c @@ -0,0 +1,10 @@ +// 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_all)) { + // CHECK-LABEL: define preserve_allcc void @foo() +} + Index: test/CodeGen/preserve_most.c =================================================================== --- test/CodeGen/preserve_most.c +++ test/CodeGen/preserve_most.c @@ -0,0 +1,10 @@ +// 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() +} + Index: test/Sema/preserve_all-call-conv.c =================================================================== --- test/Sema/preserve_all-call-conv.c +++ test/Sema/preserve_all-call-conv.c @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 %s -fsyntax-only -triple x86_64-unknown-unknown -verify +// RUN: %clang_cc1 %s -fsyntax-only -triple arm64-unknown-unknown -verify + +void __attribute__((preserve_all)) foo(void *ptr) { +} + +void __attribute__((preserve_all(1))) baz(void *ptr) { // expected-error {{'preserve_all' attribute takes no arguments}} +} + +void (__attribute__((preserve_all)) *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_all))'}} +void (*pfoo3)(void *) = foo; // expected-warning {{incompatible pointer types initializing 'void (*)(void *)' with an expression of type 'void (void *) __attribute__((preserve_all))'}} + +typedef void typedef_fun_t(int); +typedef_fun_t typedef_fun; // expected-note {{previous declaration is here}} +void __attribute__((preserve_all)) typedef_fun(int x) { } // expected-error {{function declared 'preserve_all' here was previously declared without calling convention}} + +struct type_test {} __attribute__((preserve_all)); // expected-warning {{'preserve_all' attribute only applies to functions and methods}} Index: test/Sema/preserve_most-call-conv.c =================================================================== --- test/Sema/preserve_most-call-conv.c +++ test/Sema/preserve_most-call-conv.c @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 %s -fsyntax-only -triple x86_64-unknown-unknown -verify +// RUN: %clang_cc1 %s -fsyntax-only -triple arm64-unknown-unknown -verify + +void __attribute__((preserve_most)) foo(void *ptr) { +} + +void __attribute__((preserve_most(1))) baz(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 void typedef_fun_t(int); +typedef_fun_t typedef_fun; // expected-note {{previous declaration is here}} +void __attribute__((preserve_most)) typedef_fun(int x) { } // expected-error {{function declared 'preserve_most' here was previously declared without calling convention}} + +struct type_test {} __attribute__((preserve_most)); // expected-warning {{'preserve_most' attribute only applies to functions and methods}} Index: tools/libclang/CXType.cpp =================================================================== --- tools/libclang/CXType.cpp +++ tools/libclang/CXType.cpp @@ -534,6 +534,8 @@ TCALLINGCONV(AAPCS_VFP); TCALLINGCONV(IntelOclBicc); TCALLINGCONV(Swift); + TCALLINGCONV(PreserveMost); + TCALLINGCONV(PreserveAll); case CC_SpirFunction: return CXCallingConv_Unexposed; case CC_SpirKernel: return CXCallingConv_Unexposed; break;