; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
; RUN: llc < %s -mtriple=thumbv6m-none-eabi -frame-pointer=none                          -verify-machineinstrs | FileCheck %s --check-prefix=FP-NONE
; RUN: llc < %s -mtriple=thumbv6m-none-eabi -frame-pointer=all                           -verify-machineinstrs | FileCheck %s --check-prefix=FP-ALL
; RUN: llc < %s -mtriple=thumbv6m-none-eabi -frame-pointer=all -mattr=+aapcs-frame-chain -verify-machineinstrs | FileCheck %s --check-prefix=FP-AAPCS

define void @ra_call() {
; FP-NONE-LABEL: ra_call:
; FP-NONE:       @ %bb.0: @ %entry
; FP-NONE-NEXT:    .save {r7, lr}
; FP-NONE-NEXT:    push {r7, lr}
; FP-NONE-NEXT:    mov r0, lr
; FP-NONE-NEXT:    bl sink_ptr
; FP-NONE-NEXT:    pop {r7, pc}
;
; FP-ALL-LABEL: ra_call:
; FP-ALL:       @ %bb.0: @ %entry
; FP-ALL-NEXT:    .save {r7, lr}
; FP-ALL-NEXT:    push {r7, lr}
; FP-ALL-NEXT:    .setfp r7, sp
; FP-ALL-NEXT:    add r7, sp, #0
; FP-ALL-NEXT:    mov r0, lr
; FP-ALL-NEXT:    bl sink_ptr
; FP-ALL-NEXT:    pop {r7, pc}
;
; FP-AAPCS-LABEL: ra_call:
; FP-AAPCS:       @ %bb.0: @ %entry
; FP-AAPCS-NEXT:    .save {lr}
; FP-AAPCS-NEXT:    push {lr}
; FP-AAPCS-NEXT:    mov r3, r11
; FP-AAPCS-NEXT:    .save {r11}
; FP-AAPCS-NEXT:    push {r3}
; FP-AAPCS-NEXT:    .setfp r11, sp
; FP-AAPCS-NEXT:    mov r11, sp
; FP-AAPCS-NEXT:    mov r0, lr
; FP-AAPCS-NEXT:    bl sink_ptr
; FP-AAPCS-NEXT:    pop {r0}
; FP-AAPCS-NEXT:    mov r11, r0
; FP-AAPCS-NEXT:    pop {pc}
entry:
  %r = tail call ptr @llvm.returnaddress(i32 0)
  tail call void @sink_ptr(ptr %r)
  ret void
}

define ptr @ra_return() {
; FP-NONE-LABEL: ra_return:
; FP-NONE:       @ %bb.0: @ %entry
; FP-NONE-NEXT:    mov r0, lr
; FP-NONE-NEXT:    bx lr
;
; FP-ALL-LABEL: ra_return:
; FP-ALL:       @ %bb.0: @ %entry
; FP-ALL-NEXT:    .save {r7, lr}
; FP-ALL-NEXT:    push {r7, lr}
; FP-ALL-NEXT:    .setfp r7, sp
; FP-ALL-NEXT:    add r7, sp, #0
; FP-ALL-NEXT:    mov r0, lr
; FP-ALL-NEXT:    pop {r7, pc}
;
; FP-AAPCS-LABEL: ra_return:
; FP-AAPCS:       @ %bb.0: @ %entry
; FP-AAPCS-NEXT:    .save {lr}
; FP-AAPCS-NEXT:    push {lr}
; FP-AAPCS-NEXT:    mov r3, r11
; FP-AAPCS-NEXT:    .save {r11}
; FP-AAPCS-NEXT:    push {r3}
; FP-AAPCS-NEXT:    .setfp r11, sp
; FP-AAPCS-NEXT:    mov r11, sp
; FP-AAPCS-NEXT:    mov r0, lr
; FP-AAPCS-NEXT:    pop {r1}
; FP-AAPCS-NEXT:    mov r11, r1
; FP-AAPCS-NEXT:    pop {pc}
entry:
  %r = tail call ptr @llvm.returnaddress(i32 0)
  ret ptr %r
}

