1 ; RUN: llc -mtriple=x86_64-pc-windows-coreclr < %s | FileCheck %s
3 declare void @ProcessCLRException()
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:
30 ; CHECK-LABEL: test1: # @test1
31 ; CHECK-NEXT: [[L_begin:.*func_begin.*]]:
32 define void @test1() personality i8* bitcast (void ()* @ProcessCLRException to i8*) {
35 ; CHECK: .seh_endprologue
36 ; CHECK: [[L_before_f1:.+]]:
37 ; CHECK-NEXT: movl $1, %ecx
39 ; CHECK-NEXT: [[L_after_f1:.+]]:
41 to label %inner_try unwind label %finally.pad
44 ; CHECK: [[L_before_f2:.+]]:
45 ; CHECK-NEXT: movl $2, %ecx
47 ; CHECK-NEXT: [[L_after_f2:.+]]:
49 to label %finally.clone unwind label %catch1.pad
51 ; CHECK: .seh_proc [[L_catch1:[^ ]+]]
52 %catch1 = catchpad [i32 1]
53 to label %catch1.body unwind label %catch2.pad
55 ; CHECK: leaq {{[0-9]+}}(%rcx), %rbp
56 ; ^ establisher frame pointer passed in rcx
57 ; CHECK: .seh_endprologue
58 ; CHECK: movq %rdx, %rcx
59 ; ^ exception pointer passed in rdx
61 %exn1 = call i8 addrspace(1)* @llvm.eh.exceptionpointer.p1i8(token %catch1)
62 call void @g(i8 addrspace(1)* %exn1)
63 ; CHECK: [[L_before_f3:.+]]:
64 ; CHECK-NEXT: movl $3, %ecx
66 ; CHECK-NEXT: [[L_after_f3:.+]]:
68 to label %catch1.ret unwind label %catch.end
70 catchret %catch1 to label %finally.clone
72 ; CHECK: .seh_proc [[L_catch2:[^ ]+]]
73 %catch2 = catchpad [i32 2]
74 to label %catch2.body unwind label %catch.end
76 ; CHECK: leaq {{[0-9]+}}(%rcx), %rbp
77 ; ^ establisher frame pointer passed in rcx
78 ; CHECK: .seh_endprologue
79 ; CHECK: movq %rdx, %rcx
80 ; ^ exception pointer passed in rdx
82 %exn2 = call i8 addrspace(1)* @llvm.eh.exceptionpointer.p1i8(token %catch2)
83 call void @g(i8 addrspace(1)* %exn2)
84 ; CHECK: [[L_before_f4:.+]]:
85 ; CHECK-NEXT: movl $4, %ecx
87 ; CHECK-NEXT: [[L_after_f4:.+]]:
89 to label %try_in_catch unwind label %catch.end
91 ; CHECK: # %try_in_catch
92 ; CHECK: [[L_before_f5:.+]]:
93 ; CHECK-NEXT: movl $5, %ecx
95 ; CHECK-NEXT: [[L_after_f5:.+]]:
97 to label %catch2.ret unwind label %fault.pad
99 ; CHECK: .seh_proc [[L_fault:[^ ]+]]
100 %fault = cleanuppad [i32 undef]
101 ; CHECK: leaq {{[0-9]+}}(%rcx), %rbp
102 ; ^ establisher frame pointer passed in rcx
103 ; CHECK: .seh_endprologue
104 ; CHECK: [[L_before_f6:.+]]:
105 ; CHECK-NEXT: movl $6, %ecx
106 ; CHECK-NEXT: callq f
107 ; CHECK-NEXT: [[L_after_f6:.+]]:
108 invoke void @f(i32 6)
109 to label %fault.ret unwind label %fault.end
111 cleanupret %fault unwind label %catch.end
113 cleanupendpad %fault unwind label %catch.end
115 catchret %catch2 to label %finally.clone
117 catchendpad unwind label %finally.pad
122 ; CHECK: .seh_proc [[L_finally:[^ ]+]]
123 %finally = cleanuppad []
124 ; CHECK: leaq {{[0-9]+}}(%rcx), %rbp
125 ; ^ establisher frame pointer passed in rcx
126 ; CHECK: .seh_endprologue
127 ; CHECK: [[L_before_f7:.+]]:
128 ; CHECK-NEXT: movl $7, %ecx
129 ; CHECK-NEXT: callq f
130 ; CHECK-NEXT: [[L_after_f7:.+]]:
131 invoke void @f(i32 7)
132 to label %finally.ret unwind label %finally.end
134 cleanupret %finally unwind to caller
136 cleanupendpad %finally unwind to caller
140 ; CHECK: [[L_end:.*func_end.*]]:
143 ; Now check for EH table in xdata (following standard xdata)
144 ; CHECK-LABEL: .section .xdata
145 ; standard xdata comes here
146 ; CHECK: .long 4{{$}}
147 ; ^ number of funclets
148 ; CHECK-NEXT: .long [[L_catch1]]-[[L_begin]]
149 ; ^ offset from L_begin to start of 1st funclet
150 ; CHECK-NEXT: .long [[L_catch2]]-[[L_begin]]
151 ; ^ offset from L_begin to start of 2nd funclet
152 ; CHECK-NEXT: .long [[L_fault]]-[[L_begin]]
153 ; ^ offset from L_begin to start of 3rd funclet
154 ; CHECK-NEXT: .long [[L_finally]]-[[L_begin]]
155 ; ^ offset from L_begin to start of 4th funclet
156 ; CHECK-NEXT: .long [[L_end]]-[[L_begin]]
157 ; ^ offset from L_begin to end of last funclet
158 ; CHECK-NEXT: .long 7
159 ; ^ number of EH clauses
160 ; Clause 1: call f(2) is guarded by catch1
161 ; CHECK-NEXT: .long 0
162 ; ^ flags (0 => catch handler)
163 ; CHECK-NEXT: .long ([[L_before_f2]]-[[L_begin]])+1
164 ; ^ offset of start of clause
165 ; CHECK-NEXT: .long ([[L_after_f2]]-[[L_begin]])+1
166 ; ^ offset of end of clause
167 ; CHECK-NEXT: .long [[L_catch1]]-[[L_begin]]
168 ; ^ offset of start of handler
169 ; CHECK-NEXT: .long [[L_catch2]]-[[L_begin]]
170 ; ^ offset of end of handler
171 ; CHECK-NEXT: .long 1
172 ; ^ type token of catch (from catchpad)
173 ; Clause 2: call f(2) is also guarded by catch2
174 ; CHECK-NEXT: .long 0
175 ; ^ flags (0 => catch handler)
176 ; CHECK-NEXT: .long ([[L_before_f2]]-[[L_begin]])+1
177 ; ^ offset of start of clause
178 ; CHECK-NEXT: .long ([[L_after_f2]]-[[L_begin]])+1
179 ; ^ offset of end of clause
180 ; CHECK-NEXT: .long [[L_catch2]]-[[L_begin]]
181 ; ^ offset of start of handler
182 ; CHECK-NEXT: .long [[L_fault]]-[[L_begin]]
183 ; ^ offset of end of handler
184 ; CHECK-NEXT: .long 2
185 ; ^ type token of catch (from catchpad)
186 ; Clause 3: calls f(1) and f(2) are guarded by finally
187 ; CHECK-NEXT: .long 2
188 ; ^ flags (2 => finally handler)
189 ; CHECK-NEXT: .long ([[L_before_f1]]-[[L_begin]])+1
190 ; ^ offset of start of clause
191 ; CHECK-NEXT: .long ([[L_after_f2]]-[[L_begin]])+1
192 ; ^ offset of end of clause
193 ; CHECK-NEXT: .long [[L_finally]]-[[L_begin]]
194 ; ^ offset of start of handler
195 ; CHECK-NEXT: .long [[L_end]]-[[L_begin]]
196 ; ^ offset of end of handler
197 ; CHECK-NEXT: .long 0
198 ; ^ type token slot (null for finally)
199 ; Clause 4: call f(3) is guarded by finally
200 ; This is a "duplicate" because the protected range (f(3))
201 ; is in funclet catch1 but the finally's immediate parent
202 ; is the main function, not that funclet.
203 ; CHECK-NEXT: .long 10
204 ; ^ flags (2 => finally handler | 8 => duplicate)
205 ; CHECK-NEXT: .long ([[L_before_f3]]-[[L_begin]])+1
206 ; ^ offset of start of clause
207 ; CHECK-NEXT: .long ([[L_after_f3]]-[[L_begin]])+1
208 ; ^ offset of end of clause
209 ; CHECK-NEXT: .long [[L_finally]]-[[L_begin]]
210 ; ^ offset of start of handler
211 ; CHECK-NEXT: .long [[L_end]]-[[L_begin]]
212 ; ^ offset of end of handler
213 ; CHECK-NEXT: .long 0
214 ; ^ type token slot (null for finally)
215 ; Clause 5: call f(5) is guarded by fault
216 ; CHECK-NEXT: .long 4
217 ; ^ flags (4 => fault handler)
218 ; CHECK-NEXT: .long ([[L_before_f5]]-[[L_begin]])+1
219 ; ^ offset of start of clause
220 ; CHECK-NEXT: .long ([[L_after_f5]]-[[L_begin]])+1
221 ; ^ offset of end of clause
222 ; CHECK-NEXT: .long [[L_fault]]-[[L_begin]]
223 ; ^ offset of start of handler
224 ; CHECK-NEXT: .long [[L_finally]]-[[L_begin]]
225 ; ^ offset of end of handler
226 ; CHECK-NEXT: .long 0
227 ; ^ type token slot (null for fault)
228 ; Clause 6: calls f(4) and f(5) are guarded by finally
229 ; This is a "duplicate" because the protected range (f(4)-f(5))
230 ; is in funclet catch2 but the finally's immediate parent
231 ; is the main function, not that funclet.
232 ; CHECK-NEXT: .long 10
233 ; ^ flags (2 => finally handler | 8 => duplicate)
234 ; CHECK-NEXT: .long ([[L_before_f4]]-[[L_begin]])+1
235 ; ^ offset of start of clause
236 ; CHECK-NEXT: .long ([[L_after_f5]]-[[L_begin]])+1
237 ; ^ offset of end of clause
238 ; CHECK-NEXT: .long [[L_finally]]-[[L_begin]]
239 ; ^ offset of start of handler
240 ; CHECK-NEXT: .long [[L_end]]-[[L_begin]]
241 ; ^ offset of end of handler
242 ; CHECK-NEXT: .long 0
243 ; ^ type token slot (null for finally)
244 ; Clause 7: call f(6) is guarded by finally
245 ; This is a "duplicate" because the protected range (f(3))
246 ; is in funclet catch1 but the finally's immediate parent
247 ; is the main function, not that funclet.
248 ; CHECK-NEXT: .long 10
249 ; ^ flags (2 => finally handler | 8 => duplicate)
250 ; CHECK-NEXT: .long ([[L_before_f6]]-[[L_begin]])+1
251 ; ^ offset of start of clause
252 ; CHECK-NEXT: .long ([[L_after_f6]]-[[L_begin]])+1
253 ; ^ offset of end of clause
254 ; CHECK-NEXT: .long [[L_finally]]-[[L_begin]]
255 ; ^ offset of start of handler
256 ; CHECK-NEXT: .long [[L_end]]-[[L_begin]]
257 ; ^ offset of end of handler
258 ; CHECK-NEXT: .long 0
259 ; ^ type token slot (null for finally)