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
35 cleanupret %0 unwind label %ehcleanup.1
37 ehcleanup.1: ; preds = %ehcleanup
39 cleanupret %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()
64 ; CHECK: call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %b)
65 ; CHECK: cleanupret %0 unwind label %catch.dispatch
66 ; CHECK: catch.dispatch:
70 ; CHECK: catchendblock: ; preds = %catch.dispatch
71 ; CHECK: catchendpad unwind to caller
72 ; CHECK-NOT: cleanuppad
75 define void @f2() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
77 %b = alloca %struct.S2, align 1
78 invoke void @g() to label %invoke.cont unwind label %ehcleanup
80 invoke.cont: ; preds = %entry
83 ehcleanup: ; preds = %entry
85 call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %b)
86 cleanupret %0 unwind label %catch.dispatch
88 catch.dispatch: ; preds = %ehcleanup
89 %1 = catchpad [i8* null, i32 u0x40, i8* null] to label %catch unwind label %catchendblock
91 catch: ; preds = %catch.dispatch
92 catchret %1 to label %catchret.dest
94 catchret.dest: ; preds = %catch
97 try.cont: ; preds = %catchret.dest, %invoke.cont
100 catchendblock: ; preds = %catch.dispatch
101 catchendpad unwind label %ehcleanup.1
103 ehcleanup.1: ; preds = %catchendblock
105 cleanupret %2 unwind to caller
109 ; This case arises when an object with a non-empty destructor must be cleaned up
110 ; outside of a try-block and an object with an empty destructor must be cleaned
111 ; within the try-block.
121 ; In this case the inner cleanup pad should be eliminated and the invoke of g()
122 ; should unwind directly to the catchpad.
124 ; CHECK: define void @f3()
126 ; CHECK: invoke void @g()
127 ; CHECK: to label %try.cont unwind label %catch.dispatch
128 ; CHECK: catch.dispatch:
129 ; CHECK: catchpad [i8* null, i32 64, i8* null]
130 ; CHECK-NEXT: to label %catch unwind label %catchendblock
133 ; CHECK: catchendblock:
134 ; CHECK: catchendpad unwind label %ehcleanup.1
135 ; CHECK: ehcleanup.1:
137 ; CHECK: call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %a)
138 ; CHECK: cleanupret %1 unwind to caller
141 define void @f3() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
143 %a = alloca %struct.S2, align 1
144 invoke void @g() to label %invoke.cont unwind label %ehcleanup
146 invoke.cont: ; preds = %entry
149 ehcleanup: ; preds = %entry
151 cleanupret %0 unwind label %catch.dispatch
153 catch.dispatch: ; preds = %ehcleanup
154 %1 = catchpad [i8* null, i32 u0x40, i8* null] to label %catch unwind label %catchendblock
156 catch: ; preds = %catch.dispatch
157 catchret %1 to label %catchret.dest
159 catchret.dest: ; preds = %catch
162 try.cont: ; preds = %catchret.dest, %invoke.cont
165 catchendblock: ; preds = %catch.dispatch
166 catchendpad unwind label %ehcleanup.1
168 ehcleanup.1: ; preds = %catchendblock
170 call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %a)
171 cleanupret %2 unwind to caller
175 ; This case arises when an object with an empty destructor may require cleanup
176 ; from either inside or outside of a try-block.
186 ; In this case, the cleanuppad should be eliminated, the invoke outside of the
187 ; call block should be converted to a call and the catchendpad should unwind
188 ; to the caller (that is, that is, exception handling continues with the parent
189 ; frame of the caller).)
191 ; CHECK: define void @f4()
193 ; CHECK: call void @g
194 ; Note: The cleanuppad simplification will insert an unconditional branch here
195 ; but it will be eliminated, placing the following invoke in the entry BB.
196 ; CHECK: invoke void @g()
197 ; CHECK: to label %try.cont unwind label %catch.dispatch
198 ; CHECK: catch.dispatch:
202 ; CHECK: catchendblock:
203 ; CHECK: catchendpad unwind to caller
204 ; CHECK-NOT: cleanuppad
207 define void @f4() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
210 to label %invoke.cont unwind label %ehcleanup
212 invoke.cont: ; preds = %entry
214 to label %try.cont unwind label %catch.dispatch
216 catch.dispatch: ; preds = %invoke.cont
217 %0 = catchpad [i8* null, i32 u0x40, i8* null] to label %catch unwind label %catchendblock
219 catch: ; preds = %catch.dispatch
220 catchret %0 to label %try.cont
222 try.cont: ; preds = %catch, %invoke.cont
225 catchendblock: ; preds = %catch.dispatch
226 catchendpad unwind label %ehcleanup
228 ehcleanup: ; preds = %catchendblock, %entry
230 cleanupret %1 unwind to caller
233 ; This tests the case where a terminatepad unwinds to a cleanuppad.
234 ; I'm not sure how this case would arise, but it seems to be syntactically
235 ; legal so I'm testing it.
237 ; CHECK: define void @f5()
239 ; CHECK: invoke void @g()
240 ; CHECK: to label %try.cont unwind label %terminate
242 ; CHECK: terminatepad [i7 4] unwind to caller
243 ; CHECK-NOT: cleanuppad
245 ; CHECK: invoke void @g()
246 ; CHECK: to label %try.cont.1 unwind label %terminate.1
247 ; CHECK: terminate.1:
248 ; CHECK: terminatepad [i7 4] unwind label %ehcleanup.2
249 ; CHECK-NOT: ehcleanup.1:
250 ; CHECK: ehcleanup.2:
251 ; CHECK: [[TMP:\%.+]] = cleanuppad
252 ; CHECK: call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %a)
253 ; CHECK: cleanupret [[TMP]] unwind to caller
255 define void @f5() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
257 %a = alloca %struct.S2, align 1
259 to label %try.cont unwind label %terminate
261 terminate: ; preds = %entry
262 terminatepad [i7 4] unwind label %ehcleanup
264 ehcleanup: ; preds = %terminate
266 cleanupret %0 unwind to caller
268 try.cont: ; preds = %entry
270 to label %try.cont.1 unwind label %terminate.1
272 terminate.1: ; preds = %try.cont
273 terminatepad [i7 4] unwind label %ehcleanup.1
275 ehcleanup.1: ; preds = %terminate.1
277 cleanupret %1 unwind label %ehcleanup.2
279 ehcleanup.2: ; preds = %ehcleanup.1
281 call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %a)
282 cleanupret %2 unwind to caller
284 try.cont.1: ; preds = %try.cont
288 ; This case tests simplification of an otherwise empty cleanup pad that contains
304 ; In this case, the cleanup pad should be eliminated and the PHI node in the
305 ; cleanup pad should be sunk into the catch dispatch block.
307 ; CHECK: define i32 @f6()
309 ; CHECK: invoke void @g()
310 ; CHECK: invoke.cont:
311 ; CHECK: invoke void @g()
312 ; CHECK-NOT: ehcleanup:
313 ; CHECK-NOT: cleanuppad
314 ; CHECK: catch.dispatch:
315 ; CHECK: %state.0 = phi i32 [ 2, %invoke.cont ], [ 1, %entry ]
317 define i32 @f6() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
320 to label %invoke.cont unwind label %ehcleanup
322 invoke.cont: ; preds = %entry
324 to label %return unwind label %ehcleanup
326 ehcleanup: ; preds = %invoke.cont, %entry
327 %state.0 = phi i32 [ 2, %invoke.cont ], [ 1, %entry ]
329 cleanupret %0 unwind label %catch.dispatch
331 catch.dispatch: ; preds = %ehcleanup
332 %1 = catchpad [i8* null, i32 u0x40, i8* null] to label %catch unwind label %catchendblock
334 catch: ; preds = %catch.dispatch
335 catchret %1 to label %return
337 catchendblock: ; preds = %catch.dispatch
338 catchendpad unwind to caller
340 return: ; preds = %invoke.cont, %catch
341 %retval.0 = phi i32 [ %state.0, %catch ], [ 0, %invoke.cont ]
345 ; This case tests another variation of simplification of an otherwise empty
346 ; cleanup pad that contains a PHI node.
363 ; In this case, the cleanup pad should be eliminated and the PHI node in the
364 ; cleanup pad should be merged with the PHI node in the catch dispatch block.
366 ; CHECK: define i32 @f7()
368 ; CHECK: invoke void @g()
369 ; CHECK: invoke.cont:
370 ; CHECK: invoke void @g()
371 ; CHECK: invoke.cont.1:
372 ; CHECK: invoke void @g()
373 ; CHECK-NOT: ehcleanup:
374 ; CHECK-NOT: cleanuppad
375 ; CHECK: catch.dispatch:
376 ; CHECK: %state.1 = phi i32 [ 1, %entry ], [ 3, %invoke.cont.1 ], [ 2, %invoke.cont ]
378 define i32 @f7() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
381 to label %invoke.cont unwind label %catch.dispatch
383 invoke.cont: ; preds = %entry
385 to label %invoke.cont.1 unwind label %ehcleanup
387 invoke.cont.1: ; preds = %invoke.cont
389 to label %return unwind label %ehcleanup
391 ehcleanup: ; preds = %invoke.cont.1, %invoke.cont
392 %state.0 = phi i32 [ 3, %invoke.cont.1 ], [ 2, %invoke.cont ]
394 cleanupret %0 unwind label %catch.dispatch
396 catch.dispatch: ; preds = %ehcleanup, %entry
397 %state.1 = phi i32 [ %state.0, %ehcleanup ], [ 1, %entry ]
398 %1 = catchpad [i8* null, i32 u0x40, i8* null] to label %catch unwind label %catchendblock
400 catch: ; preds = %catch.dispatch
401 catchret %1 to label %return
403 catchendblock: ; preds = %catch.dispatch
404 catchendpad unwind to caller
406 return: ; preds = %invoke.cont.1, %catch
407 %retval.0 = phi i32 [ %state.1, %catch ], [ 0, %invoke.cont.1 ]
411 ; This case tests a scenario where an empty cleanup pad is not dominated by all
412 ; of the predecessors of its successor, but the successor references a PHI node
413 ; in the empty cleanup pad.
415 ; Conceptually, the case being modeled is something like this:
432 ; While that C++ syntax isn't legal, the IR below is.
434 ; In this case, the PHI node that is sunk from ehcleanup to catch.dispatch
435 ; should have an incoming value entry for path from 'foo' that references the
438 ; CHECK: define void @f8()
440 ; CHECK: invoke void @g()
441 ; CHECK: invoke.cont:
442 ; CHECK: invoke void @g()
443 ; CHECK-NOT: ehcleanup:
444 ; CHECK-NOT: cleanuppad
445 ; CHECK: catch.dispatch:
446 ; CHECK: %x = phi i32 [ 2, %invoke.cont ], [ 1, %entry ], [ %x, %catch.cont ]
448 define void @f8() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
451 to label %invoke.cont unwind label %ehcleanup
453 invoke.cont: ; preds = %entry
455 to label %return unwind label %ehcleanup
457 ehcleanup: ; preds = %invoke.cont, %entry
458 %x = phi i32 [ 2, %invoke.cont ], [ 1, %entry ]
460 cleanupret %0 unwind label %catch.dispatch
462 catch.dispatch: ; preds = %ehcleanup, %catch.cont
463 %1 = catchpad [i8* null, i32 u0x40, i8* null] to label %catch unwind label %catchendblock
465 catch: ; preds = %catch.dispatch
466 call void @use_x(i32 %x)
467 catchret %1 to label %catch.cont
469 catchendblock: ; preds = %catch.dispatch
470 catchendpad unwind to caller
472 catch.cont: ; preds = %catch
474 to label %return unwind label %catch.dispatch
476 return: ; preds = %invoke.cont, %catch.cont
480 %struct.S = type { i8 }
481 %struct.S2 = type { i8 }
482 declare void @"\01??1S2@@QEAA@XZ"(%struct.S2*)
484 declare void @use_x(i32 %x)
486 declare i32 @__CxxFrameHandler3(...)