define ptr @callee_saved_low() {
; FP-NONE-LABEL: callee_saved_low:
; FP-NONE:       @ %bb.0: @ %entry
; FP-NONE-NEXT:    .save {r4, r5, r7, lr}
; FP-NONE-NEXT:    push {r4, r5, r7, lr}
; FP-NONE-NEXT:    mov r0, lr
; FP-NONE-NEXT:    @APP
; FP-NONE-NEXT:    @NO_APP
; FP-NONE-NEXT:    pop {r4, r5, r7, pc}
;
; FP-ALL-LABEL: callee_saved_low:
; FP-ALL:       @ %bb.0: @ %entry
; FP-ALL-NEXT:    .save {r4, r5, r7, lr}
; FP-ALL-NEXT:    push {r4, r5, r7, lr}
; FP-ALL-NEXT:    .setfp r7, sp, #8
; FP-ALL-NEXT:    add r7, sp, #8
; FP-ALL-NEXT:    mov r0, lr
; FP-ALL-NEXT:    @APP
; FP-ALL-NEXT:    @NO_APP
; FP-ALL-NEXT:    pop {r4, r5, r7, pc}
;
; FP-AAPCS-LABEL: callee_saved_low:
; FP-AAPCS:       @ %bb.0: @ %entry
; FP-AAPCS-NEXT:    .save {lr}
; FP-AAPCS-NEXT:    push {lr}
; FP-AAPCS-NEXT:    mov r3, r11
; FP-AAPCS-NEXT:    .save {r11}
; FP-AAPCS-NEXT:    push {r3}
; FP-AAPCS-NEXT:    .setfp r11, sp
; FP-AAPCS-NEXT:    mov r11, sp
; FP-AAPCS-NEXT:    .save {r4, r5}
; FP-AAPCS-NEXT:    push {r4, r5}
; FP-AAPCS-NEXT:    mov r0, lr
; FP-AAPCS-NEXT:    @APP
; FP-AAPCS-NEXT:    @NO_APP
; FP-AAPCS-NEXT:    pop {r4, r5}
; FP-AAPCS-NEXT:    pop {r1}
; FP-AAPCS-NEXT:    mov r11, r1
; FP-AAPCS-NEXT:    pop {pc}
entry:
  call void asm sideeffect "", "~{r4},~{r5}"()
  %r = tail call ptr @llvm.returnaddress(i32 0)
  ret ptr %r
}

