llvm/llvm/test/CodeGen/Thumb/frame-chain.ll

; RUN: llc -mtriple thumbv6m-arm-none-eabi -filetype asm -o - %s -frame-pointer=all --verify-machineinstrs | FileCheck %s --check-prefixes=FP,LEAF-FP
; RUN: llc -mtriple thumbv6m-arm-none-eabi -filetype asm -o - %s -frame-pointer=all -mattr=+aapcs-frame-chain --verify-machineinstrs | FileCheck %s --check-prefixes=FP-AAPCS,LEAF-FP-AAPCS
; RUN: llc -mtriple thumbv6m-arm-none-eabi -filetype asm -o - %s -frame-pointer=non-leaf --verify-machineinstrs | FileCheck %s --check-prefixes=FP,LEAF-NOFP
; RUN: llc -mtriple thumbv6m-arm-none-eabi -filetype asm -o - %s -frame-pointer=non-leaf -mattr=+aapcs-frame-chain --verify-machineinstrs | FileCheck %s --check-prefixes=FP-AAPCS,LEAF-NOFP-AAPCS
; RUN: llc -mtriple thumbv6m-arm-none-eabi -filetype asm -o - %s -frame-pointer=none --verify-machineinstrs | FileCheck %s --check-prefixes=NOFP,LEAF-NOFP
; RUN: llc -mtriple thumbv6m-arm-none-eabi -filetype asm -o - %s -frame-pointer=none -mattr=+aapcs-frame-chain --verify-machineinstrs | FileCheck %s --check-prefixes=NOFP-AAPCS,LEAF-NOFP-AAPCS

define dso_local noundef i32 @leaf(i32 noundef %0) {
; LEAF-FP-LABEL: leaf:
; LEAF-FP:       @ %bb.0:
; LEAF-FP-NEXT:    .pad #4
; LEAF-FP-NEXT:    sub sp, #4
; LEAF-FP-NEXT:    str r0, [sp]
; LEAF-FP-NEXT:    adds r0, r0, #4
; LEAF-FP-NEXT:    add sp, #4
; LEAF-FP-NEXT:    bx lr
;
; LEAF-FP-AAPCS-LABEL: leaf:
; LEAF-FP-AAPCS:       @ %bb.0:
; LEAF-FP-AAPCS-NEXT:    .save {lr}
; LEAF-FP-AAPCS-NEXT:    push {lr}
; LEAF-FP-AAPCS-NEXT:    mov lr, r11
; LEAF-FP-AAPCS-NEXT:    .save {r11}
; LEAF-FP-AAPCS-NEXT:    push {lr}
; LEAF-FP-AAPCS-NEXT:    .setfp r11, sp
; LEAF-FP-AAPCS-NEXT:    mov r11, sp
; LEAF-FP-AAPCS-NEXT:    .pad #4
; LEAF-FP-AAPCS-NEXT:    sub sp, #4
; LEAF-FP-AAPCS-NEXT:    str r0, [sp]
; LEAF-FP-AAPCS-NEXT:    adds r0, r0, #4
; LEAF-FP-AAPCS-NEXT:    add sp, #4
; LEAF-FP-AAPCS-NEXT:    pop {r1}
; LEAF-FP-AAPCS-NEXT:    mov r11, r1
; LEAF-FP-AAPCS-NEXT:    pop {pc}
;
; LEAF-NOFP-LABEL: leaf:
; LEAF-NOFP:       @ %bb.0:
; LEAF-NOFP-NEXT:    .pad #4
; LEAF-NOFP-NEXT:    sub sp, #4
; LEAF-NOFP-NEXT:    str r0, [sp]
; LEAF-NOFP-NEXT:    adds r0, r0, #4
; LEAF-NOFP-NEXT:    add sp, #4
; LEAF-NOFP-NEXT:    bx lr
;
; LEAF-NOFP-AAPCS-LABEL: leaf:
; LEAF-NOFP-AAPCS:       @ %bb.0:
; LEAF-NOFP-AAPCS-NEXT:    .pad #4
; LEAF-NOFP-AAPCS-NEXT:    sub sp, #4
; LEAF-NOFP-AAPCS-NEXT:    str r0, [sp]
; LEAF-NOFP-AAPCS-NEXT:    adds r0, r0, #4
; LEAF-NOFP-AAPCS-NEXT:    add sp, #4
; LEAF-NOFP-AAPCS-NEXT:    bx lr
  %2 = alloca i32, align 4
  store i32 %0, ptr %2, align 4
  %3 = load i32, ptr %2, align 4
  %4 = add nsw i32 %3, 4
  ret i32 %4
}

