Skip to content

Commit 7c190e7

Browse files
varungandhi-appleetcwilde
authored andcommitted
[CodeGen] Fix codegen for __attribute__((swiftasynccall)).
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. Differential Revision: https://reviews.llvm.org/D95984
1 parent f16964c commit 7c190e7

File tree

5 files changed

+125
-7
lines changed

5 files changed

+125
-7
lines changed

clang/lib/CodeGen/CGCall.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,7 @@ unsigned CodeGenTypes::ClangCallConvToLLVMCallConv(CallingConv CC) {
6666
case CC_PreserveMost: return llvm::CallingConv::PreserveMost;
6767
case CC_PreserveAll: return llvm::CallingConv::PreserveAll;
6868
case CC_Swift: return llvm::CallingConv::Swift;
69-
// [FIXME: swiftasynccc] Update to SwiftAsync once LLVM support lands.
70-
case CC_SwiftAsync:
71-
return llvm::CallingConv::Swift;
69+
case CC_SwiftAsync: return llvm::CallingConv::SwiftTail;
7270
}
7371
}
7472

@@ -5309,10 +5307,13 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
53095307
if (CGM.getLangOpts().ObjCAutoRefCount)
53105308
AddObjCARCExceptionMetadata(CI);
53115309

5312-
// Set tail call kind if necessary.
5310+
// Adjust tail call behavior based on TargetDecl's attributes and CallInfo.
53135311
if (llvm::CallInst *Call = dyn_cast<llvm::CallInst>(CI)) {
53145312
if (TargetDecl && TargetDecl->hasAttr<NotTailCalledAttr>())
53155313
Call->setTailCallKind(llvm::CallInst::TCK_NoTail);
5314+
else if (CallInfo.getASTCallingConvention() == CC_SwiftAsync &&
5315+
CurFnInfo->getASTCallingConvention() == CC_SwiftAsync)
5316+
Call->setTailCallKind(llvm::CallInst::TCK_Tail);
53165317
else if (IsMustTail)
53175318
Call->setTailCallKind(llvm::CallInst::TCK_MustTail);
53185319
}

clang/test/CodeGen/64bit-swiftcall.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@
66
// REQUIRES: aarch64-registered-target,x86-registered-target
77

88
#define SWIFTCALL __attribute__((swiftcall))
9+
#define SWIFTASYNCCALL __attribute__((swiftasynccall))
910
#define OUT __attribute__((swift_indirect_result))
1011
#define ERROR __attribute__((swift_error_result))
1112
#define CONTEXT __attribute__((swift_context))
13+
#define ASYNC_CONTEXT __attribute__((swift_async_context))
1214