define ptr @callee_saved_high() {
; FP-NONE-LABEL: callee_saved_high:
; FP-NONE:       @ %bb.0: @ %entry
; FP-NONE-NEXT:    mov r3, r9
; FP-NONE-NEXT:    mov r2, r8
; FP-NONE-NEXT:    .save {r8, r9}
; FP-NONE-NEXT:    push {r2, r3}
; FP-NONE-NEXT:    mov r0, lr
; FP-NONE-NEXT:    @APP
; FP-NONE-NEXT:    @NO_APP
; FP-NONE-NEXT:    pop {r1, r2}
; FP-NONE-NEXT:    mov r8, r1
; FP-NONE-NEXT:    mov r9, r2
; FP-NONE-NEXT:    bx lr
;
; FP-ALL-LABEL: callee_saved_high:
; FP-ALL:       @ %bb.0: @ %entry
; FP-ALL-NEXT:    .save {r7, lr}
; FP-ALL-NEXT:    push {r7, lr}
; FP-ALL-NEXT:    .setfp r7, sp
; FP-ALL-NEXT:    add r7, sp, #0
; FP-ALL-NEXT:    mov r3, r9
; FP-ALL-NEXT:    mov r2, r8
; FP-ALL-NEXT:    .save {r8, r9}
; FP-ALL-NEXT:    push {r2, r3}
; FP-ALL-NEXT:    mov r0, lr
; FP-ALL-NEXT:    @APP
; FP-ALL-NEXT:    @NO_APP
; FP-ALL-NEXT:    pop {r1, r2}
; FP-ALL-NEXT:    mov r8, r1
; FP-ALL-NEXT:    mov r9, r2
; FP-ALL-NEXT:    pop {r7, pc}
;
; FP-AAPCS-LABEL: callee_saved_high:
; FP-AAPCS:       @ %bb.0: @ %entry
; FP-AAPCS-NEXT:    .save {lr}
; FP-AAPCS-NEXT:    push {lr}
; FP-AAPCS-NEXT:    mov r3, r11
; FP-AAPCS-NEXT:    .save {r11}
; FP-AAPCS-NEXT:    push {r3}
; FP-AAPCS-NEXT:    .setfp r11, sp
; FP-AAPCS-NEXT:    mov r11, sp
; FP-AAPCS-NEXT:    mov r3, r9
; FP-AAPCS-NEXT:    mov r2, r8
; FP-AAPCS-NEXT:    .save {r8, r9}
; FP-AAPCS-NEXT:    push {r2, r3}
; FP-AAPCS-NEXT:    mov r0, lr
; FP-AAPCS-NEXT:    @APP
; FP-AAPCS-NEXT:    @NO_APP
; FP-AAPCS-NEXT:    pop {r1, r2}
; FP-AAPCS-NEXT:    mov r8, r1
; FP-AAPCS-NEXT:    mov r9, r2
; FP-AAPCS-NEXT:    pop {r1}
; FP-AAPCS-NEXT:    mov r11, r1
; FP-AAPCS-NEXT:    pop {pc}
entry:
  call void asm sideeffect "", "~{r8},~{r9}"()
  %r = tail call ptr @llvm.returnaddress(i32 0)
  ret ptr %r
}

define ptr @large_alloca() {
; FP-NONE-LABEL: large_alloca:
; FP-NONE:       @ %bb.0: @ %entry
; FP-NONE-NEXT:    .save {r4, r5, r6, lr}
; FP-NONE-NEXT:    push {r4, r5, r6, lr}
; FP-NONE-NEXT:    ldr r6, .LCPI4_0
; FP-NONE-NEXT:    .pad #2000
; FP-NONE-NEXT:    add sp, r6
; FP-NONE-NEXT:    mov r4, lr
; FP-NONE-NEXT:    mov r0, sp
; FP-NONE-NEXT:    bl sink_ptr
; FP-NONE-NEXT:    mov r0, r4
; FP-NONE-NEXT:    ldr r6, .LCPI4_1
; FP-NONE-NEXT:    add sp, r6
; FP-NONE-NEXT:    pop {r4, r5, r6, pc}
; FP-NONE-NEXT:    .p2align 2
; FP-NONE-NEXT:  @ %bb.1:
; FP-NONE-NEXT:  .LCPI4_0:
; FP-NONE-NEXT:    .long 4294965296 @ 0xfffff830
; FP-NONE-NEXT:  .LCPI4_1:
; FP-NONE-NEXT:    .long 2000 @ 0x7d0
;
; FP-ALL-LABEL: large_alloca:
; FP-ALL:       @ %bb.0: @ %entry
; FP-ALL-NEXT:    .save {r4, r6, r7, lr}
; FP-ALL-NEXT:    push {r4, r6, r7, lr}
; FP-ALL-NEXT:    .setfp r7, sp, #8
; FP-ALL-NEXT:    add r7, sp, #8
; FP-ALL-NEXT:    ldr r6, .LCPI4_0
; FP-ALL-NEXT:    .pad #2000
; FP-ALL-NEXT:    add sp, r6
; FP-ALL-NEXT:    mov r4, lr
; FP-ALL-NEXT:    mov r0, sp
; FP-ALL-NEXT:    bl sink_ptr
; FP-ALL-NEXT:    mov r0, r4
; FP-ALL-NEXT:    subs r6, r7, #7
; FP-ALL-NEXT:    subs r6, #1
; FP-ALL-NEXT:    mov sp, r6
; FP-ALL-NEXT:    pop {r4, r6, r7, pc}
; FP-ALL-NEXT:    .p2align 2
; FP-ALL-NEXT:  @ %bb.1:
; FP-ALL-NEXT:  .LCPI4_0:
; FP-ALL-NEXT:    .long 4294965296 @ 0xfffff830
;
; FP-AAPCS-LABEL: large_alloca:
; FP-AAPCS:       @ %bb.0: @ %entry
; FP-AAPCS-NEXT:    .save {lr}
; FP-AAPCS-NEXT:    push {lr}
; FP-AAPCS-NEXT:    mov r3, r11
; FP-AAPCS-NEXT:    .save {r11}
; FP-AAPCS-NEXT:    push {r3}
; FP-AAPCS-NEXT:    .setfp r11, sp
; FP-AAPCS-NEXT:    mov r11, sp
; FP-AAPCS-NEXT:    .save {r4, r7}
; FP-AAPCS-NEXT:    push {r4, r7}
; FP-AAPCS-NEXT:    ldr r7, .LCPI4_0
; FP-AAPCS-NEXT:    .pad #2000
; FP-AAPCS-NEXT:    add sp, r7
; FP-AAPCS-NEXT:    mov r4, lr
; FP-AAPCS-NEXT:    mov r0, sp
; FP-AAPCS-NEXT:    bl sink_ptr
; FP-AAPCS-NEXT:    mov r0, r4
; FP-AAPCS-NEXT:    mov r7, r11
; FP-AAPCS-NEXT:    subs r7, #8
; FP-AAPCS-NEXT:    mov sp, r7
; FP-AAPCS-NEXT:    pop {r4, r7}
; FP-AAPCS-NEXT:    pop {r1}
; FP-AAPCS-NEXT:    mov r11, r1
; FP-AAPCS-NEXT:    pop {pc}
; FP-AAPCS-NEXT:    .p2align 2
; FP-AAPCS-NEXT:  @ %bb.1:
; FP-AAPCS-NEXT:  .LCPI4_0:
; FP-AAPCS-NEXT:    .long 4294965296 @ 0xfffff830
entry:
  %big = alloca i8, i32 2000
  tail call void @sink_ptr(ptr %big)
  %r = tail call ptr @llvm.returnaddress(i32 0)
  ret ptr %r
}

