reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    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() "no-frame-pointer-elim"="true" {
; 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() "no-frame-pointer-elim"="true" {
; 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() "no-frame-pointer-elim"="true" {
; 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() "no-frame-pointer-elim-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() "no-frame-pointer-elim"="true" {
; 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() "no-frame-pointer-elim-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() "no-frame-pointer-elim"="true" {
; 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) "no-frame-pointer-elim"="true" {
; 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
}