1315
// CHECK-DAG: %struct.atomic_padded = type { { %struct.packed, [7 x i8] } }
1416
// CHECK-DAG: %struct.packed = type <{ i64, i8 }>
@@ -33,9 +35,15 @@ SWIFTCALL struct_reallybig indirect_result_3(OUT int *arg0, OUT float *arg1) { _
3335
SWIFTCALL void context_1(CONTEXT void *self) {}
3436
// CHECK-LABEL: define {{.*}} void @context_1(i8* swiftself
3537

38+
SWIFTASYNCCALL void async_context_1(ASYNC_CONTEXT void *ctx) {}
39+
// CHECK-LABEL: define {{.*}} void @async_context_1(i8* swiftasync
40+
3641
SWIFTCALL void context_2(void *arg0, CONTEXT void *self) {}
3742
// CHECK-LABEL: define {{.*}} void @context_2(i8*{{.*}}, i8* swiftself
3843

44+
SWIFTASYNCCALL void async_context_2(void *arg0, ASYNC_CONTEXT void *ctx) {}
45+
// CHECK-LABEL: define {{.*}} void @async_context_2(i8*{{.*}}, i8* swiftasync
46+
3947
SWIFTCALL void context_error_1(CONTEXT int *self, ERROR float **error) {}
4048
// CHECK-LABEL: define {{.*}} void @context_error_1(i32* swiftself{{.*}}, float** swifterror %0)
4149
// CHECK: [[TEMP:%.*]] = alloca float*, align 8

clang/test/CodeGen/arm-swiftcall.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,15 @@ SWIFTCALL struct_reallybig indirect_result_3(OUT int *arg0, OUT float *arg1) { _
2727
SWIFTCALL void context_1(CONTEXT void *self) {}
2828
// CHECK-LABEL: define{{.*}} void @context_1(i8* swiftself
2929

30+
SWIFTASYNCCALL void async_context_1(ASYNC_CONTEXT void *self) {}
31+
// CHECK-LABEL: define{{.*}} void @async_context_1(i8* swiftasync
32+
3033
SWIFTCALL void context_2(void *arg0, CONTEXT void *self) {}
3134
// CHECK-LABEL: define{{.*}} void @context_2(i8*{{.*}}, i8* swiftself
3235

36+
SWIFTASYNCCALL void async_context_2(void *arg0, ASYNC_CONTEXT void *self) {}
37+
// CHECK-LABEL: define{{.*}} void @async_context_2(i8*{{.*}}, i8* swiftasync
38+
3339
SWIFTCALL void context_error_1(CONTEXT int *self, ERROR float **error) {}
3440
// CHECK-LABEL: define{{.*}} void @context_error_1(i32* swiftself{{.*}}, float** swifterror %0)
3541
// CHECK: [[TEMP:%.*]] = alloca float*, align 4
@@ -55,9 +61,6 @@ void test_context_error_1() {
5561
SWIFTCALL void context_error_2(short s, CONTEXT int *self, ERROR float **error) {}
5662
// CHECK-LABEL: define{{.*}} void @context_error_2(i16{{.*}}, i32* swiftself{{.*}}, float** swifterror %0)
5763

58-
SWIFTASYNCCALL void async_context_1(ASYNC_CONTEXT void *self) {}
59-
// CHECK-LABEL: define {{.*}} void @async_context_1(i8* swiftasync
60-
6164
/*****************************************************************************/
6265
/********************************** LOWERING *********************************/
6366
/*****************************************************************************/
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -target-cpu core2 -emit-llvm -o - %s | FileCheck %s
2+
// RUN: %clang_cc1 -triple arm64-apple-ios9 -target-cpu cyclone -emit-llvm -o - %s | FileCheck %s
3+
// RUN: %clang_cc1 -triple armv7-apple-darwin9 -emit-llvm -o - %s | FileCheck %s
4+
// RUN: %clang_cc1 -triple armv7s-apple-ios9 -emit-llvm -o - %s | FileCheck %s
5+
// RUN: %clang_cc1 -triple armv7k-apple-ios9 -emit-llvm -o - %s | FileCheck %s
6+
7+
// Test tail call behavior when a swiftasynccall function is called
8+
// from another swiftasynccall function.
9+
10+
#define SWIFTCALL __attribute__((swiftcall))
11+
#define SWIFTASYNCCALL __attribute__((swiftasynccall))
12+
#define ASYNC_CONTEXT __attribute__((swift_async_context))
13+
14+
// CHECK-LABEL: swifttailcc void @async_leaf1(i8* swiftasync
15+
SWIFTASYNCCALL void async_leaf1(char * ASYNC_CONTEXT ctx) {
16+
*ctx += 1;
17+
}
18+
19+
// CHECK-LABEL: swifttailcc void @async_leaf2(i8* swiftasync
20+
SWIFTASYNCCALL void async_leaf2(char * ASYNC_CONTEXT ctx) {
21+
*ctx += 2;
22+
}
23+
24+
// CHECK-LABEL: swifttailcc void @async_branch
25+
// CHECK: tail call swifttailcc void @async_leaf1
26+
// CHECK: tail call swifttailcc void @async_leaf2
27+
SWIFTASYNCCALL void async_branch(_Bool b, char * ASYNC_CONTEXT ctx) {
28+
if (b) {
29+
return async_leaf1(ctx);
30+
} else {
31+
return async_leaf2(ctx);
32+
}
33+
}
34+
35+
// CHECK-LABEL: swifttailcc void @async_loop
36+
// CHECK: tail call swifttailcc void @async_leaf1
37+
// CHECK: tail call swifttailcc void @async_leaf2
38+
// CHECK: tail call swifttailcc void @async_loop
39+
SWIFTASYNCCALL void async_loop(unsigned u, char * ASYNC_CONTEXT ctx) {
40+
if (u == 0) {
41+
return async_leaf1(ctx);
42+
} else if (u == 1) {
43+
return async_leaf2(ctx);
44+
}
45+
return async_loop(u - 2, ctx);
46+
}
47+
48+
// Forward-declaration + mutual recursion is okay.
49+
50+
SWIFTASYNCCALL void async_mutual_loop2(unsigned u, char * ASYNC_CONTEXT ctx);
51+
52+
// CHECK: swifttailcc void @async_mutual_loop
53+
// CHECK: tail call swifttailcc void @async_leaf
54+
// CHECK: tail call swifttailcc void @async_leaf
55+
// CHECK: tail call swifttailcc void @async_mutual_loop
56+
SWIFTASYNCCALL void async_mutual_loop1(unsigned u, char * ASYNC_CONTEXT ctx) {
57+
if (u == 0) {
58+
return async_leaf1(ctx);
59+
} else if (u == 1) {
60+
return async_leaf2(ctx);
61+
}
62+
return async_mutual_loop2(u - 2, ctx);
63+
}
64+
65+
// CHECK: swifttailcc void @async_mutual_loop
66+
// CHECK: tail call swifttailcc void @async_leaf1
67+
// CHECK: tail call swifttailcc void @async_leaf2
68+
// CHECK: tail call swifttailcc void @async_mutual_loop1
69+
SWIFTASYNCCALL void async_mutual_loop2(unsigned u, char * ASYNC_CONTEXT ctx) {
70+
if (u == 0) {
71+
return async_leaf1(ctx);
72+
} else if (u == 1) {
73+
return async_leaf2(ctx);
74+
}
75+
return async_mutual_loop1(u - 2, ctx);
76+
}
77+
78+
// When swiftasynccall functions are called by non-swiftasynccall functions,
79+
// the call isn't marked as a tail call.
80+
81+
// CHECK-LABEL: swiftcc i8 @sync_calling_async
82+
// CHECK-NOT: tail call
83+
// CHECK: call swifttailcc void @async_branch
84+
// CHECK-NOT: tail call
85+
// CHECK: call swifttailcc void @async_loop
86+
SWIFTCALL char sync_calling_async(_Bool b, unsigned u) {
87+
char x = 'a';
88+
async_branch(b, &x);
89+
async_loop(u, &x);
90+
return x;
91+
}
92+
93+
// CHECK-LABEL: i8 @c_calling_async
94+
// CHECK-NOT: tail call
95+
// CHECK: call swifttailcc void @async_branch
96+
// CHECK-NOT: tail call
97+
// CHECK: call swifttailcc void @async_loop
98+
char c_calling_async(_Bool b, unsigned u) {
99+
char x = 'a';
100+
async_branch(b, &x);
101+
async_loop(u, &x);
102+
return x;
103+
}
104+

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,5 @@
66
void __attribute__((__swiftcall__)) f(void) {}
77
// CHECK-LABEL: define dso_local swiftcc void @f()
88

9+
void __attribute__((__swiftasynccall__)) f_async(void) {}
10+
// CHECK-LABEL: define dso_local swifttailcc void @f_async()

0 commit comments

Comments
 (0)