[ORC] Add std::tuple support to SimplePackedSerialization.
[llvm-project.git] / llvm / test / Transforms / SimplifyCFG / X86 / empty-cleanuppad.ll
blob7e378d1ed09b913f66e32784f5274db52b821151
1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt < %s -simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S -hoist-common-insts=true | FileCheck %s
4 ; ModuleID = 'cppeh-simplify.cpp'
5 target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
6 target triple = "x86_64-pc-windows-msvc18.0.0"
9 ; This case arises when two objects with empty destructors are cleaned up.
11 ; void f1() {
12 ;   S a;
13 ;   S b;
14 ;   g();
15 ; }
17 ; In this case, both cleanup pads can be eliminated and the invoke can be
18 ; converted to a call.
20 define void @f1() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
21 ; CHECK-LABEL: @f1(
22 ; CHECK-NEXT:  entry:
23 ; CHECK-NEXT:    call void @g()
24 ; CHECK-NEXT:    ret void
26 entry:
27   invoke void @g() to label %invoke.cont unwind label %ehcleanup
29 invoke.cont:                                      ; preds = %entry
30   ret void
32 ehcleanup:                                        ; preds = %entry
33   %0 = cleanuppad within none []
34   cleanupret from %0 unwind label %ehcleanup.1
36 ehcleanup.1:                                      ; preds = %ehcleanup
37   %1 = cleanuppad within none []
38   cleanupret from %1 unwind to caller
42 ; This case arises when an object with an empty destructor must be cleaned up
43 ; outside of a try-block and an object with a non-empty destructor must be
44 ; cleaned up within the try-block.
46 ; void f2() {
47 ;   S a;
48 ;   try {
49 ;     S2 b;
50 ;     g();
51 ;   } catch (...) {}
52 ; }
54 ; In this case, the outermost cleanup pad can be eliminated and the catch block
55 ; should unwind to the caller (that is, exception handling continues with the
56 ; parent frame of the caller).
58 define void @f2() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
59 ; CHECK-LABEL: @f2(
60 ; CHECK-NEXT:  entry:
61 ; CHECK-NEXT:    [[B:%.*]] = alloca [[STRUCT_S2:%.*]], align 1
62 ; CHECK-NEXT:    invoke void @g()
63 ; CHECK-NEXT:    to label [[TRY_CONT:%.*]] unwind label [[EHCLEANUP:%.*]]
64 ; CHECK:       ehcleanup:
65 ; CHECK-NEXT:    [[TMP0:%.*]] = cleanuppad within none []
66 ; CHECK-NEXT:    call void @"\01??1S2@@QEAA@XZ"(%struct.S2* [[B]])
67 ; CHECK-NEXT:    cleanupret from [[TMP0]] unwind label [[CATCH_DISPATCH:%.*]]
68 ; CHECK:       catch.dispatch:
69 ; CHECK-NEXT:    [[CS1:%.*]] = catchswitch within none [label %catch] unwind to caller
70 ; CHECK:       catch:
71 ; CHECK-NEXT:    [[TMP1:%.*]] = catchpad within [[CS1]] [i8* null, i32 64, i8* null]
72 ; CHECK-NEXT:    catchret from [[TMP1]] to label [[TRY_CONT]]
73 ; CHECK:       try.cont:
74 ; CHECK-NEXT:    ret void
76 entry:
77   %b = alloca %struct.S2, align 1
78   invoke void @g() to label %invoke.cont unwind label %ehcleanup
80 invoke.cont:                                      ; preds = %entry
81   br label %try.cont
83 ehcleanup:                                        ; preds = %entry
84   %0 = cleanuppad within none []
85   call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %b)
86   cleanupret from %0 unwind label %catch.dispatch
88 catch.dispatch:                                   ; preds = %ehcleanup
89   %cs1 = catchswitch within none [label %catch] unwind label %ehcleanup.1
91 catch:                                            ; preds = %catch.dispatch
92   %1 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
93   catchret from %1 to label %catchret.dest
95 catchret.dest:                                    ; preds = %catch
96   br label %try.cont
98 try.cont:                                         ; preds = %catchret.dest, %invoke.cont
99   ret void
101 ehcleanup.1:
102   %2 = cleanuppad within none []
103   cleanupret from %2 unwind to caller
107 ; This case arises when an object with a non-empty destructor must be cleaned up
108 ; outside of a try-block and an object with an empty destructor must be cleaned
109 ; within the try-block.
111 ; void f3() {
112 ;   S2 a;
113 ;   try {
114 ;     S b;
115 ;     g();
116 ;   } catch (...) {}
117 ; }
119 ; In this case the inner cleanup pad should be eliminated and the invoke of g()
120 ; should unwind directly to the catchpad.
122 define void @f3() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
123 ; CHECK-LABEL: @f3(
124 ; CHECK-NEXT:  entry:
125 ; CHECK-NEXT:    [[A:%.*]] = alloca [[STRUCT_S2:%.*]], align 1
126 ; CHECK-NEXT:    invoke void @g()
127 ; CHECK-NEXT:    to label [[TRY_CONT:%.*]] unwind label [[CATCH_DISPATCH:%.*]]
128 ; CHECK:       catch.dispatch:
129 ; CHECK-NEXT:    [[CS1:%.*]] = catchswitch within none [label %catch] unwind label [[EHCLEANUP_1:%.*]]
130 ; CHECK:       catch:
131 ; CHECK-NEXT:    [[CP2:%.*]] = catchpad within [[CS1]] [i8* null, i32 64, i8* null]
132 ; CHECK-NEXT:    catchret from [[CP2]] to label [[TRY_CONT]]
133 ; CHECK:       try.cont:
134 ; CHECK-NEXT:    ret void
135 ; CHECK:       ehcleanup.1:
136 ; CHECK-NEXT:    [[CP3:%.*]] = cleanuppad within none []
137 ; CHECK-NEXT:    call void @"\01??1S2@@QEAA@XZ"(%struct.S2* [[A]])
138 ; CHECK-NEXT:    cleanupret from [[CP3]] unwind to caller
140 entry:
141   %a = alloca %struct.S2, align 1
142   invoke void @g() to label %invoke.cont unwind label %ehcleanup
144 invoke.cont:                                      ; preds = %entry
145   br label %try.cont
147 ehcleanup:                                        ; preds = %entry
148   %0 = cleanuppad within none []
149   cleanupret from %0 unwind label %catch.dispatch
151 catch.dispatch:                                   ; preds = %ehcleanup
152   %cs1 = catchswitch within none [label %catch] unwind label %ehcleanup.1
154 catch:                                            ; preds = %catch.dispatch
155   %cp2 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
156   catchret from %cp2 to label %catchret.dest
158 catchret.dest:                                    ; preds = %catch
159   br label %try.cont
161 try.cont:                                         ; preds = %catchret.dest, %invoke.cont
162   ret void
164 ehcleanup.1:
165   %cp3 = cleanuppad within none []
166   call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %a)
167   cleanupret from %cp3 unwind to caller
171 ; This case arises when an object with an empty destructor may require cleanup
172 ; from either inside or outside of a try-block.
174 ; void f4() {
175 ;   S a;
176 ;   g();
177 ;   try {
178 ;     g();
179 ;   } catch (...) {}
180 ; }
182 ; In this case, the cleanuppad should be eliminated, the invoke outside of the
183 ; catch block should be converted to a call (that is, that is, exception
184 ; handling continues with the parent frame of the caller).)
186 ; Note: The cleanuppad simplification will insert an unconditional branch here
187 ;       but it will be eliminated, placing the following invoke in the entry BB.
189 define void @f4() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
190 ; CHECK-LABEL: @f4(
191 ; CHECK-NEXT:  entry:
192 ; CHECK-NEXT:    call void @g()
193 ; CHECK-NEXT:    invoke void @g()
194 ; CHECK-NEXT:    to label [[TRY_CONT:%.*]] unwind label [[CATCH_DISPATCH:%.*]]
195 ; CHECK:       catch.dispatch:
196 ; CHECK-NEXT:    [[CS1:%.*]] = catchswitch within none [label %catch] unwind to caller
197 ; CHECK:       catch:
198 ; CHECK-NEXT:    [[TMP0:%.*]] = catchpad within [[CS1]] [i8* null, i32 64, i8* null]
199 ; CHECK-NEXT:    catchret from [[TMP0]] to label [[TRY_CONT]]
200 ; CHECK:       try.cont:
201 ; CHECK-NEXT:    ret void
203 entry:
204   invoke void @g()
205   to label %invoke.cont unwind label %ehcleanup
207 invoke.cont:                                      ; preds = %entry
208   invoke void @g()
209   to label %try.cont unwind label %catch.dispatch
211 catch.dispatch:                                   ; preds = %invoke.cont
212   %cs1 = catchswitch within none [label %catch] unwind label %ehcleanup
214 catch:                                            ; preds = %catch.dispatch
215   %0 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
216   catchret from %0 to label %try.cont
218 try.cont:                                         ; preds = %catch, %invoke.cont
219   ret void
221 ehcleanup:
222   %cp2 = cleanuppad within none []
223   cleanupret from %cp2 unwind to caller
226 ; This case tests simplification of an otherwise empty cleanup pad that contains
227 ; a PHI node.
229 ; int f6() {
230 ;   int state = 1;
231 ;   try {
232 ;     S a;
233 ;     g();
234 ;     state = 2;
235 ;     g();
236 ;   } catch (...) {
237 ;     return state;
238 ;   }
239 ;   return 0;
240 ; }
242 ; In this case, the cleanup pad should be eliminated and the PHI node in the
243 ; cleanup pad should be sunk into the catch dispatch block.
245 define i32 @f6() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
246 ; CHECK-LABEL: @f6(
247 ; CHECK-NEXT:  entry:
248 ; CHECK-NEXT:    invoke void @g()
249 ; CHECK-NEXT:    to label [[INVOKE_CONT:%.*]] unwind label [[CATCH_DISPATCH:%.*]]
250 ; CHECK:       invoke.cont:
251 ; CHECK-NEXT:    invoke void @g()
252 ; CHECK-NEXT:    to label [[RETURN:%.*]] unwind label [[CATCH_DISPATCH]]
253 ; CHECK:       catch.dispatch:
254 ; CHECK-NEXT:    [[STATE_0:%.*]] = phi i32 [ 2, [[INVOKE_CONT]] ], [ 1, [[ENTRY:%.*]] ]
255 ; CHECK-NEXT:    [[CS1:%.*]] = catchswitch within none [label %catch] unwind to caller
256 ; CHECK:       catch:
257 ; CHECK-NEXT:    [[TMP0:%.*]] = catchpad within [[CS1]] [i8* null, i32 64, i8* null]
258 ; CHECK-NEXT:    catchret from [[TMP0]] to label [[RETURN]]
259 ; CHECK:       return:
260 ; CHECK-NEXT:    [[RETVAL_0:%.*]] = phi i32 [ [[STATE_0]], [[CATCH:%.*]] ], [ 0, [[INVOKE_CONT]] ]
261 ; CHECK-NEXT:    ret i32 [[RETVAL_0]]
263 entry:
264   invoke void @g()
265   to label %invoke.cont unwind label %ehcleanup
267 invoke.cont:                                      ; preds = %entry
268   invoke void @g()
269   to label %return unwind label %ehcleanup
271 ehcleanup:                                        ; preds = %invoke.cont, %entry
272   %state.0 = phi i32 [ 2, %invoke.cont ], [ 1, %entry ]
273   %0 = cleanuppad within none []
274   cleanupret from %0 unwind label %catch.dispatch
276 catch.dispatch:                                   ; preds = %ehcleanup
277   %cs1 = catchswitch within none [label %catch] unwind to caller
279 catch:                                            ; preds = %catch.dispatch
280   %1 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
281   catchret from %1 to label %return
283 return:                                           ; preds = %invoke.cont, %catch
284   %retval.0 = phi i32 [ %state.0, %catch ], [ 0, %invoke.cont ]
285   ret i32 %retval.0
288 ; This case tests another variation of simplification of an otherwise empty
289 ; cleanup pad that contains a PHI node.
291 ; int f7() {
292 ;   int state = 1;
293 ;   try {
294 ;     g();
295 ;     state = 2;
296 ;     S a;
297 ;     g();
298 ;     state = 3;
299 ;     g();
300 ;   } catch (...) {
301 ;     return state;
302 ;   }
303 ;   return 0;
304 ; }
306 ; In this case, the cleanup pad should be eliminated and the PHI node in the
307 ; cleanup pad should be merged with the PHI node in the catch dispatch block.
309 define i32 @f7() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
310 ; CHECK-LABEL: @f7(
311 ; CHECK-NEXT:  entry:
312 ; CHECK-NEXT:    invoke void @g()
313 ; CHECK-NEXT:    to label [[INVOKE_CONT:%.*]] unwind label [[CATCH_DISPATCH:%.*]]
314 ; CHECK:       invoke.cont:
315 ; CHECK-NEXT:    invoke void @g()
316 ; CHECK-NEXT:    to label [[INVOKE_CONT_1:%.*]] unwind label [[CATCH_DISPATCH]]
317 ; CHECK:       invoke.cont.1:
318 ; CHECK-NEXT:    invoke void @g()
319 ; CHECK-NEXT:    to label [[RETURN:%.*]] unwind label [[CATCH_DISPATCH]]
320 ; CHECK:       catch.dispatch:
321 ; CHECK-NEXT:    [[STATE_1:%.*]] = phi i32 [ 1, [[ENTRY:%.*]] ], [ 3, [[INVOKE_CONT_1]] ], [ 2, [[INVOKE_CONT]] ]
322 ; CHECK-NEXT:    [[CS1:%.*]] = catchswitch within none [label %catch] unwind to caller
323 ; CHECK:       catch:
324 ; CHECK-NEXT:    [[TMP0:%.*]] = catchpad within [[CS1]] [i8* null, i32 64, i8* null]
325 ; CHECK-NEXT:    catchret from [[TMP0]] to label [[RETURN]]
326 ; CHECK:       return:
327 ; CHECK-NEXT:    [[RETVAL_0:%.*]] = phi i32 [ [[STATE_1]], [[CATCH:%.*]] ], [ 0, [[INVOKE_CONT_1]] ]
328 ; CHECK-NEXT:    ret i32 [[RETVAL_0]]
330 entry:
331   invoke void @g()
332   to label %invoke.cont unwind label %catch.dispatch
334 invoke.cont:                                      ; preds = %entry
335   invoke void @g()
336   to label %invoke.cont.1 unwind label %ehcleanup
338 invoke.cont.1:                                    ; preds = %invoke.cont
339   invoke void @g()
340   to label %return unwind label %ehcleanup
342 ehcleanup:                                        ; preds = %invoke.cont.1, %invoke.cont
343   %state.0 = phi i32 [ 3, %invoke.cont.1 ], [ 2, %invoke.cont ]
344   %0 = cleanuppad within none []
345   cleanupret from %0 unwind label %catch.dispatch
347 catch.dispatch:                                   ; preds = %ehcleanup, %entry
348   %state.1 = phi i32 [ %state.0, %ehcleanup ], [ 1, %entry ]
349   %cs1 = catchswitch within none [label %catch] unwind to caller
351 catch:                                            ; preds = %catch.dispatch
352   %1 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
353   catchret from %1 to label %return
355 return:                                           ; preds = %invoke.cont.1, %catch
356   %retval.0 = phi i32 [ %state.1, %catch ], [ 0, %invoke.cont.1 ]
357   ret i32 %retval.0
360 ; This case tests a scenario where an empty cleanup pad is not dominated by all
361 ; of the predecessors of its successor, but the successor references a PHI node
362 ; in the empty cleanup pad.
364 ; Conceptually, the case being modeled is something like this:
366 ; int f8() {
367 ;   int x = 1;
368 ;   try {
369 ;     S a;
370 ;     g();
371 ;     x = 2;
372 ; retry:
373 ;     g();
374 ;     return
375 ;   } catch (...) {
376 ;     use_x(x);
377 ;   }
378 ;   goto retry;
379 ; }
381 ; While that C++ syntax isn't legal, the IR below is.
383 ; In this case, the PHI node that is sunk from ehcleanup to catch.dispatch
384 ; should have an incoming value entry for path from 'foo' that references the
385 ; PHI node itself.
387 define void @f8() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
388 ; CHECK-LABEL: @f8(
389 ; CHECK-NEXT:  entry:
390 ; CHECK-NEXT:    invoke void @g()
391 ; CHECK-NEXT:    to label [[INVOKE_CONT:%.*]] unwind label [[CATCH_DISPATCH:%.*]]
392 ; CHECK:       invoke.cont:
393 ; CHECK-NEXT:    invoke void @g()
394 ; CHECK-NEXT:    to label [[RETURN:%.*]] unwind label [[CATCH_DISPATCH]]
395 ; CHECK:       catch.dispatch:
396 ; CHECK-NEXT:    [[X:%.*]] = phi i32 [ 2, [[INVOKE_CONT]] ], [ 1, [[ENTRY:%.*]] ], [ [[X]], [[CATCH_CONT:%.*]] ]
397 ; CHECK-NEXT:    [[CS1:%.*]] = catchswitch within none [label %catch] unwind to caller
398 ; CHECK:       catch:
399 ; CHECK-NEXT:    [[TMP0:%.*]] = catchpad within [[CS1]] [i8* null, i32 64, i8* null]
400 ; CHECK-NEXT:    call void @use_x(i32 [[X]])
401 ; CHECK-NEXT:    catchret from [[TMP0]] to label [[CATCH_CONT]]
402 ; CHECK:       catch.cont:
403 ; CHECK-NEXT:    invoke void @g()
404 ; CHECK-NEXT:    to label [[RETURN]] unwind label [[CATCH_DISPATCH]]
405 ; CHECK:       return:
406 ; CHECK-NEXT:    ret void
408 entry:
409   invoke void @g()
410   to label %invoke.cont unwind label %ehcleanup
412 invoke.cont:                                      ; preds = %entry
413   invoke void @g()
414   to label %return unwind label %ehcleanup
416 ehcleanup:                                        ; preds = %invoke.cont, %entry
417   %x = phi i32 [ 2, %invoke.cont ], [ 1, %entry ]
418   %0 = cleanuppad within none []
419   cleanupret from %0 unwind label %catch.dispatch
421 catch.dispatch:                                   ; preds = %ehcleanup, %catch.cont
422   %cs1 = catchswitch within none [label %catch] unwind to caller
424 catch:                                            ; preds = %catch.dispatch
425   %1 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
426   call void @use_x(i32 %x)
427   catchret from %1 to label %catch.cont
429 catch.cont:                                       ; preds = %catch
430   invoke void @g()
431   to label %return unwind label %catch.dispatch
433 return:                                           ; preds = %invoke.cont, %catch.cont
434   ret void
436 define i32 @f9() personality i32 (...)* @__CxxFrameHandler3 {
437 ; CHECK-LABEL: @f9(
438 ; CHECK-NEXT:  entry:
439 ; CHECK-NEXT:    [[S:%.*]] = alloca i8, align 1
440 ; CHECK-NEXT:    call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[S]])
441 ; CHECK-NEXT:    [[BC:%.*]] = bitcast i8* [[S]] to %struct.S2*
442 ; CHECK-NEXT:    invoke void @"\01??1S2@@QEAA@XZ"(%struct.S2* [[BC]])
443 ; CHECK-NEXT:    to label [[TRY_CONT:%.*]] unwind label [[CATCH_DISPATCH:%.*]]
444 ; CHECK:       catch.dispatch:
445 ; CHECK-NEXT:    [[CATCH_SWITCH:%.*]] = catchswitch within none [label %catch] unwind to caller
446 ; CHECK:       catch:
447 ; CHECK-NEXT:    [[CATCH_PAD:%.*]] = catchpad within [[CATCH_SWITCH]] [i8* null, i32 0, i8* null]
448 ; CHECK-NEXT:    catchret from [[CATCH_PAD]] to label [[TRY_CONT]]
449 ; CHECK:       try.cont:
450 ; CHECK-NEXT:    ret i32 0
452 entry:
453   %s = alloca i8, align 1
454   call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull %s)
455   %bc = bitcast i8* %s to %struct.S2*
456   invoke void @"\01??1S2@@QEAA@XZ"(%struct.S2* %bc)
457   to label %try.cont unwind label %ehcleanup
459 ehcleanup:
460   %cleanup.pad = cleanuppad within none []
461   call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull %s)
462   cleanupret from %cleanup.pad unwind label %catch.dispatch
464 catch.dispatch:
465   %catch.switch = catchswitch within none [label %catch] unwind to caller
467 catch:
468   %catch.pad = catchpad within %catch.switch [i8* null, i32 0, i8* null]
469   catchret from %catch.pad to label %try.cont
471 try.cont:
472   ret i32 0
475 define void @f10(i32 %V) personality i32 (...)* @__CxxFrameHandler3 {
476 ; CHECK-LABEL: @f10(
477 ; CHECK-NEXT:  entry:
478 ; CHECK-NEXT:    call void @g()
479 ; CHECK-NEXT:    unreachable
481 entry:
482   invoke void @g()
483   to label %unreachable unwind label %cleanup
485 unreachable:
486   unreachable
488 cleanup:
489   %cp = cleanuppad within none []
490   switch i32 %V, label %cleanupret1 [
491   i32 0, label %cleanupret2
492   ]
494 cleanupret1:
495   cleanupret from %cp unwind to caller
497 cleanupret2:
498   cleanupret from %cp unwind to caller
501 ;   This case tests the handling of an empty cleanup pad that
502 ;   contains a lifetime_end intrinsic and does not dominate its
503 ;   successor.
504 define void @f11() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
505 ; CHECK-LABEL: @f11(
506 ; CHECK-NEXT:  entry:
507 ; CHECK-NEXT:    invoke void @g()
508 ; CHECK-NEXT:    to label [[INVOKE_CONT:%.*]] unwind label [[CATCH_DISPATCH:%.*]]
509 ; CHECK:       invoke.cont:
510 ; CHECK-NEXT:    invoke void @g()
511 ; CHECK-NEXT:    to label [[INVOKE_CONT2:%.*]] unwind label [[CATCH_DISPATCH]]
512 ; CHECK:       invoke.cont2:
513 ; CHECK-NEXT:    invoke void @g()
514 ; CHECK-NEXT:    to label [[RETURN:%.*]] unwind label [[CATCH_DISPATCH]]
515 ; CHECK:       catch.dispatch:
516 ; CHECK-NEXT:    [[CS1:%.*]] = catchswitch within none [label %catch] unwind to caller
517 ; CHECK:       catch:
518 ; CHECK-NEXT:    [[TMP0:%.*]] = catchpad within [[CS1]] [i8* null, i32 64, i8* null]
519 ; CHECK-NEXT:    catchret from [[TMP0]] to label [[RETURN]]
520 ; CHECK:       return:
521 ; CHECK-NEXT:    ret void
523 entry:
524   invoke void @g()
525   to label %invoke.cont unwind label %ehcleanup
527 invoke.cont:                                      ; preds = %entry
528   invoke void @g()
529   to label %invoke.cont2 unwind label %ehcleanup
531 invoke.cont2:                                     ; preds = %invoke.cont
532   invoke void @g()
533   to label %return unwind label %catch.dispatch
535 ehcleanup:                                        ; preds = %invoke.cont, %entry
536   %x = phi i8* [ undef, %invoke.cont ], [ undef, %entry ]
537   %0 = cleanuppad within none []
538   call void @llvm.lifetime.end.p0i8(i64 16, i8* nonnull %x)
539   cleanupret from %0 unwind label %catch.dispatch
541 catch.dispatch:                                   ; preds = %ehcleanup, %invoke.cont
542   %cs1 = catchswitch within none [label %catch] unwind to caller
544 catch:                                            ; preds = %catch.dispatch
545   %1 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
546   catchret from %1 to label %return
548 return:                                           ; preds = %invoke.cont, %catch.cont
549   ret void
552 %struct.S = type { i8 }
553 %struct.S2 = type { i8 }
554 declare void @"\01??1S2@@QEAA@XZ"(%struct.S2*)
555 declare void @g()
556 declare void @use_x(i32 %x)
558 declare i32 @__CxxFrameHandler3(...)
560 declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture)
561 declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture)