[InstCombine] Signed saturation patterns
[llvm-core.git] / test / CodeGen / Thumb / frame-access.ll
blobff1d57db94483b8ec91975f338a1d86e07be06c3
1 ; RUN: llc -mtriple=thumbv6m-eabi -frame-pointer=none %s -o - | FileCheck %s
3 ; struct S { int x[128]; } s;
4 ; int f(int *, int, int, int, struct S);
5 ; int g(int *, int, int, int, int, int);
6 ; int h(int *, int *, int *);
7 ; int u(int *, int *, int *, struct S, struct S);
9 %struct.S = type { [128 x i32] }
10 %struct.__va_list = type { i8* }
12 @s = common dso_local global %struct.S zeroinitializer, align 4
14 declare void @llvm.va_start(i8*)
15 declare dso_local i32 @g(i32*, i32, i32, i32, i32, i32) local_unnamed_addr
16 declare dso_local i32 @f(i32*, i32, i32, i32, %struct.S* byval align 4) local_unnamed_addr
17 declare dso_local i32 @h(i32*, i32*, i32*) local_unnamed_addr
18 declare dso_local i32 @u(i32*, i32*, i32*, %struct.S* byval align 4, %struct.S* byval align 4) local_unnamed_addr
21 ; Test access to arguments, passed on stack (including varargs)
24 ; Usual case, access via SP
25 ; int test_args_sp(int a, int b, int c, int d, int e) {
26 ;   int v[4];
27 ;   return g(v, a, b, c, d, e);
28 ; }
29 define dso_local i32 @test_args_sp(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) local_unnamed_addr {
30 entry:
31   %v = alloca [4 x i32], align 4
32   %0 = bitcast [4 x i32]* %v to i8*
33   %arraydecay = getelementptr inbounds [4 x i32], [4 x i32]* %v, i32 0, i32 0
34   %call = call i32 @g(i32* nonnull %arraydecay, i32 %a, i32 %b, i32 %c, i32 %d, i32 %e)
35   ret i32 %call
37 ; CHECK-LABEL: test_args_sp
38 ; Load `e`
39 ; CHECK:       ldr    r0, [sp, #32]
40 ; CHECK-NEXT:  str    r3, [sp]
41 ; Pass `e` on stack
42 ; CHECK-NEXT:  str    r0, [sp, #4]
43 ; CHECK:       bl    g
45 ; int test_varargs_sp(int a, ...) {
46 ;   int v[4];
47 ;   __builtin_va_list ap;
48 ;   __builtin_va_start(ap, a);
49 ;   return g(v, a, 0, 0, 0, 0);
50 ; }
51 define dso_local i32 @test_varargs_sp(i32 %a, ...) local_unnamed_addr  {
52 entry:
53   %v = alloca [4 x i32], align 4
54   %ap = alloca %struct.__va_list, align 4
55   %0 = bitcast [4 x i32]* %v to i8*
56   %1 = bitcast %struct.__va_list* %ap to i8*
57   call void @llvm.va_start(i8* nonnull %1)
58   %arraydecay = getelementptr inbounds [4 x i32], [4 x i32]* %v, i32 0, i32 0
59   %call = call i32 @g(i32* nonnull %arraydecay, i32 %a, i32 0, i32 0, i32 0, i32 0)
60   ret i32 %call
62 ; CHECK-LABEL: test_varargs_sp
63 ; Three incoming varargs in registers
64 ; CHECK:       sub sp, #12
65 ; CHECK:       sub sp, #28
66 ; Incoming arguments area is accessed via SP
67 ; CHECK:       add r0, sp, #36
68 ; CHECK:       stm r0!, {r1, r2, r3}
70 ; Re-aligned stack, access via FP
71 ; int test_args_realign(int a, int b, int c, int d, int e) {
72 ;   __attribute__((aligned(16))) int v[4];
73 ;   return g(v, a, b, c, d, e);
74 ; }
75 ; Function Attrs: nounwind
76 define dso_local i32 @test_args_realign(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) local_unnamed_addr  {
77 entry:
78   %v = alloca [4 x i32], align 16
79   %0 = bitcast [4 x i32]* %v to i8*
80   %arraydecay = getelementptr inbounds [4 x i32], [4 x i32]* %v, i32 0, i32 0
81   %call = call i32 @g(i32* nonnull %arraydecay, i32 %a, i32 %b, i32 %c, i32 %d, i32 %e)
82   ret i32 %call
84 ; CHECK-LABEL: test_args_realign
85 ; Setup frame pointer
86 ; CHECK:       add r7, sp, #8
87 ; Align stack
88 ; CHECK:       mov  r4, sp
89 ; CHECK-NEXT:  lsrs r4, r4, #4
90 ; CHECK-NEXT:  lsls r4, r4, #4
91 ; CHECK-NEXT:  mov  sp, r4
92 ; Load `e` via FP
93 ; CHECK:       ldr r0, [r7, #8]
94 ; CHECK-NEXT:  str r3, [sp]
95 ; Pass `e` as argument
96 ; CHECK-NEXT:  str r0, [sp, #4]
97 ; CHECK:       bl    g
99 ; int test_varargs_realign(int a, ...) {
100 ;   __attribute__((aligned(16))) int v[4];
101 ;   __builtin_va_list ap;
102 ;   __builtin_va_start(ap, a);
103 ;   return g(v, a, 0, 0, 0, 0);
104 ; }
105 define dso_local i32 @test_varargs_realign(i32 %a, ...) local_unnamed_addr  {
106 entry:
107   %v = alloca [4 x i32], align 16
108   %ap = alloca %struct.__va_list, align 4
109   %0 = bitcast [4 x i32]* %v to i8*
110   %1 = bitcast %struct.__va_list* %ap to i8*
111   call void @llvm.va_start(i8* nonnull %1)
112   %arraydecay = getelementptr inbounds [4 x i32], [4 x i32]* %v, i32 0, i32 0
113   %call = call i32 @g(i32* nonnull %arraydecay, i32 %a, i32 0, i32 0, i32 0, i32 0)
114   ret i32 %call
116 ; CHECK-LABEL: test_varargs_realign
117 ; Three incoming register varargs
118 ; CHECK:       sub sp, #12
119 ; Setup frame pointer
120 ; CHECK:       add r7, sp, #8
121 ; Align stack
122 ; CHECK:       mov  r4, sp
123 ; CHECK-NEXT:  lsrs r4, r4, #4
124 ; CHECK-NEXT:  lsls r4, r4, #4
125 ; CHECK-NEXT:  mov  sp, r4
126 ; Incoming register varargs stored via FP
127 ; CHECK:      mov r0, r7
128 ; CHECK-NEXT: adds r0, #8
129 ; CHECK-NEXT: stm r0!, {r1, r2, r3}
130 ; VLAs present, access via FP
131 ; int test_args_vla(int a, int b, int c, int d, int e) {
132 ;   int v[a];
133 ;   return g(v, a, b, c, d, e);
134 ; }
135 define dso_local i32 @test_args_vla(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) local_unnamed_addr  {
136 entry:
137   %vla = alloca i32, i32 %a, align 4
138   %call = call i32 @g(i32* nonnull %vla, i32 %a, i32 %b, i32 %c, i32 %d, i32 %e)
139   ret i32 %call
141 ; CHECK-LABEL: test_args_vla
142 ; Setup frame pointer
143 ; CHECK:       add r7, sp, #12
144 ; Allocate outgoing stack arguments space
145 ; CHECK:       sub sp, #4
146 ; Load `e` via FP
147 ; CHECK:       ldr r5, [r7, #8]
148 ; Pass `d` and `e` as arguments
149 ; CHECK-NEXT:  str r3, [sp]
150 ; CHECK-NEXT:  str r5, [sp, #4]
151 ; CHECK:       bl  g
153 ; int test_varargs_vla(int a, ...) {
154 ;   int v[a];
155 ;   __builtin_va_list ap;
156 ;   __builtin_va_start(ap, a);
157 ;   return g(v, a, 0, 0, 0, 0);
158 ; }
159 define dso_local i32 @test_varargs_vla(i32 %a, ...) local_unnamed_addr  {
160 entry:
161   %ap = alloca %struct.__va_list, align 4
162   %vla = alloca i32, i32 %a, align 4
163   %0 = bitcast %struct.__va_list* %ap to i8*
164   call void @llvm.va_start(i8* nonnull %0)
165   %call = call i32 @g(i32* nonnull %vla, i32 %a, i32 0, i32 0, i32 0, i32 0)
166   ret i32 %call
168 ; CHECK-LABEL: test_varargs_vla
169 ; Three incoming register varargs
170 ; CHECK:       sub sp, #12
171 ; Setup frame pointer
172 ; CHECK:       add r7, sp, #8
173 ; Register varargs stored via FP
174 ; CHECK-DAG:  str r3, [r7, #16]
175 ; CHECK-DAG:  str r2, [r7, #12]
176 ; CHECK-DAG:  str r1, [r7, #8]
178 ; Moving SP, access via SP
179 ; int test_args_moving_sp(int a, int b, int c, int d, int e) {
180 ;   int v[4];
181 ;   return f(v, a, b + c + d, e, s) + h(v, v+1, v+2);
182 ; }
183 define dso_local i32 @test_args_moving_sp(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) local_unnamed_addr  {
184 entry:
185   %v = alloca [4 x i32], align 4
186   %0 = bitcast [4 x i32]* %v to i8*
187   %arraydecay = getelementptr inbounds [4 x i32], [4 x i32]* %v, i32 0, i32 0
188   %add = add nsw i32 %c, %b
189   %add1 = add nsw i32 %add, %d
190   %call = call i32 @f(i32* nonnull %arraydecay, i32 %a, i32 %add1, i32 %e, %struct.S* byval nonnull align 4 @s)
191   %add.ptr = getelementptr inbounds [4 x i32], [4 x i32]* %v, i32 0, i32 1
192   %add.ptr5 = getelementptr inbounds [4 x i32], [4 x i32]* %v, i32 0, i32 2
193   %call6 = call i32 @h(i32* nonnull %arraydecay, i32* nonnull %add.ptr, i32* nonnull %add.ptr5)
194   %add7 = add nsw i32 %call6, %call
195   ret i32 %add7
197 ; CHECK-LABEL: test_args_moving_sp
198 ; 20 bytes callee-saved area
199 ; CHECK:       push {r4, r5, r6, r7, lr}
200 ; 20 bytes locals
201 ; CHECK:       sub sp, #20
202 ; Setup base pointer
203 ; CHECK:       mov r6, sp
204 ; Allocate outgoing arguments space
205 ; CHECK:       sub sp, #508
206 ; CHECK:       sub sp, #4
207 ; Load `e` via BP, 40 = 20 + 20
208 ; CHECK:       ldr r3, [r6, #40]
209 ; CHECK:       bl  f
210 ; Stack restored before next call
211 ; CHECK-NEXT:  add sp, #508
212 ; CHECK-NEXT:  add sp, #4
213 ; CHECK:       bl  h
215 ; int test_varargs_moving_sp(int a, ...) {
216 ;   int v[4];
217 ;   __builtin_va_list ap;
218 ;   __builtin_va_start(ap, a);
219 ;   return f(v, a, 0, 0, s) + h(v, v+1, v+2);
220 ; }
221 define dso_local i32 @test_varargs_moving_sp(i32 %a, ...) local_unnamed_addr  {
222 entry:
223   %v = alloca [4 x i32], align 4
224   %ap = alloca %struct.__va_list, align 4
225   %0 = bitcast [4 x i32]* %v to i8*
226   %1 = bitcast %struct.__va_list* %ap to i8*
227   call void @llvm.va_start(i8* nonnull %1)
228   %arraydecay = getelementptr inbounds [4 x i32], [4 x i32]* %v, i32 0, i32 0
229   %call = call i32 @f(i32* nonnull %arraydecay, i32 %a, i32 0, i32 0, %struct.S* byval nonnull align 4 @s)
230   %add.ptr = getelementptr inbounds [4 x i32], [4 x i32]* %v, i32 0, i32 1
231   %add.ptr5 = getelementptr inbounds [4 x i32], [4 x i32]* %v, i32 0, i32 2
232   %call6 = call i32 @h(i32* nonnull %arraydecay, i32* nonnull %add.ptr, i32* nonnull %add.ptr5)
233   %add = add nsw i32 %call6, %call
234   ret i32 %add
236 ; CHECK-LABEL: test_varargs_moving_sp
237 ; Three incoming register varargs
238 ; CHECK:       sub sp, #12
239 ; 16 bytes callee-saves
240 ; CHECK:       push {r4, r5, r6, lr}
241 ; 20 bytes locals
242 ; CHECK:       sub sp, #20
243 ; Incoming varargs stored via BP, 36 = 20 + 16
244 ; CHECK:       mov r0, r6
245 ; CHECK-NEXT:  adds r0, #36
246 ; CHECK-NEXT:  stm r0!, {r1, r2, r3}
249 ; Access to locals
252 ; Usual case, access via SP.
253 ; int test_local(int n) {
254 ;   int v[4];
255 ;   int x, y, z;
256 ;   h(&x, &y, &z);
257 ;   return g(v, x, y, z, 0, 0);
258 ; }
259 define dso_local i32 @test_local(i32 %n) local_unnamed_addr  {
260 entry:
261   %v = alloca [4 x i32], align 4
262   %x = alloca i32, align 4
263   %y = alloca i32, align 4
264   %z = alloca i32, align 4
265   %0 = bitcast [4 x i32]* %v to i8*
266   %1 = bitcast i32* %x to i8*
267   %2 = bitcast i32* %y to i8*
268   %3 = bitcast i32* %z to i8*
269   %call = call i32 @h(i32* nonnull %x, i32* nonnull %y, i32* nonnull %z)
270   %arraydecay = getelementptr inbounds [4 x i32], [4 x i32]* %v, i32 0, i32 0
271   %4 = load i32, i32* %x, align 4
272   %5 = load i32, i32* %y, align 4
273   %6 = load i32, i32* %z, align 4
274   %call1 = call i32 @g(i32* nonnull %arraydecay, i32 %4, i32 %5, i32 %6, i32 0, i32 0)
275   ret i32 %call1
277 ; CHECK-LABEL: test_local
278 ; Arguments to `h` relative to SP
279 ; CHECK:       add r0, sp, #20
280 ; CHECK-NEXT:  add r1, sp, #16
281 ; CHECK-NEXT:  add r2, sp, #12
282 ; CHECK-NEXT:  bl  h
283 ; Load `x`, `y`, and `z` via SP
284 ; CHECK:       ldr r1, [sp, #20]
285 ; CHECK-NEXT:  ldr r2, [sp, #16]
286 ; CHECK-NEXT:  ldr r3, [sp, #12]
287 ; CHECK:       bl  g
289 ; Re-aligned stack, access via SP.
290 ; int test_local_realign(int n) {
291 ;   __attribute__((aligned(16))) int v[4];
292 ;   int x, y, z;
293 ;   h(&x, &y, &z);
294 ;   return g(v, x, y, z, 0, 0);
295 ; }
296 define dso_local i32 @test_local_realign(i32 %n) local_unnamed_addr  {
297 entry:
298   %v = alloca [4 x i32], align 16
299   %x = alloca i32, align 4
300   %y = alloca i32, align 4
301   %z = alloca i32, align 4
302   %0 = bitcast [4 x i32]* %v to i8*
303   %1 = bitcast i32* %x to i8*
304   %2 = bitcast i32* %y to i8*
305   %3 = bitcast i32* %z to i8*
306   %call = call i32 @h(i32* nonnull %x, i32* nonnull %y, i32* nonnull %z)
307   %arraydecay = getelementptr inbounds [4 x i32], [4 x i32]* %v, i32 0, i32 0
308   %4 = load i32, i32* %x, align 4
309   %5 = load i32, i32* %y, align 4
310   %6 = load i32, i32* %z, align 4
311   %call1 = call i32 @g(i32* nonnull %arraydecay, i32 %4, i32 %5, i32 %6, i32 0, i32 0)
312   ret i32 %call1
314 ; CHECK-LABEL: test_local_realign
315 ; Setup frame pointer
316 ; CHECK:       add r7, sp, #8
317 ; Re-align stack
318 ; CHECK:       mov r4, sp
319 ; CHECK-NEXT:  lsrs r4, r4, #4
320 ; CHECK-NEXT:  lsls r4, r4, #4
321 ; CHECK-NEXT:  mov  sp, r4
322 ; Arguments to `h` computed relative to SP
323 ; CHECK:       add r0, sp, #28
324 ; CHECK-NEXT:  add r1, sp, #24
325 ; CHECK-NEXT:  add r2, sp, #20
326 ; CHECK-NEXT:  bl  h
327 ; Load `x`, `y`, and `z` via SP for passing to `g`
328 ; CHECK:       ldr r1, [sp, #28]
329 ; CHECK-NEXT:  ldr r2, [sp, #24]
330 ; CHECK-NEXT:  ldr r3, [sp, #20]
331 ; CHECK:       bl  g
333 ; VLAs, access via BP.
334 ; int test_local_vla(int n) {
335 ;   int v[n];
336 ;   int x, y, z;
337 ;   h(&x, &y, &z);
338 ;   return g(v, x, y, z, 0, 0);
339 ; }
340 define dso_local i32 @test_local_vla(i32 %n) local_unnamed_addr  {
341 entry:
342   %x = alloca i32, align 4
343   %y = alloca i32, align 4
344   %z = alloca i32, align 4
345   %vla = alloca i32, i32 %n, align 4
346   %0 = bitcast i32* %x to i8*
347   %1 = bitcast i32* %y to i8*
348   %2 = bitcast i32* %z to i8*
349   %call = call i32 @h(i32* nonnull %x, i32* nonnull %y, i32* nonnull %z)
350   %3 = load i32, i32* %x, align 4
351   %4 = load i32, i32* %y, align 4
352   %5 = load i32, i32* %z, align 4
353   %call1 = call i32 @g(i32* nonnull %vla, i32 %3, i32 %4, i32 %5, i32 0, i32 0)
354   ret i32 %call1
356 ; CHECK-LABEL: test_local_vla
357 ; Setup frame pointer
358 ; CHECK:       add  r7, sp, #12
359 ; Setup base pointer
360 ; CHECK:       mov  r6, sp
361 ; CHECK:       mov  r5, r6
362 ; Arguments to `h` compute relative to BP
363 ; CHECK:       adds r0, r6, #7
364 ; CHECK-NEXT:  adds r0, #1
365 ; CHECK-NEXT:  adds r1, r6, #4
366 ; CHECK-NEXT:  mov  r2, r6
367 ; CHECK-NEXT:  bl   h
368 ; Load `x`, `y`, `z` via BP (r5 should still have the value of r6 from the move
369 ; above)
370 ; CHECK:       ldr r3, [r5]
371 ; CHECK-NEXT:  ldr r2, [r5, #4]
372 ; CHECK-NEXT:  ldr r1, [r5, #8]
373 ; CHECK:       bl  g
375 ;  Moving SP, access via SP.
376 ; int test_local_moving_sp(int n) {
377 ;   int v[4];
378 ;   int x, y, z;
379 ;   return u(v, &x, &y, s, s) + u(v, &y, &z, s, s);
380 ; }
381 define dso_local i32 @test_local_moving_sp(i32 %n) local_unnamed_addr {
382 entry:
383   %v = alloca [4 x i32], align 4
384   %x = alloca i32, align 4
385   %y = alloca i32, align 4
386   %z = alloca i32, align 4
387   %0 = bitcast [4 x i32]* %v to i8*
388   %1 = bitcast i32* %x to i8*
389   %2 = bitcast i32* %y to i8*
390   %3 = bitcast i32* %z to i8*
391   %arraydecay = getelementptr inbounds [4 x i32], [4 x i32]* %v, i32 0, i32 0
392   %call = call i32 @u(i32* nonnull %arraydecay, i32* nonnull %x, i32* nonnull %y, %struct.S* byval nonnull align 4 @s, %struct.S* byval nonnull align 4 @s)
393   %call2 = call i32 @u(i32* nonnull %arraydecay, i32* nonnull %y, i32* nonnull %z, %struct.S* byval nonnull align 4 @s, %struct.S* byval nonnull align 4 @s)
394   %add = add nsw i32 %call2, %call
395   ret i32 %add
397 ; CHECK-LABEL: test_local_moving_sp
398 ; Locals area
399 ; CHECK:      sub sp, #36
400 ; Setup BP
401 ; CHECK:      mov r6, sp
402 ; Outoging arguments
403 ; CHECK:      sub sp, #508
404 ; CHECK-NEXT: sub sp, #508
405 ; CHECK-NEXT: sub sp, #8
406 ; Argument addresses computed relative to BP
407 ; CHECK:      adds r0, r6, #7
408 ; CHECK-NEXT: adds r0, #13
409 ; CHECK:      adds r1, r6, #7
410 ; CHECK-NEXT: adds r1, #9
411 ; CHECK:      adds r5, r6, #7
412 ; CHECK-NEXT: adds r5, #5
413 ; CHECK:      bl   u
414 ; Stack restored before next call
415 ; CHECK:      add  sp, #508
416 ; CHECK-NEXT: add  sp, #508
417 ; CHECK-NEXT: add  sp, #8
418 ; CHECK:      bl   u