1; RUN: llc -verify-machineinstrs < %s -mtriple=thumbv7k-apple-watchos | FileCheck %s 2 3declare swifttailcc void @callee_stack0() 4declare swifttailcc void @callee_stack4([4 x i32], i32) 5declare swifttailcc void @callee_stack20([4 x i32], [5 x i32]) 6declare extern_weak swifttailcc void @callee_weak() 7 8define swifttailcc void @caller_to0_from0() nounwind { 9; CHECK-LABEL: _caller_to0_from0: 10 11 tail call swifttailcc void @callee_stack0() 12 ret void 13; CHECK-NOT: add 14; CHECK-NOT: sub 15; CHECK: b.w _callee_stack0 16} 17 18define swifttailcc void @caller_to0_from4([4 x i32], i32) { 19; CHECK-LABEL: _caller_to0_from4: 20 21 tail call swifttailcc void @callee_stack0() 22 ret void 23 24; CHECK: add sp, #16 25; CHECK-NEXT: b.w _callee_stack0 26} 27 28define swifttailcc void @caller_to4_from0() { 29; Key point is that the "42" should go #16 below incoming stack 30; pointer (we didn't have arg space to reuse). 31 tail call swifttailcc void @callee_stack4([4 x i32] undef, i32 42) 32 ret void 33 34; CHECK-LABEL: _caller_to4_from0: 35; CHECK: sub sp, #16 36; CHECK: movs [[TMP:r[0-9]+]], #42 37; CHECK: str [[TMP]], [sp] 38; CHECK-NOT: add sp 39; CHECK: b.w _callee_stack4 40 41} 42 43define swifttailcc void @caller_to4_from4([4 x i32], i32 %a) { 44; CHECK-LABEL: _caller_to4_from4: 45; CHECK-NOT: sub sp 46; Key point is that the "%a" should go where at SP on entry. 47 tail call swifttailcc void @callee_stack4([4 x i32] undef, i32 42) 48 ret void 49 50; CHECK: str {{r[0-9]+}}, [sp] 51; CHECK-NOT: add sp 52; CHECK-NEXT: b.w _callee_stack4 53} 54 55define swifttailcc void @caller_to20_from4([4 x i32], i32 %a) { 56; CHECK-LABEL: _caller_to20_from4: 57; CHECK: sub sp, #16 58 59; Important point is that the call reuses the "dead" argument space 60; above %a on the stack. If it tries to go below incoming-SP then the 61; _callee will not deallocate the space, even in swifttailcc. 62 tail call swifttailcc void @callee_stack20([4 x i32] undef, [5 x i32] [i32 1, i32 2, i32 3, i32 4, i32 5]) 63 64; CHECK: str {{.*}}, [sp] 65; CHECK: str {{.*}}, [sp, #4] 66; CHECK: str {{.*}}, [sp, #8] 67; CHECK: str {{.*}}, [sp, #12] 68; CHECK: str {{.*}}, [sp, #16] 69; CHECK-NOT: add sp 70; CHECK-NOT: sub sp 71; CHECK: b.w _callee_stack20 72 ret void 73} 74 75 76define swifttailcc void @caller_to4_from24([4 x i32], i64 %a, i64 %b, i64 %c) { 77; CHECK-LABEL: _caller_to4_from24: 78 79 80; Key point is that the "%a" should go where at #16 above SP on entry. 81 tail call swifttailcc void @callee_stack4([4 x i32] undef, i32 42) 82 ret void 83 84; CHECK: str {{.*}}, [sp, #16] 85; CHECK: add sp, #16 86; CHECK-NEXT: b.w _callee_stack4 87} 88 89 90define swifttailcc void @caller_to20_from20([4 x i32], [5 x i32] %a) { 91; CHECK-LABEL: _caller_to20_from20: 92; CHECK-NOT: add sp, 93; CHECK-NOT: sub sp, 94 95; Here we want to make sure that both loads happen before the stores: 96; otherwise either %a or %b.w will be wrongly clobbered. 97 tail call swifttailcc void @callee_stack20([4 x i32] undef, [5 x i32] %a) 98 ret void 99 100 ; If these ever get interleaved make sure aliasing slots don't clobber each 101 ; other. 102; CHECK: ldrd {{.*}}, {{.*}}, [sp, #12] 103; CHECK: ldm.w sp, 104; CHECK: stm.w 105; CHECK: strd 106; CHECK-NEXT: b.w _callee_stack20 107} 108 109define swifttailcc void @disable_tail_calls() nounwind "disable-tail-calls"="true" { 110; CHECK-LABEL: disable_tail_calls: 111 112 tail call swifttailcc void @callee_stack0() 113 ret void 114 115; CHECK: bl _callee_stack0 116; CHECK: ret 117} 118 119define swifttailcc void @normal_ret_with_stack([4 x i32], i32 %a) { 120; CHECK: _normal_ret_with_stack: 121; CHECK: add sp, #16 122; CHECK: bx lr 123 ret void 124} 125 126declare { [2 x float] } @get_vec2() 127 128define void @fromC_totail() { 129; COMMON-LABEL: fromC_totail: 130; COMMON: puch {r4, lr} 131; COMMON: sub sp, #8 132 133; COMMON-NOT: sub sp, 134; COMMON: movs [[TMP:r[0-9]+]], #42 135; COMMON: str [[TMP]], [sp] 136; COMMON: bl _callee_stack4 137 ; We must reset the stack to where it was before the call by undoing its extra stack pop. 138; COMMON: sub sp, #16 139; COMMON: str [[TMP]], [sp] 140; COMMON: bl callee_stack4 141; COMMON: sub sp, #16 142 143 call swifttailcc void @callee_stack4([4 x i32] undef, i32 42) 144 call swifttailcc void @callee_stack4([4 x i32] undef, i32 42) 145 ret void 146} 147 148define void @fromC_totail_noreservedframe(i32 %len) { 149; COMMON-LABEL: fromC_totail_noreservedframe: 150; COMMON: sub.w sp, sp, r{{.*}} 151 152; COMMON: movs [[TMP:r[0-9]+]], #42 153 ; Note stack is subtracted here to allocate space for arg 154; COMMON: sub.w sp, #16 155; COMMON: str [[TMP]], [sp] 156; COMMON: bl _callee_stack4 157 ; And here. 158; COMMON: sub sp, #16 159; COMMON: str [[TMP]], [sp] 160; COMMON: bl _callee_stack4 161 ; But not restored here because callee_stack8 did that for us. 162; COMMON-NOT: sub sp, 163 164 ; Variable sized allocation prevents reserving frame at start of function so each call must allocate any stack space it needs. 165 %var = alloca i32, i32 %len 166 167 call swifttailcc void @callee_stack4([4 x i32] undef, i32 42) 168 call swifttailcc void @callee_stack4([4 x i32] undef, i32 42) 169 ret void 170} 171 172declare void @Ccallee_stack4([4 x i32], i32) 173 174define swifttailcc void @fromtail_toC() { 175; COMMON-LABEL: fromtail_toC: 176; COMMON: push {r4, lr} 177; COMMON: sub sp, #8 178 179; COMMON-NOT: sub sp, 180; COMMON: movs [[TMP:r[0-9]+]], #42 181; COMMON: str [[TMP]], [sp] 182; COMMON: bl _Ccallee_stack4 183 ; C callees will return with the stack exactly where we left it, so we mustn't try to fix anything. 184; COMMON-NOT: add sp, 185; COMMON-NOT: sub sp, 186; COMMON: str [[TMP]], [sp]{{$}} 187; COMMON: bl _Ccallee_stack4 188; COMMON-NOT: sub sp, 189 190 call void @Ccallee_stack4([4 x i32] undef, i32 42) 191 call void @Ccallee_stack4([4 x i32] undef, i32 42) 192 ret void 193} 194 195declare swifttailcc ptr @SwiftSelf(ptr swiftasync %context, ptr swiftself %closure) 196define swiftcc ptr @CallSwiftSelf(ptr swiftself %closure, ptr %context) { 197; CHECK-LABEL: CallSwiftSelf: 198; CHECK: push{{.*}}r10 199 %res = call swifttailcc ptr @SwiftSelf(ptr swiftasync %context, ptr swiftself %closure) 200 ret ptr %res 201} 202