varungandhi-apple updated this revision to Diff 333421.
varungandhi-apple added a comment.
Fix codegen + add tests for methods and function pointers.
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
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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits