varungandhi-apple updated this revision to Diff 335293.
varungandhi-apple added a comment.
Herald added subscribers: llvm-commits, dexonsmith, hiraditya.
Herald added a project: LLVM.

1. Remove '::' when calling static function.
2. Fix bug in function merging around missing musttail.
3. Add off-by-default check in verifier for swifttailcc->swifttailcc tail calls 
that are not marked musttail.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D95984/new/

https://reviews.llvm.org/D95984

Files:
  clang/lib/AST/ExprCXX.cpp
  clang/lib/CodeGen/CGCall.cpp
  clang/lib/CodeGen/CGStmt.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
  llvm/lib/IR/Verifier.cpp
  llvm/lib/Transforms/IPO/MergeFunctions.cpp

Index: llvm/lib/Transforms/IPO/MergeFunctions.cpp
===================================================================
--- llvm/lib/Transforms/IPO/MergeFunctions.cpp
+++ llvm/lib/Transforms/IPO/MergeFunctions.cpp
@@ -713,7 +713,10 @@
 
   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()) {
Index: llvm/lib/IR/Verifier.cpp
===================================================================
--- llvm/lib/IR/Verifier.cpp
+++ llvm/lib/IR/Verifier.cpp
@@ -3288,7 +3288,24 @@
   return Copy;
 }
 
+static cl::opt<bool> EnableSwiftTailCCMustTailCheck(
+    "enable-swifttailcc-musttail-check", cl::init(false),
+    cl::desc("Check that tail calls from swifttailcc functions to"
+             " swifttailcc functions are marked musttail."));
+
 void Verifier::verifyMustTailCall(CallInst &CI) {
+  if (!CI.isMustTailCall()) {
+    if (EnableSwiftTailCCMustTailCheck &&
+        CI.getCallingConv() == CallingConv::SwiftTail &&
+        CI.getCaller()->getCallingConv() == CallingConv::SwiftTail &&
+        isa_and_nonnull<ReturnInst>(CI.getNextNode())) {
+      Assert(false,
+             "tail call from swifttail->swiftail should be marked musttail",
+             &CI);
+    }
+    return;
+  }
+
   Assert(!CI.isInlineAsm(), "cannot use musttail call with inline asm", &CI);
 
   // - The caller and callee prototypes must match.  Pointer types of
@@ -3354,9 +3371,7 @@
 
 void Verifier::visitCallInst(CallInst &CI) {
   visitCallBase(CI);
-
-  if (CI.isMustTailCall())
-    verifyMustTailCall(CI);
+  verifyMustTailCall(CI);
 }
 
 void Verifier::visitInvokeInst(InvokeInst &II) {
Index: clang/test/CodeGen/swift-call-conv.c
===================================================================
--- clang/test/CodeGen/swift-call-conv.c
+++ clang/test/CodeGen/swift-call-conv.c
@@ -6,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()
Index: clang/test/CodeGen/swift-async-call-conv.c
===================================================================
--- /dev/null
+++ 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
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/CGStmt.cpp
===================================================================
--- clang/lib/CodeGen/CGStmt.cpp
+++ clang/lib/CodeGen/CGStmt.cpp
@@ -1145,6 +1145,37 @@
 };
 } // 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 :).
@@ -1203,8 +1234,11 @@
   } 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()) {
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;
   }
 }
 
Index: clang/lib/AST/ExprCXX.cpp
===================================================================
--- clang/lib/AST/ExprCXX.cpp
+++ clang/lib/AST/ExprCXX.cpp
@@ -670,6 +670,7 @@
     return cast<CXXMethodDecl>(MemExpr->getMemberDecl());
 
   // FIXME: Will eventually need to cope with member pointers.
+  // NOTE: Update makeTailCallIfSwiftAsync on fixing this.
   return nullptr;
 }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to