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