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
152 ; CHECK-NEXT: fldt f80
154 ; CHECK-NEXT: faddp %st, %st(1)
155 ; CHECK-NEXT: fstpt f80
156 ; CHECK-NEXT: movl %ebp, %esp
157 ; CHECK-NEXT: popl %ebp
160 ; CHECK0-LABEL: test_isr_x87:
161 ; CHECK0: # %bb.0: # %entry
162 ; CHECK0-NEXT: pushl %ebp
163 ; CHECK0-NEXT: movl %esp, %ebp
164 ; CHECK0-NEXT: andl $-16, %esp
165 ; CHECK0-NEXT: fldt f80
167 ; CHECK0-NEXT: faddp %st, %st(1)
168 ; CHECK0-NEXT: fstpt f80
169 ; CHECK0-NEXT: movl %ebp, %esp
170 ; CHECK0-NEXT: popl %ebp
173 %ld = load x86_fp80, ptr @f80, align 4
174 %add = fadd x86_fp80 %ld, 0xK3FFF8000000000000000
175 store x86_fp80 %add, ptr @f80, align 4
179 ; Use the interrupt_frame pointer to check the offsets.
180 ; No return address, arguments start at EBP+4.
181 define dso_local x86_intrcc void @test_fp_1(ptr byval(%struct.interrupt_frame) %p) #0 {
182 ; CHECK-LABEL: test_fp_1:
183 ; CHECK: # %bb.0: # %entry
184 ; CHECK-NEXT: pushl %ebp
185 ; CHECK-NEXT: movl %esp, %ebp
186 ; CHECK-NEXT: pushl %ecx
187 ; CHECK-NEXT: pushl %eax
188 ; CHECK-NEXT: andl $-16, %esp
189 ; CHECK-NEXT: leal 20(%ebp), %eax
190 ; CHECK-NEXT: leal 4(%ebp), %ecx
191 ; CHECK-NEXT: movl %ecx, sink_address
192 ; CHECK-NEXT: movl %eax, sink_address
193 ; CHECK-NEXT: leal -8(%ebp), %esp
194 ; CHECK-NEXT: popl %eax
195 ; CHECK-NEXT: popl %ecx
196 ; CHECK-NEXT: popl %ebp
199 ; CHECK0-LABEL: test_fp_1:
200 ; CHECK0: # %bb.0: # %entry
201 ; CHECK0-NEXT: pushl %ebp
202 ; CHECK0-NEXT: movl %esp, %ebp
203 ; CHECK0-NEXT: pushl %ecx
204 ; CHECK0-NEXT: pushl %eax
205 ; CHECK0-NEXT: andl $-16, %esp
206 ; CHECK0-NEXT: leal 4(%ebp), %ecx
207 ; CHECK0-NEXT: movl %ecx, %eax
208 ; CHECK0-NEXT: addl $16, %eax
209 ; CHECK0-NEXT: movl %ecx, sink_address
210 ; CHECK0-NEXT: movl %eax, sink_address
211 ; CHECK0-NEXT: leal -8(%ebp), %esp
212 ; CHECK0-NEXT: popl %eax
213 ; CHECK0-NEXT: popl %ecx
214 ; CHECK0-NEXT: popl %ebp
217 %arrayidx2 = getelementptr inbounds %struct.interrupt_frame, ptr %p, i32 0, i32 4
218 store volatile ptr %p, ptr @sink_address
219 store volatile ptr %arrayidx2, ptr @sink_address
223 ; The error code is between EBP and the interrupt_frame.
224 define dso_local x86_intrcc void @test_fp_2(ptr byval(%struct.interrupt_frame) %p, i32 %err) #0 {
225 ; CHECK-LABEL: test_fp_2:
226 ; CHECK: # %bb.0: # %entry
227 ; CHECK-NEXT: pushl %ebp
228 ; CHECK-NEXT: movl %esp, %ebp
229 ; CHECK-NEXT: pushl %edx
230 ; CHECK-NEXT: pushl %ecx
231 ; CHECK-NEXT: pushl %eax
232 ; CHECK-NEXT: andl $-16, %esp
233 ; CHECK-NEXT: movl 4(%ebp), %eax
234 ; CHECK-NEXT: leal 24(%ebp), %ecx
235 ; CHECK-NEXT: leal 8(%ebp), %edx
236 ; CHECK-NEXT: movl %edx, sink_address
237 ; CHECK-NEXT: movl %ecx, sink_address
238 ; CHECK-NEXT: movl %eax, sink_i32
239 ; CHECK-NEXT: leal -12(%ebp), %esp
240 ; CHECK-NEXT: popl %eax
241 ; CHECK-NEXT: popl %ecx
242 ; CHECK-NEXT: popl %edx
243 ; CHECK-NEXT: popl %ebp
244 ; CHECK-NEXT: addl $4, %esp
247 ; CHECK0-LABEL: test_fp_2:
248 ; CHECK0: # %bb.0: # %entry
249 ; CHECK0-NEXT: pushl %ebp
250 ; CHECK0-NEXT: movl %esp, %ebp
251 ; CHECK0-NEXT: pushl %edx
252 ; CHECK0-NEXT: pushl %ecx
253 ; CHECK0-NEXT: pushl %eax
254 ; CHECK0-NEXT: andl $-16, %esp
255 ; CHECK0-NEXT: movl 4(%ebp), %eax
256 ; CHECK0-NEXT: leal 8(%ebp), %edx
257 ; CHECK0-NEXT: movl %edx, %ecx
258 ; CHECK0-NEXT: addl $16, %ecx
259 ; CHECK0-NEXT: movl %edx, sink_address
260 ; CHECK0-NEXT: movl %ecx, sink_address
261 ; CHECK0-NEXT: movl %eax, sink_i32
262 ; CHECK0-NEXT: leal -12(%ebp), %esp
263 ; CHECK0-NEXT: popl %eax
264 ; CHECK0-NEXT: popl %ecx
265 ; CHECK0-NEXT: popl %edx
266 ; CHECK0-NEXT: popl %ebp
267 ; CHECK0-NEXT: addl $4, %esp
270 %arrayidx2 = getelementptr inbounds %struct.interrupt_frame, ptr %p, i32 0, i32 4
271 store volatile ptr %p, ptr @sink_address
272 store volatile ptr %arrayidx2, ptr @sink_address
273 store volatile i32 %err, ptr @sink_i32
277 ; Test argument copy elision when copied to a local alloca.
278 define x86_intrcc void @test_copy_elide(ptr byval(%struct.interrupt_frame) %frame, i32 %err) #0 {
279 ; CHECK-LABEL: test_copy_elide:
280 ; CHECK: # %bb.0: # %entry
281 ; CHECK-NEXT: pushl %ebp
282 ; CHECK-NEXT: movl %esp, %ebp
283 ; CHECK-NEXT: pushl %eax
284 ; CHECK-NEXT: andl $-16, %esp
285 ; CHECK-NEXT: leal 4(%ebp), %eax
286 ; CHECK-NEXT: movl %eax, sink_address
287 ; CHECK-NEXT: leal -4(%ebp), %esp
288 ; CHECK-NEXT: popl %eax
289 ; CHECK-NEXT: popl %ebp
290 ; CHECK-NEXT: addl $4, %esp
293 ; CHECK0-LABEL: test_copy_elide:
294 ; CHECK0: # %bb.0: # %entry
295 ; CHECK0-NEXT: pushl %ebp
296 ; CHECK0-NEXT: movl %esp, %ebp
297 ; CHECK0-NEXT: pushl %eax
298 ; CHECK0-NEXT: andl $-16, %esp
299 ; CHECK0-NEXT: movl 4(%ebp), %eax
300 ; CHECK0-NEXT: leal 4(%ebp), %eax
301 ; CHECK0-NEXT: movl %eax, sink_address
302 ; CHECK0-NEXT: leal -4(%ebp), %esp
303 ; CHECK0-NEXT: popl %eax
304 ; CHECK0-NEXT: popl %ebp
305 ; CHECK0-NEXT: addl $4, %esp
308 %err.addr = alloca i32, align 4
309 store i32 %err, ptr %err.addr, align 4
310 store volatile ptr %err.addr, ptr @sink_address
314 ; Disabling dynamic realignment with attributes should work
315 define x86_intrcc void @test_isr_no_realign(ptr byval(%struct.interrupt_frame) %frame) #1 {
316 ; CHECK-LABEL: test_isr_no_realign:
318 ; CHECK-NEXT: pushl %eax
320 ; CHECK-NEXT: movl 12(%esp), %eax
322 ; CHECK-NEXT: #NO_APP
323 ; CHECK-NEXT: popl %eax
326 ; CHECK0-LABEL: test_isr_no_realign:
328 ; CHECK0-NEXT: pushl %eax
330 ; CHECK0-NEXT: leal 4(%esp), %eax
331 ; CHECK0-NEXT: movl 8(%eax), %eax
333 ; CHECK0-NEXT: #NO_APP
334 ; CHECK0-NEXT: popl %eax
336 %pflags = getelementptr inbounds %struct.interrupt_frame, ptr %frame, i32 0, i32 2
337 %flags = load i32, ptr %pflags, align 4
338 call void asm sideeffect "", "r"(i32 %flags)
342 ; The stackrealign attribute should work, and the function's alignment
343 ; should be respected over the default 16-byte alignment required by the calling
345 define x86_intrcc void @test_isr_realign(ptr byval(%struct.interrupt_frame) %frame, i32 %ecode) #2 {
346 ; CHECK-LABEL: test_isr_realign:
348 ; CHECK-NEXT: pushl %ebp
349 ; CHECK-NEXT: movl %esp, %ebp
350 ; CHECK-NEXT: pushl %eax
351 ; CHECK-NEXT: andl $-32, %esp
352 ; CHECK-NEXT: subl $32, %esp
353 ; CHECK-NEXT: movl 4(%ebp), %eax
354 ; CHECK-NEXT: movl %eax, (%esp)
355 ; CHECK-NEXT: leal -4(%ebp), %esp
356 ; CHECK-NEXT: popl %eax
357 ; CHECK-NEXT: popl %ebp
358 ; CHECK-NEXT: addl $4, %esp
361 ; CHECK0-LABEL: test_isr_realign:
363 ; CHECK0-NEXT: pushl %ebp
364 ; CHECK0-NEXT: movl %esp, %ebp
365 ; CHECK0-NEXT: pushl %eax
366 ; CHECK0-NEXT: andl $-32, %esp
367 ; CHECK0-NEXT: subl $32, %esp
368 ; CHECK0-NEXT: movl 4(%ebp), %eax
369 ; CHECK0-NEXT: movl %eax, (%esp)
370 ; CHECK0-NEXT: leal -4(%ebp), %esp
371 ; CHECK0-NEXT: popl %eax
372 ; CHECK0-NEXT: popl %ebp
373 ; CHECK0-NEXT: addl $4, %esp
375 %ecode.stack = alloca i32, align 32
376 store i32 %ecode, ptr %ecode.stack
381 attributes #0 = { nounwind "frame-pointer"="all" }
382 attributes #1 = { nounwind "no-realign-stack" }
383 attributes #2 = { nounwind "stackrealign" }