1 ; RUN: opt < %s -simplifycfg -S | FileCheck %s
3 ; ModuleID = 'cppeh-simplify.cpp'
4 target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
5 target triple = "x86_64-pc-windows-msvc18.0.0"
8 ; This case arises when two objects with empty destructors are cleaned up.
16 ; In this case, both cleanup pads can be eliminated and the invoke can be
17 ; converted to a call.
19 ; CHECK: define void @f1()
21 ; CHECK: call void @g()
23 ; CHECK-NOT: cleanuppad
26 define void @f1() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
28 invoke void @g() to label %invoke.cont unwind label %ehcleanup
30 invoke.cont: ; preds = %entry
33 ehcleanup: ; preds = %entry
34 %0 = cleanuppad within none []
35 cleanupret from %0 unwind label %ehcleanup.1
37 ehcleanup.1: ; preds = %ehcleanup
38 %1 = cleanuppad within none []
39 cleanupret from %1 unwind to caller
43 ; This case arises when an object with an empty destructor must be cleaned up
44 ; outside of a try-block and an object with a non-empty destructor must be
45 ; cleaned up within the try-block.
55 ; In this case, the outermost cleanup pad can be eliminated and the catch block
56 ; should unwind to the caller (that is, exception handling continues with the
57 ; parent frame of the caller).
59 ; CHECK: define void @f2()
61 ; CHECK: invoke void @g()
63 ; CHECK: cleanuppad within none
64 ; CHECK: call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %b)
65 ; CHECK: cleanupret from %0 unwind label %catch.dispatch
66 ; CHECK: catch.dispatch:
67 ; CHECK: catchswitch within none [label %catch] unwind to caller
71 ; CHECK-NOT: cleanuppad
74 define void @f2() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
76 %b = alloca %struct.S2, align 1
77 invoke void @g() to label %invoke.cont unwind label %ehcleanup
79 invoke.cont: ; preds = %entry
82 ehcleanup: ; preds = %entry
83 %0 = cleanuppad within none []
84 call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %b)
85 cleanupret from %0 unwind label %catch.dispatch
87 catch.dispatch: ; preds = %ehcleanup
88 %cs1 = catchswitch within none [label %catch] unwind label %ehcleanup.1
90 catch: ; preds = %catch.dispatch
91 %1 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
92 catchret from %1 to label %catchret.dest
94 catchret.dest: ; preds = %catch
97 try.cont: ; preds = %catchret.dest, %invoke.cont
101 %2 = cleanuppad within none []
102 cleanupret from %2 unwind to caller
106 ; This case arises when an object with a non-empty destructor must be cleaned up
107 ; outside of a try-block and an object with an empty destructor must be cleaned
108 ; within the try-block.
118 ; In this case the inner cleanup pad should be eliminated and the invoke of g()
119 ; should unwind directly to the catchpad.
121 ; CHECK-LABEL: define void @f3()
123 ; CHECK: invoke void @g()
124 ; CHECK: to label %try.cont unwind label %catch.dispatch
125 ; CHECK: catch.dispatch:
126 ; CHECK-NEXT: catchswitch within none [label %catch] unwind label %ehcleanup.1
128 ; CHECK: catchpad within %cs1 [i8* null, i32 64, i8* null]
130 ; CHECK: ehcleanup.1:
132 ; CHECK: call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %a)
133 ; CHECK: cleanupret from %cp3 unwind to caller
136 define void @f3() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
138 %a = alloca %struct.S2, align 1
139 invoke void @g() to label %invoke.cont unwind label %ehcleanup
141 invoke.cont: ; preds = %entry
144 ehcleanup: ; preds = %entry
145 %0 = cleanuppad within none []
146 cleanupret from %0 unwind label %catch.dispatch
148 catch.dispatch: ; preds = %ehcleanup
149 %cs1 = catchswitch within none [label %catch] unwind label %ehcleanup.1
151 catch: ; preds = %catch.dispatch
152 %cp2 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
153 catchret from %cp2 to label %catchret.dest
155 catchret.dest: ; preds = %catch
158 try.cont: ; preds = %catchret.dest, %invoke.cont
162 %cp3 = cleanuppad within none []
163 call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %a)
164 cleanupret from %cp3 unwind to caller
168 ; This case arises when an object with an empty destructor may require cleanup
169 ; from either inside or outside of a try-block.
179 ; In this case, the cleanuppad should be eliminated, the invoke outside of the
180 ; catch block should be converted to a call (that is, that is, exception
181 ; handling continues with the parent frame of the caller).)
183 ; CHECK-LABEL: define void @f4()
185 ; CHECK: call void @g
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.
188 ; CHECK: invoke void @g()
189 ; CHECK: to label %try.cont unwind label %catch.dispatch
190 ; CHECK: catch.dispatch:
191 ; CHECK: catchswitch within none [label %catch] unwind to caller
195 ; CHECK-NOT: cleanuppad
198 define void @f4() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
201 to label %invoke.cont unwind label %ehcleanup
203 invoke.cont: ; preds = %entry
205 to label %try.cont unwind label %catch.dispatch
207 catch.dispatch: ; preds = %invoke.cont
208 %cs1 = catchswitch within none [label %catch] unwind label %ehcleanup
210 catch: ; preds = %catch.dispatch
211 %0 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
212 catchret from %0 to label %try.cont
214 try.cont: ; preds = %catch, %invoke.cont
218 %cp2 = cleanuppad within none []
219 cleanupret from %cp2 unwind to caller
222 ; This tests the case where a terminatepad unwinds to a cleanuppad.
223 ; I'm not sure how this case would arise, but it seems to be syntactically
224 ; legal so I'm testing it.
226 ; CHECK-LABEL: define void @f5()
228 ; CHECK: invoke void @g()
229 ; CHECK: to label %try.cont unwind label %terminate
231 ; CHECK: terminatepad within none [i7 4] unwind to caller
232 ; CHECK-NOT: cleanuppad
234 ; CHECK: invoke void @g()
235 ; CHECK: to label %try.cont.1 unwind label %terminate.1
236 ; CHECK: terminate.1:
237 ; CHECK: terminatepad within none [i7 4] unwind label %ehcleanup.2
238 ; CHECK-NOT: ehcleanup.1:
239 ; CHECK: ehcleanup.2:
240 ; CHECK: [[TMP:\%.+]] = cleanuppad
241 ; CHECK: call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %a)
242 ; CHECK: cleanupret from [[TMP]] unwind to caller
244 define void @f5() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
246 %a = alloca %struct.S2, align 1
248 to label %try.cont unwind label %terminate
250 terminate: ; preds = %entry
251 terminatepad within none [i7 4] unwind label %ehcleanup
253 ehcleanup: ; preds = %terminate
254 %0 = cleanuppad within none []
255 cleanupret from %0 unwind to caller
257 try.cont: ; preds = %entry
259 to label %try.cont.1 unwind label %terminate.1
261 terminate.1: ; preds = %try.cont
262 terminatepad within none [i7 4] unwind label %ehcleanup.1
264 ehcleanup.1: ; preds = %terminate.1
265 %1 = cleanuppad within none []
266 cleanupret from %1 unwind label %ehcleanup.2
268 ehcleanup.2: ; preds = %ehcleanup.1
269 %2 = cleanuppad within none []
270 call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %a)
271 cleanupret from %2 unwind to caller
273 try.cont.1: ; preds = %try.cont
277 ; This case tests simplification of an otherwise empty cleanup pad that contains
293 ; In this case, the cleanup pad should be eliminated and the PHI node in the
294 ; cleanup pad should be sunk into the catch dispatch block.
296 ; CHECK-LABEL: define i32 @f6()
298 ; CHECK: invoke void @g()
299 ; CHECK: invoke.cont:
300 ; CHECK: invoke void @g()
301 ; CHECK-NOT: ehcleanup:
302 ; CHECK-NOT: cleanuppad
303 ; CHECK: catch.dispatch:
304 ; CHECK: %state.0 = phi i32 [ 2, %invoke.cont ], [ 1, %entry ]
306 define i32 @f6() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
309 to label %invoke.cont unwind label %ehcleanup
311 invoke.cont: ; preds = %entry
313 to label %return unwind label %ehcleanup
315 ehcleanup: ; preds = %invoke.cont, %entry
316 %state.0 = phi i32 [ 2, %invoke.cont ], [ 1, %entry ]
317 %0 = cleanuppad within none []
318 cleanupret from %0 unwind label %catch.dispatch
320 catch.dispatch: ; preds = %ehcleanup
321 %cs1 = catchswitch within none [label %catch] unwind to caller
323 catch: ; preds = %catch.dispatch
324 %1 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
325 catchret from %1 to label %return
327 return: ; preds = %invoke.cont, %catch
328 %retval.0 = phi i32 [ %state.0, %catch ], [ 0, %invoke.cont ]
332 ; This case tests another variation of simplification of an otherwise empty
333 ; cleanup pad that contains a PHI node.
350 ; In this case, the cleanup pad should be eliminated and the PHI node in the
351 ; cleanup pad should be merged with the PHI node in the catch dispatch block.
353 ; CHECK-LABEL: define i32 @f7()
355 ; CHECK: invoke void @g()
356 ; CHECK: invoke.cont:
357 ; CHECK: invoke void @g()
358 ; CHECK: invoke.cont.1:
359 ; CHECK: invoke void @g()
360 ; CHECK-NOT: ehcleanup:
361 ; CHECK-NOT: cleanuppad
362 ; CHECK: catch.dispatch:
363 ; CHECK: %state.1 = phi i32 [ 1, %entry ], [ 3, %invoke.cont.1 ], [ 2, %invoke.cont ]
365 define i32 @f7() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
368 to label %invoke.cont unwind label %catch.dispatch
370 invoke.cont: ; preds = %entry
372 to label %invoke.cont.1 unwind label %ehcleanup
374 invoke.cont.1: ; preds = %invoke.cont
376 to label %return unwind label %ehcleanup
378 ehcleanup: ; preds = %invoke.cont.1, %invoke.cont
379 %state.0 = phi i32 [ 3, %invoke.cont.1 ], [ 2, %invoke.cont ]
380 %0 = cleanuppad within none []
381 cleanupret from %0 unwind label %catch.dispatch
383 catch.dispatch: ; preds = %ehcleanup, %entry
384 %state.1 = phi i32 [ %state.0, %ehcleanup ], [ 1, %entry ]
385 %cs1 = catchswitch within none [label %catch] unwind to caller
387 catch: ; preds = %catch.dispatch
388 %1 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
389 catchret from %1 to label %return
391 return: ; preds = %invoke.cont.1, %catch
392 %retval.0 = phi i32 [ %state.1, %catch ], [ 0, %invoke.cont.1 ]
396 ; This case tests a scenario where an empty cleanup pad is not dominated by all
397 ; of the predecessors of its successor, but the successor references a PHI node
398 ; in the empty cleanup pad.
400 ; Conceptually, the case being modeled is something like this:
417 ; While that C++ syntax isn't legal, the IR below is.
419 ; In this case, the PHI node that is sunk from ehcleanup to catch.dispatch
420 ; should have an incoming value entry for path from 'foo' that references the
423 ; CHECK-LABEL: define void @f8()
425 ; CHECK: invoke void @g()
426 ; CHECK: invoke.cont:
427 ; CHECK: invoke void @g()
428 ; CHECK-NOT: ehcleanup:
429 ; CHECK-NOT: cleanuppad
430 ; CHECK: catch.dispatch:
431 ; CHECK: %x = phi i32 [ 2, %invoke.cont ], [ 1, %entry ], [ %x, %catch.cont ]
433 define void @f8() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
436 to label %invoke.cont unwind label %ehcleanup
438 invoke.cont: ; preds = %entry
440 to label %return unwind label %ehcleanup
442 ehcleanup: ; preds = %invoke.cont, %entry
443 %x = phi i32 [ 2, %invoke.cont ], [ 1, %entry ]
444 %0 = cleanuppad within none []
445 cleanupret from %0 unwind label %catch.dispatch
447 catch.dispatch: ; preds = %ehcleanup, %catch.cont
448 %cs1 = catchswitch within none [label %catch] unwind to caller
450 catch: ; preds = %catch.dispatch
451 %1 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
452 call void @use_x(i32 %x)
453 catchret from %1 to label %catch.cont
455 catch.cont: ; preds = %catch
457 to label %return unwind label %catch.dispatch
459 return: ; preds = %invoke.cont, %catch.cont
463 %struct.S = type { i8 }
464 %struct.S2 = type { i8 }
465 declare void @"\01??1S2@@QEAA@XZ"(%struct.S2*)
467 declare void @use_x(i32 %x)
469 declare i32 @__CxxFrameHandler3(...)