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
111 ; CHECK-NEXT: pushl %ebp
113 ; CHECK-NEXT: #NO_APP
114 ; CHECK-NEXT: popl %ebp
115 ; CHECK-NEXT: leal -12(%ebp), %esp
116 ; CHECK-NEXT: popl %eax
117 ; CHECK-NEXT: popl %ebx
118 ; CHECK-NEXT: popl %ecx
119 ; CHECK-NEXT: popl %ebp
120 ; CHECK-NEXT: addl $4, %esp
123 ; CHECK0-LABEL: test_isr_clobbers:
125 ; CHECK0-NEXT: pushl %ebp
126 ; CHECK0-NEXT: movl %esp, %ebp
127 ; CHECK0-NEXT: pushl %ecx
128 ; CHECK0-NEXT: pushl %ebx
129 ; CHECK0-NEXT: pushl %eax
130 ; CHECK0-NEXT: andl $-16, %esp
132 ; CHECK0-NEXT: pushl %ebp
134 ; CHECK0-NEXT: #NO_APP
135 ; CHECK0-NEXT: popl %ebp
136 ; CHECK0-NEXT: leal -12(%ebp), %esp
137 ; CHECK0-NEXT: popl %eax
138 ; CHECK0-NEXT: popl %ebx
139 ; CHECK0-NEXT: popl %ecx
140 ; CHECK0-NEXT: popl %ebp
141 ; CHECK0-NEXT: addl $4, %esp
143 call void asm sideeffect "", "~{eax},~{ebx},~{ecx},~{ebp}"()
147 @f80 = common global x86_fp80 0xK00000000000000000000, align 4
149 ; Test that the presence of x87 does not crash the FP stackifier
150 define x86_intrcc void @test_isr_x87(ptr byval(%struct.interrupt_frame) %frame) nounwind {
151 ; CHECK-LABEL: test_isr_x87:
152 ; CHECK: # %bb.0: # %entry
153 ; CHECK-NEXT: pushl %ebp
154 ; CHECK-NEXT: movl %esp, %ebp
155 ; CHECK-NEXT: andl $-16, %esp
156 ; CHECK-NEXT: fldt f80
158 ; CHECK-NEXT: faddp %st, %st(1)
159 ; CHECK-NEXT: fstpt f80
160 ; CHECK-NEXT: movl %ebp, %esp
161 ; CHECK-NEXT: popl %ebp
164 ; CHECK0-LABEL: test_isr_x87:
165 ; CHECK0: # %bb.0: # %entry
166 ; CHECK0-NEXT: pushl %ebp
167 ; CHECK0-NEXT: movl %esp, %ebp
168 ; CHECK0-NEXT: andl $-16, %esp
169 ; CHECK0-NEXT: fldt f80
171 ; CHECK0-NEXT: faddp %st, %st(1)
172 ; CHECK0-NEXT: fstpt f80
173 ; CHECK0-NEXT: movl %ebp, %esp
174 ; CHECK0-NEXT: popl %ebp
177 %ld = load x86_fp80, ptr @f80, align 4
178 %add = fadd x86_fp80 %ld, 0xK3FFF8000000000000000
179 store x86_fp80 %add, ptr @f80, align 4
183 ; Use the interrupt_frame pointer to check the offsets.
184 ; No return address, arguments start at EBP+4.
185 define dso_local x86_intrcc void @test_fp_1(ptr byval(%struct.interrupt_frame) %p) #0 {
186 ; CHECK-LABEL: test_fp_1:
187 ; CHECK: # %bb.0: # %entry
188 ; CHECK-NEXT: pushl %ebp
189 ; CHECK-NEXT: movl %esp, %ebp
190 ; CHECK-NEXT: pushl %ecx
191 ; CHECK-NEXT: pushl %eax
192 ; CHECK-NEXT: andl $-16, %esp
193 ; CHECK-NEXT: leal 20(%ebp), %eax
194 ; CHECK-NEXT: leal 4(%ebp), %ecx
195 ; CHECK-NEXT: movl %ecx, sink_address
196 ; CHECK-NEXT: movl %eax, sink_address
197 ; CHECK-NEXT: leal -8(%ebp), %esp
198 ; CHECK-NEXT: popl %eax
199 ; CHECK-NEXT: popl %ecx
200 ; CHECK-NEXT: popl %ebp
203 ; CHECK0-LABEL: test_fp_1:
204 ; CHECK0: # %bb.0: # %entry
205 ; CHECK0-NEXT: pushl %ebp
206 ; CHECK0-NEXT: movl %esp, %ebp
207 ; CHECK0-NEXT: pushl %ecx
208 ; CHECK0-NEXT: pushl %eax
209 ; 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
237 ; CHECK-NEXT: movl 4(%ebp), %eax
238 ; CHECK-NEXT: leal 24(%ebp), %ecx
239 ; CHECK-NEXT: leal 8(%ebp), %edx
240 ; CHECK-NEXT: movl %edx, sink_address
241 ; CHECK-NEXT: movl %ecx, sink_address
242 ; CHECK-NEXT: movl %eax, sink_i32
243 ; CHECK-NEXT: leal -12(%ebp), %esp
244 ; CHECK-NEXT: popl %eax
245 ; CHECK-NEXT: popl %ecx
246 ; CHECK-NEXT: popl %edx
247 ; CHECK-NEXT: popl %ebp
248 ; CHECK-NEXT: addl $4, %esp
251 ; CHECK0-LABEL: test_fp_2:
252 ; CHECK0: # %bb.0: # %entry
253 ; CHECK0-NEXT: pushl %ebp
254 ; CHECK0-NEXT: movl %esp, %ebp
255 ; CHECK0-NEXT: pushl %edx
256 ; CHECK0-NEXT: pushl %ecx
257 ; CHECK0-NEXT: pushl %eax
258 ; CHECK0-NEXT: andl $-16, %esp
259 ; CHECK0-NEXT: movl 4(%ebp), %eax
260 ; CHECK0-NEXT: leal 8(%ebp), %edx
261 ; CHECK0-NEXT: movl %edx, %ecx
262 ; CHECK0-NEXT: addl $16, %ecx
263 ; CHECK0-NEXT: movl %edx, sink_address
264 ; CHECK0-NEXT: movl %ecx, sink_address
265 ; CHECK0-NEXT: movl %eax, sink_i32
266 ; CHECK0-NEXT: leal -12(%ebp), %esp
267 ; CHECK0-NEXT: popl %eax
268 ; CHECK0-NEXT: popl %ecx
269 ; CHECK0-NEXT: popl %edx
270 ; CHECK0-NEXT: popl %ebp
271 ; CHECK0-NEXT: addl $4, %esp
274 %arrayidx2 = getelementptr inbounds %struct.interrupt_frame, ptr %p, i32 0, i32 4
275 store volatile ptr %p, ptr @sink_address
276 store volatile ptr %arrayidx2, ptr @sink_address
277 store volatile i32 %err, ptr @sink_i32
281 ; Test argument copy elision when copied to a local alloca.
282 define x86_intrcc void @test_copy_elide(ptr byval(%struct.interrupt_frame) %frame, i32 %err) #0 {
283 ; CHECK-LABEL: test_copy_elide:
284 ; CHECK: # %bb.0: # %entry
285 ; CHECK-NEXT: pushl %ebp
286 ; CHECK-NEXT: movl %esp, %ebp
287 ; CHECK-NEXT: pushl %eax
288 ; CHECK-NEXT: andl $-16, %esp
289 ; CHECK-NEXT: leal 4(%ebp), %eax
290 ; CHECK-NEXT: movl %eax, sink_address
291 ; CHECK-NEXT: leal -4(%ebp), %esp
292 ; CHECK-NEXT: popl %eax
293 ; CHECK-NEXT: popl %ebp
294 ; CHECK-NEXT: addl $4, %esp
297 ; CHECK0-LABEL: test_copy_elide:
298 ; CHECK0: # %bb.0: # %entry
299 ; CHECK0-NEXT: pushl %ebp
300 ; CHECK0-NEXT: movl %esp, %ebp
301 ; CHECK0-NEXT: pushl %eax
302 ; CHECK0-NEXT: andl $-16, %esp
303 ; CHECK0-NEXT: movl 4(%ebp), %eax
304 ; CHECK0-NEXT: leal 4(%ebp), %eax
305 ; CHECK0-NEXT: movl %eax, sink_address
306 ; CHECK0-NEXT: leal -4(%ebp), %esp
307 ; CHECK0-NEXT: popl %eax
308 ; CHECK0-NEXT: popl %ebp
309 ; CHECK0-NEXT: addl $4, %esp
312 %err.addr = alloca i32, align 4
313 store i32 %err, ptr %err.addr, align 4
314 store volatile ptr %err.addr, ptr @sink_address
318 ; Disabling dynamic realignment with attributes should work
319 define x86_intrcc void @test_isr_no_realign(ptr byval(%struct.interrupt_frame) %frame) #1 {
320 ; CHECK-LABEL: test_isr_no_realign:
322 ; CHECK-NEXT: pushl %eax
324 ; CHECK-NEXT: movl 12(%esp), %eax
326 ; CHECK-NEXT: #NO_APP
327 ; CHECK-NEXT: popl %eax
330 ; CHECK0-LABEL: test_isr_no_realign:
332 ; CHECK0-NEXT: pushl %eax
334 ; CHECK0-NEXT: leal 4(%esp), %eax
335 ; CHECK0-NEXT: movl 8(%eax), %eax
337 ; CHECK0-NEXT: #NO_APP
338 ; CHECK0-NEXT: popl %eax
340 %pflags = getelementptr inbounds %struct.interrupt_frame, ptr %frame, i32 0, i32 2
341 %flags = load i32, ptr %pflags, align 4
342 call void asm sideeffect "", "r"(i32 %flags)
346 ; The stackrealign attribute should work, and the function's alignment
347 ; should be respected over the default 16-byte alignment required by the calling
349 define x86_intrcc void @test_isr_realign(ptr byval(%struct.interrupt_frame) %frame, i32 %ecode) #2 {
350 ; CHECK-LABEL: test_isr_realign:
352 ; CHECK-NEXT: pushl %ebp
353 ; CHECK-NEXT: movl %esp, %ebp
354 ; CHECK-NEXT: pushl %eax
355 ; CHECK-NEXT: andl $-32, %esp
356 ; CHECK-NEXT: subl $32, %esp
357 ; CHECK-NEXT: movl 4(%ebp), %eax
358 ; CHECK-NEXT: movl %eax, (%esp)
359 ; CHECK-NEXT: leal -4(%ebp), %esp
360 ; CHECK-NEXT: popl %eax
361 ; CHECK-NEXT: popl %ebp
362 ; CHECK-NEXT: addl $4, %esp
365 ; CHECK0-LABEL: test_isr_realign:
367 ; CHECK0-NEXT: pushl %ebp
368 ; CHECK0-NEXT: movl %esp, %ebp
369 ; CHECK0-NEXT: pushl %eax
370 ; CHECK0-NEXT: andl $-32, %esp
371 ; CHECK0-NEXT: subl $32, %esp
372 ; CHECK0-NEXT: movl 4(%ebp), %eax
373 ; CHECK0-NEXT: movl %eax, (%esp)
374 ; CHECK0-NEXT: leal -4(%ebp), %esp
375 ; CHECK0-NEXT: popl %eax
376 ; CHECK0-NEXT: popl %ebp
377 ; CHECK0-NEXT: addl $4, %esp
379 %ecode.stack = alloca i32, align 32
380 store i32 %ecode, ptr %ecode.stack
385 attributes #0 = { nounwind "frame-pointer"="all" }
386 attributes #1 = { nounwind "no-realign-stack" }
387 attributes #2 = { nounwind "stackrealign" }