| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 
 | ; RUN: llc -mtriple=thumbv7m-none-eabi -o - %s | FileCheck %s
declare void @foo()
; Leaf function, no frame so no need for a frame pointer.
define void @leaf() {
; CHECK-LABEL: leaf:
; CHECK-NOT: push
; CHECK-NOT: sp
; CHECK-NOT: pop
; CHECK: bx lr
  ret void
}
; Leaf function, frame pointer is requested but we don't need any stack frame,
; so don't create a frame pointer.
define void @leaf_nofpelim() "frame-pointer"="all" {
; CHECK-LABEL: leaf_nofpelim:
; CHECK-NOT: push
; CHECK-NOT: sp
; CHECK-NOT: pop
; CHECK: bx lr
  ret void
}
; Leaf function, frame pointer is requested and we need a stack frame, so we
; need to use a frame pointer.
define void @leaf_lowreg_nofpelim() "frame-pointer"="all" {
; CHECK-LABEL: leaf_lowreg_nofpelim:
; CHECK: push {r4, r6, r7, lr}
; CHECK: add r7, sp, #8
; CHECK: pop {r4, r6, r7, pc}
  call void asm sideeffect "", "~{r4}" ()
  ret void
}
; Leaf function, frame pointer is requested and we need a stack frame, so we
; need to use a frame pointer. A high register is pushed to the stack, so we
; must use two push/pop instructions to ensure that fp and sp are adjacent on
; the stack.
define void @leaf_highreg_nofpelim() "frame-pointer"="all" {
; CHECK-LABEL: leaf_highreg_nofpelim:
; CHECK: push {r6, r7, lr}
; CHECK: add r7, sp, #4
; CHECK: str r8, [sp, #-4]!
; CHECK: ldr r8, [sp], #4
; CHECK: pop {r6, r7, pc}
  call void asm sideeffect "", "~{r8}" ()
  ret void
}
; Leaf function, frame pointer requested for non-leaf functions only, so no
; need for a stack frame.
define void @leaf_nononleaffpelim() "frame-pointer"="non-leaf" {
; CHECK-LABEL: leaf_nononleaffpelim:
; CHECK-NOT: push
; CHECK-NOT: sp
; CHECK-NOT: pop
; CHECK: bx lr
  ret void
}
; Has a call, but still no need for a frame pointer.
define void @call() {
; CHECK-LABEL: call:
; CHECK: push {[[DUMMYREG:r[0-9]+]], lr}
; CHECK-NOT: sp
; CHECK: bl foo
; CHECK: pop {[[DUMMYREG]], pc}
  call void @foo()
  ret void
}
; Has a call, and frame pointer requested.
define void @call_nofpelim() "frame-pointer"="all" {
; CHECK-LABEL: call_nofpelim:
; CHECK: push {r7, lr}
; CHECK: mov r7, sp
; CHECK: bl foo
; CHECK: pop {r7, pc}
  call void @foo()
  ret void
}
; Has a call, and frame pointer requested for non-leaf function.
define void @call_nononleaffpelim() "frame-pointer"="non-leaf" {
; CHECK-LABEL: call_nononleaffpelim:
; CHECK: push {r7, lr}
; CHECK: mov r7, sp
; CHECK: bl foo
; CHECK: pop {r7, pc}
  call void @foo()
  ret void
}
; Has a high register clobbered, no need for a frame pointer.
define void @highreg() {
; CHECK-LABEL: highreg:
; CHECK: push.w {r8, lr}
; CHECK-NOT: sp
; CHECK: bl foo
; CHECK: pop.w {r8, pc}
  call void asm sideeffect "", "~{r8}" ()
  call void @foo()
  ret void
}
; Has a high register clobbered, frame pointer requested. We need to split the
; push into two, to ensure that r7 and sp are adjacent on the stack.
define void @highreg_nofpelim() "frame-pointer"="all" {
; CHECK-LABEL: highreg_nofpelim:
; CHECK: push {[[DUMMYREG:r[0-9]+]], r7, lr}
; CHECK: add r7, sp, #4
; CHECK: str r8, [sp, #-4]!
; CHECK: bl foo
; CHECK: ldr r8, [sp], #4
; CHECK: pop {[[DUMMYREG]], r7, pc}
  call void asm sideeffect "", "~{r8}" ()
  call void @foo()
  ret void
}
; Has a high register clobbered, frame required due to variable-sized alloca.
; We need a frame pointer to correctly restore the stack, but don't need to
; split the push/pop here, because the frame pointer not required by the ABI.
define void @highreg_alloca(i32 %a) {
; CHECK-LABEL: highreg_alloca:
; CHECK: push.w {[[SOMEREGS:.*]], r7, r8, lr}
; CHECK: add r7, sp, #{{[0-9]+}}
; CHECK: bl foo
; CHECK: pop.w {[[SOMEREGS]], r7, r8, pc}
  %alloca = alloca i32, i32 %a, align 4
  call void @foo()
  call void asm sideeffect "", "~{r8}" ()
  ret void
}
; Has a high register clobbered, frame required due to both variable-sized
; alloca and ABI. We do need to split the push/pop here.
define void @highreg_alloca_nofpelim(i32 %a) "frame-pointer"="all" {
; CHECK-LABEL: highreg_alloca_nofpelim:
; CHECK: push {[[SOMEREGS:.*]], r7, lr}
; CHECK: add r7, sp, #{{[0-9]+}}
; CHECK: str r8, [sp, #-4]!
; CHECK: bl foo
; CHECK: ldr r8, [sp], #4
; CHECK: pop {[[SOMEREGS]], r7, pc}
  %alloca = alloca i32, i32 %a, align 4
  call void @foo()
  call void asm sideeffect "", "~{r8}" ()
  ret void
}
 |