blob: 832cebe3252bfd86d8f7515342289e7636a27947 [file] [log] [blame]
Oliver Stannard9aa6f012016-08-23 09:19:22 +00001; 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() "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.
28define void @leaf_lowreg_nofpelim() "no-frame-pointer-elim"="true" {
29; CHECK-LABEL: leaf_lowreg_nofpelim:
Reid Klecknerbdfc05f2016-10-11 21:14:03 +000030; CHECK: push {r4, r6, r7, lr}
31; CHECK: add r7, sp, #8
32; CHECK: pop {r4, r6, r7, pc}
Oliver Stannard9aa6f012016-08-23 09:19:22 +000033 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() "no-frame-pointer-elim"="true" {
42; CHECK-LABEL: leaf_highreg_nofpelim:
Reid Klecknerbdfc05f2016-10-11 21:14:03 +000043; CHECK: push {r6, r7, lr}
44; CHECK: add r7, sp, #4
Oliver Stannard9aa6f012016-08-23 09:19:22 +000045; CHECK: str r8, [sp, #-4]!
46; CHECK: ldr r8, [sp], #4
Reid Klecknerbdfc05f2016-10-11 21:14:03 +000047; CHECK: pop {r6, r7, pc}
Oliver Stannard9aa6f012016-08-23 09:19:22 +000048 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() "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.
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() "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.
86define 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.
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() "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.
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) "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}