xref: /llvm-project/llvm/test/CodeGen/ARM/tailcc-call.ll (revision 19d2e42be2cd586456ae03374b5fd3e22d9d14f2)
1; RUN: llc -verify-machineinstrs < %s -mtriple=thumbv7k-apple-watchos | FileCheck %s
2
3declare tailcc void @callee_stack0()
4declare tailcc void @callee_stack4([4 x i32], i32)
5declare tailcc void @callee_stack20([4 x i32], [5 x i32])
6declare extern_weak tailcc void @callee_weak()
7
8define tailcc void @caller_to0_from0() nounwind {
9; CHECK-LABEL: _caller_to0_from0:
10
11  tail call tailcc void @callee_stack0()
12  ret void
13; CHECK-NOT: add
14; CHECK-NOT: sub
15; CHECK: b.w _callee_stack0
16}
17
18define tailcc void @caller_to0_from4([4 x i32], i32) {
19; CHECK-LABEL: _caller_to0_from4:
20
21  tail call tailcc void @callee_stack0()
22  ret void
23
24; CHECK: add sp, #16
25; CHECK-NEXT: b.w _callee_stack0
26}
27
28define tailcc 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 tailcc 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 tailcc 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 tailcc 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 tailcc 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 tailcc.
62  tail call tailcc 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 tailcc 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 tailcc 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 tailcc 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 tailcc 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 tailcc void @disable_tail_calls() nounwind "disable-tail-calls"="true" {
110; CHECK-LABEL: disable_tail_calls:
111
112  tail call tailcc void @callee_stack0()
113  ret void
114
115; CHECK: bl _callee_stack0
116; CHECK: ret
117}
118
119define tailcc 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 tailcc void @callee_stack4([4 x i32] undef, i32 42)
144  call tailcc 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 tailcc void @callee_stack4([4 x i32] undef, i32 42)
168  call tailcc void @callee_stack4([4 x i32] undef, i32 42)
169  ret void
170}
171
172declare void @Ccallee_stack4([4 x i32], i32)
173
174define tailcc 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
195; Don't try to return by popping pc if there's stack to reclaim.
196define tailcc void @notail_stackclean([4 x i32], i32) {
197; COMMON-LABEL: notail_stackclean:
198; COMMON: pop {r7, lr}
199; COMMON: add sp, #8
200; COMMON: bx lr
201
202
203  call void @callee_stack0()
204  ret void
205}
206