Home | History | Annotate | Download | only in Thumb
      1 ; RUN: llc -mtriple=thumbv6m-eabi -disable-fp-elim=false %s -o - | FileCheck %s
      2 
      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);
      8 
      9 %struct.S = type { [128 x i32] }
     10 %struct.__va_list = type { i8* }
     11 
     12 @s = common dso_local global %struct.S zeroinitializer, align 4
     13 
     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
     19 
     20 ;
     21 ; Test access to arguments, passed on stack (including varargs)
     22 ;
     23 
     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
     36 }
     37 ; CHECK-LABEL: test_args_sp
     38 ; Load `e`
     39 ; CHECK:       ldr    r0, [sp, #40]
     40 ; CHECK-NEXT:  mov    r5, sp
     41 ; CHECK-NEXT:  str    r3, [r5]
     42 ; Pass `e` on stack
     43 ; CHECK-NEXT:  str    r0, [r5, #4]
     44 ; CHECK:       bl    g
     45 
     46 ; int test_varargs_sp(int a, ...) {
     47 ;   int v[4];
     48 ;   __builtin_va_list ap;
     49 ;   __builtin_va_start(ap, a);
     50 ;   return g(v, a, 0, 0, 0, 0);
     51 ; }
     52 define dso_local i32 @test_varargs_sp(i32 %a, ...) local_unnamed_addr  {
     53 entry:
     54   %v = alloca [4 x i32], align 4
     55   %ap = alloca %struct.__va_list, align 4
     56   %0 = bitcast [4 x i32]* %v to i8*
     57   %1 = bitcast %struct.__va_list* %ap to i8*
     58   call void @llvm.va_start(i8* nonnull %1)
     59   %arraydecay = getelementptr inbounds [4 x i32], [4 x i32]* %v, i32 0, i32 0
     60   %call = call i32 @g(i32* nonnull %arraydecay, i32 %a, i32 0, i32 0, i32 0, i32 0)
     61   ret i32 %call
     62 }
     63 ; CHECK-LABEL: test_varargs_sp
     64 ; Three incoming varargs in registers
     65 ; CHECK:       sub sp, #12
     66 ; CHECK:       sub sp, #28
     67 ; Incoming arguments area is accessed via SP
     68 ; CHECK:       add r0, sp, #36
     69 ; CHECK:       stm r0!, {r1, r2, r3}
     70 
     71 ; Re-aligned stack, access via FP
     72 ; int test_args_realign(int a, int b, int c, int d, int e) {
     73 ;   __attribute__((aligned(16))) int v[4];
     74 ;   return g(v, a, b, c, d, e);
     75 ; }
     76 ; Function Attrs: nounwind
     77 define dso_local i32 @test_args_realign(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) local_unnamed_addr  {
     78 entry:
     79   %v = alloca [4 x i32], align 16
     80   %0 = bitcast [4 x i32]* %v to i8*
     81   %arraydecay = getelementptr inbounds [4 x i32], [4 x i32]* %v, i32 0, i32 0
     82   %call = call i32 @g(i32* nonnull %arraydecay, i32 %a, i32 %b, i32 %c, i32 %d, i32 %e)
     83   ret i32 %call
     84 }
     85 ; CHECK-LABEL: test_args_realign
     86 ; Setup frame pointer
     87 ; CHECK:       add r7, sp, #8
     88 ; Align stack
     89 ; CHECK:       mov  r4, sp
     90 ; CHECK-NEXT:  lsrs r4, r4, #4
     91 ; CHECK-NEXT:  lsls r4, r4, #4
     92 ; CHECK-NEXT:  mov  sp, r4
     93 ; Load `e` via FP
     94 ; CHECK:       ldr r0, [r7, #8]
     95 ; CHECK-NEXT:  mov r5, sp
     96 ; CHECK-NEXT:  str r3, [r5]
     97 ; Pass `e` as argument
     98 ; CHECK-NEXT:  str r0, [r5, #4]
     99 ; CHECK:       bl    g
    100 
    101 ; int test_varargs_realign(int a, ...) {
    102 ;   __attribute__((aligned(16))) int v[4];
    103 ;   __builtin_va_list ap;
    104 ;   __builtin_va_start(ap, a);
    105 ;   return g(v, a, 0, 0, 0, 0);
    106 ; }
    107 define dso_local i32 @test_varargs_realign(i32 %a, ...) local_unnamed_addr  {
    108 entry:
    109   %v = alloca [4 x i32], align 16
    110   %ap = alloca %struct.__va_list, align 4
    111   %0 = bitcast [4 x i32]* %v to i8*
    112   %1 = bitcast %struct.__va_list* %ap to i8*
    113   call void @llvm.va_start(i8* nonnull %1)
    114   %arraydecay = getelementptr inbounds [4 x i32], [4 x i32]* %v, i32 0, i32 0
    115   %call = call i32 @g(i32* nonnull %arraydecay, i32 %a, i32 0, i32 0, i32 0, i32 0)
    116   ret i32 %call
    117 }
    118 ; CHECK-LABEL: test_varargs_realign
    119 ; Three incoming register varargs
    120 ; CHECK:       sub sp, #12
    121 ; Setup frame pointer
    122 ; CHECK:       add r7, sp, #8
    123 ; Align stack
    124 ; CHECK:       mov  r4, sp
    125 ; CHECK-NEXT:  lsrs r4, r4, #4
    126 ; CHECK-NEXT:  lsls r4, r4, #4
    127 ; CHECK-NEXT:  mov  sp, r4
    128 ; Incoming register varargs stored via FP
    129 ; CHECK:       str r3, [r7, #16]
    130 ; CHECK-NEXT:  str r2, [r7, #12]
    131 ; CHECK-NEXT:  str r1, [r7, #8]
    132 
    133 ; VLAs present, access via FP
    134 ; int test_args_vla(int a, int b, int c, int d, int e) {
    135 ;   int v[a];
    136 ;   return g(v, a, b, c, d, e);
    137 ; }
    138 define dso_local i32 @test_args_vla(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) local_unnamed_addr  {
    139 entry:
    140   %vla = alloca i32, i32 %a, align 4
    141   %call = call i32 @g(i32* nonnull %vla, i32 %a, i32 %b, i32 %c, i32 %d, i32 %e)
    142   ret i32 %call
    143 }
    144 ; CHECK-LABEL: test_args_vla
    145 ; Setup frame pointer
    146 ; CHECK:       add r7, sp, #12
    147 ; Allocate outgoing stack arguments space
    148 ; CHECK:       sub sp, #4
    149 ; Load `e` via FP
    150 ; CHECK:       ldr r5, [r7, #8]
    151 ; CHECK-NEXT:  mov r0, sp
    152 ; Pass `d` and `e` as arguments
    153 ; CHECK-NEXT:  stm r0!, {r3, r5}
    154 ; CHECK:       bl  g
    155 
    156 ; int test_varargs_vla(int a, ...) {
    157 ;   int v[a];
    158 ;   __builtin_va_list ap;
    159 ;   __builtin_va_start(ap, a);
    160 ;   return g(v, a, 0, 0, 0, 0);
    161 ; }
    162 define dso_local i32 @test_varargs_vla(i32 %a, ...) local_unnamed_addr  {
    163 entry:
    164   %ap = alloca %struct.__va_list, align 4
    165   %vla = alloca i32, i32 %a, align 4
    166   %0 = bitcast %struct.__va_list* %ap to i8*
    167   call void @llvm.va_start(i8* nonnull %0)
    168   %call = call i32 @g(i32* nonnull %vla, i32 %a, i32 0, i32 0, i32 0, i32 0)
    169   ret i32 %call
    170 }
    171 ; CHECK-LABEL: test_varargs_vla
    172 ; Three incoming register varargs
    173 ; CHECK:       sub sp, #12
    174 ; Setup frame pointer
    175 ; CHECK:       add r7, sp, #8
    176 ; Register varargs stored via FP
    177 ; CHECK:       str r3, [r7, #16]
    178 ; CHECK-NEXT:  str r2, [r7, #12]
    179 ; CHECK-NEXT:  str r1, [r7, #8]
    180 
    181 ; Moving SP, access via SP
    182 ; int test_args_moving_sp(int a, int b, int c, int d, int e) {
    183 ;   int v[4];
    184 ;   return f(v, a, b + c + d, e, s) + h(v, v+1, v+2);
    185 ; }
    186 define dso_local i32 @test_args_moving_sp(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) local_unnamed_addr  {
    187 entry:
    188   %v = alloca [4 x i32], align 4
    189   %0 = bitcast [4 x i32]* %v to i8*
    190   %arraydecay = getelementptr inbounds [4 x i32], [4 x i32]* %v, i32 0, i32 0
    191   %add = add nsw i32 %c, %b
    192   %add1 = add nsw i32 %add, %d
    193   %call = call i32 @f(i32* nonnull %arraydecay, i32 %a, i32 %add1, i32 %e, %struct.S* byval nonnull align 4 @s)
    194   %add.ptr = getelementptr inbounds [4 x i32], [4 x i32]* %v, i32 0, i32 1
    195   %add.ptr5 = getelementptr inbounds [4 x i32], [4 x i32]* %v, i32 0, i32 2
    196   %call6 = call i32 @h(i32* nonnull %arraydecay, i32* nonnull %add.ptr, i32* nonnull %add.ptr5)
    197   %add7 = add nsw i32 %call6, %call
    198   ret i32 %add7
    199 }
    200 ; CHECK-LABEL: test_args_moving_sp
    201 ; 20 bytes callee-saved area
    202 ; CHECK:       push {r4, r5, r6, r7, lr}
    203 ; 20 bytes locals
    204 ; CHECK:       sub sp, #20
    205 ; Allocate outgoing arguments space
    206 ; CHECK:       sub sp, #508
    207 ; CHECK:       sub sp, #4
    208 ; Load `e` via SP, 552 = 512 + 20 + 20
    209 ; CHECK:       ldr r3, [sp, #552]
    210 ; CHECK:       bl  f
    211 ; Stack restored before next call
    212 ; CHECK-NEXT:  add sp, #508
    213 ; CHECK-NEXT:  add sp, #4
    214 ; CHECK:       bl  h
    215 
    216 ; int test_varargs_moving_sp(int a, ...) {
    217 ;   int v[4];
    218 ;   __builtin_va_list ap;
    219 ;   __builtin_va_start(ap, a);
    220 ;   return f(v, a, 0, 0, s) + h(v, v+1, v+2);
    221 ; }
    222 define dso_local i32 @test_varargs_moving_sp(i32 %a, ...) local_unnamed_addr  {
    223 entry:
    224   %v = alloca [4 x i32], align 4
    225   %ap = alloca %struct.__va_list, align 4
    226   %0 = bitcast [4 x i32]* %v to i8*
    227   %1 = bitcast %struct.__va_list* %ap to i8*
    228   call void @llvm.va_start(i8* nonnull %1)
    229   %arraydecay = getelementptr inbounds [4 x i32], [4 x i32]* %v, i32 0, i32 0
    230   %call = call i32 @f(i32* nonnull %arraydecay, i32 %a, i32 0, i32 0, %struct.S* byval nonnull align 4 @s)
    231   %add.ptr = getelementptr inbounds [4 x i32], [4 x i32]* %v, i32 0, i32 1
    232   %add.ptr5 = getelementptr inbounds [4 x i32], [4 x i32]* %v, i32 0, i32 2
    233   %call6 = call i32 @h(i32* nonnull %arraydecay, i32* nonnull %add.ptr, i32* nonnull %add.ptr5)
    234   %add = add nsw i32 %call6, %call
    235   ret i32 %add
    236 }
    237 ; CHECK-LABEL: test_varargs_moving_sp
    238 ; Three incoming register varargs
    239 ; CHECK:       sub sp, #12
    240 ; 16 bytes callee-saves
    241 ; CHECK:       push {r4, r5, r7, lr}
    242 ; 20 bytes locals
    243 ; CHECK:       sub sp, #20
    244 ; Incoming varargs stored via SP, 36 = 20 + 16
    245 ; CHECK:       add r0, sp, #36
    246 ; CHECK-NEXT:  stm r0!, {r1, r2, r3}
    247 
    248 ;
    249 ; Access to locals
    250 ;
    251 
    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
    276 }
    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
    288 
    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
    313 }
    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
    332 
    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
    355 }
    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
    374 
    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
    396 }
    397 ; CHECK-LABEL: test_local_moving_sp
    398 ; Locals area
    399 ; CHECK:      sub sp, #36
    400 ; Outoging arguments
    401 ; CHECK:      sub sp, #508
    402 ; CHECK-NEXT: sub sp, #508
    403 ; CHECK-NEXT: sub sp, #8
    404 ; Argument addresses computed relative to SP
    405 ; CHECK:      add  r4, sp, #1020
    406 ; CHECK-NEXT: adds r4, #24
    407 ; CHECK:      add  r1, sp, #1020
    408 ; CHECK-NEXT: adds r1, #20
    409 ; CHECK:      add  r5, sp, #1020
    410 ; CHECK-NEXT: adds r5, #16
    411 ; CHECK:      bl   u
    412 ; Stack restored before next call
    413 ; CHECK:      add  sp, #508
    414 ; CHECK-NEXT: add  sp, #508
    415 ; CHECK-NEXT: add  sp, #8
    416 ; CHECK:      bl   u
    417