56675fefae748c6d1c87c55836e920f11bee8894
[oota-llvm.git] / test / CodeGen / WinEH / wineh-coreclr.ll
1 ; RUN: llc -mtriple=x86_64-pc-windows-coreclr < %s | FileCheck %s
2
3 declare void @ProcessCLRException()
4 declare void @f(i32)
5
6 ; Simplified IR for pseudo-C# like the following:
7 ; void test1() {
8 ;   try {
9 ;     f(1);
10 ;     try {
11 ;       f(2);
12 ;     } catch (type1) {
13 ;       f(3);
14 ;     } catch (type2) [
15 ;       f(4);
16 ;       try {
17 ;         f(5);
18 ;       } fault {
19 ;         f(6);
20 ;       }
21 ;     }
22 ;   } finally {
23 ;     f(7);
24 ;   }
25 ;   f(8);
26 ; }
27
28 ; CHECK-LABEL: test1:     # @test1
29 ; CHECK-NEXT: [[L_begin:.*func_begin.*]]:
30 define void @test1() personality i8* bitcast (void ()* @ProcessCLRException to i8*) {
31 entry:
32 ; CHECK: # %entry
33 ; CHECK: .seh_endprologue
34 ; CHECK: [[L_before_f1:.+]]:
35 ; CHECK-NEXT: movl $1, %ecx
36 ; CHECK-NEXT: callq f
37 ; CHECK-NEXT: [[L_after_f1:.+]]:
38   invoke void @f(i32 1)
39     to label %inner_try unwind label %finally.pad
40 inner_try:
41 ; CHECK: # %inner_try
42 ; CHECK: [[L_before_f2:.+]]:
43 ; CHECK-NEXT: movl $2, %ecx
44 ; CHECK-NEXT: callq f
45 ; CHECK-NEXT: [[L_after_f2:.+]]:
46   invoke void @f(i32 2)
47     to label %finally.clone unwind label %catch1.pad
48 catch1.pad:
49 ; CHECK: .seh_proc [[L_catch1:[^ ]+]]
50   %catch1 = catchpad [i32 1]
51     to label %catch1.body unwind label %catch2.pad
52 catch1.body:
53 ; CHECK: .seh_endprologue
54 ; CHECK: [[L_before_f3:.+]]:
55 ; CHECK-NEXT: movl $3, %ecx
56 ; CHECK-NEXT: callq f
57 ; CHECK-NEXT: [[L_after_f3:.+]]:
58   invoke void @f(i32 3)
59     to label %catch1.ret unwind label %catch.end
60 catch1.ret:
61   catchret %catch1 to label %finally.clone
62 catch2.pad:
63 ; CHECK: .seh_proc [[L_catch2:[^ ]+]]
64   %catch2 = catchpad [i32 2]
65     to label %catch2.body unwind label %catch.end
66 catch2.body:
67 ; CHECK: .seh_endprologue
68 ; CHECK: [[L_before_f4:.+]]:
69 ; CHECK-NEXT: movl $4, %ecx
70 ; CHECK-NEXT: callq f
71 ; CHECK-NEXT: [[L_after_f4:.+]]:
72   invoke void @f(i32 4)
73     to label %try_in_catch unwind label %catch.end
74 try_in_catch:
75 ; CHECK: # %try_in_catch
76 ; CHECK: [[L_before_f5:.+]]:
77 ; CHECK-NEXT: movl $5, %ecx
78 ; CHECK-NEXT: callq f
79 ; CHECK-NEXT: [[L_after_f5:.+]]:
80   invoke void @f(i32 5)
81     to label %catch2.ret unwind label %fault.pad
82 fault.pad:
83 ; CHECK: .seh_proc [[L_fault:[^ ]+]]
84   %fault = cleanuppad [i32 undef]
85 ; CHECK: .seh_endprologue
86 ; CHECK: [[L_before_f6:.+]]:
87 ; CHECK-NEXT: movl $6, %ecx
88 ; CHECK-NEXT: callq f
89 ; CHECK-NEXT: [[L_after_f6:.+]]:
90   invoke void @f(i32 6)
91     to label %fault.ret unwind label %fault.end
92 fault.ret:
93   cleanupret %fault unwind label %catch.end
94 fault.end:
95   cleanupendpad %fault unwind label %catch.end
96 catch2.ret:
97   catchret %catch2 to label %finally.clone
98 catch.end:
99   catchendpad unwind label %finally.pad
100 finally.clone:
101   call void @f(i32 7)
102   br label %tail
103 finally.pad:
104 ; CHECK: .seh_proc [[L_finally:[^ ]+]]
105   %finally = cleanuppad []
106 ; CHECK: .seh_endprologue
107 ; CHECK: [[L_before_f7:.+]]:
108 ; CHECK-NEXT: movl $7, %ecx
109 ; CHECK-NEXT: callq f
110 ; CHECK-NEXT: [[L_after_f7:.+]]:
111   invoke void @f(i32 7)
112     to label %finally.ret unwind label %finally.end
113 finally.ret:
114   cleanupret %finally unwind to caller
115 finally.end:
116    cleanupendpad %finally unwind to caller
117 tail:
118   call void @f(i32 8)
119   ret void
120 ; CHECK: [[L_end:.*func_end.*]]:
121 }
122
123 ; Now check for EH table in xdata (following standard xdata)
124 ; CHECK-LABEL: .section .xdata
125 ; standard xdata comes here
126 ; CHECK:      .long 4{{$}}
127 ;                   ^ number of funclets
128 ; CHECK-NEXT: .long [[L_catch1]]-[[L_begin]]
129 ;                   ^ offset from L_begin to start of 1st funclet
130 ; CHECK-NEXT: .long [[L_catch2]]-[[L_begin]]
131 ;                   ^ offset from L_begin to start of 2nd funclet
132 ; CHECK-NEXT: .long [[L_fault]]-[[L_begin]]
133 ;                   ^ offset from L_begin to start of 3rd funclet
134 ; CHECK-NEXT: .long [[L_finally]]-[[L_begin]]
135 ;                   ^ offset from L_begin to start of 4th funclet
136 ; CHECK-NEXT: .long [[L_end]]-[[L_begin]]
137 ;                   ^ offset from L_begin to end of last funclet
138 ; CHECK-NEXT: .long 7
139 ;                   ^ number of EH clauses
140 ; Clause 1: call f(2) is guarded by catch1
141 ; CHECK-NEXT: .long 0
142 ;                   ^ flags (0 => catch handler)
143 ; CHECK-NEXT: .long ([[L_before_f2]]-[[L_begin]])+1
144 ;                   ^ offset of start of clause
145 ; CHECK-NEXT: .long ([[L_after_f2]]-[[L_begin]])+1
146 ;                   ^ offset of end of clause
147 ; CHECK-NEXT: .long [[L_catch1]]-[[L_begin]]
148 ;                   ^ offset of start of handler
149 ; CHECK-NEXT: .long [[L_catch2]]-[[L_begin]]
150 ;                   ^ offset of end of handler
151 ; CHECK-NEXT: .long 1
152 ;                   ^ type token of catch (from catchpad)
153 ; Clause 2: call f(2) is also guarded by catch2
154 ; CHECK-NEXT: .long 0
155 ;                   ^ flags (0 => catch handler)
156 ; CHECK-NEXT: .long ([[L_before_f2]]-[[L_begin]])+1
157 ;                   ^ offset of start of clause
158 ; CHECK-NEXT: .long ([[L_after_f2]]-[[L_begin]])+1
159 ;                   ^ offset of end of clause
160 ; CHECK-NEXT: .long [[L_catch2]]-[[L_begin]]
161 ;                   ^ offset of start of handler
162 ; CHECK-NEXT: .long [[L_fault]]-[[L_begin]]
163 ;                   ^ offset of end of handler
164 ; CHECK-NEXT: .long 2
165 ;                   ^ type token of catch (from catchpad)
166 ; Clause 3: calls f(1) and f(2) are guarded by finally
167 ; CHECK-NEXT: .long 2
168 ;                   ^ flags (2 => finally handler)
169 ; CHECK-NEXT: .long ([[L_before_f1]]-[[L_begin]])+1
170 ;                   ^ offset of start of clause
171 ; CHECK-NEXT: .long ([[L_after_f2]]-[[L_begin]])+1
172 ;                   ^ offset of end of clause
173 ; CHECK-NEXT: .long [[L_finally]]-[[L_begin]]
174 ;                   ^ offset of start of handler
175 ; CHECK-NEXT: .long [[L_end]]-[[L_begin]]
176 ;                   ^ offset of end of handler
177 ; CHECK-NEXT: .long 0
178 ;                   ^ type token slot (null for finally)
179 ; Clause 4: call f(3) is guarded by finally
180 ;           This is a "duplicate" because the protected range (f(3))
181 ;           is in funclet catch1 but the finally's immediate parent
182 ;           is the main function, not that funclet.
183 ; CHECK-NEXT: .long 10
184 ;                   ^ flags (2 => finally handler | 8 => duplicate)
185 ; CHECK-NEXT: .long ([[L_before_f3]]-[[L_begin]])+1
186 ;                   ^ offset of start of clause
187 ; CHECK-NEXT: .long ([[L_after_f3]]-[[L_begin]])+1
188 ;                   ^ offset of end of clause
189 ; CHECK-NEXT: .long [[L_finally]]-[[L_begin]]
190 ;                   ^ offset of start of handler
191 ; CHECK-NEXT: .long [[L_end]]-[[L_begin]]
192 ;                   ^ offset of end of handler
193 ; CHECK-NEXT: .long 0
194 ;                   ^ type token slot (null for finally)
195 ; Clause 5: call f(5) is guarded by fault
196 ; CHECK-NEXT: .long 4
197 ;                   ^ flags (4 => fault handler)
198 ; CHECK-NEXT: .long ([[L_before_f5]]-[[L_begin]])+1
199 ;                   ^ offset of start of clause
200 ; CHECK-NEXT: .long ([[L_after_f5]]-[[L_begin]])+1
201 ;                   ^ offset of end of clause
202 ; CHECK-NEXT: .long [[L_fault]]-[[L_begin]]
203 ;                   ^ offset of start of handler
204 ; CHECK-NEXT: .long [[L_finally]]-[[L_begin]]
205 ;                   ^ offset of end of handler
206 ; CHECK-NEXT: .long 0
207 ;                   ^ type token slot (null for fault)
208 ; Clause 6: calls f(4) and f(5) are guarded by finally
209 ;           This is a "duplicate" because the protected range (f(4)-f(5))
210 ;           is in funclet catch2 but the finally's immediate parent
211 ;           is the main function, not that funclet.
212 ; CHECK-NEXT: .long 10
213 ;                   ^ flags (2 => finally handler | 8 => duplicate)
214 ; CHECK-NEXT: .long ([[L_before_f4]]-[[L_begin]])+1
215 ;                   ^ offset of start of clause
216 ; CHECK-NEXT: .long ([[L_after_f5]]-[[L_begin]])+1
217 ;                   ^ offset of end of clause
218 ; CHECK-NEXT: .long [[L_finally]]-[[L_begin]]
219 ;                   ^ offset of start of handler
220 ; CHECK-NEXT: .long [[L_end]]-[[L_begin]]
221 ;                   ^ offset of end of handler
222 ; CHECK-NEXT: .long 0
223 ;                   ^ type token slot (null for finally)
224 ; Clause 7: call f(6) is guarded by finally
225 ;           This is a "duplicate" because the protected range (f(3))
226 ;           is in funclet catch1 but the finally's immediate parent
227 ;           is the main function, not that funclet.
228 ; CHECK-NEXT: .long 10
229 ;                   ^ flags (2 => finally handler | 8 => duplicate)
230 ; CHECK-NEXT: .long ([[L_before_f6]]-[[L_begin]])+1
231 ;                   ^ offset of start of clause
232 ; CHECK-NEXT: .long ([[L_after_f6]]-[[L_begin]])+1
233 ;                   ^ offset of end of clause
234 ; CHECK-NEXT: .long [[L_finally]]-[[L_begin]]
235 ;                   ^ offset of start of handler
236 ; CHECK-NEXT: .long [[L_end]]-[[L_begin]]
237 ;                   ^ offset of end of handler
238 ; CHECK-NEXT: .long 0
239 ;                   ^ type token slot (null for finally)