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: leaq {{[0-9]+}}(%rcx), %rbp
54 ; ^ establisher frame pointer passed in rcx
55 ; CHECK: .seh_endprologue
56 ; CHECK: [[L_before_f3:.+]]:
57 ; CHECK-NEXT: movl $3, %ecx
59 ; CHECK-NEXT: [[L_after_f3:.+]]:
61 to label %catch1.ret unwind label %catch.end
63 catchret %catch1 to label %finally.clone
65 ; CHECK: .seh_proc [[L_catch2:[^ ]+]]
66 %catch2 = catchpad [i32 2]
67 to label %catch2.body unwind label %catch.end
69 ; CHECK: leaq {{[0-9]+}}(%rcx), %rbp
70 ; ^ establisher frame pointer passed in rcx
71 ; CHECK: .seh_endprologue
72 ; CHECK: [[L_before_f4:.+]]:
73 ; CHECK-NEXT: movl $4, %ecx
75 ; CHECK-NEXT: [[L_after_f4:.+]]:
77 to label %try_in_catch unwind label %catch.end
79 ; CHECK: # %try_in_catch
80 ; CHECK: [[L_before_f5:.+]]:
81 ; CHECK-NEXT: movl $5, %ecx
83 ; CHECK-NEXT: [[L_after_f5:.+]]:
85 to label %catch2.ret unwind label %fault.pad
87 ; CHECK: .seh_proc [[L_fault:[^ ]+]]
88 %fault = cleanuppad [i32 undef]
89 ; CHECK: leaq {{[0-9]+}}(%rcx), %rbp
90 ; ^ establisher frame pointer passed in rcx
91 ; CHECK: .seh_endprologue
92 ; CHECK: [[L_before_f6:.+]]:
93 ; CHECK-NEXT: movl $6, %ecx
95 ; CHECK-NEXT: [[L_after_f6:.+]]:
97 to label %fault.ret unwind label %fault.end
99 cleanupret %fault unwind label %catch.end
101 cleanupendpad %fault unwind label %catch.end
103 catchret %catch2 to label %finally.clone
105 catchendpad unwind label %finally.pad
110 ; CHECK: .seh_proc [[L_finally:[^ ]+]]
111 %finally = cleanuppad []
112 ; CHECK: leaq {{[0-9]+}}(%rcx), %rbp
113 ; ^ establisher frame pointer passed in rcx
114 ; CHECK: .seh_endprologue
115 ; CHECK: [[L_before_f7:.+]]:
116 ; CHECK-NEXT: movl $7, %ecx
117 ; CHECK-NEXT: callq f
118 ; CHECK-NEXT: [[L_after_f7:.+]]:
119 invoke void @f(i32 7)
120 to label %finally.ret unwind label %finally.end
122 cleanupret %finally unwind to caller
124 cleanupendpad %finally unwind to caller
128 ; CHECK: [[L_end:.*func_end.*]]:
131 ; Now check for EH table in xdata (following standard xdata)
132 ; CHECK-LABEL: .section .xdata
133 ; standard xdata comes here
134 ; CHECK: .long 4{{$}}
135 ; ^ number of funclets
136 ; CHECK-NEXT: .long [[L_catch1]]-[[L_begin]]
137 ; ^ offset from L_begin to start of 1st funclet
138 ; CHECK-NEXT: .long [[L_catch2]]-[[L_begin]]
139 ; ^ offset from L_begin to start of 2nd funclet
140 ; CHECK-NEXT: .long [[L_fault]]-[[L_begin]]
141 ; ^ offset from L_begin to start of 3rd funclet
142 ; CHECK-NEXT: .long [[L_finally]]-[[L_begin]]
143 ; ^ offset from L_begin to start of 4th funclet
144 ; CHECK-NEXT: .long [[L_end]]-[[L_begin]]
145 ; ^ offset from L_begin to end of last funclet
146 ; CHECK-NEXT: .long 7
147 ; ^ number of EH clauses
148 ; Clause 1: call f(2) is guarded by catch1
149 ; CHECK-NEXT: .long 0
150 ; ^ flags (0 => catch handler)
151 ; CHECK-NEXT: .long ([[L_before_f2]]-[[L_begin]])+1
152 ; ^ offset of start of clause
153 ; CHECK-NEXT: .long ([[L_after_f2]]-[[L_begin]])+1
154 ; ^ offset of end of clause
155 ; CHECK-NEXT: .long [[L_catch1]]-[[L_begin]]
156 ; ^ offset of start of handler
157 ; CHECK-NEXT: .long [[L_catch2]]-[[L_begin]]
158 ; ^ offset of end of handler
159 ; CHECK-NEXT: .long 1
160 ; ^ type token of catch (from catchpad)
161 ; Clause 2: call f(2) is also guarded by catch2
162 ; CHECK-NEXT: .long 0
163 ; ^ flags (0 => catch handler)
164 ; CHECK-NEXT: .long ([[L_before_f2]]-[[L_begin]])+1
165 ; ^ offset of start of clause
166 ; CHECK-NEXT: .long ([[L_after_f2]]-[[L_begin]])+1
167 ; ^ offset of end of clause
168 ; CHECK-NEXT: .long [[L_catch2]]-[[L_begin]]
169 ; ^ offset of start of handler
170 ; CHECK-NEXT: .long [[L_fault]]-[[L_begin]]
171 ; ^ offset of end of handler
172 ; CHECK-NEXT: .long 2
173 ; ^ type token of catch (from catchpad)
174 ; Clause 3: calls f(1) and f(2) are guarded by finally
175 ; CHECK-NEXT: .long 2
176 ; ^ flags (2 => finally handler)
177 ; CHECK-NEXT: .long ([[L_before_f1]]-[[L_begin]])+1
178 ; ^ offset of start of clause
179 ; CHECK-NEXT: .long ([[L_after_f2]]-[[L_begin]])+1
180 ; ^ offset of end of clause
181 ; CHECK-NEXT: .long [[L_finally]]-[[L_begin]]
182 ; ^ offset of start of handler
183 ; CHECK-NEXT: .long [[L_end]]-[[L_begin]]
184 ; ^ offset of end of handler
185 ; CHECK-NEXT: .long 0
186 ; ^ type token slot (null for finally)
187 ; Clause 4: call f(3) is guarded by finally
188 ; This is a "duplicate" because the protected range (f(3))
189 ; is in funclet catch1 but the finally's immediate parent
190 ; is the main function, not that funclet.
191 ; CHECK-NEXT: .long 10
192 ; ^ flags (2 => finally handler | 8 => duplicate)
193 ; CHECK-NEXT: .long ([[L_before_f3]]-[[L_begin]])+1
194 ; ^ offset of start of clause
195 ; CHECK-NEXT: .long ([[L_after_f3]]-[[L_begin]])+1
196 ; ^ offset of end of clause
197 ; CHECK-NEXT: .long [[L_finally]]-[[L_begin]]
198 ; ^ offset of start of handler
199 ; CHECK-NEXT: .long [[L_end]]-[[L_begin]]
200 ; ^ offset of end of handler
201 ; CHECK-NEXT: .long 0
202 ; ^ type token slot (null for finally)
203 ; Clause 5: call f(5) is guarded by fault
204 ; CHECK-NEXT: .long 4
205 ; ^ flags (4 => fault handler)
206 ; CHECK-NEXT: .long ([[L_before_f5]]-[[L_begin]])+1
207 ; ^ offset of start of clause
208 ; CHECK-NEXT: .long ([[L_after_f5]]-[[L_begin]])+1
209 ; ^ offset of end of clause
210 ; CHECK-NEXT: .long [[L_fault]]-[[L_begin]]
211 ; ^ offset of start of handler
212 ; CHECK-NEXT: .long [[L_finally]]-[[L_begin]]
213 ; ^ offset of end of handler
214 ; CHECK-NEXT: .long 0
215 ; ^ type token slot (null for fault)
216 ; Clause 6: calls f(4) and f(5) are guarded by finally
217 ; This is a "duplicate" because the protected range (f(4)-f(5))
218 ; is in funclet catch2 but the finally's immediate parent
219 ; is the main function, not that funclet.
220 ; CHECK-NEXT: .long 10
221 ; ^ flags (2 => finally handler | 8 => duplicate)
222 ; CHECK-NEXT: .long ([[L_before_f4]]-[[L_begin]])+1
223 ; ^ offset of start of clause
224 ; CHECK-NEXT: .long ([[L_after_f5]]-[[L_begin]])+1
225 ; ^ offset of end of clause
226 ; CHECK-NEXT: .long [[L_finally]]-[[L_begin]]
227 ; ^ offset of start of handler
228 ; CHECK-NEXT: .long [[L_end]]-[[L_begin]]
229 ; ^ offset of end of handler
230 ; CHECK-NEXT: .long 0
231 ; ^ type token slot (null for finally)
232 ; Clause 7: call f(6) is guarded by finally
233 ; This is a "duplicate" because the protected range (f(3))
234 ; is in funclet catch1 but the finally's immediate parent
235 ; is the main function, not that funclet.
236 ; CHECK-NEXT: .long 10
237 ; ^ flags (2 => finally handler | 8 => duplicate)
238 ; CHECK-NEXT: .long ([[L_before_f6]]-[[L_begin]])+1
239 ; ^ offset of start of clause
240 ; CHECK-NEXT: .long ([[L_after_f6]]-[[L_begin]])+1
241 ; ^ offset of end of clause
242 ; CHECK-NEXT: .long [[L_finally]]-[[L_begin]]
243 ; ^ offset of start of handler
244 ; CHECK-NEXT: .long [[L_end]]-[[L_begin]]
245 ; ^ offset of end of handler
246 ; CHECK-NEXT: .long 0
247 ; ^ type token slot (null for finally)