define ptr @var_alloca(i32 %size) {
; FP-NONE-LABEL: var_alloca:
; FP-NONE:       @ %bb.0: @ %entry
; FP-NONE-NEXT:    .save {r4, r6, r7, lr}
; FP-NONE-NEXT:    push {r4, r6, r7, lr}
; FP-NONE-NEXT:    .setfp r7, sp, #8
; FP-NONE-NEXT:    add r7, sp, #8
; FP-NONE-NEXT:    mov r6, sp
; FP-NONE-NEXT:    mov r4, lr
; FP-NONE-NEXT:    adds r0, r0, #7
; FP-NONE-NEXT:    movs r1, #7
; FP-NONE-NEXT:    bics r0, r1
; FP-NONE-NEXT:    mov r1, sp
; FP-NONE-NEXT:    subs r0, r1, r0
; FP-NONE-NEXT:    mov sp, r0
; FP-NONE-NEXT:    bl sink_ptr
; FP-NONE-NEXT:    mov r0, r4
; FP-NONE-NEXT:    subs r6, r7, #7
; FP-NONE-NEXT:    subs r6, #1
; FP-NONE-NEXT:    mov sp, r6
; FP-NONE-NEXT:    pop {r4, r6, r7, pc}
;
; FP-ALL-LABEL: var_alloca:
; FP-ALL:       @ %bb.0: @ %entry
; FP-ALL-NEXT:    .save {r4, r6, r7, lr}
; FP-ALL-NEXT:    push {r4, r6, r7, lr}
; FP-ALL-NEXT:    .setfp r7, sp, #8
; FP-ALL-NEXT:    add r7, sp, #8
; FP-ALL-NEXT:    mov r6, sp
; FP-ALL-NEXT:    mov r4, lr
; FP-ALL-NEXT:    adds r0, r0, #7
; FP-ALL-NEXT:    movs r1, #7
; FP-ALL-NEXT:    bics r0, r1
; FP-ALL-NEXT:    mov r1, sp
; FP-ALL-NEXT:    subs r0, r1, r0
; FP-ALL-NEXT:    mov sp, r0
; FP-ALL-NEXT:    bl sink_ptr
; FP-ALL-NEXT:    mov r0, r4
; FP-ALL-NEXT:    subs r6, r7, #7
; FP-ALL-NEXT:    subs r6, #1
; FP-ALL-NEXT:    mov sp, r6
; FP-ALL-NEXT:    pop {r4, r6, r7, pc}
;
; FP-AAPCS-LABEL: var_alloca:
; FP-AAPCS:       @ %bb.0: @ %entry
; FP-AAPCS-NEXT:    .save {lr}
; FP-AAPCS-NEXT:    push {lr}
; FP-AAPCS-NEXT:    mov r3, r11
; FP-AAPCS-NEXT:    .save {r11}
; FP-AAPCS-NEXT:    push {r3}
; FP-AAPCS-NEXT:    .setfp r11, sp
; FP-AAPCS-NEXT:    mov r11, sp
; FP-AAPCS-NEXT:    .save {r4, r6}
; FP-AAPCS-NEXT:    push {r4, r6}
; FP-AAPCS-NEXT:    mov r6, sp
; FP-AAPCS-NEXT:    mov r4, lr
; FP-AAPCS-NEXT:    adds r0, r0, #7
; FP-AAPCS-NEXT:    movs r1, #7
; FP-AAPCS-NEXT:    bics r0, r1
; FP-AAPCS-NEXT:    mov r1, sp
; FP-AAPCS-NEXT:    subs r0, r1, r0
; FP-AAPCS-NEXT:    mov sp, r0
; FP-AAPCS-NEXT:    bl sink_ptr
; FP-AAPCS-NEXT:    mov r0, r4
; FP-AAPCS-NEXT:    mov r6, r11
; FP-AAPCS-NEXT:    subs r6, #8
; FP-AAPCS-NEXT:    mov sp, r6
; FP-AAPCS-NEXT:    pop {r4, r6}
; FP-AAPCS-NEXT:    pop {r1}
; FP-AAPCS-NEXT:    mov r11, r1
; FP-AAPCS-NEXT:    pop {pc}
entry:
  %var = alloca i8, i32 %size
  tail call void @sink_ptr(ptr %var)
  %r = tail call ptr @llvm.returnaddress(i32 0)
  ret ptr %r
}

