xref: /llvm-project/llvm/test/CodeGen/ARM/swifttailcc-call.ll (revision bed1c7f061aa12417aa081e334afdba45767b938)
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