[clang] 92dcb1d - [Clang] Introduce Swift async calling convention.
Varun Gandhi via cfe-commits
cfe-commits at lists.llvm.org
Fri Jul 9 11:50:20 PDT 2021
Author: Varun Gandhi
Date: 2021-07-09T11:50:10-07:00
New Revision: 92dcb1d2db8c4de48df0af806dca631523cd4169
URL: https://github.com/llvm/llvm-project/commit/92dcb1d2db8c4de48df0af806dca631523cd4169
DIFF: https://github.com/llvm/llvm-project/commit/92dcb1d2db8c4de48df0af806dca631523cd4169.diff
LOG: [Clang] Introduce Swift async calling convention.
This change is intended as initial setup. The plan is to add
more semantic checks later. I plan to update the documentation
as more semantic checks are added (instead of documenting the
details up front). Most of the code closely mirrors that for
the Swift calling convention. Three places are marked as
[FIXME: swiftasynccc]; those will be addressed once the
corresponding convention is introduced in LLVM.
Reviewed By: rjmccall
Differential Revision: https://reviews.llvm.org/D95561
Added:
clang/test/CodeGen/swift-async-call-conv.c
Modified:
clang/include/clang-c/Index.h
clang/include/clang/Basic/Attr.td
clang/include/clang/Basic/AttrDocs.td
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/include/clang/Basic/Features.def
clang/include/clang/Basic/Specifiers.h
clang/include/clang/CodeGen/SwiftCallingConv.h
clang/lib/AST/ExprCXX.cpp
clang/lib/AST/ItaniumMangle.cpp
clang/lib/AST/MicrosoftMangle.cpp
clang/lib/AST/Type.cpp
clang/lib/AST/TypePrinter.cpp
clang/lib/Basic/Targets/AArch64.cpp
clang/lib/Basic/Targets/ARM.cpp
clang/lib/Basic/Targets/PPC.h
clang/lib/Basic/Targets/SystemZ.h
clang/lib/Basic/Targets/WebAssembly.h
clang/lib/Basic/Targets/X86.h
clang/lib/CodeGen/CGCall.cpp
clang/lib/CodeGen/CGDebugInfo.cpp
clang/lib/CodeGen/CGStmt.cpp
clang/lib/Sema/SemaDeclAttr.cpp
clang/lib/Sema/SemaType.cpp
clang/test/CodeGen/64bit-swiftcall.c
clang/test/CodeGen/arm-swiftcall.c
clang/test/CodeGen/debug-info-cc.c
clang/test/CodeGen/swift-call-conv.c
clang/test/Sema/attr-c2x.c
clang/test/Sema/attr-swiftcall.c
clang/test/Sema/no_callconv.cpp
clang/test/SemaCXX/attr-swiftcall.cpp
clang/tools/libclang/CXType.cpp
llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h
llvm/lib/Demangle/MicrosoftDemangle.cpp
llvm/lib/Demangle/MicrosoftDemangleNodes.cpp
llvm/lib/Transforms/IPO/MergeFunctions.cpp
llvm/test/Demangle/ms-mangle.test
Removed:
################################################################################
diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h
index c7d3b4e10622..26844d1c74f3 100644
--- a/clang/include/clang-c/Index.h
+++ b/clang/include/clang-c/Index.h
@@ -33,7 +33,7 @@
* compatible, thus CINDEX_VERSION_MAJOR is expected to remain stable.
*/
#define CINDEX_VERSION_MAJOR 0
-#define CINDEX_VERSION_MINOR 61
+#define CINDEX_VERSION_MINOR 62
#define CINDEX_VERSION_ENCODE(major, minor) (((major)*10000) + ((minor)*1))
@@ -3418,6 +3418,7 @@ enum CXCallingConv {
CXCallingConv_PreserveMost = 14,
CXCallingConv_PreserveAll = 15,
CXCallingConv_AArch64VectorCall = 16,
+ CXCallingConv_SwiftAsync = 17,
CXCallingConv_Invalid = 100,
CXCallingConv_Unexposed = 200
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index bfcf5f798d8f..e27efd404c21 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -2459,6 +2459,11 @@ def SwiftCall : DeclOrTypeAttr {
let Documentation = [SwiftCallDocs];
}
+def SwiftAsyncCall : DeclOrTypeAttr {
+ let Spellings = [Clang<"swiftasynccall">];
+ let Documentation = [SwiftAsyncCallDocs];
+}
+
def SwiftContext : ParameterABIAttr {
let Spellings = [Clang<"swift_context">];
let Documentation = [SwiftContextDocs];
diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index bf51b05acaaa..0a665fee7686 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -4527,7 +4527,8 @@ def SwiftContextDocs : Documentation {
let Category = DocCatVariable;
let Content = [{
The ``swift_context`` attribute marks a parameter of a ``swiftcall``
-function as having the special context-parameter ABI treatment.
+or ``swiftasynccall`` function as having the special context-parameter
+ABI treatment.
This treatment generally passes the context value in a special register
which is normally callee-preserved.
@@ -4540,14 +4541,39 @@ A context parameter must have pointer or reference type.
}];
}
+def SwiftAsyncCallDocs : Documentation {
+ let Category = DocCatVariable;
+ let Content = [{
+The ``swiftasynccall`` attribute indicates that a function is
+compatible with the low-level conventions of Swift async functions,
+provided it declares the right formal arguments.
+
+In most respects, this is similar to the ``swiftcall`` attribute, except for
+the following:
+- A parameter may be marked ``swift_async_context``, ``swift_context``
+ or ``swift_indirect_result`` (with the same restrictions on parameter
+ ordering as ``swiftcall``) but the parameter attribute
+ ``swift_error_result`` is not permitted.
+- A ``swiftasynccall`` function must have return type ``void``.
+- Within a ``swiftasynccall`` function, a call to a ``swiftasynccall``
+ function that is the immediate operand of a ``return`` statement is
+ guaranteed to be performed as a tail call. This syntax is allowed even
+ in C as an extension (a call to a void-returning function cannot be a
+ return operand in standard C). If something in the calling function would
+ semantically be performed after a guaranteed tail call, such as the
+ non-trivial destruction of a local variable or temporary,
+ then the program is ill-formed.
+ }];
+}
+
def SwiftAsyncContextDocs : Documentation {
let Category = DocCatVariable;
let Content = [{
-The ``swift_async_context`` attribute marks a parameter as having the
-special asynchronous context-parameter ABI treatment.
+The ``swift_async_context`` attribute marks a parameter of a ``swiftasynccall``
+function as having the special asynchronous context-parameter ABI treatment.
-This treatment generally passes the context value in a special register
-which is normally callee-preserved.
+If the function is not ``swiftasynccall``, this attribute only generates
+extended frame information.
A context parameter must have pointer or reference type.
}];
@@ -4592,7 +4618,8 @@ def SwiftIndirectResultDocs : Documentation {
let Category = DocCatVariable;
let Content = [{
The ``swift_indirect_result`` attribute marks a parameter of a ``swiftcall``
-function as having the special indirect-result ABI treatment.
+or ``swiftasynccall`` function as having the special indirect-result ABI
+treatment.
This treatment gives the parameter the target's normal indirect-result
ABI treatment, which may involve passing it
diff erently from an ordinary
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index a9d738895033..c8d848b41d35 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3154,7 +3154,8 @@ def warn_nsdictionary_duplicate_key : Warning<
def note_nsdictionary_duplicate_key_here : Note<
"previous equal key is here">;
def err_swift_param_attr_not_swiftcall : Error<
- "'%0' parameter can only be used with swiftcall calling convention">;
+ "'%0' parameter can only be used with swiftcall%select{ or swiftasynccall|}1 "
+ "calling convention%select{|s}1">;
def err_swift_indirect_result_not_first : Error<
"'swift_indirect_result' parameters must be first parameters of function">;
def err_swift_error_result_not_after_swift_context : Error<
diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def
index 592e3e33baf1..6ca0e646b865 100644
--- a/clang/include/clang/Basic/Features.def
+++ b/clang/include/clang/Basic/Features.def
@@ -93,6 +93,9 @@ FEATURE(memory_sanitizer,
FEATURE(thread_sanitizer, LangOpts.Sanitize.has(SanitizerKind::Thread))
FEATURE(dataflow_sanitizer, LangOpts.Sanitize.has(SanitizerKind::DataFlow))
FEATURE(scudo, LangOpts.Sanitize.hasOneOf(SanitizerKind::Scudo))
+FEATURE(swiftasynccc,
+ PP.getTargetInfo().checkCallingConvention(CC_SwiftAsync) ==
+ clang::TargetInfo::CCCR_OK)
// Objective-C features
FEATURE(objc_arr, LangOpts.ObjCAutoRefCount) // FIXME: REMOVE?
FEATURE(objc_arc, LangOpts.ObjCAutoRefCount)
diff --git a/clang/include/clang/Basic/Specifiers.h b/clang/include/clang/Basic/Specifiers.h
index bd5a4d6fb8d9..1c38b411e083 100644
--- a/clang/include/clang/Basic/Specifiers.h
+++ b/clang/include/clang/Basic/Specifiers.h
@@ -266,6 +266,7 @@ namespace clang {
CC_SpirFunction, // default for OpenCL functions on SPIR target
CC_OpenCLKernel, // inferred for OpenCL kernels
CC_Swift, // __attribute__((swiftcall))
+ CC_SwiftAsync, // __attribute__((swiftasynccall))
CC_PreserveMost, // __attribute__((preserve_most))
CC_PreserveAll, // __attribute__((preserve_all))
CC_AArch64VectorCall, // __attribute__((aarch64_vector_pcs))
@@ -284,6 +285,7 @@ namespace clang {
case CC_SpirFunction:
case CC_OpenCLKernel:
case CC_Swift:
+ case CC_SwiftAsync:
return false;
default:
return true;
diff --git a/clang/include/clang/CodeGen/SwiftCallingConv.h b/clang/include/clang/CodeGen/SwiftCallingConv.h
index 2c5e9a6de7e2..b1a638a58a09 100644
--- a/clang/include/clang/CodeGen/SwiftCallingConv.h
+++ b/clang/include/clang/CodeGen/SwiftCallingConv.h
@@ -6,7 +6,8 @@
//
//===----------------------------------------------------------------------===//
//
-// Defines constants and types related to Swift ABI lowering.
+// Defines constants and types related to Swift ABI lowering. The same ABI
+// lowering applies to both sync and async functions.
//
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp
index 26844f412f36..c98cfd74dab0 100644
--- a/clang/lib/AST/ExprCXX.cpp
+++ b/clang/lib/AST/ExprCXX.cpp
@@ -671,6 +671,7 @@ CXXMethodDecl *CXXMemberCallExpr::getMethodDecl() const {
return cast<CXXMethodDecl>(MemExpr->getMemberDecl());
// FIXME: Will eventually need to cope with member pointers.
+ // NOTE: Update makeTailCallIfSwiftAsync on fixing this.
return nullptr;
}
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index c40916308611..8cbac66fcf00 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -3106,6 +3106,8 @@ StringRef CXXNameMangler::getCallingConvQualifierName(CallingConv CC) {
return "ms_abi";
case CC_Swift:
return "swiftcall";
+ case CC_SwiftAsync:
+ return "swiftasynccall";
}
llvm_unreachable("bad calling convention");
}
diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp
index 3176077804fc..fe10ce5bc0ef 100644
--- a/clang/lib/AST/MicrosoftMangle.cpp
+++ b/clang/lib/AST/MicrosoftMangle.cpp
@@ -2728,6 +2728,8 @@ void MicrosoftCXXNameMangler::mangleCallingConvention(CallingConv CC) {
// ::= J # __export __fastcall
// ::= Q # __vectorcall
// ::= S # __attribute__((__swiftcall__)) // Clang-only
+ // ::= T # __attribute__((__swiftasynccall__))
+ // // Clang-only
// ::= w # __regcall
// The 'export' calling conventions are from a bygone era
// (*cough*Win16*cough*) when functions were declared for export with
@@ -2747,6 +2749,7 @@ void MicrosoftCXXNameMangler::mangleCallingConvention(CallingConv CC) {
case CC_X86FastCall: Out << 'I'; break;
case CC_X86VectorCall: Out << 'Q'; break;
case CC_Swift: Out << 'S'; break;
+ case CC_SwiftAsync: Out << 'T'; break;
case CC_PreserveMost: Out << 'U'; break;
case CC_X86RegCall: Out << 'w'; break;
}
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index d58cb43b6e7b..d3d0003e5adb 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -3142,6 +3142,7 @@ StringRef FunctionType::getNameForCallConv(CallingConv CC) {
case CC_SpirFunction: return "spir_function";
case CC_OpenCLKernel: return "opencl_kernel";
case CC_Swift: return "swiftcall";
+ case CC_SwiftAsync: return "swiftasynccall";
case CC_PreserveMost: return "preserve_most";
case CC_PreserveAll: return "preserve_all";
}
@@ -3558,6 +3559,7 @@ bool AttributedType::isCallingConv() const {
case attr::ThisCall:
case attr::RegCall:
case attr::SwiftCall:
+ case attr::SwiftAsyncCall:
case attr::VectorCall:
case attr::AArch64VectorPcs:
case attr::Pascal:
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index 47e48506dc96..a866ca978bc8 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -976,6 +976,9 @@ void TypePrinter::printFunctionAfter(const FunctionType::ExtInfo &Info,
case CC_Swift:
OS << " __attribute__((swiftcall))";
break;
+ case CC_SwiftAsync:
+ OS << "__attribute__((swiftasynccall))";
+ break;
case CC_PreserveMost:
OS << " __attribute__((preserve_most))";
break;
@@ -1706,6 +1709,7 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
case attr::StdCall: OS << "stdcall"; break;
case attr::ThisCall: OS << "thiscall"; break;
case attr::SwiftCall: OS << "swiftcall"; break;
+ case attr::SwiftAsyncCall: OS << "swiftasynccall"; break;
case attr::VectorCall: OS << "vectorcall"; break;
case attr::Pascal: OS << "pascal"; break;
case attr::MSABI: OS << "ms_abi"; break;
diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp
index 82273a5e97ae..4070ac727d16 100644
--- a/clang/lib/Basic/Targets/AArch64.cpp
+++ b/clang/lib/Basic/Targets/AArch64.cpp
@@ -576,6 +576,7 @@ AArch64TargetInfo::checkCallingConvention(CallingConv CC) const {
switch (CC) {
case CC_C:
case CC_Swift:
+ case CC_SwiftAsync:
case CC_PreserveMost:
case CC_PreserveAll:
case CC_OpenCLKernel:
@@ -850,6 +851,7 @@ WindowsARM64TargetInfo::checkCallingConvention(CallingConv CC) const {
case CC_PreserveMost:
case CC_PreserveAll:
case CC_Swift:
+ case CC_SwiftAsync:
case CC_Win64:
return CCCR_OK;
default:
diff --git a/clang/lib/Basic/Targets/ARM.cpp b/clang/lib/Basic/Targets/ARM.cpp
index 12439fcbeff9..0e4048f8d5ff 100644
--- a/clang/lib/Basic/Targets/ARM.cpp
+++ b/clang/lib/Basic/Targets/ARM.cpp
@@ -1138,6 +1138,7 @@ ARMTargetInfo::checkCallingConvention(CallingConv CC) const {
case CC_AAPCS:
case CC_AAPCS_VFP:
case CC_Swift:
+ case CC_SwiftAsync:
case CC_OpenCLKernel:
return CCCR_OK;
default:
@@ -1217,6 +1218,7 @@ WindowsARMTargetInfo::checkCallingConvention(CallingConv CC) const {
case CC_PreserveMost:
case CC_PreserveAll:
case CC_Swift:
+ case CC_SwiftAsync:
return CCCR_OK;
default:
return CCCR_Warning;
diff --git a/clang/lib/Basic/Targets/PPC.h b/clang/lib/Basic/Targets/PPC.h
index 18ee1194c759..bd79c68ce3f7 100644
--- a/clang/lib/Basic/Targets/PPC.h
+++ b/clang/lib/Basic/Targets/PPC.h
@@ -454,6 +454,8 @@ class LLVM_LIBRARY_VISIBILITY PPC64TargetInfo : public PPCTargetInfo {
switch (CC) {
case CC_Swift:
return CCCR_OK;
+ case CC_SwiftAsync:
+ return CCCR_Error;
default:
return CCCR_Warning;
}
diff --git a/clang/lib/Basic/Targets/SystemZ.h b/clang/lib/Basic/Targets/SystemZ.h
index 39fdcf90d0c8..1cbc4902d4e7 100644
--- a/clang/lib/Basic/Targets/SystemZ.h
+++ b/clang/lib/Basic/Targets/SystemZ.h
@@ -143,6 +143,8 @@ class LLVM_LIBRARY_VISIBILITY SystemZTargetInfo : public TargetInfo {
case CC_Swift:
case CC_OpenCLKernel:
return CCCR_OK;
+ case CC_SwiftAsync:
+ return CCCR_Error;
default:
return CCCR_Warning;
}
diff --git a/clang/lib/Basic/Targets/WebAssembly.h b/clang/lib/Basic/Targets/WebAssembly.h
index b29730c5d706..c3e5d7e572c3 100644
--- a/clang/lib/Basic/Targets/WebAssembly.h
+++ b/clang/lib/Basic/Targets/WebAssembly.h
@@ -129,6 +129,8 @@ class LLVM_LIBRARY_VISIBILITY WebAssemblyTargetInfo : public TargetInfo {
case CC_C:
case CC_Swift:
return CCCR_OK;
+ case CC_SwiftAsync:
+ return CCCR_Error;
default:
return CCCR_Warning;
}
diff --git a/clang/lib/Basic/Targets/X86.h b/clang/lib/Basic/Targets/X86.h
index e798962617a3..fcaaf50624e9 100644
--- a/clang/lib/Basic/Targets/X86.h
+++ b/clang/lib/Basic/Targets/X86.h
@@ -357,6 +357,8 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo {
case CC_IntelOclBicc:
case CC_OpenCLKernel:
return CCCR_OK;
+ case CC_SwiftAsync:
+ return CCCR_Error;
default:
return CCCR_Warning;
}
@@ -717,6 +719,7 @@ class LLVM_LIBRARY_VISIBILITY X86_64TargetInfo : public X86TargetInfo {
switch (CC) {
case CC_C:
case CC_Swift:
+ case CC_SwiftAsync:
case CC_X86VectorCall:
case CC_IntelOclBicc:
case CC_Win64:
@@ -798,6 +801,7 @@ class LLVM_LIBRARY_VISIBILITY WindowsX86_64TargetInfo
case CC_PreserveAll:
case CC_X86_64SysV:
case CC_Swift:
+ case CC_SwiftAsync:
case CC_X86RegCall:
case CC_OpenCLKernel:
return CCCR_OK;
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 7655902b1a36..47a4ed35be85 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -66,6 +66,7 @@ unsigned CodeGenTypes::ClangCallConvToLLVMCallConv(CallingConv CC) {
case CC_PreserveMost: return llvm::CallingConv::PreserveMost;
case CC_PreserveAll: return llvm::CallingConv::PreserveAll;
case CC_Swift: return llvm::CallingConv::Swift;
+ case CC_SwiftAsync: return llvm::CallingConv::SwiftTail;
}
}
@@ -773,7 +774,7 @@ CodeGenTypes::arrangeLLVMFunctionInfo(CanQualType resultType,
// Force target independent argument handling for the host visible
// kernel functions.
computeSPIRKernelABIInfo(CGM, *FI);
- } else if (info.getCC() == CC_Swift) {
+ } else if (info.getCC() == CC_Swift || info.getCC() == CC_SwiftAsync) {
swiftcall::computeABIInfo(CGM, *FI);
} else {
getABIInfo().computeInfo(*FI);
@@ -4029,11 +4030,11 @@ void CodeGenFunction::EmitNonNullArgCheck(RValue RV, QualType ArgType,
// later, so we can't check it directly.
static bool hasInAllocaArgs(CodeGenModule &CGM, CallingConv ExplicitCC,
ArrayRef<QualType> ArgTypes) {
- // The Swift calling convention doesn't go through the target-specific
- // argument classification, so it never uses inalloca.
+ // The Swift calling conventions don't go through the target-specific
+ // argument classification, they never use inalloca.
// TODO: Consider limiting inalloca use to only calling conventions supported
// by MSVC.
- if (ExplicitCC == CC_Swift)
+ if (ExplicitCC == CC_Swift || ExplicitCC == CC_SwiftAsync)
return false;
if (!CGM.getTarget().getCXXABI().isMicrosoft())
return false;
diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp
index 0363fd7023f3..adace59c9ee6 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -1314,6 +1314,9 @@ static unsigned getDwarfCC(CallingConv CC) {
return llvm::dwarf::DW_CC_LLVM_OpenCLKernel;
case CC_Swift:
return llvm::dwarf::DW_CC_LLVM_Swift;
+ case CC_SwiftAsync:
+ // [FIXME: swiftasynccc] Update to SwiftAsync once LLVM support lands.
+ return llvm::dwarf::DW_CC_LLVM_Swift;
case CC_PreserveMost:
return llvm::dwarf::DW_CC_LLVM_PreserveMost;
case CC_PreserveAll:
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index 85390f2b1464..6f6dcfa58a7f 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -1176,6 +1176,38 @@ struct SaveRetExprRAII {
};
} // namespace
+/// If we have 'return f(...);', where both caller and callee are SwiftAsync,
+/// codegen it as 'tail call ...; ret void;'.
+static void makeTailCallIfSwiftAsync(const CallExpr *CE, CGBuilderTy &Builder,
+ const CGFunctionInfo *CurFnInfo) {
+ auto calleeQualType = CE->getCallee()->getType();
+ const FunctionType *calleeType = nullptr;
+ if (calleeQualType->isFunctionPointerType() ||
+ calleeQualType->isFunctionReferenceType() ||
+ calleeQualType->isBlockPointerType() ||
+ calleeQualType->isMemberFunctionPointerType()) {
+ calleeType = calleeQualType->getPointeeType()->castAs<FunctionType>();
+ } else if (auto *ty = dyn_cast<FunctionType>(calleeQualType)) {
+ calleeType = ty;
+ } else if (auto CMCE = dyn_cast<CXXMemberCallExpr>(CE)) {
+ if (auto methodDecl = CMCE->getMethodDecl()) {
+ // getMethodDecl() doesn't handle member pointers at the moment.
+ calleeType = methodDecl->getType()->castAs<FunctionType>();
+ } else {
+ return;
+ }
+ } else {
+ return;
+ }
+ if (calleeType->getCallConv() == CallingConv::CC_SwiftAsync &&
+ (CurFnInfo->getASTCallingConvention() == CallingConv::CC_SwiftAsync)) {
+ auto CI = cast<llvm::CallInst>(&Builder.GetInsertBlock()->back());
+ CI->setTailCallKind(llvm::CallInst::TCK_MustTail);
+ Builder.CreateRetVoid();
+ Builder.ClearInsertionPoint();
+ }
+}
+
/// EmitReturnStmt - Note that due to GCC extensions, this can have an operand
/// if the function returns void, or may be missing one if the function returns
/// non-void. Fun stuff :).
@@ -1234,8 +1266,11 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
} else if (!ReturnValue.isValid() || (RV && RV->getType()->isVoidType())) {
// Make sure not to return anything, but evaluate the expression
// for side effects.
- if (RV)
+ if (RV) {
EmitAnyExpr(RV);
+ if (auto *CE = dyn_cast<CallExpr>(RV))
+ makeTailCallIfSwiftAsync(CE, Builder, CurFnInfo);
+ }
} else if (!RV) {
// Do nothing (return value is left uninitialized)
} else if (FnRetTy->isReferenceType()) {
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 0741b5f6fda9..5db74630de79 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -4561,6 +4561,9 @@ static void handleCallConvAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
case ParsedAttr::AT_SwiftCall:
D->addAttr(::new (S.Context) SwiftCallAttr(S.Context, AL));
return;
+ case ParsedAttr::AT_SwiftAsyncCall:
+ D->addAttr(::new (S.Context) SwiftAsyncCallAttr(S.Context, AL));
+ return;
case ParsedAttr::AT_VectorCall:
D->addAttr(::new (S.Context) VectorCallAttr(S.Context, AL));
return;
@@ -4725,6 +4728,9 @@ bool Sema::CheckCallingConvAttr(const ParsedAttr &Attrs, CallingConv &CC,
case ParsedAttr::AT_SwiftCall:
CC = CC_Swift;
break;
+ case ParsedAttr::AT_SwiftAsyncCall:
+ CC = CC_SwiftAsync;
+ break;
case ParsedAttr::AT_VectorCall:
CC = CC_X86VectorCall;
break;
@@ -8101,6 +8107,7 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_Pascal:
case ParsedAttr::AT_RegCall:
case ParsedAttr::AT_SwiftCall:
+ case ParsedAttr::AT_SwiftAsyncCall:
case ParsedAttr::AT_VectorCall:
case ParsedAttr::AT_MSABI:
case ParsedAttr::AT_SysVABI:
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index ef0320fb26f8..b78331cdfe91 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -117,6 +117,7 @@ static void diagnoseBadTypeAttribute(Sema &S, const ParsedAttr &attr,
case ParsedAttr::AT_RegCall: \
case ParsedAttr::AT_Pascal: \
case ParsedAttr::AT_SwiftCall: \
+ case ParsedAttr::AT_SwiftAsyncCall: \
case ParsedAttr::AT_VectorCall: \
case ParsedAttr::AT_AArch64VectorPcs: \
case ParsedAttr::AT_MSABI: \
@@ -2780,16 +2781,21 @@ static void checkExtParameterInfos(Sema &S, ArrayRef<QualType> paramTypes,
llvm::function_ref<SourceLocation(unsigned)> getParamLoc) {
assert(EPI.ExtParameterInfos && "shouldn't get here without param infos");
- bool hasCheckedSwiftCall = false;
- auto checkForSwiftCC = [&](unsigned paramIndex) {
- // Only do this once.
- if (hasCheckedSwiftCall) return;
- hasCheckedSwiftCall = true;
- if (EPI.ExtInfo.getCC() == CC_Swift) return;
+ bool emittedError = false;
+ auto actualCC = EPI.ExtInfo.getCC();
+ enum class RequiredCC { OnlySwift, SwiftOrSwiftAsync };
+ auto checkCompatible = [&](unsigned paramIndex, RequiredCC required) {
+ bool isCompatible =
+ (required == RequiredCC::OnlySwift)
+ ? (actualCC == CC_Swift)
+ : (actualCC == CC_Swift || actualCC == CC_SwiftAsync);
+ if (isCompatible || emittedError)
+ return;
S.Diag(getParamLoc(paramIndex), diag::err_swift_param_attr_not_swiftcall)
- << getParameterABISpelling(EPI.ExtParameterInfos[paramIndex].getABI());
+ << getParameterABISpelling(EPI.ExtParameterInfos[paramIndex].getABI())
+ << (required == RequiredCC::OnlySwift);
+ emittedError = true;
};
-
for (size_t paramIndex = 0, numParams = paramTypes.size();
paramIndex != numParams; ++paramIndex) {
switch (EPI.ExtParameterInfos[paramIndex].getABI()) {
@@ -2800,7 +2806,7 @@ static void checkExtParameterInfos(Sema &S, ArrayRef<QualType> paramTypes,
// swift_indirect_result parameters must be a prefix of the function
// arguments.
case ParameterABI::SwiftIndirectResult:
- checkForSwiftCC(paramIndex);
+ checkCompatible(paramIndex, RequiredCC::SwiftOrSwiftAsync);
if (paramIndex != 0 &&
EPI.ExtParameterInfos[paramIndex - 1].getABI()
!= ParameterABI::SwiftIndirectResult) {
@@ -2810,16 +2816,16 @@ static void checkExtParameterInfos(Sema &S, ArrayRef<QualType> paramTypes,
continue;
case ParameterABI::SwiftContext:
- checkForSwiftCC(paramIndex);
+ checkCompatible(paramIndex, RequiredCC::SwiftOrSwiftAsync);
continue;
+ // SwiftAsyncContext is not limited to swiftasynccall functions.
case ParameterABI::SwiftAsyncContext:
- // FIXME: might want to require swiftasynccc when it exists
continue;
// swift_error parameters must be preceded by a swift_context parameter.
case ParameterABI::SwiftErrorResult:
- checkForSwiftCC(paramIndex);
+ checkCompatible(paramIndex, RequiredCC::OnlySwift);
if (paramIndex == 0 ||
EPI.ExtParameterInfos[paramIndex - 1].getABI() !=
ParameterABI::SwiftContext) {
@@ -7361,6 +7367,8 @@ static Attr *getCCTypeAttr(ASTContext &Ctx, ParsedAttr &Attr) {
return createSimpleAttr<PascalAttr>(Ctx, Attr);
case ParsedAttr::AT_SwiftCall:
return createSimpleAttr<SwiftCallAttr>(Ctx, Attr);
+ case ParsedAttr::AT_SwiftAsyncCall:
+ return createSimpleAttr<SwiftAsyncCallAttr>(Ctx, Attr);
case ParsedAttr::AT_VectorCall:
return createSimpleAttr<VectorCallAttr>(Ctx, Attr);
case ParsedAttr::AT_AArch64VectorPcs:
diff --git a/clang/test/CodeGen/64bit-swiftcall.c b/clang/test/CodeGen/64bit-swiftcall.c
index b8b1e56b1b17..dd9abc957bd0 100644
--- a/clang/test/CodeGen/64bit-swiftcall.c
+++ b/clang/test/CodeGen/64bit-swiftcall.c
@@ -6,9 +6,11 @@
// REQUIRES: aarch64-registered-target,x86-registered-target
#define SWIFTCALL __attribute__((swiftcall))
+#define SWIFTASYNCCALL __attribute__((swiftasynccall))
#define OUT __attribute__((swift_indirect_result))
#define ERROR __attribute__((swift_error_result))
#define CONTEXT __attribute__((swift_context))
+#define ASYNC_CONTEXT __attribute__((swift_async_context))
// CHECK-DAG: %struct.atomic_padded = type { { %struct.packed, [7 x i8] } }
// CHECK-DAG: %struct.packed = type <{ i64, i8 }>
@@ -33,9 +35,15 @@ SWIFTCALL struct_reallybig indirect_result_3(OUT int *arg0, OUT float *arg1) { _
SWIFTCALL void context_1(CONTEXT void *self) {}
// CHECK-LABEL: define {{.*}} void @context_1(i8* swiftself
+SWIFTASYNCCALL void async_context_1(ASYNC_CONTEXT void *ctx) {}
+// CHECK-LABEL: define {{.*}} void @async_context_1(i8* swiftasync
+
SWIFTCALL void context_2(void *arg0, CONTEXT void *self) {}
// CHECK-LABEL: define {{.*}} void @context_2(i8*{{.*}}, i8* swiftself
+SWIFTASYNCCALL void async_context_2(void *arg0, ASYNC_CONTEXT void *ctx) {}
+// CHECK-LABEL: define {{.*}} void @async_context_2(i8*{{.*}}, i8* swiftasync
+
SWIFTCALL void context_error_1(CONTEXT int *self, ERROR float **error) {}
// CHECK-LABEL: define {{.*}} void @context_error_1(i32* swiftself{{.*}}, float** swifterror %0)
// CHECK: [[TEMP:%.*]] = alloca float*, align 8
diff --git a/clang/test/CodeGen/arm-swiftcall.c b/clang/test/CodeGen/arm-swiftcall.c
index f3775e9f4d45..0104ccf2f7d8 100644
--- a/clang/test/CodeGen/arm-swiftcall.c
+++ b/clang/test/CodeGen/arm-swiftcall.c
@@ -3,6 +3,7 @@
// RUN: %clang_cc1 -triple armv7k-apple-ios9 -emit-llvm -o - %s | FileCheck %s
#define SWIFTCALL __attribute__((swiftcall))
+#define SWIFTASYNCCALL __attribute__((swiftasynccall))
#define OUT __attribute__((swift_indirect_result))
#define ERROR __attribute__((swift_error_result))
#define CONTEXT __attribute__((swift_context))
@@ -26,9 +27,15 @@ SWIFTCALL struct_reallybig indirect_result_3(OUT int *arg0, OUT float *arg1) { _
SWIFTCALL void context_1(CONTEXT void *self) {}
// CHECK-LABEL: define{{.*}} void @context_1(i8* swiftself
+SWIFTASYNCCALL void async_context_1(ASYNC_CONTEXT void *self) {}
+// CHECK-LABEL: define{{.*}} void @async_context_1(i8* swiftasync
+
SWIFTCALL void context_2(void *arg0, CONTEXT void *self) {}
// CHECK-LABEL: define{{.*}} void @context_2(i8*{{.*}}, i8* swiftself
+SWIFTASYNCCALL void async_context_2(void *arg0, ASYNC_CONTEXT void *self) {}
+// CHECK-LABEL: define{{.*}} void @async_context_2(i8*{{.*}}, i8* swiftasync
+
SWIFTCALL void context_error_1(CONTEXT int *self, ERROR float **error) {}
// CHECK-LABEL: define{{.*}} void @context_error_1(i32* swiftself{{.*}}, float** swifterror %0)
// CHECK: [[TEMP:%.*]] = alloca float*, align 4
@@ -54,9 +61,6 @@ void test_context_error_1() {
SWIFTCALL void context_error_2(short s, CONTEXT int *self, ERROR float **error) {}
// CHECK-LABEL: define{{.*}} void @context_error_2(i16{{.*}}, i32* swiftself{{.*}}, float** swifterror %0)
-SWIFTCALL void async_context_1(ASYNC_CONTEXT void *self) {}
-// CHECK-LABEL: define {{.*}} void @async_context_1(i8* swiftasync
-
/*****************************************************************************/
/********************************** LOWERING *********************************/
/*****************************************************************************/
diff --git a/clang/test/CodeGen/debug-info-cc.c b/clang/test/CodeGen/debug-info-cc.c
index fe158550a627..a64515e31d1a 100644
--- a/clang/test/CodeGen/debug-info-cc.c
+++ b/clang/test/CodeGen/debug-info-cc.c
@@ -19,6 +19,7 @@
// CC_SpirFunction, // default for OpenCL functions on SPIR target
// CC_OpenCLKernel, // inferred for OpenCL kernels
// CC_Swift, // __attribute__((swiftcall))
+// CC_SwiftAsync, // __attribute__((swiftasynccall))
// CC_PreserveMost, // __attribute__((preserve_most))
// CC_PreserveAll, // __attribute__((preserve_all))
// };
@@ -56,6 +57,13 @@ __attribute__((swiftcall)) int add_swiftcall(int a, int b) {
return a+b;
}
+// [FIXME: swiftasynccc] Update debuginfo tag to SwiftAsync once LLVM support lands.
+// LINUX: !DISubprogram({{.*}}"add_swiftasynccall", {{.*}}type: ![[FTY:[0-9]+]]
+// LINUX: ![[FTY]] = !DISubroutineType({{.*}}cc: DW_CC_LLVM_Swift,
+__attribute__((swiftasynccall)) int add_swiftasynccall(int a, int b, int c) {
+ return a+b+c;
+}
+
// LINUX: !DISubprogram({{.*}}"add_inteloclbicc", {{.*}}type: ![[FTY:[0-9]+]]
// LINUX: ![[FTY]] = !DISubroutineType({{.*}}cc: DW_CC_LLVM_IntelOclBicc,
__attribute__((intel_ocl_bicc)) int add_inteloclbicc(int a, int b) {
diff --git a/clang/test/CodeGen/swift-async-call-conv.c b/clang/test/CodeGen/swift-async-call-conv.c
new file mode 100644
index 000000000000..2e261f14183e
--- /dev/null
+++ b/clang/test/CodeGen/swift-async-call-conv.c
@@ -0,0 +1,184 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -target-cpu core2 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple arm64-apple-ios9 -target-cpu cyclone -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple armv7-apple-darwin9 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple armv7s-apple-ios9 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple armv7k-apple-ios9 -emit-llvm -o - %s | FileCheck %s
+
+// RUN: %clang_cc1 -x c++ -triple x86_64-apple-darwin10 -target-cpu core2 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=CPPONLY
+// RUN: %clang_cc1 -x c++ -triple arm64-apple-ios9 -target-cpu cyclone -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=CPPONLY
+// RUN: %clang_cc1 -x c++ -triple armv7-apple-darwin9 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=CPPONLY
+// RUN: %clang_cc1 -x c++ -triple armv7s-apple-ios9 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=CPPONLY
+// RUN: %clang_cc1 -x c++ -triple armv7k-apple-ios9 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=CPPONLY
+
+// Test tail call behavior when a swiftasynccall function is called
+// from another swiftasynccall function.
+
+#define SWIFTCALL __attribute__((swiftcall))
+#define SWIFTASYNCCALL __attribute__((swiftasynccall))
+#define ASYNC_CONTEXT __attribute__((swift_async_context))
+
+// CHECK-LABEL: swifttailcc void {{.*}}async_leaf1{{.*}}(i8* swiftasync
+SWIFTASYNCCALL void async_leaf1(char * ASYNC_CONTEXT ctx) {
+ *ctx += 1;
+}
+
+// CHECK-LABEL: swifttailcc void {{.*}}async_leaf2{{.*}}(i8* swiftasync
+SWIFTASYNCCALL void async_leaf2(char * ASYNC_CONTEXT ctx) {
+ *ctx += 2;
+}
+
+#if __cplusplus
+ #define MYBOOL bool
+#else
+ #define MYBOOL _Bool
+#endif
+
+// CHECK-LABEL: swifttailcc void {{.*}}async_branch{{.*}}i8* swiftasync
+// CHECK: musttail call swifttailcc void @{{.*}}async_leaf1
+// CHECK-NEXT: ret void
+// CHECK: musttail call swifttailcc void @{{.*}}async_leaf2
+// CHECK-NEXT: ret void
+SWIFTASYNCCALL void async_branch(MYBOOL b, char * ASYNC_CONTEXT ctx) {
+ if (b) {
+ return async_leaf1(ctx);
+ } else {
+ return async_leaf2(ctx);
+ }
+}
+
+// CHECK-LABEL: swifttailcc void {{.*}}async_not_all_tail
+// CHECK-NOT: musttail call swifttailcc void @{{.*}}async_leaf1
+// CHECK: call swifttailcc void @{{.*}}async_leaf1
+// CHECK-NOT: ret void
+// CHECK: musttail call swifttailcc void @{{.*}}async_leaf2
+// CHECK-NEXT: ret void
+SWIFTASYNCCALL void async_not_all_tail(char * ASYNC_CONTEXT ctx) {
+ async_leaf1(ctx);
+ return async_leaf2(ctx);
+}
+
+// CHECK-LABEL: swifttailcc void {{.*}}async_loop
+// CHECK: musttail call swifttailcc void @{{.*}}async_leaf1
+// CHECK-NEXT: ret void
+// CHECK: musttail call swifttailcc void @{{.*}}async_leaf2
+// CHECK-NEXT: ret void
+// CHECK: musttail call swifttailcc void @{{.*}}async_loop
+// CHECK-NEXT: ret void
+SWIFTASYNCCALL void async_loop(unsigned u, char * ASYNC_CONTEXT ctx) {
+ if (u == 0) {
+ return async_leaf1(ctx);
+ } else if (u == 1) {
+ return async_leaf2(ctx);
+ }
+ return async_loop(u - 2, ctx);
+}
+
+// Forward-declaration + mutual recursion is okay.
+
+SWIFTASYNCCALL void async_mutual_loop2(unsigned u, char * ASYNC_CONTEXT ctx);
+
+// CHECK-LABEL: swifttailcc void {{.*}}async_mutual_loop1
+// CHECK: musttail call swifttailcc void @{{.*}}async_leaf1
+// CHECK-NEXT: ret void
+// CHECK: musttail call swifttailcc void @{{.*}}async_leaf2
+// CHECK-NEXT: ret void
+// There is some bugginess around FileCheck's greediness/matching,
+// so skipping the check for async_mutual_loop2 here.
+SWIFTASYNCCALL void async_mutual_loop1(unsigned u, char * ASYNC_CONTEXT ctx) {
+ if (u == 0) {
+ return async_leaf1(ctx);
+ } else if (u == 1) {
+ return async_leaf2(ctx);
+ }
+ return async_mutual_loop2(u - 2, ctx);
+}
+
+// CHECK-LABEL: swifttailcc void {{.*}}async_mutual_loop2
+// CHECK: musttail call swifttailcc void @{{.*}}async_leaf1
+// CHECK-NEXT: ret void
+// CHECK: musttail call swifttailcc void @{{.*}}async_leaf2
+// CHECK-NEXT: ret void
+// CHECK: musttail call swifttailcc void @{{.*}}async_mutual_loop1
+// CHECK-NEXT: ret void
+SWIFTASYNCCALL void async_mutual_loop2(unsigned u, char * ASYNC_CONTEXT ctx) {
+ if (u == 0) {
+ return async_leaf1(ctx);
+ } else if (u == 1) {
+ return async_leaf2(ctx);
+ }
+ return async_mutual_loop1(u - 2, ctx);
+}
+
+// When swiftasynccall functions are called by non-swiftasynccall functions,
+// the call isn't marked as a tail call.
+
+// CHECK-LABEL: swiftcc i8 {{.*}}sync_calling_async
+// CHECK-NOT: tail call
+// CHECK: call swifttailcc void @{{.*}}async_branch
+// CHECK-NOT: tail call
+// CHECK: call swifttailcc void @{{.*}}async_loop
+SWIFTCALL char sync_calling_async(MYBOOL b, unsigned u) {
+ char x = 'a';
+ async_branch(b, &x);
+ async_loop(u, &x);
+ return x;
+}
+
+// CHECK-LABEL: i8 {{.*}}c_calling_async
+// CHECK-NOT: tail call
+// CHECK: call swifttailcc void @{{.*}}async_branch
+// CHECK-NOT: tail call
+// CHECK: call swifttailcc void @{{.*}}async_loop
+char c_calling_async(MYBOOL b, unsigned u) {
+ char x = 'a';
+ async_branch(b, &x);
+ async_loop(u, &x);
+ return x;
+}
+
+#if __cplusplus
+struct S {
+ SWIFTASYNCCALL void (*fptr)(char * ASYNC_CONTEXT);
+
+ SWIFTASYNCCALL void async_leaf_method(char * ASYNC_CONTEXT ctx) {
+ *ctx += 1;
+ }
+ SWIFTASYNCCALL void async_nonleaf_method1(char * ASYNC_CONTEXT ctx) {
+ return async_leaf_method(ctx);
+ }
+ SWIFTASYNCCALL void async_nonleaf_method2(char * ASYNC_CONTEXT ctx) {
+ return this->async_leaf_method(ctx);
+ }
+};
+
+SWIFTASYNCCALL void (S::*async_leaf_method_ptr)(char * ASYNC_CONTEXT) = &S::async_leaf_method;
+
+// CPPONLY-LABEL: swifttailcc void {{.*}}async_struct_field_and_methods
+// CPPONLY: musttail call swifttailcc void %{{[0-9]+}}
+// CPPONLY: musttail call swifttailcc void @{{.*}}async_nonleaf_method1
+// CPPONLY: musttail call swifttailcc void %{{[0-9]+}}
+// CPPONLY: musttail call swifttailcc void @{{.*}}async_nonleaf_method2
+// CPPONLY-NOT: musttail call swifttailcc void @{{.*}}async_leaf_method
+// ^ TODO: Member pointers should also work.
+SWIFTASYNCCALL void async_struct_field_and_methods(int i, S &sref, S *sptr) {
+ char x = 'a';
+ if (i == 0) {
+ return (*sref.fptr)(&x);
+ } else if (i == 1) {
+ return sref.async_nonleaf_method1(&x);
+ } else if (i == 2) {
+ return (*(sptr->fptr))(&x);
+ } else if (i == 3) {
+ return sptr->async_nonleaf_method2(&x);
+ } else if (i == 4) {
+ return (sref.*async_leaf_method_ptr)(&x);
+ }
+ return (sptr->*async_leaf_method_ptr)(&x);
+}
+
+// CPPONLY-LABEL: define{{.*}} swifttailcc void @{{.*}}async_nonleaf_method1
+// CPPONLY: musttail call swifttailcc void @{{.*}}async_leaf_method
+
+// CPPONLY-LABEL: define{{.*}} swifttailcc void @{{.*}}async_nonleaf_method2
+// CPPONLY: musttail call swifttailcc void @{{.*}}async_leaf_method
+#endif
diff --git a/clang/test/CodeGen/swift-call-conv.c b/clang/test/CodeGen/swift-call-conv.c
index 31d70b33a498..c5972541b4b1 100644
--- a/clang/test/CodeGen/swift-call-conv.c
+++ b/clang/test/CodeGen/swift-call-conv.c
@@ -1,5 +1,4 @@
// RUN: %clang_cc1 -triple aarch64-unknown-windows-msvc -emit-llvm %s -o - | FileCheck %s
-// RUN: %clang_cc1 -triple thumbv7-unknown-windows-msvc -emit-llvm %s -o - | FileCheck %s
// RUN: %clang_cc1 -triple x86_64-unknown-windows-msvc -emit-llvm %s -o - | FileCheck %s
// REQUIRES: aarch64-registered-target,arm-registered-target,x86-registered-target
@@ -7,3 +6,5 @@
void __attribute__((__swiftcall__)) f(void) {}
// CHECK-LABEL: define dso_local swiftcc void @f()
+void __attribute__((__swiftasynccall__)) f_async(void) {}
+// CHECK-LABEL: define dso_local swifttailcc void @f_async()
diff --git a/clang/test/Sema/attr-c2x.c b/clang/test/Sema/attr-c2x.c
index 016b1f58e3a7..9662220d383e 100644
--- a/clang/test/Sema/attr-c2x.c
+++ b/clang/test/Sema/attr-c2x.c
@@ -16,6 +16,8 @@ enum [[clang::flag_enum]] EnumFlag {
void context_okay(void *context [[clang::swift_context]]) [[clang::swiftcall]];
void context_okay2(void *context [[clang::swift_context]], void *selfType, char **selfWitnessTable) [[clang::swiftcall]];
+void context_async_okay(void *context [[clang::swift_async_context]]) [[clang::swiftasynccall]];
+void context_async_okay2(void *context [[clang::swift_async_context]], void *selfType, char **selfWitnessTable) [[clang::swiftasynccall]];
[[clang::ownership_returns(foo)]] void *f1(void);
[[clang::ownership_returns(foo)]] void *f2(); // expected-warning {{'ownership_returns' attribute only applies to non-K&R-style functions}}
diff --git a/clang/test/Sema/attr-swiftcall.c b/clang/test/Sema/attr-swiftcall.c
index a29fe0e94b43..71f811f23883 100644
--- a/clang/test/Sema/attr-swiftcall.c
+++ b/clang/test/Sema/attr-swiftcall.c
@@ -2,22 +2,30 @@
// RUN: %clang_cc1 -triple x86_64-unknown-windows -fsyntax-only -verify %s
#define SWIFTCALL __attribute__((swiftcall))
+#define SWIFTASYNCCALL __attribute__((swiftasynccall))
#define INDIRECT_RESULT __attribute__((swift_indirect_result))
#define ERROR_RESULT __attribute__((swift_error_result))
#define CONTEXT __attribute__((swift_context))
#define ASYNC_CONTEXT __attribute__((swift_async_context))
int notAFunction SWIFTCALL; // expected-warning {{'swiftcall' only applies to function types; type here is 'int'}}
+int notAnAsyncFunction SWIFTASYNCCALL; // expected-warning {{'swiftasynccall' only applies to function types; type here is 'int'}}
void variadic(int x, ...) SWIFTCALL; // expected-error {{variadic function cannot use swiftcall calling convention}}
+void variadic_async(int x, ...) SWIFTASYNCCALL; // expected-error {{variadic function cannot use swiftasynccall calling convention}}
void unprototyped() SWIFTCALL; // expected-error {{function with no prototype cannot use the swiftcall calling convention}}
+void unprototyped_async() SWIFTASYNCCALL; // expected-error {{function with no prototype cannot use the swiftasynccall calling convention}}
void multiple_ccs(int x) SWIFTCALL __attribute__((vectorcall)); // expected-error {{vectorcall and swiftcall attributes are not compatible}}
+void multiple_ccs_async(int x) SWIFTASYNCCALL __attribute__((vectorcall)); // expected-error {{vectorcall and swiftasynccall attributes are not compatible}}
void (*functionPointer)(void) SWIFTCALL;
+void (*asyncFunctionPointer)(void) SWIFTASYNCCALL;
-void indirect_result_nonswift(INDIRECT_RESULT void *out); // expected-error {{'swift_indirect_result' parameter can only be used with swiftcall calling convention}}
+void indirect_result_nonswift(INDIRECT_RESULT void *out); // expected-error {{'swift_indirect_result' parameter can only be used with swiftcall or swiftasynccall calling convention}}
void indirect_result_bad_position(int first, INDIRECT_RESULT void *out) SWIFTCALL; // expected-error {{'swift_indirect_result' parameters must be first parameters of function}}
void indirect_result_bad_type(INDIRECT_RESULT int out) SWIFTCALL; // expected-error {{'swift_indirect_result' parameter must have pointer type; type here is 'int'}}
void indirect_result_single(INDIRECT_RESULT void *out) SWIFTCALL;
void indirect_result_multiple(INDIRECT_RESULT void *out1, INDIRECT_RESULT void *out2) SWIFTCALL;
+void indirect_result_single_async(INDIRECT_RESULT void *out) SWIFTASYNCCALL;
+void indirect_result_multiple_async(INDIRECT_RESULT void *out1, INDIRECT_RESULT void *out2) SWIFTASYNCCALL;
void error_result_nonswift(ERROR_RESULT void **error); // expected-error {{'swift_error_result' parameter can only be used with swiftcall calling convention}} expected-error{{'swift_error_result' parameter must follow 'swift_context' parameter}}
void error_result_bad_position2(int first, ERROR_RESULT void **error) SWIFTCALL; // expected-error {{'swift_error_result' parameter must follow 'swift_context' parameter}}
@@ -26,10 +34,12 @@ void error_result_bad_type2(CONTEXT void *context, ERROR_RESULT int *error) SWIF
void error_result_okay(int a, int b, CONTEXT void *context, ERROR_RESULT void **error) SWIFTCALL;
void error_result_okay2(CONTEXT void *context, ERROR_RESULT void **error, void *selfType, char **selfWitnessTable) SWIFTCALL;
-void context_nonswift(CONTEXT void *context); // expected-error {{'swift_context' parameter can only be used with swiftcall calling convention}}
+void context_nonswift(CONTEXT void *context); // expected-error {{'swift_context' parameter can only be used with swiftcall or swiftasynccall calling convention}}
void context_bad_type(CONTEXT int context) SWIFTCALL; // expected-error {{'swift_context' parameter must have pointer type; type here is 'int'}}
void context_okay(CONTEXT void *context) SWIFTCALL;
void context_okay2(CONTEXT void *context, void *selfType, char **selfWitnessTable) SWIFTCALL;
+void context_okay_async(CONTEXT void *context) SWIFTASYNCCALL;
+void context_okay2_async(CONTEXT void *context, void *selfType, char **selfWitnessTable) SWIFTASYNCCALL;
void async_context_okay_for_now(ASYNC_CONTEXT void *context);
void async_context_bad_type(ASYNC_CONTEXT int context) SWIFTCALL; // expected-error {{'swift_async_context' parameter must have pointer type; type here is 'int'}}
diff --git a/clang/test/Sema/no_callconv.cpp b/clang/test/Sema/no_callconv.cpp
index 49ce0e88eda8..a8b3c91e0e3f 100644
--- a/clang/test/Sema/no_callconv.cpp
+++ b/clang/test/Sema/no_callconv.cpp
@@ -11,6 +11,7 @@ void __attribute__((regcall)) funcB() {} // expected-error {{'regcall' calling c
void __attribute__((ms_abi)) funcH() {} // expected-error {{'ms_abi' calling convention is not supported for this target}}
void __attribute__((intel_ocl_bicc)) funcJ() {} // expected-error {{'intel_ocl_bicc' calling convention is not supported for this target}}
void __attribute__((swiftcall)) funcK() {} // expected-error {{'swiftcall' calling convention is not supported for this target}}
+void __attribute__((swiftasynccall)) funcKK() {} // expected-error {{'swiftasynccall' calling convention is not supported for this target}}
void __attribute__((pascal)) funcG() {} // expected-error {{'pascal' calling convention is not supported for this target}}
void __attribute__((preserve_most)) funcL() {} // expected-error {{'preserve_most' calling convention is not supported for this target}}
void __attribute__((preserve_all)) funcM() {} // expected-error {{'preserve_all' calling convention is not supported for this target}}
@@ -26,6 +27,7 @@ void __attribute__((regcall)) funcB() {}
void __attribute__((ms_abi)) funcH() {}
void __attribute__((intel_ocl_bicc)) funcJ() {}
void __attribute__((swiftcall)) funcK() {}
+void __attribute__((swiftasynccall)) funcKK() {}
void __attribute__((preserve_most)) funcL() {}
void __attribute__((preserve_all)) funcM() {}
diff --git a/clang/test/SemaCXX/attr-swiftcall.cpp b/clang/test/SemaCXX/attr-swiftcall.cpp
index eb9538e31044..7f4b7806d001 100644
--- a/clang/test/SemaCXX/attr-swiftcall.cpp
+++ b/clang/test/SemaCXX/attr-swiftcall.cpp
@@ -1,20 +1,28 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify %s
#define SWIFTCALL __attribute__((swiftcall))
+#define SWIFTASYNCCALL __attribute__((swiftasynccall))
#define INDIRECT_RESULT __attribute__((swift_indirect_result))
#define ERROR_RESULT __attribute__((swift_error_result))
#define CONTEXT __attribute__((swift_context))
+#define ASYNC_CONTEXT __attribute__((swift_async_context))
int notAFunction SWIFTCALL; // expected-warning {{'swiftcall' only applies to function types; type here is 'int'}}
+int notAnAsyncFunction SWIFTASYNCCALL; // expected-warning {{'swiftasynccall' only applies to function types; type here is 'int'}}
void variadic(int x, ...) SWIFTCALL; // expected-error {{variadic function cannot use swiftcall calling convention}}
+void variadic_async(int x, ...) SWIFTASYNCCALL; // expected-error {{variadic function cannot use swiftasynccall calling convention}}
void multiple_ccs(int x) SWIFTCALL __attribute__((vectorcall)); // expected-error {{vectorcall and swiftcall attributes are not compatible}}
+void multiple_ccs_async(int x) SWIFTASYNCCALL __attribute__((vectorcall)); // expected-error {{vectorcall and swiftasynccall attributes are not compatible}}
void (*functionPointer)(void) SWIFTCALL;
+void (*asyncFunctionPointer)(void) SWIFTASYNCCALL;
-void indirect_result_nonswift(INDIRECT_RESULT void *out); // expected-error {{'swift_indirect_result' parameter can only be used with swiftcall calling convention}}
+void indirect_result_nonswift(INDIRECT_RESULT void *out); // expected-error {{'swift_indirect_result' parameter can only be used with swiftcall or swiftasynccall calling convention}}
void indirect_result_bad_position(int first, INDIRECT_RESULT void *out) SWIFTCALL; // expected-error {{'swift_indirect_result' parameters must be first parameters of function}}
void indirect_result_bad_type(INDIRECT_RESULT int out) SWIFTCALL; // expected-error {{'swift_indirect_result' parameter must have pointer type; type here is 'int'}}
void indirect_result_single(INDIRECT_RESULT void *out) SWIFTCALL;
void indirect_result_multiple(INDIRECT_RESULT void *out1, INDIRECT_RESULT void *out2) SWIFTCALL;
+void indirect_result_single_async(INDIRECT_RESULT void *out) SWIFTASYNCCALL;
+void indirect_result_multiple_async(INDIRECT_RESULT void *out1, INDIRECT_RESULT void *out2) SWIFTASYNCCALL;
void error_result_nonswift(ERROR_RESULT void **error); // expected-error {{'swift_error_result' parameter can only be used with swiftcall calling convention}} expected-error{{'swift_error_result' parameter must follow 'swift_context' parameter}}
void error_result_bad_position2(int first, ERROR_RESULT void **error) SWIFTCALL; // expected-error {{'swift_error_result' parameter must follow 'swift_context' parameter}}
@@ -23,10 +31,17 @@ void error_result_bad_type2(CONTEXT void *context, ERROR_RESULT int *error) SWIF
void error_result_okay(int a, int b, CONTEXT void *context, ERROR_RESULT void **error) SWIFTCALL;
void error_result_okay(CONTEXT void *context, ERROR_RESULT void **error, void *selfType, char **selfWitnessTable) SWIFTCALL;
-void context_nonswift(CONTEXT void *context); // expected-error {{'swift_context' parameter can only be used with swiftcall calling convention}}
+void context_nonswift(CONTEXT void *context); // expected-error {{'swift_context' parameter can only be used with swiftcall or swiftasynccall calling convention}}
void context_bad_type(CONTEXT int context) SWIFTCALL; // expected-error {{'swift_context' parameter must have pointer type; type here is 'int'}}
void context_okay(CONTEXT void *context) SWIFTCALL;
void context_okay(CONTEXT void *context, void *selfType, char **selfWitnessTable) SWIFTCALL;
+void context_okay_async(CONTEXT void *context) SWIFTASYNCCALL;
+void context_okay2_async(CONTEXT void *context, void *selfType, char **selfWitnessTable) SWIFTASYNCCALL;
+
+void async_context_nonswift(ASYNC_CONTEXT void *context); // OK
+void async_context_bad_type(ASYNC_CONTEXT int context) SWIFTASYNCCALL; // expected-error {{'swift_async_context' parameter must have pointer type; type here is 'int'}}
+void async_context_okay(ASYNC_CONTEXT void *context) SWIFTASYNCCALL;
+void async_context_okay(void *someArg, ASYNC_CONTEXT void *context, void *otherArg) SWIFTASYNCCALL;
template <class T> void indirect_result_temp_okay1(INDIRECT_RESULT T *out) SWIFTCALL;
template <class T> void indirect_result_temp_okay2(INDIRECT_RESULT T out) SWIFTCALL; // expected-note {{candidate template ignored: substitution failure [with T = int]: 'swift_indirect_result' parameter must have pointer type; type here is 'int'}}
diff --git a/clang/tools/libclang/CXType.cpp b/clang/tools/libclang/CXType.cpp
index f8c36df35607..0199c95b356d 100644
--- a/clang/tools/libclang/CXType.cpp
+++ b/clang/tools/libclang/CXType.cpp
@@ -664,6 +664,7 @@ CXCallingConv clang_getFunctionTypeCallingConv(CXType X) {
TCALLINGCONV(AAPCS_VFP);
TCALLINGCONV(IntelOclBicc);
TCALLINGCONV(Swift);
+ TCALLINGCONV(SwiftAsync);
TCALLINGCONV(PreserveMost);
TCALLINGCONV(PreserveAll);
case CC_SpirFunction: return CXCallingConv_Unexposed;
diff --git a/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h b/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h
index 18eafd62df43..77446e9b0f07 100644
--- a/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h
+++ b/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h
@@ -67,7 +67,8 @@ enum class CallingConv : uint8_t {
Eabi,
Vectorcall,
Regcall,
- Swift, // Clang-only
+ Swift, // Clang-only
+ SwiftAsync, // Clang-only
};
enum class ReferenceKind : uint8_t { None, LValueRef, RValueRef };
diff --git a/llvm/lib/Demangle/MicrosoftDemangle.cpp b/llvm/lib/Demangle/MicrosoftDemangle.cpp
index 2596eed71e23..a98d9fe45fe1 100644
--- a/llvm/lib/Demangle/MicrosoftDemangle.cpp
+++ b/llvm/lib/Demangle/MicrosoftDemangle.cpp
@@ -1713,6 +1713,8 @@ CallingConv Demangler::demangleCallingConvention(StringView &MangledName) {
return CallingConv::Vectorcall;
case 'S':
return CallingConv::Swift;
+ case 'T':
+ return CallingConv::SwiftAsync;
}
return CallingConv::None;
diff --git a/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp b/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp
index 9a64e2821be8..9fe157bf0d2a 100644
--- a/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp
+++ b/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp
@@ -110,6 +110,9 @@ static void outputCallingConvention(OutputStream &OS, CallingConv CC) {
case CallingConv::Swift:
OS << "__attribute__((__swiftcall__)) ";
break;
+ case CallingConv::SwiftAsync:
+ OS << "__attribute__((__swiftasynccall__)) ";
+ break;
default:
break;
}
diff --git a/llvm/lib/Transforms/IPO/MergeFunctions.cpp b/llvm/lib/Transforms/IPO/MergeFunctions.cpp
index 91af6e0cb72e..8eac6c86b08d 100644
--- a/llvm/lib/Transforms/IPO/MergeFunctions.cpp
+++ b/llvm/lib/Transforms/IPO/MergeFunctions.cpp
@@ -709,7 +709,10 @@ void MergeFunctions::writeThunk(Function *F, Function *G) {
CallInst *CI = Builder.CreateCall(F, Args);
ReturnInst *RI = nullptr;
- CI->setTailCall();
+ bool isSwiftTailCall = F->getCallingConv() == CallingConv::SwiftTail &&
+ G->getCallingConv() == CallingConv::SwiftTail;
+ CI->setTailCallKind(isSwiftTailCall ? llvm::CallInst::TCK_MustTail
+ : llvm::CallInst::TCK_Tail);
CI->setCallingConv(F->getCallingConv());
CI->setAttributes(F->getAttributes());
if (H->getReturnType()->isVoidTy()) {
diff --git a/llvm/test/Demangle/ms-mangle.test b/llvm/test/Demangle/ms-mangle.test
index c77802ca0e85..6995d7019666 100644
--- a/llvm/test/Demangle/ms-mangle.test
+++ b/llvm/test/Demangle/ms-mangle.test
@@ -341,6 +341,9 @@
?swift_func@@YSXXZ
; CHECK: void __attribute__((__swiftcall__)) swift_func(void)
+?swift_async_func@@YTXXZ
+; CHECK: void __attribute__((__swiftasynccall__)) swift_async_func(void)
+
??$fn_tmpl@$1?extern_c_func@@YAXXZ@@YAXXZ
; CHECK: void __cdecl fn_tmpl<&void __cdecl extern_c_func(void)>(void)
More information about the cfe-commits
mailing list