201 lines · c
1// RUN: %clang_cc1 -no-enable-noundef-analysis -triple x86_64-apple-darwin10 -target-cpu core2 -emit-llvm -o - %s | FileCheck %s2// RUN: %clang_cc1 -no-enable-noundef-analysis -triple arm64-apple-ios9 -target-cpu cyclone -emit-llvm -o - %s | FileCheck %s3// RUN: %clang_cc1 -no-enable-noundef-analysis -triple armv7-apple-darwin9 -emit-llvm -o - %s | FileCheck %s4// RUN: %clang_cc1 -no-enable-noundef-analysis -triple armv7s-apple-ios9 -emit-llvm -o - %s | FileCheck %s5// RUN: %clang_cc1 -no-enable-noundef-analysis -triple armv7k-apple-ios9 -emit-llvm -o - %s | FileCheck %s6 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=CPPONLY8// 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=CPPONLY9// RUN: %clang_cc1 -no-enable-noundef-analysis -x c++ -triple armv7-apple-darwin9 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=CPPONLY10// RUN: %clang_cc1 -no-enable-noundef-analysis -x c++ -triple armv7s-apple-ios9 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=CPPONLY11// RUN: %clang_cc1 -no-enable-noundef-analysis -x c++ -triple armv7k-apple-ios9 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=CPPONLY12 13// Test tail call behavior when a swiftasynccall function is called14// 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{{.*}}(ptr swiftasync21SWIFTASYNCCALL void async_leaf1(char * ASYNC_CONTEXT ctx) {22 *ctx += 1;23}24 25// CHECK-LABEL: swifttailcc void {{.*}}async_leaf2{{.*}}(ptr swiftasync26SWIFTASYNCCALL void async_leaf2(char * ASYNC_CONTEXT ctx) {27 *ctx += 2;28}29 30#if __cplusplus31 #define MYBOOL bool32#else33 #define MYBOOL _Bool34#endif35 36// CHECK-LABEL: swifttailcc void {{.*}}async_branch{{.*}}ptr swiftasync37// CHECK: musttail call swifttailcc void @{{.*}}async_leaf138// CHECK-NEXT: ret void39// CHECK: musttail call swifttailcc void @{{.*}}async_leaf240// CHECK-NEXT: ret void41SWIFTASYNCCALL 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_tail50// CHECK-NOT: musttail call swifttailcc void @{{.*}}async_leaf151// CHECK: call swifttailcc void @{{.*}}async_leaf152// CHECK-NOT: ret void53// CHECK: musttail call swifttailcc void @{{.*}}async_leaf254// CHECK-NEXT: ret void55SWIFTASYNCCALL 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_loop61// CHECK: musttail call swifttailcc void @{{.*}}async_leaf162// CHECK-NEXT: ret void63// CHECK: musttail call swifttailcc void @{{.*}}async_leaf264// CHECK-NEXT: ret void65// CHECK: musttail call swifttailcc void @{{.*}}async_loop66// CHECK-NEXT: ret void67SWIFTASYNCCALL 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 78SWIFTASYNCCALL void async_mutual_loop2(unsigned u, char * ASYNC_CONTEXT ctx);79 80// CHECK-LABEL: swifttailcc void {{.*}}async_mutual_loop181// CHECK: musttail call swifttailcc void @{{.*}}async_leaf182// CHECK-NEXT: ret void83// CHECK: musttail call swifttailcc void @{{.*}}async_leaf284// CHECK-NEXT: ret void85// There is some bugginess around FileCheck's greediness/matching,86// so skipping the check for async_mutual_loop2 here.87SWIFTASYNCCALL 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_loop297// CHECK: musttail call swifttailcc void @{{.*}}async_leaf198// CHECK-NEXT: ret void99// CHECK: musttail call swifttailcc void @{{.*}}async_leaf2100// CHECK-NEXT: ret void101// CHECK: musttail call swifttailcc void @{{.*}}async_mutual_loop1102// CHECK-NEXT: ret void103SWIFTASYNCCALL 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_async116// CHECK-NOT: tail call117// CHECK: call swifttailcc void @{{.*}}async_branch118// CHECK-NOT: tail call119// CHECK: call swifttailcc void @{{.*}}async_loop120SWIFTCALL 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_async128// CHECK-NOT: tail call129// CHECK: call swifttailcc void @{{.*}}async_branch130// CHECK-NOT: tail call131// CHECK: call swifttailcc void @{{.*}}async_loop132char 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 __cplusplus140struct 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 154SWIFTASYNCCALL void (S::*async_leaf_method_ptr)(char * ASYNC_CONTEXT) = &S::async_leaf_method;155 156// CPPONLY-LABEL: swifttailcc void {{.*}}async_struct_field_and_methods157// CPPONLY: musttail call swifttailcc void %{{[0-9]+}}158// CPPONLY: musttail call swifttailcc void @{{.*}}async_nonleaf_method1159// CPPONLY: musttail call swifttailcc void %{{[0-9]+}}160// CPPONLY: musttail call swifttailcc void @{{.*}}async_nonleaf_method2161// CPPONLY-NOT: musttail call swifttailcc void @{{.*}}async_leaf_method162// ^ TODO: Member pointers should also work.163SWIFTASYNCCALL 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_method1180// CPPONLY: musttail call swifttailcc void @{{.*}}async_leaf_method181 182// CPPONLY-LABEL: define{{.*}} swifttailcc void @{{.*}}async_nonleaf_method2183// CPPONLY: musttail call swifttailcc void @{{.*}}async_leaf_method184#endif185 186// Passing this as an argument requires a coerce-and-expand operation,187// which requires a temporary. Make sure that cleaning up that temporary188// doesn't mess around with the musttail handling.189struct coerce_and_expand {190 char a,b,c,d;191};192struct coerce_and_expand return_coerced(void);193SWIFTASYNCCALL void take_coerced_async(struct coerce_and_expand);194 195// CHECK-LABEL: swifttailcc void @{{.*}}test_coerced196SWIFTASYNCCALL void test_coerced() {197 // CHECK: musttail call swifttailcc void @{{.*}}take_coerced_async198 // CHECK-NEXT: ret void199 return take_coerced_async(return_coerced());200}201