1 | // RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fms-extensions -emit-llvm -o - | opt -instnamer -S | FileCheck %s |
2 | |
3 | void g(void); |
4 | |
5 | ////////////////////////////////////////////////////////////////////////////// |
6 | // __leave with __except |
7 | |
8 | // Nothing in the __try block can trap, so __try.cont isn't created. |
9 | int __leave_with___except_simple() { |
10 | int myres = 0; |
11 | __try { |
12 | myres = 15; |
13 | __leave; |
14 | myres = 23; |
15 | } __except (1) { |
16 | return 0; |
17 | } |
18 | return 1; |
19 | } |
20 | // CHECK-LABEL: define dso_local i32 @__leave_with___except_simple() |
21 | // CHECK: store i32 15, i32* %myres |
22 | // CHECK-NEXT: br label %[[tryleave:[^ ]*]] |
23 | // CHECK-NOT: store i32 23 |
24 | // CHECK: [[tryleave]] |
25 | // CHECK-NEXT: ret i32 1 |
26 | |
27 | |
28 | // The "normal" case. |
29 | int __leave_with___except() { |
30 | int myres = 0; |
31 | __try { |
32 | g(); |
33 | __leave; |
34 | myres = 23; |
35 | } __except (1) { |
36 | return 0; |
37 | } |
38 | return 1; |
39 | } |
40 | // CHECK-LABEL: define dso_local i32 @__leave_with___except() |
41 | // CHECK: invoke void @g() |
42 | // CHECK-NEXT: to label %[[cont:.*]] unwind label %{{.*}} |
43 | // For __excepts, instead of an explicit __try.__leave label, we could use |
44 | // use invoke.cont as __leave jump target instead. However, not doing this |
45 | // keeps the CodeGen code simpler, __leave is very rare, and SimplifyCFG will |
46 | // simplify this anyways. |
47 | // CHECK: [[cont]] |
48 | // CHECK-NEXT: br label %[[tryleave:[^ ]*]] |
49 | // CHECK-NOT: store i32 23 |
50 | // CHECK: [[tryleave]] |
51 | // CHECK-NEXT: br label % |
52 | |
53 | |
54 | ////////////////////////////////////////////////////////////////////////////// |
55 | // __leave with __finally |
56 | |
57 | void abort(void) __attribute__((noreturn)); |
58 | |
59 | // Nothing in the __try block can trap, so __finally.cont and friends aren't |
60 | // created. |
61 | int __leave_with___finally_simple() { |
62 | int myres = 0; |
63 | __try { |
64 | myres = 15; |
65 | __leave; |
66 | myres = 23; |
67 | } __finally { |
68 | return 0; |
69 | } |
70 | return 1; |
71 | } |
72 | // CHECK-LABEL: define dso_local i32 @__leave_with___finally_simple() |
73 | // CHECK: store i32 15, i32* %myres |
74 | // CHECK-NEXT: br label %[[tryleave:[^ ]*]] |
75 | // CHECK-NOT: store i32 23 |
76 | // CHECK: [[tryleave]] |
77 | // CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() |
78 | // CHECK-NEXT: call void @"?fin$0@0@__leave_with___finally_simple@@"(i8 0, i8* %[[fp]]) |
79 | |
80 | // __finally block doesn't return, __finally.cont doesn't exist. |
81 | int __leave_with___finally_noreturn() { |
82 | int myres = 0; |
83 | __try { |
84 | myres = 15; |
85 | __leave; |
86 | myres = 23; |
87 | } __finally { |
88 | abort(); |
89 | } |
90 | return 1; |
91 | } |
92 | // CHECK-LABEL: define dso_local i32 @__leave_with___finally_noreturn() |
93 | // CHECK: store i32 15, i32* %myres |
94 | // CHECK-NEXT: br label %[[tryleave:[^ ]*]] |
95 | // CHECK-NOT: store i32 23 |
96 | // CHECK: [[tryleave]] |
97 | // CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() |
98 | // CHECK-NEXT: call void @"?fin$0@0@__leave_with___finally_noreturn@@"(i8 0, i8* %[[fp]]) |
99 | |
100 | // The "normal" case. |
101 | int __leave_with___finally() { |
102 | int myres = 0; |
103 | __try { |
104 | g(); |
105 | __leave; |
106 | myres = 23; |
107 | } __finally { |
108 | return 0; |
109 | } |
110 | return 1; |
111 | } |
112 | // CHECK-LABEL: define dso_local i32 @__leave_with___finally() |
113 | // CHECK: invoke void @g() |
114 | // CHECK-NEXT: to label %[[cont:.*]] unwind label %{{.*}} |
115 | // For __finally, there needs to be an explicit __try.__leave, because |
116 | // abnormal.termination.slot needs to be set there. |
117 | // CHECK: [[cont]] |
118 | // CHECK-NEXT: br label %[[tryleave:[^ ]*]] |
119 | // CHECK-NOT: store i32 23 |
120 | // CHECK: [[tryleave]] |
121 | // CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() |
122 | // CHECK-NEXT: call void @"?fin$0@0@__leave_with___finally@@"(i8 0, i8* %[[fp]]) |
123 | |
124 | |
125 | ////////////////////////////////////////////////////////////////////////////// |
126 | // Mixed, nested cases. |
127 | |
128 | int nested___except___finally() { |
129 | int myres = 0; |
130 | __try { |
131 | __try { |
132 | g(); |
133 | } __finally { |
134 | g(); |
135 | __leave; // Refers to the outer __try, not the __finally! |
136 | myres = 23; |
137 | return 0; |
138 | } |
139 | |
140 | myres = 51; |
141 | } __except (1) { |
142 | } |
143 | return 1; |
144 | } |
145 | // CHECK-LABEL: define dso_local i32 @nested___except___finally() |
146 | |
147 | // CHECK-LABEL: invoke void @g() |
148 | // CHECK-NEXT: to label %[[g1_cont1:.*]] unwind label %[[g1_lpad:.*]] |
149 | |
150 | // CHECK: [[g1_cont1]] |
151 | // CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() |
152 | // CHECK-NEXT: invoke void @"?fin$0@0@nested___except___finally@@"(i8 0, i8* %[[fp]]) |
153 | // CHECK-NEXT: to label %[[fin_cont:.*]] unwind label %[[g2_lpad:.*]] |
154 | |
155 | // CHECK: [[fin_cont]] |
156 | // CHECK: store i32 51, i32* % |
157 | // CHECK-NEXT: br label %[[trycont:[^ ]*]] |
158 | |
159 | // CHECK: [[g1_lpad]] |
160 | // CHECK-NEXT: cleanuppad |
161 | // CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() |
162 | // CHECK-NEXT: invoke void @"?fin$0@0@nested___except___finally@@"(i8 1, i8* %[[fp]]) |
163 | // CHECK-NEXT: to label %[[g1_resume:.*]] unwind label %[[g2_lpad]] |
164 | // CHECK: cleanupret {{.*}} unwind label %[[g2_lpad]] |
165 | |
166 | // CHECK: [[g2_lpad]] |
167 | // CHECK: catchpad {{.*}} [i8* null] |
168 | // CHECK: catchret |
169 | // CHECK: br label %[[trycont]] |
170 | |
171 | // CHECK: [[trycont]] |
172 | // CHECK-NEXT: ret i32 1 |
173 | |
174 | // CHECK-LABEL: define internal void @"?fin$0@0@nested___except___finally@@"(i8 %abnormal_termination, i8* %frame_pointer) |
175 | // CHECK: call void @g() |
176 | // CHECK: unreachable |
177 | |
178 | int nested___except___except() { |
179 | int myres = 0; |
180 | __try { |
181 | __try { |
182 | g(); |
183 | myres = 16; |
184 | } __except (1) { |
185 | g(); |
186 | __leave; // Refers to the outer __try, not the __except we're in! |
187 | myres = 23; |
188 | return 0; |
189 | } |
190 | |
191 | myres = 51; |
192 | } __except (1) { |
193 | } |
194 | return 1; |
195 | } |
196 | // The order of basic blocks in the below doesn't matter. |
197 | // CHECK-LABEL: define dso_local i32 @nested___except___except() |
198 | |
199 | // CHECK-LABEL: invoke void @g() |
200 | // CHECK-NEXT: to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]] |
201 | |
202 | // CHECK: [[g1_lpad]] |
203 | // CHECK: catchpad {{.*}} [i8* null] |
204 | // CHECK: catchret {{.*}} to label %[[except:[^ ]*]] |
205 | // CHECK: [[except]] |
206 | // CHECK: invoke void @g() |
207 | // CHECK-NEXT: to label %[[g2_cont:.*]] unwind label %[[g2_lpad:.*]] |
208 | |
209 | // CHECK: [[g2_lpad]] |
210 | // CHECK: catchpad {{.*}} [i8* null] |
211 | // CHECK: catchret |
212 | // CHECK: br label %[[trycont4:[^ ]*]] |
213 | |
214 | // CHECK: [[trycont4]] |
215 | // CHECK-NEXT: ret i32 1 |
216 | |
217 | // CHECK: [[g2_cont]] |
218 | // CHECK-NEXT: br label %[[tryleave:[^ ]*]] |
219 | // CHECK-NOT: store i32 23 |
220 | |
221 | // CHECK: [[g1_cont]] |
222 | // CHECK: store i32 16, i32* %myres |
223 | // CHECK-NEXT: br label %[[trycont:[^ ]*]] |
224 | |
225 | // CHECK: [[trycont]] |
226 | // CHECK-NEXT: store i32 51, i32* %myres |
227 | // CHECK-NEXT: br label %[[tryleave]] |
228 | |
229 | // CHECK: [[tryleave]] |
230 | // CHECK-NEXT: br label %[[trycont4]] |
231 | |
232 | int nested___finally___except() { |
233 | int myres = 0; |
234 | __try { |
235 | __try { |
236 | g(); |
237 | } __except (1) { |
238 | g(); |
239 | __leave; // Refers to the outer __try, not the __except! |
240 | myres = 23; |
241 | return 0; |
242 | } |
243 | |
244 | myres = 51; |
245 | } __finally { |
246 | } |
247 | return 1; |
248 | } |
249 | // The order of basic blocks in the below doesn't matter. |
250 | // CHECK-LABEL: define dso_local i32 @nested___finally___except() |
251 | |
252 | // CHECK-LABEL: invoke void @g() |
253 | // CHECK-NEXT: to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]] |
254 | |
255 | // CHECK: [[g1_lpad]] |
256 | // CHECK: catchpad |
257 | // CHECK: catchret |
258 | // CHECK: invoke void @g() |
259 | // CHECK-NEXT: to label %[[g2_cont:.*]] unwind label %[[g2_lpad:.*]] |
260 | |
261 | // CHECK: [[g2_cont]] |
262 | // CHECK: br label %[[tryleave:[^ ]*]] |
263 | // CHECK-NOT: 23 |
264 | |
265 | // CHECK: [[g1_cont]] |
266 | // CHECK-NEXT: br label %[[trycont:[^ ]*]] |
267 | |
268 | // CHECK: [[trycont]] |
269 | // CHECK: store i32 51, i32* % |
270 | // CHECK-NEXT: br label %[[tryleave]] |
271 | |
272 | // CHECK: [[tryleave]] |
273 | // CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() |
274 | // CHECK-NEXT: call void @"?fin$0@0@nested___finally___except@@"(i8 0, i8* %[[fp]]) |
275 | // CHECK-NEXT: ret i32 1 |
276 | |
277 | // CHECK: [[g2_lpad]] |
278 | // CHECK: cleanuppad |
279 | // CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() |
280 | // CHECK-NEXT: call void @"?fin$0@0@nested___finally___except@@"(i8 1, i8* %[[fp]]) |
281 | // CHECK: cleanupret {{.*}} unwind to caller |
282 | |
283 | // CHECK-LABEL: define internal void @"?fin$0@0@nested___finally___except@@"(i8 %abnormal_termination, i8* %frame_pointer) |
284 | // CHECK: ret void |
285 | |
286 | int nested___finally___finally() { |
287 | int myres = 0; |
288 | __try { |
289 | __try { |
290 | g(); |
291 | myres = 16; |
292 | } __finally { |
293 | g(); |
294 | __leave; // Refers to the outer __try, not the __finally we're in! |
295 | myres = 23; |
296 | return 0; |
297 | } |
298 | |
299 | myres = 51; |
300 | } __finally { |
301 | } |
302 | return 1; |
303 | } |
304 | // The order of basic blocks in the below doesn't matter. |
305 | // CHECK-LABEL: define dso_local i32 @nested___finally___finally() |
306 | |
307 | // CHECK: invoke void @g() |
308 | // CHECK-NEXT: to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]] |
309 | |
310 | // CHECK: [[g1_cont]] |
311 | // CHECK: store i32 16, i32* %[[myres:[^ ]*]], |
312 | // CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() |
313 | // CHECK-NEXT: invoke void @"?fin$1@0@nested___finally___finally@@"(i8 0, i8* %[[fp]]) |
314 | // CHECK-NEXT: to label %[[finally_cont:.*]] unwind label %[[g2_lpad:.*]] |
315 | |
316 | // CHECK: [[finally_cont]] |
317 | // CHECK: store i32 51, i32* %[[myres]] |
318 | // CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() |
319 | // CHECK-NEXT: call void @"?fin$0@0@nested___finally___finally@@"(i8 0, i8* %[[fp]]) |
320 | // CHECK-NEXT: ret i32 1 |
321 | |
322 | // CHECK: [[g1_lpad]] |
323 | // CHECK-NEXT: %[[padtoken:[^ ]*]] = cleanuppad within none [] |
324 | // CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() |
325 | // CHECK-NEXT: invoke void @"?fin$1@0@nested___finally___finally@@"(i8 1, i8* %[[fp]]) |
326 | // CHECK-NEXT: to label %[[finally_cont2:.*]] unwind label %[[g2_lpad]] |
327 | // CHECK: [[finally_cont2]] |
328 | // CHECK: cleanupret from %[[padtoken]] unwind label %[[g2_lpad]] |
329 | |
330 | // CHECK: [[g2_lpad]] |
331 | // CHECK-NEXT: %[[padtoken:[^ ]*]] = cleanuppad within none [] |
332 | // CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() |
333 | // CHECK-NEXT: call void @"?fin$0@0@nested___finally___finally@@"(i8 1, i8* %[[fp]]) |
334 | // CHECK: cleanupret from %[[padtoken]] unwind to caller |
335 | |
336 | // CHECK-LABEL: define internal void @"?fin$0@0@nested___finally___finally@@"(i8 %abnormal_termination, i8* %frame_pointer) |
337 | // CHECK: ret void |
338 | |
339 | // CHECK-LABEL: define internal void @"?fin$1@0@nested___finally___finally@@"(i8 %abnormal_termination, i8* %frame_pointer) |
340 | // CHECK: call void @g() |
341 | // CHECK: unreachable |
342 | |