Skip to content

Commit a2b8bfb

Browse files
Correctly handle method calls and function pointers for swiftasync.
Fixes rdar://75367789.
1 parent 0c7dc30 commit a2b8bfb

File tree

3 files changed

+70
-8
lines changed

3 files changed

+70
-8
lines changed

clang/lib/AST/ExprCXX.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -670,6 +670,7 @@ CXXMethodDecl *CXXMemberCallExpr::getMethodDecl() const {
670670
return cast<CXXMethodDecl>(MemExpr->getMemberDecl());
671671

672672
// FIXME: Will eventually need to cope with member pointers.
673+
// NOTE: Update makeTailCallIfSwiftAsync on fixing this.
673674
return nullptr;
674675
}
675676

clang/lib/CodeGen/CGStmt.cpp

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1149,10 +1149,25 @@ struct SaveRetExprRAII {
11491149
/// codegen it as 'tail call ...; ret void;'.
11501150
static void makeTailCallIfSwiftAsync(const CallExpr *CE, CGBuilderTy &Builder,
11511151
const CGFunctionInfo *CurFnInfo) {
1152-
auto callee = CE->getDirectCallee();
1153-
if (!callee)
1152+
auto calleeQualType = CE->getCallee()->getType();
1153+
const FunctionType *calleeType = nullptr;
1154+
if (calleeQualType->isFunctionPointerType() ||
1155+
calleeQualType->isFunctionReferenceType() ||
1156+
calleeQualType->isBlockPointerType() ||
1157+
calleeQualType->isMemberFunctionPointerType()) {
1158+
calleeType = calleeQualType->getPointeeType()->castAs<FunctionType>();
1159+
} else if (auto *ty = dyn_cast<FunctionType>(calleeQualType)) {
1160+
calleeType = ty;
1161+
} else if (auto CMCE = dyn_cast<CXXMemberCallExpr>(CE)) {
1162+
if (auto methodDecl = CMCE->getMethodDecl()) {
1163+
// getMethodDecl() doesn't handle member pointers at the moment.
1164+
calleeType = methodDecl->getType()->castAs<FunctionType>();
1165+
} else {
1166+
return;
1167+
}
1168+
} else {
11541169
return;
1155-
auto calleeType = callee->getFunctionType();
1170+
}
11561171
if (calleeType->getCallConv() == CallingConv::CC_SwiftAsync
11571172
&& (CurFnInfo->getASTCallingConvention() ==
11581173
CallingConv::CC_SwiftAsync)) {

clang/test/CodeGen/swift-async-call-conv.c

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44
// RUN: %clang_cc1 -triple armv7s-apple-ios9 -emit-llvm -o - %s | FileCheck %s
55
// RUN: %clang_cc1 -triple armv7k-apple-ios9 -emit-llvm -o - %s | FileCheck %s
66

7-
// RUN: %clang_cc1 -x c++ -triple x86_64-apple-darwin10 -target-cpu core2 -emit-llvm -o - %s | FileCheck %s
8-
// RUN: %clang_cc1 -x c++ -triple arm64-apple-ios9 -target-cpu cyclone -emit-llvm -o - %s | FileCheck %s
9-
// RUN: %clang_cc1 -x c++ -triple armv7-apple-darwin9 -emit-llvm -o - %s | FileCheck %s
10-
// RUN: %clang_cc1 -x c++ -triple armv7s-apple-ios9 -emit-llvm -o - %s | FileCheck %s
11-
// RUN: %clang_cc1 -x c++ -triple armv7k-apple-ios9 -emit-llvm -o - %s | FileCheck %s
7+
// 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
8+
// RUN: %clang_cc1 -x c++ -triple arm64-apple-ios9 -target-cpu cyclone -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=CPPONLY
9+
// RUN: %clang_cc1 -x c++ -triple armv7-apple-darwin9 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=CPPONLY
10+
// RUN: %clang_cc1 -x c++ -triple armv7s-apple-ios9 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=CPPONLY
11+
// RUN: %clang_cc1 -x c++ -triple armv7k-apple-ios9 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=CPPONLY
1212

1313
// Test tail call behavior when a swiftasynccall function is called
1414
// from another swiftasynccall function.
@@ -136,3 +136,49 @@ char c_calling_async(MYBOOL b, unsigned u) {
136136
return x;
137137
}
138138

139+
#if __cplusplus
140+
struct S {
141+
SWIFTASYNCCALL void (*fptr)(char * ASYNC_CONTEXT);
142+
143+
SWIFTASYNCCALL void async_leaf_method(char * ASYNC_CONTEXT ctx) {
144+
*ctx += 1;
145+
}
146+
SWIFTASYNCCALL void async_nonleaf_method1(char * ASYNC_CONTEXT ctx) {
147+
return async_leaf_method(ctx);
148+
}
149+
SWIFTASYNCCALL void async_nonleaf_method2(char * ASYNC_CONTEXT ctx) {
150+
return this->async_leaf_method(ctx);
151+
}
152+
};
153+
154+
SWIFTASYNCCALL void (S::*async_leaf_method_ptr)(char * ASYNC_CONTEXT) = &S::async_leaf_method;
155+
156+
// CPPONLY-LABEL: swifttailcc void {{.*}}async_struct_field_and_methods
157+
// CPPONLY: musttail call swifttailcc void %{{[0-9]+}}
158+
// CPPONLY: musttail call swifttailcc void @{{.*}}async_nonleaf_method1
159+
// CPPONLY: musttail call swifttailcc void %{{[0-9]+}}
160+
// CPPONLY: musttail call swifttailcc void @{{.*}}async_nonleaf_method2
161+
// CPPONLY-NOT: musttail call swifttailcc void @{{.*}}async_leaf_method
162+
// ^ TODO: Member pointers should also work.
163+
SWIFTASYNCCALL void async_struct_field_and_methods(int i, S &sref, S *sptr) {
164+
char x = 'a';
165+
if (i == 0) {
166+
return (*sref.fptr)(&x);
167+
} else if (i == 1) {
168+
return sref.async_nonleaf_method1(&x);
169+
} else if (i == 2) {
170+
return (*(sptr->fptr))(&x);
171+
} else if (i == 3) {
172+
return sptr->async_nonleaf_method2(&x);
173+
} else if (i == 4) {
174+
return (sref.*async_leaf_method_ptr)(&x);
175+
}
176+
return (sptr->*async_leaf_method_ptr)(&x);
177+
}
178+
179+
// CPPONLY-LABEL: define{{.*}} swifttailcc void @{{.*}}async_nonleaf_method1
180+
// CPPONLY: musttail call swifttailcc void @{{.*}}async_leaf_method
181+
182+
// CPPONLY-LABEL: define{{.*}} swifttailcc void @{{.*}}async_nonleaf_method2
183+
// CPPONLY: musttail call swifttailcc void @{{.*}}async_leaf_method
184+
#endif

0 commit comments

Comments
 (0)