Revert r354244 "[DAGCombiner] Eliminate dead stores to stack."
[llvm-complete.git] / test / CodeGen / Thumb / callee_save.ll
blobb9216e7442907fc60627887161074eb88934b4d9
1 ; RUN: llc -mtriple=thumbv6m-none-eabi < %s | FileCheck %s
3 declare i8* @llvm.returnaddress(i32)
5 ; We don't allocate high registers, so any function not using inline asm will
6 ; only need to save the low registers.
7 define void @low_regs_only() {
8 ; CHECK-LABEL: low_regs_only:
9 entry:
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
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.
18 define void @one_high() {
19 ; CHECK-LABEL: one_high:
20 entry:
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
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.
31 define void @four_high() {
32 ; CHECK-LABEL: four_high:
33 entry:
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
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.
51 define void @one_high_one_low() {
52 ; CHECK-LABEL: one_high_one_low:
53 entry:
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
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.
66 define void @four_high_four_low() {
67 ; CHECK-LABEL: four_high_four_low:
68 entry:
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
86 ; All callee-saved registers clobbered, and frame pointer is requested. r7 now
87 ; cannot be used while saving/restoring the high regs.
88 define void @four_high_four_low_frame_ptr() "no-frame-pointer-elim"="true" {
89 ; CHECK-LABEL: four_high_four_low_frame_ptr:
90 entry:
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
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.
111 define 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:
113 entry:
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
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.
133 define void @four_high_four_arg(i32 %a, i32 %b, i32 %c, i32 %d) {
134 ; CHECK-LABEL: four_high_four_arg:
135 entry:
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
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.
154 define <4 x i32> @four_high_four_return() {
155 ; CHECK-LABEL: four_high_four_return:
156 entry:
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
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.
181 define <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
183 entry:
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
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.
213 define <4 x i32> @base_pointer(i32 %a) {
214 ; CHECK-LABEL: base_pointer:
215 entry:
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