define i32 @all_arg_regs(i32 %a, i32 %b, i32 %c, i32 %d) {
; FP-NONE-LABEL: all_arg_regs:
; FP-NONE:       @ %bb.0: @ %entry
; FP-NONE-NEXT:    .save {r4, lr}
; FP-NONE-NEXT:    push {r4, lr}
; FP-NONE-NEXT:    mov r4, lr
; FP-NONE-NEXT:    adds r0, r0, r1
; FP-NONE-NEXT:    adds r0, r0, r2
; FP-NONE-NEXT:    adds r0, r0, r3
; FP-NONE-NEXT:    adds r0, r0, r4
; FP-NONE-NEXT:    pop {r4, pc}
;
; FP-ALL-LABEL: all_arg_regs:
; FP-ALL:       @ %bb.0: @ %entry
; FP-ALL-NEXT:    .save {r4, r6, r7, lr}
; FP-ALL-NEXT:    push {r4, r6, r7, lr}
; FP-ALL-NEXT:    .setfp r7, sp, #8
; FP-ALL-NEXT:    add r7, sp, #8
; FP-ALL-NEXT:    mov r4, lr
; FP-ALL-NEXT:    adds r0, r0, r1
; FP-ALL-NEXT:    adds r0, r0, r2
; FP-ALL-NEXT:    adds r0, r0, r3
; FP-ALL-NEXT:    adds r0, r0, r4
; FP-ALL-NEXT:    pop {r4, r6, r7, pc}
;
; FP-AAPCS-LABEL: all_arg_regs:
; FP-AAPCS:       @ %bb.0: @ %entry
; FP-AAPCS-NEXT:    .save {lr}
; FP-AAPCS-NEXT:    push {lr}
; FP-AAPCS-NEXT:    mov lr, r11
; FP-AAPCS-NEXT:    .save {r11}
; FP-AAPCS-NEXT:    push {lr}
; FP-AAPCS-NEXT:    .setfp r11, sp
; FP-AAPCS-NEXT:    mov r11, sp
; FP-AAPCS-NEXT:    .save {r4, r7}
; FP-AAPCS-NEXT:    push {r4, r7}
; FP-AAPCS-NEXT:    ldr r7, [sp, #12]
; FP-AAPCS-NEXT:    mov lr, r7
; FP-AAPCS-NEXT:    mov r4, lr
; FP-AAPCS-NEXT:    adds r0, r0, r1
; FP-AAPCS-NEXT:    adds r0, r0, r2
; FP-AAPCS-NEXT:    adds r0, r0, r3
; FP-AAPCS-NEXT:    adds r0, r0, r4
; FP-AAPCS-NEXT:    pop {r4, r7}
; FP-AAPCS-NEXT:    pop {r1}
; FP-AAPCS-NEXT:    mov r11, r1
; FP-AAPCS-NEXT:    pop {pc}
entry:
  %r = tail call ptr @llvm.returnaddress(i32 0)
  %ri = ptrtoint ptr %r to i32
  %t1 = add i32 %a, %b
  %t2 = add i32 %t1, %c
  %t3 = add i32 %t2, %d
  %t4 = add i32 %t3, %ri
  ret i32 %t4
}

define ptr @ra_depth_1() {
; FP-NONE-LABEL: ra_depth_1:
; FP-NONE:       @ %bb.0: @ %entry
; FP-NONE-NEXT:    .save {r7, lr}
; FP-NONE-NEXT:    push {r7, lr}
; FP-NONE-NEXT:    .setfp r7, sp
; FP-NONE-NEXT:    add r7, sp, #0
; FP-NONE-NEXT:    ldr r0, [r7]
; FP-NONE-NEXT:    ldr r0, [r0, #4]
; FP-NONE-NEXT:    pop {r7, pc}
;
; FP-ALL-LABEL: ra_depth_1:
; FP-ALL:       @ %bb.0: @ %entry
; FP-ALL-NEXT:    .save {r7, lr}
; FP-ALL-NEXT:    push {r7, lr}
; FP-ALL-NEXT:    .setfp r7, sp
; FP-ALL-NEXT:    add r7, sp, #0
; FP-ALL-NEXT:    ldr r0, [r7]
; FP-ALL-NEXT:    ldr r0, [r0, #4]
; FP-ALL-NEXT:    pop {r7, pc}
;
; FP-AAPCS-LABEL: ra_depth_1:
; FP-AAPCS:       @ %bb.0: @ %entry
; FP-AAPCS-NEXT:    .save {lr}
; FP-AAPCS-NEXT:    push {lr}
; FP-AAPCS-NEXT:    mov r3, r11
; FP-AAPCS-NEXT:    .save {r11}
; FP-AAPCS-NEXT:    push {r3}
; FP-AAPCS-NEXT:    .setfp r11, sp
; FP-AAPCS-NEXT:    mov r11, sp
; FP-AAPCS-NEXT:    mov r0, r11
; FP-AAPCS-NEXT:    ldr r0, [r0]
; FP-AAPCS-NEXT:    ldr r0, [r0, #4]
; FP-AAPCS-NEXT:    pop {r1}
; FP-AAPCS-NEXT:    mov r11, r1
; FP-AAPCS-NEXT:    pop {pc}
entry:
  %r = tail call ptr @llvm.returnaddress(i32 1)
  ret ptr %r
}

declare void @sink_ptr(ptr)
