1 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --no_x86_scrub_sp --version 2
2 ; RUN: llc -mtriple=i686-unknown-unknown < %s | FileCheck %s
3 ; RUN: llc -mtriple=i686-unknown-unknown -O0 < %s | FileCheck %s -check-prefix=CHECK0
5 %struct.interrupt_frame = type { i32, i32, i32, i32, i32 }
7 @sink_address = global ptr null
8 @sink_i32 = global i32 0
11 ; Spills eax, putting original esp at +4.
12 ; Stack is dyamically realigned to 16 bytes, and then reloaded to ebp - 4
13 ; With no error code, the stack is not incremented by 4 bytes before returning
14 define x86_intrcc void @test_isr_no_ecode(ptr byval(%struct.interrupt_frame) %frame) nounwind {
15 ; CHECK-LABEL: test_isr_no_ecode:
17 ; CHECK-NEXT: pushl %ebp
18 ; CHECK-NEXT: movl %esp, %ebp
19 ; CHECK-NEXT: pushl %eax
20 ; CHECK-NEXT: andl $-16, %esp
22 ; CHECK-NEXT: movl 12(%ebp), %eax
25 ; CHECK-NEXT: leal -4(%ebp), %esp
26 ; CHECK-NEXT: popl %eax
27 ; CHECK-NEXT: popl %ebp
30 ; CHECK0-LABEL: test_isr_no_ecode:
32 ; CHECK0-NEXT: pushl %ebp
33 ; CHECK0-NEXT: movl %esp, %ebp
34 ; CHECK0-NEXT: pushl %eax
35 ; CHECK0-NEXT: andl $-16, %esp
37 ; CHECK0-NEXT: leal 4(%ebp), %eax
38 ; CHECK0-NEXT: movl 8(%eax), %eax
40 ; CHECK0-NEXT: #NO_APP
41 ; CHECK0-NEXT: leal -4(%ebp), %esp
42 ; CHECK0-NEXT: popl %eax
43 ; CHECK0-NEXT: popl %ebp
45 ; CHECK-NEXT; movl %esp, %ebp
46 %pflags = getelementptr inbounds %struct.interrupt_frame, ptr %frame, i32 0, i32 2
47 %flags = load i32, ptr %pflags, align 4
48 call void asm sideeffect "", "r"(i32 %flags)
52 ; Spills eax and ecx, putting original esp at +8.
53 ; Stack is dynamically realigned to 16 bytes, and then reloaded to ebp - 8
54 ; Error code is popped from the stack with an increment of 4 before returning
55 define x86_intrcc void @test_isr_ecode(ptr byval(%struct.interrupt_frame) %frame, i32 %ecode) nounwind {
56 ; CHECK-LABEL: test_isr_ecode:
58 ; CHECK-NEXT: pushl %ebp
59 ; CHECK-NEXT: movl %esp, %ebp
60 ; CHECK-NEXT: pushl %ecx
61 ; CHECK-NEXT: pushl %eax
62 ; CHECK-NEXT: andl $-16, %esp
64 ; CHECK-NEXT: movl 4(%ebp), %eax
65 ; CHECK-NEXT: movl 16(%ebp), %ecx
68 ; CHECK-NEXT: leal -8(%ebp), %esp
69 ; CHECK-NEXT: popl %eax
70 ; CHECK-NEXT: popl %ecx
71 ; CHECK-NEXT: popl %ebp
72 ; CHECK-NEXT: addl $4, %esp
75 ; CHECK0-LABEL: test_isr_ecode:
77 ; CHECK0-NEXT: pushl %ebp
78 ; CHECK0-NEXT: movl %esp, %ebp
79 ; CHECK0-NEXT: pushl %ecx
80 ; CHECK0-NEXT: pushl %eax
81 ; CHECK0-NEXT: andl $-16, %esp
83 ; CHECK0-NEXT: movl 4(%ebp), %ecx
84 ; CHECK0-NEXT: leal 8(%ebp), %eax
85 ; CHECK0-NEXT: movl 8(%eax), %eax
87 ; CHECK0-NEXT: #NO_APP
88 ; CHECK0-NEXT: leal -8(%ebp), %esp
89 ; CHECK0-NEXT: popl %eax
90 ; CHECK0-NEXT: popl %ecx
91 ; CHECK0-NEXT: popl %ebp
92 ; CHECK0-NEXT: addl $4, %esp
94 %pflags = getelementptr inbounds %struct.interrupt_frame, ptr %frame, i32 0, i32 2
95 %flags = load i32, ptr %pflags, align 4
96 call x86_fastcallcc void asm sideeffect "", "r,r"(i32 %flags, i32 %ecode)
100 ; All clobbered registers must be saved
101 define x86_intrcc void @test_isr_clobbers(ptr byval(%struct.interrupt_frame) %frame, i32 %ecode) nounwind {
102 ; CHECK-LABEL: test_isr_clobbers:
104 ; CHECK-NEXT: pushl %ebp
105 ; CHECK-NEXT: movl %esp, %ebp
106 ; CHECK-NEXT: pushl %ecx
107 ; CHECK-NEXT: pushl %ebx
108 ; CHECK-NEXT: pushl %eax
109 ; CHECK-NEXT: andl $-16, %esp
112 ; CHECK-NEXT: #NO_APP
113 ; CHECK-NEXT: leal -12(%ebp), %esp
114 ; CHECK-NEXT: popl %eax
115 ; CHECK-NEXT: popl %ebx
116 ; CHECK-NEXT: popl %ecx
117 ; CHECK-NEXT: popl %ebp
118 ; CHECK-NEXT: addl $4, %esp
121 ; CHECK0-LABEL: test_isr_clobbers:
123 ; CHECK0-NEXT: pushl %ebp
124 ; CHECK0-NEXT: movl %esp, %ebp
125 ; CHECK0-NEXT: pushl %ecx
126 ; CHECK0-NEXT: pushl %ebx
127 ; CHECK0-NEXT: pushl %eax
128 ; CHECK0-NEXT: andl $-16, %esp
131 ; CHECK0-NEXT: #NO_APP
132 ; CHECK0-NEXT: leal -12(%ebp), %esp
133 ; CHECK0-NEXT: popl %eax
134 ; CHECK0-NEXT: popl %ebx
135 ; CHECK0-NEXT: popl %ecx
136 ; CHECK0-NEXT: popl %ebp
137 ; CHECK0-NEXT: addl $4, %esp
139 call void asm sideeffect "", "~{eax},~{ebx},~{ecx},~{ebp}"()
143 @f80 = common global x86_fp80 0xK00000000000000000000, align 4
145 ; Test that the presence of x87 does not crash the FP stackifier
146 define x86_intrcc void @test_isr_x87(ptr byval(%struct.interrupt_frame) %frame) nounwind {
147 ; CHECK-LABEL: test_isr_x87:
148 ; CHECK: # %bb.0: # %entry
149 ; CHECK-NEXT: pushl %ebp
150 ; CHECK-NEXT: movl %esp, %ebp
151 ; CHECK-NEXT: andl $-16, %esp
153 ; CHECK-NEXT: fldt f80
155 ; CHECK-NEXT: faddp %st, %st(1)
156 ; CHECK-NEXT: fstpt f80
157 ; CHECK-NEXT: movl %ebp, %esp
158 ; CHECK-NEXT: popl %ebp
161 ; CHECK0-LABEL: test_isr_x87:
162 ; CHECK0: # %bb.0: # %entry
163 ; CHECK0-NEXT: pushl %ebp
164 ; CHECK0-NEXT: movl %esp, %ebp
165 ; CHECK0-NEXT: andl $-16, %esp
167 ; CHECK0-NEXT: fldt f80
169 ; CHECK0-NEXT: faddp %st, %st(1)
170 ; CHECK0-NEXT: fstpt f80
171 ; CHECK0-NEXT: movl %ebp, %esp
172 ; CHECK0-NEXT: popl %ebp
175 %ld = load x86_fp80, ptr @f80, align 4
176 %add = fadd x86_fp80 %ld, 0xK3FFF8000000000000000
177 store x86_fp80 %add, ptr @f80, align 4
181 ; Use the interrupt_frame pointer to check the offsets.
182 ; No return address, arguments start at EBP+4.
183 define dso_local x86_intrcc void @test_fp_1(ptr byval(%struct.interrupt_frame) %p) #0 {
184 ; CHECK-LABEL: test_fp_1:
185 ; CHECK: # %bb.0: # %entry
186 ; CHECK-NEXT: pushl %ebp
187 ; CHECK-NEXT: movl %esp, %ebp
188 ; CHECK-NEXT: pushl %ecx
189 ; CHECK-NEXT: pushl %eax
190 ; CHECK-NEXT: andl $-16, %esp
192 ; CHECK-NEXT: leal 20(%ebp), %eax
193 ; CHECK-NEXT: leal 4(%ebp), %ecx
194 ; CHECK-NEXT: movl %ecx, sink_address
195 ; CHECK-NEXT: movl %eax, sink_address
196 ; CHECK-NEXT: leal -8(%ebp), %esp
197 ; CHECK-NEXT: popl %eax
198 ; CHECK-NEXT: popl %ecx
199 ; CHECK-NEXT: popl %ebp
202 ; CHECK0-LABEL: test_fp_1:
203 ; CHECK0: # %bb.0: # %entry
204 ; CHECK0-NEXT: pushl %ebp
205 ; CHECK0-NEXT: movl %esp, %ebp
206 ; CHECK0-NEXT: pushl %ecx
207 ; CHECK0-NEXT: pushl %eax
208 ; CHECK0-NEXT: andl $-16, %esp
210 ; CHECK0-NEXT: leal 4(%ebp), %ecx
211 ; CHECK0-NEXT: movl %ecx, %eax
212 ; CHECK0-NEXT: addl $16, %eax
213 ; CHECK0-NEXT: movl %ecx, sink_address
214 ; CHECK0-NEXT: movl %eax, sink_address
215 ; CHECK0-NEXT: leal -8(%ebp), %esp
216 ; CHECK0-NEXT: popl %eax
217 ; CHECK0-NEXT: popl %ecx
218 ; CHECK0-NEXT: popl %ebp
221 %arrayidx2 = getelementptr inbounds %struct.interrupt_frame, ptr %p, i32 0, i32 4
222 store volatile ptr %p, ptr @sink_address
223 store volatile ptr %arrayidx2, ptr @sink_address
227 ; The error code is between EBP and the interrupt_frame.
228 define dso_local x86_intrcc void @test_fp_2(ptr byval(%struct.interrupt_frame) %p, i32 %err) #0 {
229 ; CHECK-LABEL: test_fp_2:
230 ; CHECK: # %bb.0: # %entry
231 ; CHECK-NEXT: pushl %ebp
232 ; CHECK-NEXT: movl %esp, %ebp
233 ; CHECK-NEXT: pushl %edx
234 ; CHECK-NEXT: pushl %ecx
235 ; CHECK-NEXT: pushl %eax
236 ; CHECK-NEXT: andl $-16, %esp
238 ; CHECK-NEXT: movl 4(%ebp), %eax
239 ; CHECK-NEXT: leal 24(%ebp), %ecx
240 ; CHECK-NEXT: leal 8(%ebp), %edx
241 ; CHECK-NEXT: movl %edx, sink_address
242 ; CHECK-NEXT: movl %ecx, sink_address
243 ; CHECK-NEXT: movl %eax, sink_i32
244 ; CHECK-NEXT: leal -12(%ebp), %esp
245 ; CHECK-NEXT: popl %eax
246 ; CHECK-NEXT: popl %ecx
247 ; CHECK-NEXT: popl %edx
248 ; CHECK-NEXT: popl %ebp
249 ; CHECK-NEXT: addl $4, %esp
252 ; CHECK0-LABEL: test_fp_2:
253 ; CHECK0: # %bb.0: # %entry
254 ; CHECK0-NEXT: pushl %ebp
255 ; CHECK0-NEXT: movl %esp, %ebp
256 ; CHECK0-NEXT: pushl %edx
257 ; CHECK0-NEXT: pushl %ecx
258 ; CHECK0-NEXT: pushl %eax
259 ; CHECK0-NEXT: andl $-16, %esp
261 ; CHECK0-NEXT: movl 4(%ebp), %eax
262 ; CHECK0-NEXT: leal 8(%ebp), %edx
263 ; CHECK0-NEXT: movl %edx, %ecx
264 ; CHECK0-NEXT: addl $16, %ecx
265 ; CHECK0-NEXT: movl %edx, sink_address
266 ; CHECK0-NEXT: movl %ecx, sink_address
267 ; CHECK0-NEXT: movl %eax, sink_i32
268 ; CHECK0-NEXT: leal -12(%ebp), %esp
269 ; CHECK0-NEXT: popl %eax
270 ; CHECK0-NEXT: popl %ecx
271 ; CHECK0-NEXT: popl %edx
272 ; CHECK0-NEXT: popl %ebp
273 ; CHECK0-NEXT: addl $4, %esp
276 %arrayidx2 = getelementptr inbounds %struct.interrupt_frame, ptr %p, i32 0, i32 4
277 store volatile ptr %p, ptr @sink_address
278 store volatile ptr %arrayidx2, ptr @sink_address
279 store volatile i32 %err, ptr @sink_i32
283 ; Test argument copy elision when copied to a local alloca.
284 define x86_intrcc void @test_copy_elide(ptr byval(%struct.interrupt_frame) %frame, i32 %err) #0 {
285 ; CHECK-LABEL: test_copy_elide:
286 ; CHECK: # %bb.0: # %entry
287 ; CHECK-NEXT: pushl %ebp
288 ; CHECK-NEXT: movl %esp, %ebp
289 ; CHECK-NEXT: pushl %eax
290 ; CHECK-NEXT: andl $-16, %esp
292 ; CHECK-NEXT: leal 4(%ebp), %eax
293 ; CHECK-NEXT: movl %eax, sink_address
294 ; CHECK-NEXT: leal -4(%ebp), %esp
295 ; CHECK-NEXT: popl %eax
296 ; CHECK-NEXT: popl %ebp
297 ; CHECK-NEXT: addl $4, %esp
300 ; CHECK0-LABEL: test_copy_elide:
301 ; CHECK0: # %bb.0: # %entry
302 ; CHECK0-NEXT: pushl %ebp
303 ; CHECK0-NEXT: movl %esp, %ebp
304 ; CHECK0-NEXT: pushl %eax
305 ; CHECK0-NEXT: andl $-16, %esp
307 ; CHECK0-NEXT: movl 4(%ebp), %eax
308 ; CHECK0-NEXT: leal 4(%ebp), %eax
309 ; CHECK0-NEXT: movl %eax, sink_address
310 ; CHECK0-NEXT: leal -4(%ebp), %esp
311 ; CHECK0-NEXT: popl %eax
312 ; CHECK0-NEXT: popl %ebp
313 ; CHECK0-NEXT: addl $4, %esp
316 %err.addr = alloca i32, align 4
317 store i32 %err, ptr %err.addr, align 4
318 store volatile ptr %err.addr, ptr @sink_address
322 ; Disabling dynamic realignment with attributes should work
323 define x86_intrcc void @test_isr_no_realign(ptr byval(%struct.interrupt_frame) %frame) #1 {
324 ; CHECK-LABEL: test_isr_no_realign:
326 ; CHECK-NEXT: pushl %eax
328 ; CHECK-NEXT: movl 12(%esp), %eax
330 ; CHECK-NEXT: #NO_APP
331 ; CHECK-NEXT: popl %eax
334 ; CHECK0-LABEL: test_isr_no_realign:
336 ; CHECK0-NEXT: pushl %eax
338 ; CHECK0-NEXT: leal 4(%esp), %eax
339 ; CHECK0-NEXT: movl 8(%eax), %eax
341 ; CHECK0-NEXT: #NO_APP
342 ; CHECK0-NEXT: popl %eax
344 %pflags = getelementptr inbounds %struct.interrupt_frame, ptr %frame, i32 0, i32 2
345 %flags = load i32, ptr %pflags, align 4
346 call void asm sideeffect "", "r"(i32 %flags)
350 ; The stackrealign attribute should work, and the function's alignment
351 ; should be respected over the default 16-byte alignment required by the calling
353 define x86_intrcc void @test_isr_realign(ptr byval(%struct.interrupt_frame) %frame, i32 %ecode) #2 {
354 ; CHECK-LABEL: test_isr_realign:
356 ; CHECK-NEXT: pushl %ebp
357 ; CHECK-NEXT: movl %esp, %ebp
358 ; CHECK-NEXT: pushl %eax
359 ; CHECK-NEXT: andl $-32, %esp
360 ; CHECK-NEXT: subl $32, %esp
362 ; CHECK-NEXT: movl 4(%ebp), %eax
363 ; CHECK-NEXT: movl %eax, (%esp)
364 ; CHECK-NEXT: leal -4(%ebp), %esp
365 ; CHECK-NEXT: popl %eax
366 ; CHECK-NEXT: popl %ebp
367 ; CHECK-NEXT: addl $4, %esp
370 ; CHECK0-LABEL: test_isr_realign:
372 ; CHECK0-NEXT: pushl %ebp
373 ; CHECK0-NEXT: movl %esp, %ebp
374 ; CHECK0-NEXT: pushl %eax
375 ; CHECK0-NEXT: andl $-32, %esp
376 ; CHECK0-NEXT: subl $32, %esp
378 ; CHECK0-NEXT: movl 4(%ebp), %eax
379 ; CHECK0-NEXT: movl %eax, (%esp)
380 ; CHECK0-NEXT: leal -4(%ebp), %esp
381 ; CHECK0-NEXT: popl %eax
382 ; CHECK0-NEXT: popl %ebp
383 ; CHECK0-NEXT: addl $4, %esp
385 %ecode.stack = alloca i32, align 32
386 store i32 %ecode, ptr %ecode.stack
391 attributes #0 = { nounwind "frame-pointer"="all" }
392 attributes #1 = { nounwind "no-realign-stack" }
393 attributes #2 = { nounwind "stackrealign" }