1; RUN: llc -mtriple=thumbv4t-none--eabi < %s | FileCheck %s --check-prefix=CHECK-V4T
2; RUN: llc -mtriple=thumbv5t-none--eabi < %s | FileCheck %s --check-prefix=CHECK-V5T
3
4; CHECK-V4T-LABEL: clobberframe
5; CHECK-V5T-LABEL: clobberframe
6define <4 x i32> @clobberframe(<6 x i32>* %p) #0 {
7entry:
8; Prologue
9; --------
10; CHECK-V4T:    push {[[SAVED:(r[4567](, )?)+]], lr}
11; CHECK-V4T:    sub sp,
12; Stack is realigned because of the <6 x i32> type
13; CHECK-V4T:    mov sp, r4
14; CHECK-V5T:    push {[[SAVED:(r[4567](, )?)+]], lr}
15
16  %b = alloca <6 x i32>, align 16
17  %a = alloca <4 x i32>, align 16
18  %stuff = load <6 x i32>, <6 x i32>* %p, align 16
19  store <6 x i32> %stuff, <6 x i32>* %b, align 16
20  store <4 x i32> <i32 0, i32 1, i32 2, i32 3>, <4 x i32>* %a, align 16
21  %0 = load <4 x i32>, <4 x i32>* %a, align 16
22  ret <4 x i32> %0
23
24; Epilogue
25; --------
26; Stack realignment means sp is restored from frame pointer
27; CHECK-V4T:         mov sp
28; CHECK-V4T-NEXT:    ldr [[POP:r[4567]]], [sp, #16]
29; CHECK-V4T-NEXT:    mov lr, [[POP]]
30; CHECK-V4T-NEXT:    pop {[[SAVED]]}
31; CHECK-V4T-NEXT     add sp, sp, #4
32; The ISA for v4 does not support pop pc, so make sure we do not emit
33; one even when we do not need to update SP.
34; CHECK-V4T-NOT:     pop {pc}
35; CHECK-V4T:         bx lr
36; CHECK-V5T:         pop {[[SAVED]], pc}
37}
38
39; CHECK-V4T-LABEL: clobbervariadicframe
40; CHECK-V5T-LABEL: clobbervariadicframe
41define <4 x i32> @clobbervariadicframe(i32 %i, ...) #0 {
42entry:
43; Prologue
44; --------
45; CHECK-V4T:    sub sp,
46; CHECK-V4T:    push {[[SAVED:(r[4567](, )?)+]], lr}
47; CHECK-V5T:    sub sp,
48; CHECK-V5T:    push {[[SAVED:(r[4567](, )?)+]], lr}
49
50  %b = alloca <4 x i32>, align 16
51  %a = alloca <4 x i32>, align 16
52  store <4 x i32> <i32 42, i32 42, i32 42, i32 42>, <4 x i32>* %b, align 16
53  store <4 x i32> <i32 0, i32 1, i32 2, i32 3>, <4 x i32>* %a, align 16
54  %0 = load <4 x i32>, <4 x i32>* %a, align 16
55  call void @llvm.va_start(i8* null)
56  ret <4 x i32> %0
57
58; Epilogue
59; --------
60; CHECK-V4T:         ldr [[POP:r[4567]]], [sp, #12]
61; CHECK-V4T-NEXT:    mov lr, [[POP]]
62; CHECK-V4T-NEXT:    pop {[[SAVED]]}
63; CHECK-V4T-NEXT:    add sp, #16
64; CHECK-V4T-NEXT:    bx  lr
65; CHECK-V5T:         lsls r4
66; CHECK-V5T-NEXT:    mov sp, r4
67; CHECK-V5T:         ldr [[POP:r[4567]]], [sp, #12]
68; CHECK-V5T-NEXT:    mov lr, [[POP]]
69; CHECK-V5T-NEXT:    pop {[[SAVED]]}
70; CHECK-V5T-NEXT:    add sp, #16
71; CHECK-V5T-NEXT:    bx  lr
72}
73
74; CHECK-V4T-LABEL: simpleframe
75; CHECK-V5T-LABEL: simpleframe
76define i32 @simpleframe(<6 x i32>* %p) #0 {
77entry:
78; Prologue
79; --------
80; CHECK-V4T:    push    {[[SAVED:(r[4567](, )?)+]], lr}
81; CHECK-V5T:    push    {[[SAVED:(r[4567](, )?)+]], lr}
82
83  %0 = load <6 x i32>, <6 x i32>* %p, align 16
84  %1 = extractelement <6 x i32> %0, i32 0
85  %2 = extractelement <6 x i32> %0, i32 1
86  %3 = extractelement <6 x i32> %0, i32 2
87  %4 = extractelement <6 x i32> %0, i32 3
88  %5 = extractelement <6 x i32> %0, i32 4
89  %6 = extractelement <6 x i32> %0, i32 5
90  %add1 = add nsw i32 %1, %2
91  %add2 = add nsw i32 %add1, %3
92  %add3 = add nsw i32 %add2, %4
93  %add4 = add nsw i32 %add3, %5
94  %add5 = add nsw i32 %add4, %6
95  ret i32 %add5
96
97; Epilogue
98; --------
99; CHECK-V4T:    pop {[[SAVED]]}
100; The ISA for v4 does not support pop pc, so make sure we do not emit
101; one even when we do not need to update SP.
102; CHECK-V4T-NOT:     pop {pc}
103; Pop the value of LR into a scratch lo register other than r0 (it is
104; used for the return value).
105; CHECK-V4T-NEXT:    pop {[[POP_REG:r[1-3]]]}
106; CHECK-V4T-NEXT:    bx [[POP_REG]]
107; CHECK-V5T:    pop {[[SAVED]], pc}
108}
109
110; CHECK-V4T-LABEL: simplevariadicframe
111; CHECK-V5T-LABEL: simplevariadicframe
112define i32 @simplevariadicframe(i32 %i, ...) #0 {
113entry:
114; Prologue
115; --------
116; CHECK-V4T:    sub sp,
117; CHECK-V4T:    push {[[SAVED:(r[4567](, )?)+]], lr}
118; CHECK-V4T:    sub sp,
119; CHECK-V5T:    sub sp,
120; CHECK-V5T:    push {[[SAVED:(r[4567](, )?)+]], lr}
121; CHECK-V5T:    sub sp,
122
123  %a = alloca i32, align 4
124  %b = alloca i32, align 4
125  %c = alloca i32, align 4
126  %d = alloca i32, align 4
127  store i32 1, i32* %a, align 4
128  store i32 2, i32* %b, align 4
129  store i32 3, i32* %c, align 4
130  store i32 4, i32* %d, align 4
131  %0 = load i32, i32* %a, align 4
132  %inc = add nsw i32 %0, 1
133  store i32 %inc, i32* %a, align 4
134  %1 = load i32, i32* %b, align 4
135  %inc1 = add nsw i32 %1, 1
136  store i32 %inc1, i32* %b, align 4
137  %2 = load i32, i32* %c, align 4
138  %inc2 = add nsw i32 %2, 1
139  store i32 %inc2, i32* %c, align 4
140  %3 = load i32, i32* %d, align 4
141  %inc3 = add nsw i32 %3, 1
142  store i32 %inc3, i32* %d, align 4
143  %4 = load i32, i32* %a, align 4
144  %5 = load i32, i32* %b, align 4
145  %add = add nsw i32 %4, %5
146  %6 = load i32, i32* %c, align 4
147  %add4 = add nsw i32 %add, %6
148  %7 = load i32, i32* %d, align 4
149  %add5 = add nsw i32 %add4, %7
150  %add6 = add nsw i32 %add5, %i
151  call void @llvm.va_start(i8* null)
152  ret i32 %add6
153
154; Epilogue
155; --------
156; CHECK-V4T:         add sp,
157; CHECK-V4T-NEXT:    pop {[[SAVED]]}
158; Only r1 to r3 are available to pop LR.
159; r0 is used for the return value.
160; CHECK-V4T-NEXT:    pop {[[POP_REG:r[1-3]]]}
161; CHECK-V4T-NEXT:    add sp,
162; CHECK-V4T-NEXT:    bx [[POP_REG]]
163; CHECK-V5T:         add sp,
164; CHECK-V5T-NEXT:    pop {[[SAVED]]}
165; Only r1 to r3 are available to pop LR.
166; r0 is used for the return value.
167; CHECK-V5T-NEXT:    pop {[[POP_REG:r[1-3]]]}
168; CHECK-V5T-NEXT:    add sp,
169; CHECK-V5T-NEXT:    bx [[POP_REG]]
170}
171
172; CHECK-V4T-LABEL: noframe
173; CHECK-V5T-LABEL: noframe
174define i32 @noframe() #0 {
175entry:
176; Prologue
177; --------
178; CHECK-V4T-NOT: push
179; CHECK-V5T-NOT: push
180    ret i32 0;
181; Epilogue
182; --------
183; CHECK-V4T-NOT: pop
184; CHECK-V5T-NOT: pop
185; CHECK-V4T:    bx  lr
186; CHECK-V5T:    bx  lr
187}
188
189; CHECK-V4T-LABEL: novariadicframe
190; CHECK-V5T-LABEL: novariadicframe
191define i32 @novariadicframe(i32 %i, ...) #0 {
192entry:
193; Prologue
194; --------
195; CHECK-V4T:    sub sp,
196; CHECK-V4T:    push {[[SAVED:(r[4567](, )?)+]], lr}
197; CHECK-V5T:    sub sp,
198; CHECK-V5T:    push {[[SAVED:(r[4567](, )?)+]], lr}
199
200  call void @llvm.va_start(i8* null)
201  ret i32 %i;
202; Epilogue
203; --------
204; CHECK-V4T:         pop {[[SAVED]]}
205; Only r1 to r3 are available to pop LR.
206; r0 is used for the return value.
207; CHECK-V4T-NEXT:    pop {[[POP_REG:r[1-3]]]}
208; CHECK-V4T-NEXT:    add sp,
209; CHECK-V4T-NEXT:    bx [[POP_REG]]
210; CHECK-V5T:         pop {[[SAVED]]}
211; Only r1 to r3 are available to pop LR.
212; r0 is used for the return value.
213; CHECK-V5T-NEXT:    pop {[[POP_REG:r[1-3]]]}
214; CHECK-V5T-NEXT:    add sp,
215; CHECK-V5T-NEXT:    bx [[POP_REG]]
216}
217
218declare void @llvm.va_start(i8*) nounwind
219