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
}
|