b61876827cac89e9aa0fcbe7ed4cb9cc9c9e8a87
[oota-llvm.git] / test / CodeGen / X86 / wineh-coreclr.ll
1 ; RUN: llc -mtriple=x86_64-pc-windows-coreclr -verify-machineinstrs < %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: leaq [[FPOffset:[0-9]+]](%rsp), %rbp
36 ; CHECK: .seh_endprologue
37 ; CHECK: movq %rsp, [[PSPSymOffset:[0-9]+]](%rsp)
38 ; CHECK: [[L_before_f1:.+]]:
39 ; CHECK-NEXT: movl $1, %ecx
40 ; CHECK-NEXT: callq f
41 ; CHECK-NEXT: [[L_after_f1:.+]]:
42   invoke void @f(i32 1)
43     to label %inner_try unwind label %finally.pad
44 inner_try:
45 ; CHECK: # %inner_try
46 ; CHECK: [[L_before_f2:.+]]:
47 ; CHECK-NEXT: movl $2, %ecx
48 ; CHECK-NEXT: callq f
49 ; CHECK-NEXT: [[L_after_f2:.+]]:
50   invoke void @f(i32 2)
51     to label %finally.clone unwind label %catch1.pad
52 catch1.pad:
53   %cs1 = catchswitch within none [label %catch1.body, label %catch2.body] unwind label %finally.pad
54 catch1.body:
55   %catch1 = catchpad within %cs1 [i32 1]
56 ; CHECK: .seh_proc [[L_catch1:[^ ]+]]
57 ; CHECK: .seh_stackalloc [[FuncletFrameSize:[0-9]+]]
58 ;                        ^ all funclets use the same frame size
59 ; CHECK: movq [[PSPSymOffset]](%rcx), %rcx
60 ;                              ^ establisher frame pointer passed in rcx
61 ; CHECK: movq %rcx, [[PSPSymOffset]](%rsp)
62 ; CHECK: leaq [[FPOffset]](%rcx), %rbp
63 ; CHECK: .seh_endprologue
64 ; CHECK: movq %rdx, %rcx
65 ;             ^ exception pointer passed in rdx
66 ; CHECK-NEXT: callq g
67   %exn1 = call i8 addrspace(1)* @llvm.eh.exceptionpointer.p1i8(token %catch1)
68   call void @g(i8 addrspace(1)* %exn1) [ "funclet"(token %catch1) ]
69 ; CHECK: [[L_before_f3:.+]]:
70 ; CHECK-NEXT: movl $3, %ecx
71 ; CHECK-NEXT: callq f
72 ; CHECK-NEXT: [[L_after_f3:.+]]:
73   invoke void @f(i32 3) [ "funclet"(token %catch1) ]
74     to label %catch1.ret unwind label %finally.pad
75 catch1.ret:
76   catchret from %catch1 to label %finally.clone
77 catch2.body:
78   %catch2 = catchpad within %cs1 [i32 2]
79 ; CHECK: .seh_proc [[L_catch2:[^ ]+]]
80 ; CHECK: .seh_stackalloc [[FuncletFrameSize:[0-9]+]]
81 ;                        ^ all funclets use the same frame size
82 ; CHECK: movq [[PSPSymOffset]](%rcx), %rcx
83 ;                              ^ establisher frame pointer passed in rcx
84 ; CHECK: movq %rcx, [[PSPSymOffset]](%rsp)
85 ; CHECK: leaq [[FPOffset]](%rcx), %rbp
86 ; CHECK: .seh_endprologue
87 ; CHECK: movq %rdx, %rcx
88 ;             ^ exception pointer passed in rdx
89 ; CHECK-NEXT: callq g
90   %exn2 = call i8 addrspace(1)* @llvm.eh.exceptionpointer.p1i8(token %catch2)
91   call void @g(i8 addrspace(1)* %exn2) [ "funclet"(token %catch2) ]
92 ; CHECK: [[L_before_f4:.+]]:
93 ; CHECK-NEXT: movl $4, %ecx
94 ; CHECK-NEXT: callq f
95 ; CHECK-NEXT: [[L_after_f4:.+]]:
96   invoke void @f(i32 4) [ "funclet"(token %catch2) ]
97     to label %try_in_catch unwind label %finally.pad
98 try_in_catch:
99 ; CHECK: # %try_in_catch
100 ; CHECK: [[L_before_f5:.+]]:
101 ; CHECK-NEXT: movl $5, %ecx
102 ; CHECK-NEXT: callq f
103 ; CHECK-NEXT: [[L_after_f5:.+]]:
104   invoke void @f(i32 5) [ "funclet"(token %catch2) ]
105     to label %catch2.ret unwind label %fault.pad
106 fault.pad:
107 ; CHECK: .seh_proc [[L_fault:[^ ]+]]
108   %fault = cleanuppad within none [i32 undef]
109 ; CHECK: .seh_stackalloc [[FuncletFrameSize:[0-9]+]]
110 ;                        ^ all funclets use the same frame size
111 ; CHECK: movq [[PSPSymOffset]](%rcx), %rcx
112 ;                              ^ establisher frame pointer passed in rcx
113 ; CHECK: movq %rcx, [[PSPSymOffset]](%rsp)
114 ; CHECK: leaq [[FPOffset]](%rcx), %rbp
115 ; CHECK: .seh_endprologue
116 ; CHECK: [[L_before_f6:.+]]:
117 ; CHECK-NEXT: movl $6, %ecx
118 ; CHECK-NEXT: callq f
119 ; CHECK-NEXT: [[L_after_f6:.+]]:
120   invoke void @f(i32 6) [ "funclet"(token %fault) ]
121     to label %fault.ret unwind label %finally.pad
122 fault.ret:
123   cleanupret from %fault unwind label %finally.pad
124 catch2.ret:
125   catchret from %catch2 to label %finally.clone
126 finally.clone:
127   call void @f(i32 7)
128   br label %tail
129 finally.pad:
130 ; CHECK: .seh_proc [[L_finally:[^ ]+]]
131   %finally = cleanuppad within none []
132 ; CHECK: .seh_stackalloc [[FuncletFrameSize:[0-9]+]]
133 ;                        ^ all funclets use the same frame size
134 ; CHECK: movq [[PSPSymOffset]](%rcx), %rcx
135 ;                              ^ establisher frame pointer passed in rcx
136 ; CHECK: movq %rcx, [[PSPSymOffset]](%rsp)
137 ; CHECK: leaq [[FPOffset]](%rcx), %rbp
138 ; CHECK: .seh_endprologue
139 ; CHECK-NEXT: movl $7, %ecx
140 ; CHECK-NEXT: callq f
141   call void @f(i32 7) [ "funclet"(token %finally) ]
142   cleanupret from %finally unwind to caller
143 tail:
144   call void @f(i32 8)
145   ret void
146 ; CHECK: [[L_end:.*func_end.*]]:
147 }
148
149 ; FIXME: Verify that the new clauses are correct and re-enable these checks.
150
151 ; Now check for EH table in xdata (following standard xdata)
152 ; CHECKX-LABEL: .section .xdata
153 ; standard xdata comes here
154 ; CHECKX:      .long 4{{$}}
155 ;                   ^ number of funclets
156 ; CHECKX-NEXT: .long [[L_catch1]]-[[L_begin]]
157 ;                   ^ offset from L_begin to start of 1st funclet
158 ; CHECKX-NEXT: .long [[L_catch2]]-[[L_begin]]
159 ;                   ^ offset from L_begin to start of 2nd funclet
160 ; CHECKX-NEXT: .long [[L_fault]]-[[L_begin]]
161 ;                   ^ offset from L_begin to start of 3rd funclet
162 ; CHECKX-NEXT: .long [[L_finally]]-[[L_begin]]
163 ;                   ^ offset from L_begin to start of 4th funclet
164 ; CHECKX-NEXT: .long [[L_end]]-[[L_begin]]
165 ;                   ^ offset from L_begin to end of last funclet
166 ; CHECKX-NEXT: .long 7
167 ;                   ^ number of EH clauses
168 ; Clause 1: call f(2) is guarded by catch1
169 ; CHECKX-NEXT: .long 0
170 ;                   ^ flags (0 => catch handler)
171 ; CHECKX-NEXT: .long ([[L_before_f2]]-[[L_begin]])+1
172 ;                   ^ offset of start of clause
173 ; CHECKX-NEXT: .long ([[L_after_f2]]-[[L_begin]])+1
174 ;                   ^ offset of end of clause
175 ; CHECKX-NEXT: .long [[L_catch1]]-[[L_begin]]
176 ;                   ^ offset of start of handler
177 ; CHECKX-NEXT: .long [[L_catch2]]-[[L_begin]]
178 ;                   ^ offset of end of handler
179 ; CHECKX-NEXT: .long 1
180 ;                   ^ type token of catch (from catchpad)
181 ; Clause 2: call f(2) is also guarded by catch2
182 ; CHECKX-NEXT: .long 0
183 ;                   ^ flags (0 => catch handler)
184 ; CHECKX-NEXT: .long ([[L_before_f2]]-[[L_begin]])+1
185 ;                   ^ offset of start of clause
186 ; CHECKX-NEXT: .long ([[L_after_f2]]-[[L_begin]])+1
187 ;                   ^ offset of end of clause
188 ; CHECKX-NEXT: .long [[L_catch2]]-[[L_begin]]
189 ;                   ^ offset of start of handler
190 ; CHECKX-NEXT: .long [[L_fault]]-[[L_begin]]
191 ;                   ^ offset of end of handler
192 ; CHECKX-NEXT: .long 2
193 ;                   ^ type token of catch (from catchpad)
194 ; Clause 3: calls f(1) and f(2) are guarded by finally
195 ; CHECKX-NEXT: .long 2
196 ;                   ^ flags (2 => finally handler)
197 ; CHECKX-NEXT: .long ([[L_before_f1]]-[[L_begin]])+1
198 ;                   ^ offset of start of clause
199 ; CHECKX-NEXT: .long ([[L_after_f2]]-[[L_begin]])+1
200 ;                   ^ offset of end of clause
201 ; CHECKX-NEXT: .long [[L_finally]]-[[L_begin]]
202 ;                   ^ offset of start of handler
203 ; CHECKX-NEXT: .long [[L_end]]-[[L_begin]]
204 ;                   ^ offset of end of handler
205 ; CHECKX-NEXT: .long 0
206 ;                   ^ type token slot (null for finally)
207 ; Clause 4: call f(3) is guarded by finally
208 ;           This is a "duplicate" because the protected range (f(3))
209 ;           is in funclet catch1 but the finally's immediate parent
210 ;           is the main function, not that funclet.
211 ; CHECKX-NEXT: .long 10
212 ;                   ^ flags (2 => finally handler | 8 => duplicate)
213 ; CHECKX-NEXT: .long ([[L_before_f3]]-[[L_begin]])+1
214 ;                   ^ offset of start of clause
215 ; CHECKX-NEXT: .long ([[L_after_f3]]-[[L_begin]])+1
216 ;                   ^ offset of end of clause
217 ; CHECKX-NEXT: .long [[L_finally]]-[[L_begin]]
218 ;                   ^ offset of start of handler
219 ; CHECKX-NEXT: .long [[L_end]]-[[L_begin]]
220 ;                   ^ offset of end of handler
221 ; CHECKX-NEXT: .long 0
222 ;                   ^ type token slot (null for finally)
223 ; Clause 5: call f(5) is guarded by fault
224 ; CHECKX-NEXT: .long 4
225 ;                   ^ flags (4 => fault handler)
226 ; CHECKX-NEXT: .long ([[L_before_f5]]-[[L_begin]])+1
227 ;                   ^ offset of start of clause
228 ; CHECKX-NEXT: .long ([[L_after_f5]]-[[L_begin]])+1
229 ;                   ^ offset of end of clause
230 ; CHECKX-NEXT: .long [[L_fault]]-[[L_begin]]
231 ;                   ^ offset of start of handler
232 ; CHECKX-NEXT: .long [[L_finally]]-[[L_begin]]
233 ;                   ^ offset of end of handler
234 ; CHECKX-NEXT: .long 0
235 ;                   ^ type token slot (null for fault)
236 ; Clause 6: calls f(4) and f(5) are guarded by finally
237 ;           This is a "duplicate" because the protected range (f(4)-f(5))
238 ;           is in funclet catch2 but the finally's immediate parent
239 ;           is the main function, not that funclet.
240 ; CHECKX-NEXT: .long 10
241 ;                   ^ flags (2 => finally handler | 8 => duplicate)
242 ; CHECKX-NEXT: .long ([[L_before_f4]]-[[L_begin]])+1
243 ;                   ^ offset of start of clause
244 ; CHECKX-NEXT: .long ([[L_after_f5]]-[[L_begin]])+1
245 ;                   ^ offset of end of clause
246 ; CHECKX-NEXT: .long [[L_finally]]-[[L_begin]]
247 ;                   ^ offset of start of handler
248 ; CHECKX-NEXT: .long [[L_end]]-[[L_begin]]
249 ;                   ^ offset of end of handler
250 ; CHECKX-NEXT: .long 0
251 ;                   ^ type token slot (null for finally)
252 ; Clause 7: call f(6) is guarded by finally
253 ;           This is a "duplicate" because the protected range (f(3))
254 ;           is in funclet catch1 but the finally's immediate parent
255 ;           is the main function, not that funclet.
256 ; CHECKX-NEXT: .long 10
257 ;                   ^ flags (2 => finally handler | 8 => duplicate)
258 ; CHECKX-NEXT: .long ([[L_before_f6]]-[[L_begin]])+1
259 ;                   ^ offset of start of clause
260 ; CHECKX-NEXT: .long ([[L_after_f6]]-[[L_begin]])+1
261 ;                   ^ offset of end of clause
262 ; CHECKX-NEXT: .long [[L_finally]]-[[L_begin]]
263 ;                   ^ offset of start of handler
264 ; CHECKX-NEXT: .long [[L_end]]-[[L_begin]]
265 ;                   ^ offset of end of handler
266 ; CHECKX-NEXT: .long 0
267 ;                   ^ type token slot (null for finally)