Use Align for TFL::TransientStackAlignment
[llvm-core.git] / test / CodeGen / X86 / wineh-coreclr.ll
blobfd2569e4bfb03bc998d3a7b248786805d721abd5
1 ; RUN: llc -mtriple=x86_64-pc-windows-coreclr -verify-machineinstrs < %s | FileCheck %s
3 declare void @ProcessCLRException()
4 declare void @f(i32)
5 declare void @g(i8 addrspace(1)*)
6 declare i8 addrspace(1)* @llvm.eh.exceptionpointer.p1i8(token)
8 ; Simplified IR for pseudo-C# like the following:
9 ; void test1() {
10 ;   try {
11 ;     f(1);
12 ;     try {
13 ;       f(2);
14 ;     } catch (type1) {
15 ;       f(3);
16 ;     } catch (type2) {
17 ;       f(4);
18 ;       try {
19 ;         f(5);
20 ;       } fault {
21 ;         f(6);
22 ;       }
23 ;     }
24 ;   } finally {
25 ;     f(7);
26 ;   }
27 ;   f(8);
28 ; }
30 ; CHECK-LABEL: test1:     # @test1
31 ; CHECK-NEXT: [[test1_begin:.*func_begin.*]]:
32 define void @test1() personality i8* bitcast (void ()* @ProcessCLRException to i8*) {
33 entry:
34 ; CHECK: # %entry
35 ; CHECK: leaq [[FPOffset:[0-9]+]](%rsp), %rbp
36 ; CHECK: .seh_endprologue
37 ; CHECK: movq %rsp, [[PSPSymOffset:[0-9]+]](%rsp)
38 ; CHECK: [[test1_before_f1:.+]]:
39 ; CHECK-NEXT: movl $1, %ecx
40 ; CHECK-NEXT: callq f
41 ; CHECK-NEXT: [[test1_after_f1:.+]]:
42   invoke void @f(i32 1)
43     to label %inner_try unwind label %finally
44 inner_try:
45 ; CHECK: # %inner_try
46 ; CHECK: [[test1_before_f2:.+]]:
47 ; CHECK-NEXT: movl $2, %ecx
48 ; CHECK-NEXT: callq f
49 ; CHECK-NEXT: [[test1_after_f2:.+]]:
50   invoke void @f(i32 2)
51     to label %finally.clone unwind label %exn.dispatch
52 exn.dispatch:
53   %catchswitch = catchswitch within none [label %catch1, label %catch2] unwind label %finally
54 catch1:
55   %catch.pad1 = catchpad within %catchswitch [i32 1]
56 ; CHECK: .seh_proc [[test1_catch1:[^ ]+]]
57 ; CHECK: .seh_stackalloc [[FuncletFrameSize:[0-9]+]]
58 ;                        ^ all funclets use the same frame size
59 ; CHECK: movq [[PSPSymOffset]](%rcx), %rcx
60 ;                              ^ establisher frame pointer passed in rcx
61 ; CHECK: movq %rcx, [[PSPSymOffset]](%rsp)
62 ; CHECK: leaq [[FPOffset]](%rcx), %rbp
63 ; CHECK: .seh_endprologue
64 ; CHECK: movq %rdx, %rcx
65 ;             ^ exception pointer passed in rdx
66 ; CHECK-NEXT: callq g
67   %exn1 = call i8 addrspace(1)* @llvm.eh.exceptionpointer.p1i8(token %catch.pad1)
68   call void @g(i8 addrspace(1)* %exn1) [ "funclet"(token %catch.pad1) ]
69 ; CHECK: [[test1_before_f3:.+]]:
70 ; CHECK-NEXT: movl $3, %ecx
71 ; CHECK-NEXT: callq f
72 ; CHECK-NEXT: [[test1_after_f3:.+]]:
73   invoke void @f(i32 3) [ "funclet"(token %catch.pad1) ]
74     to label %catch1.ret unwind label %finally
75 catch1.ret:
76   catchret from %catch.pad1 to label %finally.clone
77 catch2:
78   %catch.pad2 = catchpad within %catchswitch [i32 2]
79 ; CHECK: .seh_proc [[test1_catch2:[^ ]+]]
80 ; CHECK: .seh_stackalloc [[FuncletFrameSize:[0-9]+]]
81 ;                        ^ all funclets use the same frame size
82 ; CHECK: movq [[PSPSymOffset]](%rcx), %rcx
83 ;                              ^ establisher frame pointer passed in rcx
84 ; CHECK: movq %rcx, [[PSPSymOffset]](%rsp)
85 ; CHECK: leaq [[FPOffset]](%rcx), %rbp
86 ; CHECK: .seh_endprologue
87 ; CHECK: movq %rdx, %rcx
88 ;             ^ exception pointer passed in rdx
89 ; CHECK-NEXT: callq g
90   %exn2 = call i8 addrspace(1)* @llvm.eh.exceptionpointer.p1i8(token %catch.pad2)
91   call void @g(i8 addrspace(1)* %exn2) [ "funclet"(token %catch.pad2) ]
92 ; CHECK: [[test1_before_f4:.+]]:
93 ; CHECK-NEXT: movl $4, %ecx
94 ; CHECK-NEXT: callq f
95 ; CHECK-NEXT: [[test1_after_f4:.+]]:
96   invoke void @f(i32 4) [ "funclet"(token %catch.pad2) ]
97     to label %try_in_catch unwind label %finally
98 try_in_catch:
99 ; CHECK: # %try_in_catch
100 ; CHECK: [[test1_before_f5:.+]]:
101 ; CHECK-NEXT: movl $5, %ecx
102 ; CHECK-NEXT: callq f
103 ; CHECK-NEXT: [[test1_after_f5:.+]]:
104   invoke void @f(i32 5) [ "funclet"(token %catch.pad2) ]
105     to label %catch2.ret unwind label %fault
106 fault:
107 ; CHECK: .seh_proc [[test1_fault:[^ ]+]]
108   %fault.pad = cleanuppad within %catch.pad2 [i32 undef]
109 ; CHECK: .seh_stackalloc [[FuncletFrameSize:[0-9]+]]
110 ;                        ^ all funclets use the same frame size
111 ; CHECK: movq [[PSPSymOffset]](%rcx), %rcx
112 ;                              ^ establisher frame pointer passed in rcx
113 ; CHECK: movq %rcx, [[PSPSymOffset]](%rsp)
114 ; CHECK: leaq [[FPOffset]](%rcx), %rbp
115 ; CHECK: .seh_endprologue
116 ; CHECK: [[test1_before_f6:.+]]:
117 ; CHECK-NEXT: movl $6, %ecx
118 ; CHECK-NEXT: callq f
119 ; CHECK-NEXT: [[test1_after_f6:.+]]:
120   invoke void @f(i32 6) [ "funclet"(token %fault.pad) ]
121     to label %fault.ret unwind label %finally
122 fault.ret:
123   cleanupret from %fault.pad unwind label %finally
124 catch2.ret:
125   catchret from %catch.pad2 to label %finally.clone
126 finally.clone:
127   call void @f(i32 7)
128   br label %tail
129 finally:
130 ; CHECK: .seh_proc [[test1_finally:[^ ]+]]
131   %finally.pad = cleanuppad within none []
132 ; CHECK: .seh_stackalloc [[FuncletFrameSize:[0-9]+]]
133 ;                        ^ all funclets use the same frame size
134 ; CHECK: movq [[PSPSymOffset]](%rcx), %rcx
135 ;                              ^ establisher frame pointer passed in rcx
136 ; CHECK: movq %rcx, [[PSPSymOffset]](%rsp)
137 ; CHECK: leaq [[FPOffset]](%rcx), %rbp
138 ; CHECK: .seh_endprologue
139 ; CHECK-NEXT: movl $7, %ecx
140 ; CHECK-NEXT: callq f
141   call void @f(i32 7) [ "funclet"(token %finally.pad) ]
142   cleanupret from %finally.pad unwind to caller
143 tail:
144   call void @f(i32 8)
145   ret void
146 ; CHECK: [[test1_end:.*func_end.*]]:
149 ; Now check for EH table in xdata (following standard xdata)
150 ; CHECK-LABEL: .section .xdata
151 ; standard xdata comes here
152 ; CHECK:      .long 4{{$}}
153 ;                   ^ number of funclets
154 ; CHECK-NEXT: .long [[test1_catch1]]-[[test1_begin]]
155 ;                   ^ offset from L_begin to start of 1st funclet
156 ; CHECK-NEXT: .long [[test1_catch2]]-[[test1_begin]]
157 ;                   ^ offset from L_begin to start of 2nd funclet
158 ; CHECK-NEXT: .long [[test1_fault]]-[[test1_begin]]
159 ;                   ^ offset from L_begin to start of 3rd funclet
160 ; CHECK-NEXT: .long [[test1_finally]]-[[test1_begin]]
161 ;                   ^ offset from L_begin to start of 4th funclet
162 ; CHECK-NEXT: .long [[test1_end]]-[[test1_begin]]
163 ;                   ^ offset from L_begin to end of last funclet
164 ; CHECK-NEXT: .long 7
165 ;                   ^ number of EH clauses
166 ; Clause 1: call f(2) is guarded by catch1
167 ; CHECK-NEXT: .long 0
168 ;                   ^ flags (0 => catch handler)
169 ; CHECK-NEXT: .long ([[test1_before_f2]]-[[test1_begin]])+1
170 ;                   ^ offset of start of clause
171 ; CHECK-NEXT: .long ([[test1_after_f2]]-[[test1_begin]])+1
172 ;                   ^ offset of end of clause
173 ; CHECK-NEXT: .long [[test1_catch1]]-[[test1_begin]]
174 ;                   ^ offset of start of handler
175 ; CHECK-NEXT: .long [[test1_catch2]]-[[test1_begin]]
176 ;                   ^ offset of end of handler
177 ; CHECK-NEXT: .long 1
178 ;                   ^ type token of catch (from catchpad)
179 ; Clause 2: call f(2) is also guarded by catch2
180 ; CHECK-NEXT: .long 0
181 ;                   ^ flags (0 => catch handler)
182 ; CHECK-NEXT: .long ([[test1_before_f2]]-[[test1_begin]])+1
183 ;                   ^ offset of start of clause
184 ; CHECK-NEXT: .long ([[test1_after_f2]]-[[test1_begin]])+1
185 ;                   ^ offset of end of clause
186 ; CHECK-NEXT: .long [[test1_catch2]]-[[test1_begin]]
187 ;                   ^ offset of start of handler
188 ; CHECK-NEXT: .long [[test1_fault]]-[[test1_begin]]
189 ;                   ^ offset of end of handler
190 ; CHECK-NEXT: .long 2
191 ;                   ^ type token of catch (from catchpad)
192 ; Clause 3: calls f(1) and f(2) are guarded by finally
193 ; CHECK-NEXT: .long 2
194 ;                   ^ flags (2 => finally handler)
195 ; CHECK-NEXT: .long ([[test1_before_f1]]-[[test1_begin]])+1
196 ;                   ^ offset of start of clause
197 ; CHECK-NEXT: .long ([[test1_after_f2]]-[[test1_begin]])+1
198 ;                   ^ offset of end of clause
199 ; CHECK-NEXT: .long [[test1_finally]]-[[test1_begin]]
200 ;                   ^ offset of start of handler
201 ; CHECK-NEXT: .long [[test1_end]]-[[test1_begin]]
202 ;                   ^ offset of end of handler
203 ; CHECK-NEXT: .long 0
204 ;                   ^ type token slot (null for finally)
205 ; Clause 4: call f(3) is guarded by finally
206 ;           This is a "duplicate" because the protected range (f(3))
207 ;           is in funclet catch1 but the finally's immediate parent
208 ;           is the main function, not that funclet.
209 ; CHECK-NEXT: .long 10
210 ;                   ^ flags (2 => finally handler | 8 => duplicate)
211 ; CHECK-NEXT: .long ([[test1_before_f3]]-[[test1_begin]])+1
212 ;                   ^ offset of start of clause
213 ; CHECK-NEXT: .long ([[test1_after_f3]]-[[test1_begin]])+1
214 ;                   ^ offset of end of clause
215 ; CHECK-NEXT: .long [[test1_finally]]-[[test1_begin]]
216 ;                   ^ offset of start of handler
217 ; CHECK-NEXT: .long [[test1_end]]-[[test1_begin]]
218 ;                   ^ offset of end of handler
219 ; CHECK-NEXT: .long 0
220 ;                   ^ type token slot (null for finally)
221 ; Clause 5: call f(5) is guarded by fault
222 ; CHECK-NEXT: .long 4
223 ;                   ^ flags (4 => fault handler)
224 ; CHECK-NEXT: .long ([[test1_before_f5]]-[[test1_begin]])+1
225 ;                   ^ offset of start of clause
226 ; CHECK-NEXT: .long ([[test1_after_f5]]-[[test1_begin]])+1
227 ;                   ^ offset of end of clause
228 ; CHECK-NEXT: .long [[test1_fault]]-[[test1_begin]]
229 ;                   ^ offset of start of handler
230 ; CHECK-NEXT: .long [[test1_finally]]-[[test1_begin]]
231 ;                   ^ offset of end of handler
232 ; CHECK-NEXT: .long 0
233 ;                   ^ type token slot (null for fault)
234 ; Clause 6: calls f(4) and f(5) are guarded by finally
235 ;           This is a "duplicate" because the protected range (f(4)-f(5))
236 ;           is in funclet catch2 but the finally's immediate parent
237 ;           is the main function, not that funclet.
238 ; CHECK-NEXT: .long 10
239 ;                   ^ flags (2 => finally handler | 8 => duplicate)
240 ; CHECK-NEXT: .long ([[test1_before_f4]]-[[test1_begin]])+1
241 ;                   ^ offset of start of clause
242 ; CHECK-NEXT: .long ([[test1_after_f5]]-[[test1_begin]])+1
243 ;                   ^ offset of end of clause
244 ; CHECK-NEXT: .long [[test1_finally]]-[[test1_begin]]
245 ;                   ^ offset of start of handler
246 ; CHECK-NEXT: .long [[test1_end]]-[[test1_begin]]
247 ;                   ^ offset of end of handler
248 ; CHECK-NEXT: .long 0
249 ;                   ^ type token slot (null for finally)
250 ; Clause 7: call f(6) is guarded by finally
251 ;           This is a "duplicate" because the protected range (f(3))
252 ;           is in funclet catch1 but the finally's immediate parent
253 ;           is the main function, not that funclet.
254 ; CHECK-NEXT: .long 10
255 ;                   ^ flags (2 => finally handler | 8 => duplicate)
256 ; CHECK-NEXT: .long ([[test1_before_f6]]-[[test1_begin]])+1
257 ;                   ^ offset of start of clause
258 ; CHECK-NEXT: .long ([[test1_after_f6]]-[[test1_begin]])+1
259 ;                   ^ offset of end of clause
260 ; CHECK-NEXT: .long [[test1_finally]]-[[test1_begin]]
261 ;                   ^ offset of start of handler
262 ; CHECK-NEXT: .long [[test1_end]]-[[test1_begin]]
263 ;                   ^ offset of end of handler
264 ; CHECK-NEXT: .long 0
265 ;                   ^ type token slot (null for finally)
267 ; Test with a cleanup that has no cleanupret, and thus needs its unwind dest
268 ; inferred from an inner catchswitch
270 ; corresponds to C# along the lines of:
271 ; void test2() {
272 ;   try {
273 ;     try {
274 ;       f(1);
275 ;     } fault {
276 ;       try {
277 ;         f(2);
278 ;       } catch(type1) {
279 ;       }
280 ;       __unreachable();
281 ;     }
282 ;   } catch(type2) {
283 ;   }
284 ; }
286 define void @test2() personality i8* bitcast (void ()* @ProcessCLRException to i8*) {
287 entry:
288   invoke void @f(i32 1)
289     to label %exit unwind label %fault
290 fault:
291   %fault.pad = cleanuppad within none [i32 undef]
292   invoke void @f(i32 2) ["funclet"(token %fault.pad)]
293     to label %unreachable unwind label %exn.dispatch.inner
294 exn.dispatch.inner:
295   %catchswitch.inner = catchswitch within %fault.pad [label %catch1] unwind label %exn.dispatch.outer
296 catch1:
297   %catch.pad1 = catchpad within %catchswitch.inner [i32 1]
298   catchret from %catch.pad1 to label %unreachable
299 exn.dispatch.outer:
300   %catchswitch.outer = catchswitch within none [label %catch2] unwind to caller
301 catch2:
302   %catch.pad2 = catchpad within %catchswitch.outer [i32 2]
303   catchret from %catch.pad2 to label %exit
304 exit:
305   ret void
306 unreachable:
307   unreachable
309 ; CHECK-LABEL: test2:     # @test2
310 ; CHECK-NEXT: [[test2_begin:.*func_begin.*]]:
311 ; CHECK: .seh_endprologue
312 ; CHECK: [[test2_before_f1:.+]]:
313 ; CHECK-NEXT: movl $1, %ecx
314 ; CHECK-NEXT: callq f
315 ; CHECK-NEXT: [[test2_after_f1:.+]]:
316 ; CHECK: .seh_proc [[test2_catch1:[^ ]+]]
317 ; CHECK: .seh_proc [[test2_catch2:[^ ]+]]
318 ; CHECK: .seh_proc [[test2_fault:[^ ]+]]
319 ; CHECK: .seh_endprologue
320 ; CHECK: [[test2_before_f2:.+]]:
321 ; CHECK-NEXT: movl $2, %ecx
322 ; CHECK-NEXT: callq f
323 ; CHECK-NEXT: int3
324 ; CHECK-NEXT: [[test2_after_f2:.+]]:
325 ; CHECK: [[test2_end:.*func_end.*]]:
328 ; Now check for EH table in xdata (following standard xdata)
329 ; CHECK-LABEL: .section .xdata
330 ; standard xdata comes here
331 ; CHECK:      .long 3{{$}}
332 ;                   ^ number of funclets
333 ; CHECK-NEXT: .long [[test2_catch1]]-[[test2_begin]]
334 ;                   ^ offset from L_begin to start of 2nd funclet
335 ; CHECK-NEXT: .long [[test2_catch2]]-[[test2_begin]]
336 ;                   ^ offset from L_begin to start of 3rd funclet
337 ; CHECK-NEXT: .long [[test2_fault]]-[[test2_begin]]
338 ;                   ^ offset from L_begin to start of 1st funclet
339 ; CHECK-NEXT: .long [[test2_end]]-[[test2_begin]]
340 ;                   ^ offset from L_begin to end of last funclet
341 ; CHECK-NEXT: .long 4
342 ;                   ^ number of EH clauses
343 ; Clause 1: call f(1) is guarded by fault
344 ; CHECK-NEXT: .long 4
345 ;                   ^ flags (4 => fault handler)
346 ; CHECK-NEXT: .long ([[test2_before_f1]]-[[test2_begin]])+1
347 ;                   ^ offset of start of clause
348 ; CHECK-NEXT: .long ([[test2_after_f1]]-[[test2_begin]])+1
349 ;                   ^ offset of end of clause
350 ; CHECK-NEXT: .long [[test2_fault]]-[[test2_begin]]
351 ;                   ^ offset of start of handler
352 ; CHECK-NEXT: .long [[test2_end]]-[[test2_begin]]
353 ;                   ^ offset of end of handler
354 ; CHECK-NEXT: .long 0
355 ;                   ^ type token slot (null for fault)
356 ; Clause 2: call f(1) is also guarded by catch2
357 ; CHECK-NEXT: .long 0
358 ;                   ^ flags (0 => catch handler)
359 ; CHECK-NEXT: .long ([[test2_before_f1]]-[[test2_begin]])+1
360 ;                   ^ offset of start of clause
361 ; CHECK-NEXT: .long ([[test2_after_f1]]-[[test2_begin]])+1
362 ;                   ^ offset of end of clause
363 ; CHECK-NEXT: .long [[test2_catch2]]-[[test2_begin]]
364 ;                   ^ offset of start of handler
365 ; CHECK-NEXT: .long [[test2_fault]]-[[test2_begin]]
366 ;                   ^ offset of end of handler
367 ; CHECK-NEXT: .long 2
368 ;                   ^ type token of catch (from catchpad)
369 ; Clause 3: calls f(2) is guarded by catch1
370 ; CHECK-NEXT: .long 0
371 ;                   ^ flags (0 => catch handler)
372 ; CHECK-NEXT: .long ([[test2_before_f2]]-[[test2_begin]])+1
373 ;                   ^ offset of start of clause
374 ; CHECK-NEXT: .long ([[test2_after_f2]]-[[test2_begin]])+1
375 ;                   ^ offset of end of clause
376 ; CHECK-NEXT: .long [[test2_catch1]]-[[test2_begin]]
377 ;                   ^ offset of start of handler
378 ; CHECK-NEXT: .long [[test2_catch2]]-[[test2_begin]]
379 ;                   ^ offset of end of handler
380 ; CHECK-NEXT: .long 1
381 ;                   ^ type token of catch (from catchpad)
382 ; Clause 4: call f(2) is also guarded by catch2
383 ;           This is a "duplicate" because the protected range (f(2))
384 ;           is in funclet fault but catch2's immediate parent
385 ;           is the main function, not that funclet.
386 ; CHECK-NEXT: .long 8
387 ;                   ^ flags (0 => catch handler | 8 => duplicate)
388 ; CHECK-NEXT: .long ([[test2_before_f2]]-[[test2_begin]])+1
389 ;                   ^ offset of start of clause
390 ; CHECK-NEXT: .long ([[test2_after_f2]]-[[test2_begin]])+1
391 ;                   ^ offset of end of clause
392 ; CHECK-NEXT: .long [[test2_catch2]]-[[test2_begin]]
393 ;                   ^ offset of start of handler
394 ; CHECK-NEXT: .long [[test2_fault]]-[[test2_begin]]
395 ;                   ^ offset of end of handler
396 ; CHECK-NEXT: .long 2
397 ;                   ^ type token of catch (from catchpad)
399 ; Test with several cleanups that need to infer their unwind dests from each
400 ; other, the inner one needing to make the inference from an invoke, ignoring
401 ; not-really-unwinding calls/unwind-to-caller catchswitches, as well as some
402 ; internal invokes/catchswitches
404 ; Corresponds to something like:
405 ; void test3() {
406 ;   try {
407 ;     f(1);
408 ;   } fault { // fault1
409 ;     try {
410 ;       try {
411 ;         f(2);
412 ;         __unreachable();
413 ;       } fault { // fault2
414 ;         try {
415 ;           f(3);
416 ;         } fault { // fault3
417 ;           try {
418 ;             f(4);
419 ;           } fault { // fault4
420 ;             f(5); // no unwind edge (e.g. front-end knew it wouldn't throw but
421 ;                    didn't bother to specify nounwind)
422 ;             try {
423 ;               try {
424 ;                 f(6);
425 ;               } catch(type 1) {
426 ;                 goto __unreachable;
427 ;               }
428 ;             } catch (type 2) { // marked "unwinds to caller" because we allow
429 ;                                // that if the unwind won't be taken (see
430 ;                                // SimplifyUnreachable & RemoveUnwindEdge)
431 ;               goto _unreachable;
432 ;             }
433 ;             f(7);
434 ;             __unreachable();
435 ;           }
436 ;         }
437 ;       }
438 ;     } fault { // fault 5
439 ;     }
440 ;   }
441 ; }
443 ; CHECK-LABEL: test3:     # @test3
444 ; CHECK-NEXT: [[test3_begin:.*func_begin.*]]:
445 define void @test3() personality i8* bitcast (void ()* @ProcessCLRException to i8*) {
446 entry:
447 ; CHECK: .seh_endprologue
448 ; CHECK: [[test3_before_f1:.+]]:
449 ; CHECK-NEXT: movl $1, %ecx
450 ; CHECK-NEXT: callq f
451 ; CHECK-NEXT: [[test3_after_f1:.+]]:
452   invoke void @f(i32 1)
453     to label %exit unwind label %fault1
454 fault1:
455  ; check lines below since this gets reordered to end-of-func
456   %fault.pad1 = cleanuppad within none [i32 undef]
457   invoke void @f(i32 2) ["funclet"(token %fault.pad1)]
458     to label %unreachable unwind label %fault2
459 fault2:
460  ; check lines below since this gets reordered to end-of-func
461   %fault.pad2 = cleanuppad within %fault.pad1 [i32 undef]
462   invoke void @f(i32 3) ["funclet"(token %fault.pad2)]
463     to label %unreachable unwind label %fault3
464 fault3:
465  ; check lines below since this gets reordered to end-of-func
466   %fault.pad3 = cleanuppad within %fault.pad2 [i32 undef]
467   invoke void @f(i32 4) ["funclet"(token %fault.pad3)]
468     to label %unreachable unwind label %fault4
469 fault4:
470 ; CHECK: .seh_proc [[test3_fault4:[^ ]+]]
471   %fault.pad4 = cleanuppad within %fault.pad3 [i32 undef]
472 ; CHECK: .seh_endprologue
473   call void @f(i32 5) ["funclet"(token %fault.pad4)]
474 ; CHECK: [[test3_before_f6:.+]]:
475 ; CHECK-NEXT: movl $6, %ecx
476 ; CHECK-NEXT: callq f
477 ; CHECK-NEXT: [[test3_after_f6:.+]]:
478   invoke void @f(i32 6) ["funclet"(token %fault.pad4)]
479     to label %fault4.cont unwind label %exn.dispatch1
480 fault4.cont:
481 ; CHECK: # %fault4.cont
482 ; CHECK: [[test3_before_f7:.+]]:
483 ; CHECK-NEXT: movl $7, %ecx
484 ; CHECK-NEXT: callq f
485 ; CHECK-NEXT: [[test3_after_f7:.+]]:
486   invoke void @f(i32 7) ["funclet"(token %fault.pad4)]
487     to label %unreachable unwind label %fault5
488 exn.dispatch1:
489   %catchswitch1 = catchswitch within %fault.pad4 [label %catch1] unwind label %exn.dispatch2
490 catch1:
491   %catch.pad1 = catchpad within %catchswitch1 [i32 1]
492 ; CHECK: .seh_proc [[test3_catch1:[^ ]+]]
493   catchret from %catch.pad1 to label %unreachable
494 exn.dispatch2:
495   %catchswitch2 = catchswitch within %fault.pad4 [label %catch2] unwind to caller
496 catch2:
497   %catch.pad2 = catchpad within %catchswitch2 [i32 2]
498 ; CHECK: .seh_proc [[test3_catch2:[^ ]+]]
499   catchret from %catch.pad2 to label %unreachable
500 fault5:
501 ; CHECK: .seh_proc [[test3_fault5:[^ ]+]]
502   %fault.pad5 = cleanuppad within %fault.pad1 [i32 undef]
503 ; CHECK: .seh_endprologue
504 cleanupret from %fault.pad5 unwind to caller
505 exit:
506   ret void
507 unreachable:
508   unreachable
509 ; CHECK: .seh_proc [[test3_fault3:[^ ]+]]
510 ; CHECK: # %fault3
511 ; CHECK: .seh_endprologue
512 ; CHECK: [[test3_before_f4:.+]]:
513 ; CHECK-NEXT: movl $4, %ecx
514 ; CHECK-NEXT: callq f
515 ; CHECK-NEXT: int3
516 ; CHECK-NEXT: [[test3_after_f4:.+]]:
517 ; CHECK: .seh_proc [[test3_fault2:[^ ]+]]
518 ; CHECK: # %fault2
519 ; CHECK: .seh_endprologue
520 ; CHECK: [[test3_before_f3:.+]]:
521 ; CHECK-NEXT: movl $3, %ecx
522 ; CHECK-NEXT: callq f
523 ; CHECK-NEXT: int3
524 ; CHECK-NEXT: [[test3_after_f3:.+]]:
525 ; CHECK: .seh_proc [[test3_fault1:[^ ]+]]
526 ; CHECK: # %fault1
527 ; CHECK: .seh_endprologue
528 ; CHECK: [[test3_before_f2:.+]]:
529 ; CHECK-NEXT: movl $2, %ecx
530 ; CHECK-NEXT: callq f
531 ; CHECK-NEXT: int3
532 ; CHECK-NEXT: [[test3_after_f2:.+]]:
533 ; CHECK: [[test3_end:.*func_end.*]]:
536 ; Now check for EH table in xdata (following standard xdata)
537 ; CHECK-LABEL: .section .xdata
538 ; standard xdata comes here
539 ; CHECK:      .long 7{{$}}
540 ;                   ^ number of funclets
541 ; CHECK-NEXT: .long [[test3_fault4]]-[[test3_begin]]
542 ;                   ^ offset from L_begin to start of 1st funclet
543 ; CHECK-NEXT: .long [[test3_catch1]]-[[test3_begin]]
544 ;                   ^ offset from L_begin to start of 2nd funclet
545 ; CHECK-NEXT: .long [[test3_catch2]]-[[test3_begin]]
546 ;                   ^ offset from L_begin to start of 3rd funclet
547 ; CHECK-NEXT: .long [[test3_fault5]]-[[test3_begin]]
548 ;                   ^ offset from L_begin to start of 4th funclet
549 ; CHECK-NEXT: .long [[test3_fault3]]-[[test3_begin]]
550 ;                   ^ offset from L_begin to start of 5th funclet
551 ; CHECK-NEXT: .long [[test3_fault2]]-[[test3_begin]]
552 ;                   ^ offset from L_begin to start of 6th funclet
553 ; CHECK-NEXT: .long [[test3_fault1]]-[[test3_begin]]
554 ;                   ^ offset from L_begin to start of 7th funclet
555 ; CHECK-NEXT: .long [[test3_end]]-[[test3_begin]]
556 ;                   ^ offset from L_begin to end of last funclet
557 ; CHECK-NEXT: .long 10
558 ;                   ^ number of EH clauses
559 ; Clause 1: call f(1) is guarded by fault1
560 ; CHECK-NEXT: .long 4
561 ;                   ^ flags (4 => fault handler)
562 ; CHECK-NEXT: .long ([[test3_before_f1]]-[[test3_begin]])+1
563 ;                   ^ offset of start of clause
564 ; CHECK-NEXT: .long ([[test3_after_f1]]-[[test3_begin]])+1
565 ;                   ^ offset of end of clause
566 ; CHECK-NEXT: .long [[test3_fault1]]-[[test3_begin]]
567 ;                   ^ offset of start of handler
568 ; CHECK-NEXT: .long [[test3_end]]-[[test3_begin]]
569 ;                   ^ offset of end of handler
570 ; CHECK-NEXT: .long 0
571 ;                   ^ type token slot (null for fault)
572 ; Clause 3: call f(6) is guarded by catch1
573 ; CHECK-NEXT: .long 0
574 ;                   ^ flags (0 => catch handler)
575 ; CHECK-NEXT: .long ([[test3_before_f6]]-[[test3_begin]])+1
576 ;                   ^ offset of start of clause
577 ; CHECK-NEXT: .long ([[test3_after_f6]]-[[test3_begin]])+1
578 ;                   ^ offset of end of clause
579 ; CHECK-NEXT: .long [[test3_catch1]]-[[test3_begin]]
580 ;                   ^ offset of start of handler
581 ; CHECK-NEXT: .long [[test3_catch2]]-[[test3_begin]]
582 ;                   ^ offset of end of handler
583 ; CHECK-NEXT: .long 1
584 ;                   ^ type token of catch (from catchpad)
585 ; Clause 3: call f(6) is also guarded by catch2
586 ; CHECK-NEXT: .long 0
587 ;                   ^ flags (0 => catch handler)
588 ; CHECK-NEXT: .long ([[test3_before_f6]]-[[test3_begin]])+1
589 ;                   ^ offset of start of clause
590 ; CHECK-NEXT: .long ([[test3_after_f6]]-[[test3_begin]])+1
591 ;                   ^ offset of end of clause
592 ; CHECK-NEXT: .long [[test3_catch2]]-[[test3_begin]]
593 ;                   ^ offset of start of handler
594 ; CHECK-NEXT: .long [[test3_fault5]]-[[test3_begin]]
595 ;                   ^ offset of end of handler
596 ; CHECK-NEXT: .long 2
597 ;                   ^ type token of catch (from catchpad)
598 ; Clause 4: call f(7) is guarded by fault5
599 ;           This is a "duplicate" because the protected range (f(6)-f(7))
600 ;           is in funclet fault4 but fault5's immediate parent
601 ;           is fault1, not that funclet.
602 ; CHECK-NEXT: .long 12
603 ;                   ^ flags (4 => fault handler | 8 => duplicate)
604 ; CHECK-NEXT: .long ([[test3_before_f7]]-[[test3_begin]])+1
605 ;                   ^ offset of start of clause
606 ; CHECK-NEXT: .long ([[test3_after_f7]]-[[test3_begin]])+1
607 ;                   ^ offset of end of clause
608 ; CHECK-NEXT: .long [[test3_fault5]]-[[test3_begin]]
609 ;                   ^ offset of start of handler
610 ; CHECK-NEXT: .long [[test3_fault3]]-[[test3_begin]]
611 ;                   ^ offset of end of handler
612 ; CHECK-NEXT: .long 0
613 ;                   ^ type token slot (null for fault)
614 ; Clause 5: call f(4) is guarded by fault4
615 ; CHECK-NEXT: .long 4
616 ;                   ^ flags (4 => fault handler)
617 ; CHECK-NEXT: .long ([[test3_before_f4]]-[[test3_begin]])+1
618 ;                   ^ offset of start of clause
619 ; CHECK-NEXT: .long ([[test3_after_f4]]-[[test3_begin]])+1
620 ;                   ^ offset of end of clause
621 ; CHECK-NEXT: .long [[test3_fault4]]-[[test3_begin]]
622 ;                   ^ offset of start of handler
623 ; CHECK-NEXT: .long [[test3_catch1]]-[[test3_begin]]
624 ;                   ^ offset of end of handler
625 ; CHECK-NEXT: .long 0
626 ;                   ^ type token slot (null for fault)
627 ; Clause 6: call f(4) is also guarded by fault5
628 ;           This is a "duplicate" because the protected range (f(4))
629 ;           is in funclet fault3 but fault5's immediate parent
630 ;           is fault1, not that funclet.
631 ; CHECK-NEXT: .long 12
632 ;                   ^ flags (4 => fault handler)
633 ; CHECK-NEXT: .long ([[test3_before_f4]]-[[test3_begin]])+1
634 ;                   ^ offset of start of clause
635 ; CHECK-NEXT: .long ([[test3_after_f4]]-[[test3_begin]])+1
636 ;                   ^ offset of end of clause
637 ; CHECK-NEXT: .long [[test3_fault5]]-[[test3_begin]]
638 ;                   ^ offset of start of handler
639 ; CHECK-NEXT: .long [[test3_fault3]]-[[test3_begin]]
640 ;                   ^ offset of end of handler
641 ; CHECK-NEXT: .long 0
642 ;                   ^ type token slot (null for fault)
643 ; Clause 7: call f(3) is guarded by fault3
644 ; CHECK-NEXT: .long 4
645 ;                   ^ flags (4 => fault handler)
646 ; CHECK-NEXT: .long ([[test3_before_f3]]-[[test3_begin]])+1
647 ;                   ^ offset of start of clause
648 ; CHECK-NEXT: .long ([[test3_after_f3]]-[[test3_begin]])+1
649 ;                   ^ offset of end of clause
650 ; CHECK-NEXT: .long [[test3_fault3]]-[[test3_begin]]
651 ;                   ^ offset of start of handler
652 ; CHECK-NEXT: .long [[test3_fault2]]-[[test3_begin]]
653 ;                   ^ offset of end of handler
654 ; CHECK-NEXT: .long 0
655 ;                   ^ type token slot (null for fault)
656 ; Clause 8: call f(3) is guarded by fault5
657 ;           This is a "duplicate" because the protected range (f(3))
658 ;           is in funclet fault2 but fault5's immediate parent
659 ;           is fault1, not that funclet.
660 ; CHECK-NEXT: .long 12
661 ;                   ^ flags (4 => fault handler | 8 => duplicate)
662 ; CHECK-NEXT: .long ([[test3_before_f3]]-[[test3_begin]])+1
663 ;                   ^ offset of start of clause
664 ; CHECK-NEXT: .long ([[test3_after_f3]]-[[test3_begin]])+1
665 ;                   ^ offset of end of clause
666 ; CHECK-NEXT: .long [[test3_fault5]]-[[test3_begin]]
667 ;                   ^ offset of start of handler
668 ; CHECK-NEXT: .long [[test3_fault3]]-[[test3_begin]]
669 ;                   ^ offset of end of handler
670 ; CHECK-NEXT: .long 0
671 ;                   ^ type token slot (null for fault)
672 ; Clause 9: call f(2) is guarded by fault2
673 ; CHECK-NEXT: .long 4
674 ;                   ^ flags (4 => fault handler)
675 ; CHECK-NEXT: .long ([[test3_before_f2]]-[[test3_begin]])+1
676 ;                   ^ offset of start of clause
677 ; CHECK-NEXT: .long ([[test3_after_f2]]-[[test3_begin]])+1
678 ;                   ^ offset of end of clause
679 ; CHECK-NEXT: .long [[test3_fault2]]-[[test3_begin]]
680 ;                   ^ offset of start of handler
681 ; CHECK-NEXT: .long [[test3_fault1]]-[[test3_begin]]
682 ;                   ^ offset of end of handler
683 ; CHECK-NEXT: .long 0
684 ;                   ^ type token slot (null for fault)
685 ; Clause 10: call f(2) is guarded by fault5
686 ; CHECK-NEXT: .long 4
687 ;                   ^ flags (4 => fault handler)
688 ; CHECK-NEXT: .long ([[test3_before_f2]]-[[test3_begin]])+1
689 ;                   ^ offset of start of clause
690 ; CHECK-NEXT: .long ([[test3_after_f2]]-[[test3_begin]])+1
691 ;                   ^ offset of end of clause
692 ; CHECK-NEXT: .long [[test3_fault5]]-[[test3_begin]]
693 ;                   ^ offset of start of handler
694 ; CHECK-NEXT: .long [[test3_fault3]]-[[test3_begin]]
695 ;                   ^ offset of end of handler
696 ; CHECK-NEXT: .long 0
697 ;                   ^ type token slot (null for fault)