define dso_local noundef i32 @non_leaf(i32 noundef %0) {
; FP-LABEL: non_leaf:
; FP:       @ %bb.0:
; FP-NEXT:    .save {r7, lr}
; FP-NEXT:    push {r7, lr}
; FP-NEXT:    .setfp r7, sp
; FP-NEXT:    add r7, sp, #0
; FP-NEXT:    .pad #8
; FP-NEXT:    sub sp, #8
; FP-NEXT:    str r0, [sp, #4]
; FP-NEXT:    bl leaf
; FP-NEXT:    adds r0, r0, #1
; FP-NEXT:    add sp, #8
; FP-NEXT:    pop {r7, pc}
;
; FP-AAPCS-LABEL: non_leaf:
; FP-AAPCS:       @ %bb.0:
; 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:    .pad #8
; FP-AAPCS-NEXT:    sub sp, #8
; FP-AAPCS-NEXT:    str r0, [sp, #4]
; FP-AAPCS-NEXT:    bl leaf
; FP-AAPCS-NEXT:    adds r0, r0, #1
; FP-AAPCS-NEXT:    add sp, #8
; FP-AAPCS-NEXT:    pop {r1}
; FP-AAPCS-NEXT:    mov r11, r1
; FP-AAPCS-NEXT:    pop {pc}
;
; NOFP-LABEL: non_leaf:
; NOFP:       @ %bb.0:
; NOFP-NEXT:    .save {r7, lr}
; NOFP-NEXT:    push {r7, lr}
; NOFP-NEXT:    .pad #8
; NOFP-NEXT:    sub sp, #8
; NOFP-NEXT:    str r0, [sp, #4]
; NOFP-NEXT:    bl leaf
; NOFP-NEXT:    adds r0, r0, #1
; NOFP-NEXT:    add sp, #8
; NOFP-NEXT:    pop {r7, pc}
;
; NOFP-AAPCS-LABEL: non_leaf:
; NOFP-AAPCS:       @ %bb.0:
; NOFP-AAPCS-NEXT:    .save {r7, lr}
; NOFP-AAPCS-NEXT:    push {r7, lr}
; NOFP-AAPCS-NEXT:    .pad #8
; NOFP-AAPCS-NEXT:    sub sp, #8
; NOFP-AAPCS-NEXT:    str r0, [sp, #4]
; NOFP-AAPCS-NEXT:    bl leaf
; NOFP-AAPCS-NEXT:    adds r0, r0, #1
; NOFP-AAPCS-NEXT:    add sp, #8
; NOFP-AAPCS-NEXT:    pop {r7, pc}
  %2 = alloca i32, align 4
  store i32 %0, ptr %2, align 4
  %3 = load i32, ptr %2, align 4
  %4 = call noundef i32 @leaf(i32 noundef %3)
  %5 = add nsw i32 %4, 1
  ret i32 %5
}

declare ptr @llvm.stacksave()
define dso_local void @required_fp(i32 %0, i32 %1) {
; FP-LABEL: required_fp:
; FP:       @ %bb.0:
; FP-NEXT:    .save {r4, r6, r7, lr}
; FP-NEXT:    push {r4, r6, r7, lr}
; FP-NEXT:    .setfp r7, sp, #8
; FP-NEXT:    add r7, sp, #8
; FP-NEXT:    .pad #24
; FP-NEXT:    sub sp, #24
; FP-NEXT:    mov r6, sp
; FP-NEXT:    mov r2, r6
; FP-NEXT:    str r1, [r2, #16]
; FP-NEXT:    str r0, [r2, #20]
; FP-NEXT:    mov r1, sp
; FP-NEXT:    str r1, [r2, #8]
; FP-NEXT:    lsls r1, r0, #2
; FP-NEXT:    adds r1, r1, #7
; FP-NEXT:    movs r3, #7
; FP-NEXT:    bics r1, r3
; FP-NEXT:    mov r3, sp
; FP-NEXT:    subs r1, r3, r1
; FP-NEXT:    mov sp, r1
; FP-NEXT:    movs r1, #0
; FP-NEXT:    str r1, [r6, #4]
; FP-NEXT:    str r0, [r2]
; FP-NEXT:    subs r6, r7, #7
; FP-NEXT:    subs r6, #1
; FP-NEXT:    mov sp, r6
; FP-NEXT:    pop {r4, r6, r7, pc}
;
; FP-AAPCS-LABEL: required_fp:
; FP-AAPCS:       @ %bb.0:
; 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, r6}
; FP-AAPCS-NEXT:    push {r4, r6}
; FP-AAPCS-NEXT:    .pad #24
; FP-AAPCS-NEXT:    sub sp, #24
; FP-AAPCS-NEXT:    mov r6, sp
; FP-AAPCS-NEXT:    mov r2, r6
; FP-AAPCS-NEXT:    str r1, [r2, #16]
; FP-AAPCS-NEXT:    str r0, [r2, #20]
; FP-AAPCS-NEXT:    mov r1, sp
; FP-AAPCS-NEXT:    str r1, [r2, #8]
; FP-AAPCS-NEXT:    lsls r1, r0, #2
; FP-AAPCS-NEXT:    adds r1, r1, #7
; FP-AAPCS-NEXT:    movs r3, #7
; FP-AAPCS-NEXT:    bics r1, r3
; FP-AAPCS-NEXT:    mov r3, sp
; FP-AAPCS-NEXT:    subs r1, r3, r1
; FP-AAPCS-NEXT:    mov sp, r1
; FP-AAPCS-NEXT:    movs r1, #0
; FP-AAPCS-NEXT:    str r1, [r6, #4]
; FP-AAPCS-NEXT:    str r0, [r2]
; 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 {r0}
; FP-AAPCS-NEXT:    mov r11, r0
; FP-AAPCS-NEXT:    pop {pc}
;
; NOFP-LABEL: required_fp:
; NOFP:       @ %bb.0:
; NOFP-NEXT:    .save {r4, r6, r7, lr}
; NOFP-NEXT:    push {r4, r6, r7, lr}
; NOFP-NEXT:    .setfp r7, sp, #8
; NOFP-NEXT:    add r7, sp, #8
; NOFP-NEXT:    .pad #24
; NOFP-NEXT:    sub sp, #24
; NOFP-NEXT:    mov r6, sp
; NOFP-NEXT:    mov r2, r6
; NOFP-NEXT:    str r1, [r2, #16]
; NOFP-NEXT:    str r0, [r2, #20]
; NOFP-NEXT:    mov r1, sp
; NOFP-NEXT:    str r1, [r2, #8]
; NOFP-NEXT:    lsls r1, r0, #2
; NOFP-NEXT:    adds r1, r1, #7
; NOFP-NEXT:    movs r3, #7
; NOFP-NEXT:    bics r1, r3
; NOFP-NEXT:    mov r3, sp
; NOFP-NEXT:    subs r1, r3, r1
; NOFP-NEXT:    mov sp, r1
; NOFP-NEXT:    movs r1, #0
; NOFP-NEXT:    str r1, [r6, #4]
; NOFP-NEXT:    str r0, [r2]
; NOFP-NEXT:    subs r6, r7, #7
; NOFP-NEXT:    subs r6, #1
; NOFP-NEXT:    mov sp, r6
; NOFP-NEXT:    pop {r4, r6, r7, pc}
;
; NOFP-AAPCS-LABEL: required_fp:
; NOFP-AAPCS:       @ %bb.0:
; NOFP-AAPCS-NEXT:    .save {lr}
; NOFP-AAPCS-NEXT:    push {lr}
; NOFP-AAPCS-NEXT:    mov lr, r11
; NOFP-AAPCS-NEXT:    .save {r11}
; NOFP-AAPCS-NEXT:    push {lr}
; NOFP-AAPCS-NEXT:    .setfp r11, sp
; NOFP-AAPCS-NEXT:    mov r11, sp
; NOFP-AAPCS-NEXT:    .save {r4, r6}
; NOFP-AAPCS-NEXT:    push {r4, r6}
; NOFP-AAPCS-NEXT:    .pad #24
; NOFP-AAPCS-NEXT:    sub sp, #24
; NOFP-AAPCS-NEXT:    mov r6, sp
; NOFP-AAPCS-NEXT:    mov r2, r6
; NOFP-AAPCS-NEXT:    str r1, [r2, #16]
; NOFP-AAPCS-NEXT:    str r0, [r2, #20]
; NOFP-AAPCS-NEXT:    mov r1, sp
; NOFP-AAPCS-NEXT:    str r1, [r2, #8]
; NOFP-AAPCS-NEXT:    lsls r1, r0, #2
; NOFP-AAPCS-NEXT:    adds r1, r1, #7
; NOFP-AAPCS-NEXT:    movs r3, #7
; NOFP-AAPCS-NEXT:    bics r1, r3
; NOFP-AAPCS-NEXT:    mov r3, sp
; NOFP-AAPCS-NEXT:    subs r1, r3, r1
; NOFP-AAPCS-NEXT:    mov sp, r1
; NOFP-AAPCS-NEXT:    movs r1, #0
; NOFP-AAPCS-NEXT:    str r1, [r6, #4]
; NOFP-AAPCS-NEXT:    str r0, [r2]
; NOFP-AAPCS-NEXT:    mov r6, r11
; NOFP-AAPCS-NEXT:    subs r6, #8
; NOFP-AAPCS-NEXT:    mov sp, r6
; NOFP-AAPCS-NEXT:    pop {r4, r6}
; NOFP-AAPCS-NEXT:    pop {r0}
; NOFP-AAPCS-NEXT:    mov r11, r0
; NOFP-AAPCS-NEXT:    pop {pc}
  %3 = alloca i32, align 4
  %4 = alloca i32, align 4
  %5 = alloca ptr, align 8
  %6 = alloca i64, align 8
  store i32 %0, ptr %3, align 4
  store i32 %1, ptr %4, align 4
  %7 = load i32, ptr %3, align 4
  %8 = zext i32 %7 to i64
  %9 = call ptr @llvm.stacksave()
  store ptr %9, ptr %5, align 8
  %10 = alloca i32, i64 %8, align 4
  store i64 %8, ptr %6, align 8
  ret void
}