1 ; RUN: llc -mtriple=x86_64-pc-windows-coreclr < %s | FileCheck %s
3 declare void @ProcessCLRException()
6 ; Simplified IR for pseudo-C# like the following:
28 ; CHECK-LABEL: test1: # @test1
29 ; CHECK-NEXT: [[L_begin:.*func_begin.*]]:
30 define void @test1() personality i8* bitcast (void ()* @ProcessCLRException to i8*) {
33 ; CHECK: .seh_endprologue
34 ; CHECK: [[L_before_f1:.+]]:
35 ; CHECK-NEXT: movl $1, %ecx
37 ; CHECK-NEXT: [[L_after_f1:.+]]:
39 to label %inner_try unwind label %finally.pad
42 ; CHECK: [[L_before_f2:.+]]:
43 ; CHECK-NEXT: movl $2, %ecx
45 ; CHECK-NEXT: [[L_after_f2:.+]]:
47 to label %finally.clone unwind label %catch1.pad
49 ; CHECK: .seh_proc [[L_catch1:[^ ]+]]
50 %catch1 = catchpad [i32 1]
51 to label %catch1.body unwind label %catch2.pad
53 ; CHECK: .seh_endprologue
54 ; CHECK: [[L_before_f3:.+]]:
55 ; CHECK-NEXT: movl $3, %ecx
57 ; CHECK-NEXT: [[L_after_f3:.+]]:
59 to label %catch1.ret unwind label %catch.end
61 catchret %catch1 to label %finally.clone
63 ; CHECK: .seh_proc [[L_catch2:[^ ]+]]
64 %catch2 = catchpad [i32 2]
65 to label %catch2.body unwind label %catch.end
67 ; CHECK: .seh_endprologue
68 ; CHECK: [[L_before_f4:.+]]:
69 ; CHECK-NEXT: movl $4, %ecx
71 ; CHECK-NEXT: [[L_after_f4:.+]]:
73 to label %try_in_catch unwind label %catch.end
75 ; CHECK: # %try_in_catch
76 ; CHECK: [[L_before_f5:.+]]:
77 ; CHECK-NEXT: movl $5, %ecx
79 ; CHECK-NEXT: [[L_after_f5:.+]]:
81 to label %catch2.ret unwind label %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
89 ; CHECK-NEXT: [[L_after_f6:.+]]:
91 to label %fault.ret unwind label %fault.end
93 cleanupret %fault unwind label %catch.end
95 cleanupendpad %fault unwind label %catch.end
97 catchret %catch2 to label %finally.clone
99 catchendpad unwind label %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
114 cleanupret %finally unwind to caller
116 cleanupendpad %finally unwind to caller
120 ; CHECK: [[L_end:.*func_end.*]]:
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)