1 // RUN: %clang_cc1 -no-enable-noundef-analysis -triple x86_64-apple-darwin10 -target-cpu core2 -emit-llvm -o - %s | FileCheck %s
2 // RUN: %clang_cc1 -no-enable-noundef-analysis -triple arm64-apple-ios9 -target-cpu cyclone -emit-llvm -o - %s | FileCheck %s
3 // RUN: %clang_cc1 -no-enable-noundef-analysis -triple armv7-apple-darwin9 -emit-llvm -o - %s | FileCheck %s
4 // RUN: %clang_cc1 -no-enable-noundef-analysis -triple armv7s-apple-ios9 -emit-llvm -o - %s | FileCheck %s
5 // RUN: %clang_cc1 -no-enable-noundef-analysis -triple armv7k-apple-ios9 -emit-llvm -o - %s | FileCheck %s
7 // RUN: %clang_cc1 -no-enable-noundef-analysis -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 -no-enable-noundef-analysis -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 -no-enable-noundef-analysis -x c++ -triple armv7-apple-darwin9 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=CPPONLY
10 // RUN: %clang_cc1 -no-enable-noundef-analysis -x c++ -triple armv7s-apple-ios9 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=CPPONLY
11 // RUN: %clang_cc1 -no-enable-noundef-analysis -x c++ -triple armv7k-apple-ios9 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=CPPONLY
13 // Test tail call behavior when a swiftasynccall function is called
14 // from another swiftasynccall function.
16 #define SWIFTCALL __attribute__((swiftcall))
17 #define SWIFTASYNCCALL __attribute__((swiftasynccall))
18 #define ASYNC_CONTEXT __attribute__((swift_async_context))
20 // CHECK-LABEL: swifttailcc void {{.*}}async_leaf1{{.*}}(ptr swiftasync
21 SWIFTASYNCCALL
void async_leaf1(char * ASYNC_CONTEXT ctx
) {
25 // CHECK-LABEL: swifttailcc void {{.*}}async_leaf2{{.*}}(ptr swiftasync
26 SWIFTASYNCCALL
void async_leaf2(char * ASYNC_CONTEXT ctx
) {
36 // CHECK-LABEL: swifttailcc void {{.*}}async_branch{{.*}}ptr swiftasync
37 // CHECK: musttail call swifttailcc void @{{.*}}async_leaf1
38 // CHECK-NEXT: ret void
39 // CHECK: musttail call swifttailcc void @{{.*}}async_leaf2
40 // CHECK-NEXT: ret void
41 SWIFTASYNCCALL
void async_branch(MYBOOL b
, char * ASYNC_CONTEXT ctx
) {
43 return async_leaf1(ctx
);
45 return async_leaf2(ctx
);
49 // CHECK-LABEL: swifttailcc void {{.*}}async_not_all_tail
50 // CHECK-NOT: musttail call swifttailcc void @{{.*}}async_leaf1
51 // CHECK: call swifttailcc void @{{.*}}async_leaf1
52 // CHECK-NOT: ret void
53 // CHECK: musttail call swifttailcc void @{{.*}}async_leaf2
54 // CHECK-NEXT: ret void
55 SWIFTASYNCCALL
void async_not_all_tail(char * ASYNC_CONTEXT ctx
) {
57 return async_leaf2(ctx
);
60 // CHECK-LABEL: swifttailcc void {{.*}}async_loop
61 // CHECK: musttail call swifttailcc void @{{.*}}async_leaf1
62 // CHECK-NEXT: ret void
63 // CHECK: musttail call swifttailcc void @{{.*}}async_leaf2
64 // CHECK-NEXT: ret void
65 // CHECK: musttail call swifttailcc void @{{.*}}async_loop
66 // CHECK-NEXT: ret void
67 SWIFTASYNCCALL
void async_loop(unsigned u
, char * ASYNC_CONTEXT ctx
) {
69 return async_leaf1(ctx
);
71 return async_leaf2(ctx
);
73 return async_loop(u
- 2, ctx
);
76 // Forward-declaration + mutual recursion is okay.
78 SWIFTASYNCCALL
void async_mutual_loop2(unsigned u
, char * ASYNC_CONTEXT ctx
);
80 // CHECK-LABEL: swifttailcc void {{.*}}async_mutual_loop1
81 // CHECK: musttail call swifttailcc void @{{.*}}async_leaf1
82 // CHECK-NEXT: ret void
83 // CHECK: musttail call swifttailcc void @{{.*}}async_leaf2
84 // CHECK-NEXT: ret void
85 // There is some bugginess around FileCheck's greediness/matching,
86 // so skipping the check for async_mutual_loop2 here.
87 SWIFTASYNCCALL
void async_mutual_loop1(unsigned u
, char * ASYNC_CONTEXT ctx
) {
89 return async_leaf1(ctx
);
91 return async_leaf2(ctx
);
93 return async_mutual_loop2(u
- 2, ctx
);
96 // CHECK-LABEL: swifttailcc void {{.*}}async_mutual_loop2
97 // CHECK: musttail call swifttailcc void @{{.*}}async_leaf1
98 // CHECK-NEXT: ret void
99 // CHECK: musttail call swifttailcc void @{{.*}}async_leaf2
100 // CHECK-NEXT: ret void
101 // CHECK: musttail call swifttailcc void @{{.*}}async_mutual_loop1
102 // CHECK-NEXT: ret void
103 SWIFTASYNCCALL
void async_mutual_loop2(unsigned u
, char * ASYNC_CONTEXT ctx
) {
105 return async_leaf1(ctx
);
107 return async_leaf2(ctx
);
109 return async_mutual_loop1(u
- 2, ctx
);
112 // When swiftasynccall functions are called by non-swiftasynccall functions,
113 // the call isn't marked as a tail call.
115 // CHECK-LABEL: swiftcc i8 {{.*}}sync_calling_async
116 // CHECK-NOT: tail call
117 // CHECK: call swifttailcc void @{{.*}}async_branch
118 // CHECK-NOT: tail call
119 // CHECK: call swifttailcc void @{{.*}}async_loop
120 SWIFTCALL
char sync_calling_async(MYBOOL b
, unsigned u
) {
127 // CHECK-LABEL: i8 {{.*}}c_calling_async
128 // CHECK-NOT: tail call
129 // CHECK: call swifttailcc void @{{.*}}async_branch
130 // CHECK-NOT: tail call
131 // CHECK: call swifttailcc void @{{.*}}async_loop
132 char c_calling_async(MYBOOL b
, unsigned u
) {
141 SWIFTASYNCCALL
void (*fptr
)(char * ASYNC_CONTEXT
);
143 SWIFTASYNCCALL
void async_leaf_method(char * ASYNC_CONTEXT ctx
) {
146 SWIFTASYNCCALL
void async_nonleaf_method1(char * ASYNC_CONTEXT ctx
) {
147 return async_leaf_method(ctx
);
149 SWIFTASYNCCALL
void async_nonleaf_method2(char * ASYNC_CONTEXT ctx
) {
150 return this->async_leaf_method(ctx
);
154 SWIFTASYNCCALL
void (S::*async_leaf_method_ptr
)(char * ASYNC_CONTEXT
) = &S::async_leaf_method
;
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
) {
166 return (*sref
.fptr
)(&x
);
168 return sref
.async_nonleaf_method1(&x
);
170 return (*(sptr
->fptr
))(&x
);
172 return sptr
->async_nonleaf_method2(&x
);
174 return (sref
.*async_leaf_method_ptr
)(&x
);
176 return (sptr
->*async_leaf_method_ptr
)(&x
);
179 // CPPONLY-LABEL: define{{.*}} swifttailcc void @{{.*}}async_nonleaf_method1
180 // CPPONLY: musttail call swifttailcc void @{{.*}}async_leaf_method
182 // CPPONLY-LABEL: define{{.*}} swifttailcc void @{{.*}}async_nonleaf_method2
183 // CPPONLY: musttail call swifttailcc void @{{.*}}async_leaf_method
186 // Passing this as an argument requires a coerce-and-expand operation,
187 // which requires a temporary. Make sure that cleaning up that temporary
188 // doesn't mess around with the musttail handling.
189 struct coerce_and_expand
{
192 struct coerce_and_expand
return_coerced(void);
193 SWIFTASYNCCALL
void take_coerced_async(struct coerce_and_expand
);
195 // CHECK-LABEL: swifttailcc void @{{.*}}test_coerced
196 SWIFTASYNCCALL
void test_coerced() {
197 // CHECK: musttail call swifttailcc void @{{.*}}take_coerced_async
198 // CHECK-NEXT: ret void
199 return take_coerced_async(return_coerced());