diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -66,9 +66,7 @@ case CC_PreserveMost: return llvm::CallingConv::PreserveMost; case CC_PreserveAll: return llvm::CallingConv::PreserveAll; case CC_Swift: return llvm::CallingConv::Swift; - // [FIXME: swiftasynccc] Update to SwiftAsync once LLVM support lands. - case CC_SwiftAsync: - return llvm::CallingConv::Swift; + case CC_SwiftAsync: return llvm::CallingConv::SwiftTail; } } @@ -5149,10 +5147,13 @@ if (CGM.getLangOpts().ObjCAutoRefCount) AddObjCARCExceptionMetadata(CI); - // Suppress tail calls if requested. + // Adjust tail call behavior based on TargetDecl's attributes and CallInfo. if (llvm::CallInst *Call = dyn_cast(CI)) { if (TargetDecl && TargetDecl->hasAttr()) Call->setTailCallKind(llvm::CallInst::TCK_NoTail); + else if (CallInfo.getASTCallingConvention() == CallingConv::CC_SwiftAsync && + CurFnInfo->getASTCallingConvention() == CallingConv::CC_SwiftAsync) + Call->setTailCallKind(llvm::CallInst::TCK_Tail); } // Add metadata for calls to MSAllocator functions diff --git a/clang/test/CodeGen/64bit-swiftcall.c b/clang/test/CodeGen/64bit-swiftcall.c --- a/clang/test/CodeGen/64bit-swiftcall.c +++ b/clang/test/CodeGen/64bit-swiftcall.c @@ -4,9 +4,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 }> @@ -31,9 +33,15 @@ 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 --- a/clang/test/CodeGen/arm-swiftcall.c +++ b/clang/test/CodeGen/arm-swiftcall.c @@ -27,9 +27,15 @@ 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 @@ -55,9 +61,6 @@ 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) -SWIFTASYNCCALL void async_context_1(ASYNC_CONTEXT void *self) {} -// CHECK-LABEL: define {{.*}} void @async_context_1(i8* swiftasync - /*****************************************************************************/ /********************************** LOWERING *********************************/ /*****************************************************************************/ diff --git a/clang/test/CodeGen/swift-async-call-conv.c b/clang/test/CodeGen/swift-async-call-conv.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/swift-async-call-conv.c @@ -0,0 +1,104 @@ +// 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 + +// 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; +} + +// CHECK-LABEL: swifttailcc void @async_branch +// CHECK: tail call swifttailcc void @async_leaf1 +// CHECK: tail call swifttailcc void @async_leaf2 +SWIFTASYNCCALL void async_branch(_Bool b, char * ASYNC_CONTEXT ctx) { + if (b) { + return async_leaf1(ctx); + } else { + return async_leaf2(ctx); + } +} + +// CHECK-LABEL: swifttailcc void @async_loop +// CHECK: tail call swifttailcc void @async_leaf1 +// CHECK: tail call swifttailcc void @async_leaf2 +// CHECK: tail call swifttailcc void @async_loop +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: swifttailcc void @async_mutual_loop +// CHECK: tail call swifttailcc void @async_leaf +// CHECK: tail call swifttailcc void @async_leaf +// CHECK: tail call swifttailcc void @async_mutual_loop +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: swifttailcc void @async_mutual_loop +// CHECK: tail call swifttailcc void @async_leaf1 +// CHECK: tail call swifttailcc void @async_leaf2 +// CHECK: tail call swifttailcc void @async_mutual_loop1 +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(_Bool 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(_Bool b, unsigned u) { + char x = 'a'; + async_branch(b, &x); + async_loop(u, &x); + return x; +} + diff --git a/clang/test/CodeGen/swift-call-conv.c b/clang/test/CodeGen/swift-call-conv.c --- a/clang/test/CodeGen/swift-call-conv.c +++ b/clang/test/CodeGen/swift-call-conv.c @@ -7,3 +7,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()