1; RUN: llc -mtriple=thumbv7m-none-eabi -o - %s | FileCheck %s
2
3declare void @foo()
4
5; Leaf function, no frame so no need for a frame pointer.
6define 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.
17define void @leaf_nofpelim() "frame-pointer"="all" {
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.
28define void @leaf_lowreg_nofpelim() "frame-pointer"="all" {
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.
41define void @leaf_highreg_nofpelim() "frame-pointer"="all" {
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.
54define void @leaf_nononleaffpelim() "frame-pointer"="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.
64define 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.
75define void @call_nofpelim() "frame-pointer"="all" {
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.
86define void @call_nononleaffpelim() "frame-pointer"="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.
97define 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.
110define void @highreg_nofpelim() "frame-pointer"="all" {
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.
126define 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.
140define void @highreg_alloca_nofpelim(i32 %a) "frame-pointer"="all" {
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