[WinEH] Fix establisher param reg in CLR funclets
[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: 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
58 ; CHECK-NEXT: callq f
59 ; CHECK-NEXT: [[L_after_f3:.+]]:
60   invoke void @f(i32 3)
61     to label %catch1.ret unwind label %catch.end
62 catch1.ret:
63   catchret %catch1 to label %finally.clone
64 catch2.pad:
65 ; CHECK: .seh_proc [[L_catch2:[^ ]+]]
66   %catch2 = catchpad [i32 2]
67     to label %catch2.body unwind label %catch.end
68 catch2.body:
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
74 ; CHECK-NEXT: callq f
75 ; CHECK-NEXT: [[L_after_f4:.+]]:
76   invoke void @f(i32 4)
77     to label %try_in_catch unwind label %catch.end
78 try_in_catch:
79 ; CHECK: # %try_in_catch
80 ; CHECK: [[L_before_f5:.+]]:
81 ; CHECK-NEXT: movl $5, %ecx
82 ; CHECK-NEXT: callq f
83 ; CHECK-NEXT: [[L_after_f5:.+]]:
84   invoke void @f(i32 5)
85     to label %catch2.ret unwind label %fault.pad
86 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
94 ; CHECK-NEXT: callq f
95 ; CHECK-NEXT: [[L_after_f6:.+]]:
96   invoke void @f(i32 6)
97     to label %fault.ret unwind label %fault.end
98 fault.ret:
99   cleanupret %fault unwind label %catch.end
100 fault.end:
101   cleanupendpad %fault unwind label %catch.end
102 catch2.ret:
103   catchret %catch2 to label %finally.clone
104 catch.end:
105   catchendpad unwind label %finally.pad
106 finally.clone:
107   call void @f(i32 7)
108   br label %tail
109 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
121 finally.ret:
122   cleanupret %finally unwind to caller
123 finally.end:
124    cleanupendpad %finally unwind to caller
125 tail:
126   call void @f(i32 8)
127   ret void
128 ; CHECK: [[L_end:.*func_end.*]]:
129 }
130
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)