[WinEH] Update exception pointer registers
[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 declare void @g(i8 addrspace(1)*)
6 declare i8 addrspace(1)* @llvm.eh.exceptionpointer.p1i8(token)
7
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 ; }
29
30 ; CHECK-LABEL: test1:     # @test1
31 ; CHECK-NEXT: [[L_begin:.*func_begin.*]]:
32 define void @test1() personality i8* bitcast (void ()* @ProcessCLRException to i8*) {
33 entry:
34 ; CHECK: # %entry
35 ; CHECK: .seh_endprologue
36 ; CHECK: [[L_before_f1:.+]]:
37 ; CHECK-NEXT: movl $1, %ecx
38 ; CHECK-NEXT: callq f
39 ; CHECK-NEXT: [[L_after_f1:.+]]:
40   invoke void @f(i32 1)
41     to label %inner_try unwind label %finally.pad
42 inner_try:
43 ; CHECK: # %inner_try
44 ; CHECK: [[L_before_f2:.+]]:
45 ; CHECK-NEXT: movl $2, %ecx
46 ; CHECK-NEXT: callq f
47 ; CHECK-NEXT: [[L_after_f2:.+]]:
48   invoke void @f(i32 2)
49     to label %finally.clone unwind label %catch1.pad
50 catch1.pad:
51 ; CHECK: .seh_proc [[L_catch1:[^ ]+]]
52   %catch1 = catchpad [i32 1]
53     to label %catch1.body unwind label %catch2.pad
54 catch1.body:
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
60 ; CHECK-NEXT: callq g
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
65 ; CHECK-NEXT: callq f
66 ; CHECK-NEXT: [[L_after_f3:.+]]:
67   invoke void @f(i32 3)
68     to label %catch1.ret unwind label %catch.end
69 catch1.ret:
70   catchret %catch1 to label %finally.clone
71 catch2.pad:
72 ; CHECK: .seh_proc [[L_catch2:[^ ]+]]
73   %catch2 = catchpad [i32 2]
74     to label %catch2.body unwind label %catch.end
75 catch2.body:
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
81 ; CHECK-NEXT: callq g
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
86 ; CHECK-NEXT: callq f
87 ; CHECK-NEXT: [[L_after_f4:.+]]:
88   invoke void @f(i32 4)
89     to label %try_in_catch unwind label %catch.end
90 try_in_catch:
91 ; CHECK: # %try_in_catch
92 ; CHECK: [[L_before_f5:.+]]:
93 ; CHECK-NEXT: movl $5, %ecx
94 ; CHECK-NEXT: callq f
95 ; CHECK-NEXT: [[L_after_f5:.+]]:
96   invoke void @f(i32 5)
97     to label %catch2.ret unwind label %fault.pad
98 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
110 fault.ret:
111   cleanupret %fault unwind label %catch.end
112 fault.end:
113   cleanupendpad %fault unwind label %catch.end
114 catch2.ret:
115   catchret %catch2 to label %finally.clone
116 catch.end:
117   catchendpad unwind label %finally.pad
118 finally.clone:
119   call void @f(i32 7)
120   br label %tail
121 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
133 finally.ret:
134   cleanupret %finally unwind to caller
135 finally.end:
136    cleanupendpad %finally unwind to caller
137 tail:
138   call void @f(i32 8)
139   ret void
140 ; CHECK: [[L_end:.*func_end.*]]:
141 }
142
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)