varungandhi-apple created this revision.
varungandhi-apple added a reviewer: rjmccall.
varungandhi-apple requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

1. It should be mapped to LLVM's swifttailcc, which is now available.
2. We should make sure we generate a tail call instead of an ordinary call.

Fixes rdar://73762895.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D95984

Files:
  clang/lib/CodeGen/CGCall.cpp
  clang/test/CodeGen/64bit-swiftcall.c
  clang/test/CodeGen/arm-swiftcall.c
  clang/test/CodeGen/swift-async-call-conv.c
  clang/test/CodeGen/swift-call-conv.c

Index: clang/test/CodeGen/swift-call-conv.c
===================================================================
--- clang/test/CodeGen/swift-call-conv.c
+++ 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()
Index: clang/test/CodeGen/swift-async-call-conv.c
===================================================================
--- /dev/null
+++ 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;
+}
+
Index: clang/test/CodeGen/arm-swiftcall.c
===================================================================
--- clang/test/CodeGen/arm-swiftcall.c
+++ 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 *********************************/
 /*****************************************************************************/
Index: clang/test/CodeGen/64bit-swiftcall.c
===================================================================
--- clang/test/CodeGen/64bit-swiftcall.c
+++ 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
Index: clang/lib/CodeGen/CGCall.cpp
===================================================================
--- clang/lib/CodeGen/CGCall.cpp
+++ 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<llvm::CallInst>(CI)) {
     if (TargetDecl && TargetDecl->hasAttr<NotTailCalledAttr>())
       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
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to