blob: 7ee80d4b9b9611e26336f8a77b712a12ae644ef6 [file] [log] [blame]
Eli Friedman5b45a392018-08-08 20:03:10 +00001; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
Sanne Woudaa9941852017-02-03 11:15:53 +00002; RUN: llc %s -o - -mtriple=thumbv8m.base | FileCheck %s
3
Momchil Velikovdc86e142017-11-14 10:36:52 +00004declare i32 @g(...)
5
6declare i32 @h0(i32, i32, i32, i32)
7define hidden i32 @f0() {
Eli Friedman5b45a392018-08-08 20:03:10 +00008; CHECK-LABEL: f0:
9; CHECK: @ %bb.0:
10; CHECK-NEXT: push {r7, lr}
11; CHECK-NEXT: bl g
12; CHECK-NEXT: movs r1, #1
13; CHECK-NEXT: movs r2, #2
14; CHECK-NEXT: movs r3, #3
15; CHECK-NEXT: ldr r7, [sp, #4]
16; CHECK-NEXT: mov lr, r7
17; CHECK-NEXT: pop {r7}
18; CHECK-NEXT: add sp, #4
19; CHECK-NEXT: b h0
Momchil Velikovdc86e142017-11-14 10:36:52 +000020 %1 = tail call i32 bitcast (i32 (...)* @g to i32 ()*)()
21 %2 = tail call i32 @h0(i32 %1, i32 1, i32 2, i32 3)
22 ret i32 %2
Sanne Woudaa9941852017-02-03 11:15:53 +000023}
24
Momchil Velikovdc86e142017-11-14 10:36:52 +000025declare i32 @h1(i32)
26define hidden i32 @f1() {
Eli Friedman5b45a392018-08-08 20:03:10 +000027; CHECK-LABEL: f1:
28; CHECK: @ %bb.0:
29; CHECK-NEXT: push {r7, lr}
30; CHECK-NEXT: bl g
31; CHECK-NEXT: pop {r7}
32; CHECK-NEXT: pop {r1}
33; CHECK-NEXT: mov lr, r1
34; CHECK-NEXT: b h1
Momchil Velikovdc86e142017-11-14 10:36:52 +000035 %1 = tail call i32 bitcast (i32 (...)* @g to i32 ()*)()
36 %2 = tail call i32 @h1(i32 %1)
37 ret i32 %2
Sanne Woudaa9941852017-02-03 11:15:53 +000038}
39
Momchil Velikovdc86e142017-11-14 10:36:52 +000040declare i32 @h2(i32, i32, i32, i32, i32)
41define hidden i32 @f2(i32, i32, i32, i32, i32) {
Eli Friedman5b45a392018-08-08 20:03:10 +000042; CHECK-LABEL: f2:
43; CHECK: @ %bb.0:
44; CHECK-NEXT: push {r4, r5, r6, lr}
45; CHECK-NEXT: mov r4, r3
46; CHECK-NEXT: mov r5, r2
47; CHECK-NEXT: mov r6, r1
48; CHECK-NEXT: bl g
49; CHECK-NEXT: cbz r0, .LBB2_2
50; CHECK-NEXT: @ %bb.1:
51; CHECK-NEXT: mov r1, r6
52; CHECK-NEXT: mov r2, r5
53; CHECK-NEXT: mov r3, r4
54; CHECK-NEXT: ldr r4, [sp, #12]
55; CHECK-NEXT: mov lr, r4
56; CHECK-NEXT: pop {r4, r5, r6}
57; CHECK-NEXT: add sp, #4
58; CHECK-NEXT: b h2
59; CHECK-NEXT: .LBB2_2:
60; CHECK-NEXT: movs r0, #0
61; CHECK-NEXT: mvns r0, r0
62; CHECK-NEXT: pop {r4, r5, r6, pc}
Momchil Velikovdc86e142017-11-14 10:36:52 +000063 %6 = tail call i32 bitcast (i32 (...)* @g to i32 ()*)()
64 %7 = icmp eq i32 %6, 0
65 br i1 %7, label %10, label %8
66
67 %9 = tail call i32 @h2(i32 %6, i32 %1, i32 %2, i32 %3, i32 %4)
68 br label %10
69
70 %11 = phi i32 [ %9, %8 ], [ -1, %5 ]
71 ret i32 %11
Momchil Velikovdc86e142017-11-14 10:36:52 +000072}
Pablo Barrio2b438582017-12-04 16:55:49 +000073
74; Make sure that tail calls to function pointers that require r0-r3 for argument
75; passing do not break the compiler.
76@fnptr = global i32 (i32, i32, i32, i32)* null
77define i32 @test3() {
78; CHECK-LABEL: test3:
Eli Friedman5b45a392018-08-08 20:03:10 +000079; CHECK: @ %bb.0:
80; CHECK-NEXT: push {r4, lr}
81; CHECK-NEXT: movw r0, :lower16:fnptr
82; CHECK-NEXT: movt r0, :upper16:fnptr
83; CHECK-NEXT: ldr r4, [r0]
84; CHECK-NEXT: movs r0, #1
85; CHECK-NEXT: movs r1, #2
86; CHECK-NEXT: movs r2, #3
87; CHECK-NEXT: movs r3, #4
88; CHECK-NEXT: blx r4
89; CHECK-NEXT: pop {r4, pc}
Pablo Barrio2b438582017-12-04 16:55:49 +000090 %1 = load i32 (i32, i32, i32, i32)*, i32 (i32, i32, i32, i32)** @fnptr
91 %2 = tail call i32 %1(i32 1, i32 2, i32 3, i32 4)
92 ret i32 %2
93}
94
95@fnptr2 = global i32 (i32, i32, i64)* null
96define i32 @test4() {
97; CHECK-LABEL: test4:
Eli Friedman5b45a392018-08-08 20:03:10 +000098; CHECK: @ %bb.0:
99; CHECK-NEXT: push {r4, lr}
100; CHECK-NEXT: movw r0, :lower16:fnptr2
101; CHECK-NEXT: movt r0, :upper16:fnptr2
102; CHECK-NEXT: ldr r4, [r0]
103; CHECK-NEXT: movs r0, #1
104; CHECK-NEXT: movs r1, #2
105; CHECK-NEXT: movs r2, #3
106; CHECK-NEXT: movs r3, #0
107; CHECK-NEXT: blx r4
108; CHECK-NEXT: pop {r4, pc}
Pablo Barrio2b438582017-12-04 16:55:49 +0000109 %1 = load i32 (i32, i32, i64)*, i32 (i32, i32, i64)** @fnptr2
110 %2 = tail call i32 %1(i32 1, i32 2, i64 3)
111 ret i32 %2
112}
113
114; Check that tail calls to function pointers where not all of r0-r3 are used for
115; parameter passing are tail-call optimized.
116; test5: params in r0, r1. r2 & r3 are free.
117@fnptr3 = global i32 (i32, i32)* null
118define i32 @test5() {
119; CHECK-LABEL: test5:
Eli Friedman5b45a392018-08-08 20:03:10 +0000120; CHECK: @ %bb.0:
121; CHECK-NEXT: movw r0, :lower16:fnptr3
122; CHECK-NEXT: movt r0, :upper16:fnptr3
123; CHECK-NEXT: ldr r2, [r0]
124; CHECK-NEXT: movs r0, #1
125; CHECK-NEXT: movs r1, #2
126; CHECK-NEXT: bx r2
Pablo Barrio2b438582017-12-04 16:55:49 +0000127 %1 = load i32 (i32, i32)*, i32 (i32, i32)** @fnptr3
128 %2 = tail call i32 %1(i32 1, i32 2)
129 ret i32 %2
130}
131
132; test6: params in r0 and r2-r3. r1 is free.
133@fnptr4 = global i32 (i32, i64)* null
134define i32 @test6() {
135; CHECK-LABEL: test6:
Eli Friedman5b45a392018-08-08 20:03:10 +0000136; CHECK: @ %bb.0:
137; CHECK-NEXT: movw r0, :lower16:fnptr4
138; CHECK-NEXT: movt r0, :upper16:fnptr4
139; CHECK-NEXT: ldr r1, [r0]
140; CHECK-NEXT: movs r0, #1
141; CHECK-NEXT: movs r2, #2
142; CHECK-NEXT: movs r3, #0
143; CHECK-NEXT: bx r1
Pablo Barrio2b438582017-12-04 16:55:49 +0000144 %1 = load i32 (i32, i64)*, i32 (i32, i64)** @fnptr4
145 %2 = tail call i32 %1(i32 1, i64 2)
146 ret i32 %2
147}
148
149; Check that tail calls to functions other than function pointers are
150; tail-call optimized.
151define i32 @test7() {
152; CHECK-LABEL: test7:
Eli Friedman5b45a392018-08-08 20:03:10 +0000153; CHECK: @ %bb.0:
154; CHECK-NEXT: movs r0, #1
155; CHECK-NEXT: movs r1, #2
156; CHECK-NEXT: movs r2, #3
157; CHECK-NEXT: movs r3, #4
158; CHECK-NEXT: b bar
Pablo Barrio2b438582017-12-04 16:55:49 +0000159 %tail = tail call i32 @bar(i32 1, i32 2, i32 3, i32 4)
160 ret i32 %tail
161}
162
163declare i32 @bar(i32, i32, i32, i32)
Momchil Velikovd2cc6fd2018-01-26 10:20:58 +0000164
165; Regression test for failure to load indirect branch target (class tcGPR) from
166; a stack slot.
167%struct.S = type { i32 }
168
169define void @test8(i32 (i32, i32, i32)* nocapture %fn, i32 %x) local_unnamed_addr {
Eli Friedman5b45a392018-08-08 20:03:10 +0000170; CHECK-LABEL: test8:
171; CHECK: @ %bb.0: @ %entry
172; CHECK-NEXT: push {r4, r5, r6, r7, lr}
173; CHECK-NEXT: sub sp, #4
174; CHECK-NEXT: mov r4, r1
175; CHECK-NEXT: str r0, [sp] @ 4-byte Spill
176; CHECK-NEXT: bl test8_u
177; CHECK-NEXT: mov r5, r0
178; CHECK-NEXT: ldr r6, [r0]
179; CHECK-NEXT: movs r7, #0
180; CHECK-NEXT: mov r0, r7
181; CHECK-NEXT: bl test8_h
182; CHECK-NEXT: mov r1, r0
183; CHECK-NEXT: mov r0, r6
184; CHECK-NEXT: mov r2, r7
185; CHECK-NEXT: bl test8_g
186; CHECK-NEXT: str r4, [r5]
187; CHECK-NEXT: movs r0, #1
188; CHECK-NEXT: movs r1, #2
189; CHECK-NEXT: movs r2, #3
190; CHECK-NEXT: ldr r3, [sp] @ 4-byte Reload
191; CHECK-NEXT: add sp, #4
192; CHECK-NEXT: ldr r4, [sp, #16]
193; CHECK-NEXT: mov lr, r4
194; CHECK-NEXT: pop {r4, r5, r6, r7}
195; CHECK-NEXT: add sp, #4
196; CHECK-NEXT: bx r3
Momchil Velikovd2cc6fd2018-01-26 10:20:58 +0000197entry:
198 %call = tail call %struct.S* bitcast (%struct.S* (...)* @test8_u to %struct.S* ()*)()
199 %a = getelementptr inbounds %struct.S, %struct.S* %call, i32 0, i32 0
200 %0 = load i32, i32* %a, align 4
201 %call1 = tail call i32 @test8_h(i32 0)
202 %call2 = tail call i32 @test8_g(i32 %0, i32 %call1, i32 0)
203 store i32 %x, i32* %a, align 4
204 %call4 = tail call i32 %fn(i32 1, i32 2, i32 3)
205 ret void
206}
207
208declare %struct.S* @test8_u(...)
209
210declare i32 @test8_g(i32, i32, i32)
211
212declare i32 @test8_h(i32)
Eli Friedman5b45a392018-08-08 20:03:10 +0000213
214; Check that we don't introduce an unnecessary spill of lr.
215declare i32 @h9(i32, i32, i32, i32)
216define i32 @test9(i32* %x, i32* %y, i32* %z, i32* %a) {
217; CHECK-LABEL: test9:
218; CHECK: @ %bb.0:
219; CHECK-NEXT: push {r4, r7}
220; CHECK-NEXT: ldr r4, [r3]
221; CHECK-NEXT: ldr r3, [r3, #4]
222; CHECK-NEXT: adds r3, r4, r3
223; CHECK-NEXT: ldr r1, [r1]
224; CHECK-NEXT: ldr r0, [r0]
225; CHECK-NEXT: ldr r2, [r2]
226; CHECK-NEXT: pop {r4, r7}
227; CHECK-NEXT: b h9
228 %zz = load i32, i32* %z
229 %xx = load i32, i32* %x
230 %yy = load i32, i32* %y
231 %aa1 = load i32, i32* %a
232 %a2 = getelementptr i32, i32* %a, i32 1
233 %aa2 = load i32, i32* %a2
234 %aa = add i32 %aa1, %aa2
235 %r = tail call i32 @h9(i32 %xx, i32 %yy, i32 %zz, i32 %aa)
236 ret i32 %r
237}