CXCallingConv_X86_64SysV = 11,
CXCallingConv_X86VectorCall = 12,
CXCallingConv_Swift = 13,
+ CXCallingConv_PreserveMost = 14,
+ CXCallingConv_PreserveAll = 15,
CXCallingConv_Invalid = 100,
CXCallingConv_Unexposed = 200
attr_inteloclbicc,
attr_ms_abi,
attr_sysv_abi,
+ attr_preserve_most,
+ attr_preserve_all,
attr_ptr32,
attr_ptr64,
attr_sptr,
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">];
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.
+ }];
+}
+
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
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 "";
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.");
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:
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");
break;
case CC_Swift:
OS << " __attribute__((swiftcall))";
+ break;
+ case CC_PreserveMost:
+ OS << " __attribute__((preserve_most))";
+ break;
+ case CC_PreserveAll:
+ OS << " __attribute__((preserve_all))";
+ break;
}
}
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 << "))";
}
case CC_X86VectorCall:
case CC_IntelOclBicc:
case CC_X86_64Win64:
+ case CC_PreserveMost:
+ case CC_PreserveAll:
return CCCR_OK;
default:
return CCCR_Warning;
switch (CC) {
case CC_C:
case CC_Swift:
+ case CC_PreserveMost:
+ case CC_PreserveAll:
return CCCR_OK;
default:
return CCCR_Warning;
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;
}
}
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;
}
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");
}
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");
}
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:
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 \
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:
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!");
}
--- /dev/null
+// 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()
+}
+
--- /dev/null
+// 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}}
TCALLINGCONV(AAPCS_VFP);
TCALLINGCONV(IntelOclBicc);
TCALLINGCONV(Swift);
+ TCALLINGCONV(PreserveMost);
+ TCALLINGCONV(PreserveAll);
case CC_SpirFunction: return CXCallingConv_Unexposed;
case CC_SpirKernel: return CXCallingConv_Unexposed;
break;