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 // 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 12 13 // Test tail call behavior when a swiftasynccall function is called 14 // from another swiftasynccall function. 15 16 #define SWIFTCALL __attribute__((swiftcall)) 17 #define SWIFTASYNCCALL __attribute__((swiftasynccall)) 18 #define ASYNC_CONTEXT __attribute__((swift_async_context)) 19 20 // CHECK-LABEL: swifttailcc void {{.*}}async_leaf1{{.*}}(i8* swiftasync 21 SWIFTASYNCCALL void async_leaf1(char * ASYNC_CONTEXT ctx) { 22 *ctx += 1; 23 } 24 25 // CHECK-LABEL: swifttailcc void {{.*}}async_leaf2{{.*}}(i8* swiftasync 26 SWIFTASYNCCALL void async_leaf2(char * ASYNC_CONTEXT ctx) { 27 *ctx += 2; 28 } 29 30 #if __cplusplus 31 #define MYBOOL bool 32 #else 33 #define MYBOOL _Bool 34 #endif 35 36 // CHECK-LABEL: swifttailcc void {{.*}}async_branch{{.*}}i8* 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) { 42 if (b) { 43 return async_leaf1(ctx); 44 } else { 45 return async_leaf2(ctx); 46 } 47 } 48 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) { 56 async_leaf1(ctx); 57 return async_leaf2(ctx); 58 } 59 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) { 68 if (u == 0) { 69 return async_leaf1(ctx); 70 } else if (u == 1) { 71 return async_leaf2(ctx); 72 } 73 return async_loop(u - 2, ctx); 74 } 75 76 // Forward-declaration + mutual recursion is okay. 77 78 SWIFTASYNCCALL void async_mutual_loop2(unsigned u, char * ASYNC_CONTEXT ctx); 79 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) { 88 if (u == 0) { 89 return async_leaf1(ctx); 90 } else if (u == 1) { 91 return async_leaf2(ctx); 92 } 93 return async_mutual_loop2(u - 2, ctx); 94 } 95 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) { 104 if (u == 0) { 105 return async_leaf1(ctx); 106 } else if (u == 1) { 107 return async_leaf2(ctx); 108 } 109 return async_mutual_loop1(u - 2, ctx); 110 } 111 112 // When swiftasynccall functions are called by non-swiftasynccall functions, 113 // the call isn't marked as a tail call. 114 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) { 121 char x = 'a'; 122 async_branch(b, &x); 123 async_loop(u, &x); 124 return x; 125 } 126 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) { 133 char x = 'a'; 134 async_branch(b, &x); 135 async_loop(u, &x); 136 return x; 137 } 138 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 185