• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1; RUN: llc -mtriple=thumbv6m-none-eabi < %s | FileCheck %s
2
3declare i8* @llvm.returnaddress(i32)
4
5; We don't allocate high registers, so any function not using inline asm will
6; only need to save the low registers.
7define void @low_regs_only() {
8; CHECK-LABEL: low_regs_only:
9entry:
10; CHECK: push {r4, r5, r6, r7, lr}
11  tail call void asm sideeffect "", "~{r4},~{r5},~{r6},~{r7}"()
12; CHECK: pop {r4, r5, r6, r7, pc}
13  ret void
14}
15
16; One high reg clobbered, but no low regs, args or returns. We can use an
17; argument/return register to help save/restore it.
18define void @one_high() {
19; CHECK-LABEL: one_high:
20entry:
21; CHECK: mov [[SAVEREG:r[0-3]]], r8
22; CHECK: push {[[SAVEREG]]}
23  tail call void asm sideeffect "", "~{r8}"()
24; CHECK: pop {[[RESTOREREG:r[0-3]]]}
25; CHECK: mov r8, [[RESTOREREG]]
26  ret void
27}
28
29; 4 high regs clobbered, but still no low regs, args or returns. We can use all
30; 4 arg/return regs for the save/restore.
31define void @four_high() {
32; CHECK-LABEL: four_high:
33entry:
34; CHECK: mov r3, r11
35; CHECK: mov r2, r10
36; CHECK: mov r1, r9
37; CHECK: mov r0, r8
38; CHECK: push {r0, r1, r2, r3}
39  tail call void asm sideeffect "", "~{r8},~{r9},~{r10},~{r11}"()
40; CHECK: pop {r0, r1, r2, r3}
41; CHECK: mov r8, r0
42; CHECK: mov r9, r1
43; CHECK: mov r10, r2
44; CHECK: mov r11, r3
45  ret void
46}
47
48; One high and one low register clobbered. lr also gets pushed to simplify the
49; return, and r7 to keep the stack aligned. Here, we could use r0-r3, r4, r7 or
50; lr to save/restore r8.
51define void @one_high_one_low() {
52; CHECK-LABEL: one_high_one_low:
53entry:
54; CHECK: push {r4, r7, lr}
55; CHECK: mov [[SAVEREG:r0|r1|r2|r3|r4|r7|lr]], r8
56; CHECK: push {[[SAVEREG]]}
57  tail call void asm sideeffect "", "~{r4},~{r8}"()
58; CHECK: pop {[[RESTOREREG:r0|r1|r2|r3|r4|r7]]}
59; CHECK: mov r8, [[RESTOREREG]]
60; CHECK: pop {r4, r7, pc}
61  ret void
62}
63
64; All callee-saved registers clobbered, r4-r7 and lr are not live after the
65; first push so can be used for pushing the high registers.
66define void @four_high_four_low() {
67; CHECK-LABEL: four_high_four_low:
68entry:
69; CHECK: push {r4, r5, r6, r7, lr}
70; CHECK: mov lr, r11
71; CHECK: mov r7, r10
72; CHECK: mov r6, r9
73; CHECK: mov r5, r8
74; CHECK: push {r5, r6, r7, lr}
75  tail call void asm sideeffect "", "~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11}"()
76; CHECK: pop {r0, r1, r2, r3}
77; CHECK: mov r8, r0
78; CHECK: mov r9, r1
79; CHECK: mov r10, r2
80; CHECK: mov r11, r3
81; CHECK: pop {r4, r5, r6, r7, pc}
82  ret void
83}
84
85
86; All callee-saved registers clobbered, and frame pointer is requested. r7 now
87; cannot be used while saving/restoring the high regs.
88define void @four_high_four_low_frame_ptr() "no-frame-pointer-elim"="true" {
89; CHECK-LABEL: four_high_four_low_frame_ptr:
90entry:
91; CHECK: push {r4, r5, r6, r7, lr}
92; CHECK: add r7, sp, #12
93; CHECK: mov lr, r11
94; CHECK: mov r6, r10
95; CHECK: mov r5, r9
96; CHECK: mov r4, r8
97; CHECK: push {r4, r5, r6, lr}
98  tail call void asm sideeffect "", "~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11}"()
99; CHECK: pop {r0, r1, r2, r3}
100; CHECK: mov r8, r0
101; CHECK: mov r9, r1
102; CHECK: mov r10, r2
103; CHECK: mov r11, r3
104; CHECK: pop {r4, r5, r6, r7, pc}
105  ret void
106}
107
108; All callee-saved registers clobbered, frame pointer is requested and
109; llvm.returnaddress used. r7 and lr now cannot be used while saving/restoring
110; the high regs.
111define void @four_high_four_low_frame_ptr_ret_addr() "no-frame-pointer-elim"="true" {
112; CHECK-LABEL: four_high_four_low_frame_ptr_ret_addr:
113entry:
114; CHECK: push {r4, r5, r6, r7, lr}
115; CHECK: mov r6, r11
116; CHECK: mov r5, r10
117; CHECK: mov r4, r9
118; CHECK: mov r3, r8
119; CHECK: push {r3, r4, r5, r6}
120  %a = tail call i8* @llvm.returnaddress(i32 0)
121  tail call void asm sideeffect "", "r,~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11}"(i8* %a)
122; CHECK: pop {r0, r1, r2, r3}
123; CHECK: mov r8, r0
124; CHECK: mov r9, r1
125; CHECK: mov r10, r2
126; CHECK: mov r11, r3
127; CHECK: pop {r4, r5, r6, r7, pc}
128  ret void
129}
130
131; 4 high regs clobbered, all 4 argument registers used. We push an extra 4 low
132; registers, so that we can use them for saving the high regs.
133define void @four_high_four_arg(i32 %a, i32 %b, i32 %c, i32 %d) {
134; CHECK-LABEL: four_high_four_arg:
135entry:
136; CHECK: push    {r5, r6, r7, lr}
137; CHECK: mov     lr, r11
138; CHECK: mov     r7, r10
139; CHECK: mov     r6, r9
140; CHECK: mov     r5, r8
141; CHECK: push    {r5, r6, r7, lr}
142  tail call void asm sideeffect "", "r,r,r,r,~{r8},~{r9},~{r10},~{r11}"(i32 %a, i32 %b, i32 %c, i32 %d)
143; CHECK: pop     {r0, r1, r2, r3}
144; CHECK: mov     r8, r0
145; CHECK: mov     r9, r1
146; CHECK: mov     r10, r2
147; CHECK: mov     r11, r3
148; CHECK: pop     {r5, r6, r7, pc}
149  ret void
150}
151
152; 4 high regs clobbered, all 4 return registers used. We push an extra 4 low
153; registers, so that we can use them for restoring the high regs.
154define <4 x i32> @four_high_four_return() {
155; CHECK-LABEL: four_high_four_return:
156entry:
157; CHECK: push    {r4, r5, r6, r7, lr}
158; CHECK: mov     lr, r11
159; CHECK: mov     r7, r10
160; CHECK: mov     r6, r9
161; CHECK: mov     r5, r8
162; CHECK: push    {r5, r6, r7, lr}
163  tail call void asm sideeffect "", "~{r8},~{r9},~{r10},~{r11}"()
164  %vecinit = insertelement <4 x i32> undef, i32 1, i32 0
165  %vecinit11 = insertelement <4 x i32> %vecinit, i32 2, i32 1
166  %vecinit12 = insertelement <4 x i32> %vecinit11, i32 3, i32 2
167  %vecinit13 = insertelement <4 x i32> %vecinit12, i32 4, i32 3
168; CHECK: pop     {r4, r5, r6, r7}
169; CHECK: mov     r8, r4
170; CHECK: mov     r9, r5
171; CHECK: mov     r10, r6
172; CHECK: mov     r11, r7
173; CHECK: pop     {r4, r5, r6, r7, pc}
174  ret <4 x i32> %vecinit13
175}
176
177; 4 high regs clobbered, all args & returns used, frame pointer requested and
178; llvm.returnaddress called. This leaves us with 3 low registers available (r4,
179; r5, r6), with which to save 4 high registers, so we have to use two pushes
180; and pops.
181define <4 x i32> @all_of_the_above(i32 %a, i32 %b, i32 %c, i32 %d) "no-frame-pointer-elim"="true" {
182; CHECK-LABEL: all_of_the_above
183entry:
184; CHECK: push    {r4, r5, r6, r7, lr}
185; CHECK: add     r7, sp, #12
186; CHECK: mov     r6, r11
187; CHECK: mov     r5, r10
188; CHECK: mov     r4, r9
189; CHECK: push    {r4, r5, r6}
190; CHECK: mov     r6, r8
191; CHECK: push    {r6}
192  tail call void asm sideeffect "", "r,r,r,r,~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11}"(i32 %a, i32 %b, i32 %c, i32 %d)
193  %e = tail call i8* @llvm.returnaddress(i32 0)
194  %f = ptrtoint i8* %e to i32
195  %vecinit = insertelement <4 x i32> undef, i32 %f, i32 0
196  %vecinit11 = insertelement <4 x i32> %vecinit, i32 2, i32 1
197  %vecinit12 = insertelement <4 x i32> %vecinit11, i32 3, i32 2
198  %vecinit13 = insertelement <4 x i32> %vecinit12, i32 4, i32 3
199; CHECK: pop     {r4, r5, r6}
200; CHECK: mov     r8, r4
201; CHECK: mov     r9, r5
202; CHECK: mov     r10, r6
203; CHECK: pop     {r4}
204; CHECK: mov     r11, r4
205; CHECK: pop     {r4, r5, r6, r7, pc}
206  ret <4 x i32> %vecinit13
207}
208
209; When a base pointer is being used, we can safely use it for saving/restoring
210; the high regs because it is set after the last push, and not used at all in the
211; epliogue. We can also use r4 for restoring the registers despite it also being
212; used when restoring sp from fp, as that happens before the first pop.
213define <4 x i32> @base_pointer(i32 %a) {
214; CHECK-LABEL: base_pointer:
215entry:
216; CHECK: push    {r4, r6, r7, lr}
217; CHECK: add     r7, sp, #8
218; CHECK: mov     lr, r9
219; CHECK: mov     r6, r8
220; CHECK: push    {r6, lr}
221; CHECK: mov     r6, sp
222  %b = alloca i32, i32 %a
223  call void asm sideeffect "", "r,~{r8},~{r9}"(i32* %b)
224  %vecinit = insertelement <4 x i32> undef, i32 1, i32 0
225  %vecinit11 = insertelement <4 x i32> %vecinit, i32 2, i32 1
226  %vecinit12 = insertelement <4 x i32> %vecinit11, i32 3, i32 2
227  %vecinit13 = insertelement <4 x i32> %vecinit12, i32 4, i32 3
228; CHECK: subs    r4, r7, #7
229; CHECK: subs    r4, #9
230; CHECK: mov     sp, r4
231; CHECK: pop     {r4, r6}
232; CHECK: mov     r8, r4
233; CHECK: mov     r9, r6
234; CHECK: pop     {r4, r6, r7, pc}
235  ret <4 x i32> %vecinit13
236}
237