blob: 0ba29043912f7e5f45189a8d999ccd02953a1245 [file] [log] [blame]
Andrew Kaylora89baa22015-09-04 23:47:34 +00001; RUN: opt < %s -simplifycfg -S | FileCheck %s
Andrew Kaylor50e4e862015-09-04 23:39:40 +00002
3; ModuleID = 'cppeh-simplify.cpp'
4target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
5target triple = "x86_64-pc-windows-msvc18.0.0"
6
7
8; This case arises when two objects with empty destructors are cleaned up.
9;
10; void f1() {
11; S a;
12; S b;
13; g();
14; }
15;
16; In this case, both cleanup pads can be eliminated and the invoke can be
17; converted to a call.
18;
19; CHECK: define void @f1()
20; CHECK: entry:
21; CHECK: call void @g()
22; CHECK: ret void
23; CHECK-NOT: cleanuppad
24; CHECK: }
25;
26define void @f1() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
27entry:
28 invoke void @g() to label %invoke.cont unwind label %ehcleanup
29
30invoke.cont: ; preds = %entry
31 ret void
32
33ehcleanup: ; preds = %entry
David Majnemer8a1c45d2015-12-12 05:38:55 +000034 %0 = cleanuppad within none []
35 cleanupret from %0 unwind label %ehcleanup.1
Andrew Kaylor50e4e862015-09-04 23:39:40 +000036
37ehcleanup.1: ; preds = %ehcleanup
David Majnemer8a1c45d2015-12-12 05:38:55 +000038 %1 = cleanuppad within none []
39 cleanupret from %1 unwind to caller
Andrew Kaylor50e4e862015-09-04 23:39:40 +000040}
41
42
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.
46;
47; void f2() {
48; S a;
49; try {
50; S2 b;
51; g();
52; } catch (...) {}
53; }
54;
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).
58;
59; CHECK: define void @f2()
60; CHECK: entry:
61; CHECK: invoke void @g()
62; CHECK: ehcleanup:
David Majnemer8a1c45d2015-12-12 05:38:55 +000063; CHECK: cleanuppad within none
Andrew Kaylor50e4e862015-09-04 23:39:40 +000064; CHECK: call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %b)
David Majnemer8a1c45d2015-12-12 05:38:55 +000065; CHECK: cleanupret from %0 unwind label %catch.dispatch
Andrew Kaylor50e4e862015-09-04 23:39:40 +000066; CHECK: catch.dispatch:
David Majnemer8a1c45d2015-12-12 05:38:55 +000067; CHECK: catchswitch within none [label %catch] unwind to caller
Andrew Kaylor50e4e862015-09-04 23:39:40 +000068; CHECK: catch:
David Majnemer8a1c45d2015-12-12 05:38:55 +000069; CHECK: catchpad
Andrew Kaylor50e4e862015-09-04 23:39:40 +000070; CHECK: catchret
Andrew Kaylor50e4e862015-09-04 23:39:40 +000071; CHECK-NOT: cleanuppad
72; CHECK: }
73;
74define void @f2() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
75entry:
76 %b = alloca %struct.S2, align 1
77 invoke void @g() to label %invoke.cont unwind label %ehcleanup
78
79invoke.cont: ; preds = %entry
80 br label %try.cont
81
82ehcleanup: ; preds = %entry
David Majnemer8a1c45d2015-12-12 05:38:55 +000083 %0 = cleanuppad within none []
Andrew Kaylor50e4e862015-09-04 23:39:40 +000084 call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %b)
David Majnemer8a1c45d2015-12-12 05:38:55 +000085 cleanupret from %0 unwind label %catch.dispatch
Andrew Kaylor50e4e862015-09-04 23:39:40 +000086
87catch.dispatch: ; preds = %ehcleanup
David Majnemer8a1c45d2015-12-12 05:38:55 +000088 %cs1 = catchswitch within none [label %catch] unwind label %ehcleanup.1
Andrew Kaylor50e4e862015-09-04 23:39:40 +000089
90catch: ; preds = %catch.dispatch
David Majnemer8a1c45d2015-12-12 05:38:55 +000091 %1 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
92 catchret from %1 to label %catchret.dest
Andrew Kaylor50e4e862015-09-04 23:39:40 +000093
94catchret.dest: ; preds = %catch
95 br label %try.cont
96
97try.cont: ; preds = %catchret.dest, %invoke.cont
98 ret void
99
David Majnemer8a1c45d2015-12-12 05:38:55 +0000100ehcleanup.1:
101 %2 = cleanuppad within none []
102 cleanupret from %2 unwind to caller
Andrew Kaylor50e4e862015-09-04 23:39:40 +0000103}
104
105
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.
109;
110; void f3() {
111; S2 a;
112; try {
113; S b;
114; g();
115; } catch (...) {}
116; }
117;
118; In this case the inner cleanup pad should be eliminated and the invoke of g()
119; should unwind directly to the catchpad.
120;
David Majnemer8a1c45d2015-12-12 05:38:55 +0000121; CHECK-LABEL: define void @f3()
Andrew Kaylor50e4e862015-09-04 23:39:40 +0000122; CHECK: entry:
123; CHECK: invoke void @g()
124; CHECK: to label %try.cont unwind label %catch.dispatch
125; CHECK: catch.dispatch:
David Majnemer8a1c45d2015-12-12 05:38:55 +0000126; CHECK-NEXT: catchswitch within none [label %catch] unwind label %ehcleanup.1
Andrew Kaylor50e4e862015-09-04 23:39:40 +0000127; CHECK: catch:
David Majnemer8a1c45d2015-12-12 05:38:55 +0000128; CHECK: catchpad within %cs1 [i8* null, i32 64, i8* null]
Andrew Kaylor50e4e862015-09-04 23:39:40 +0000129; CHECK: catchret
Andrew Kaylor50e4e862015-09-04 23:39:40 +0000130; CHECK: ehcleanup.1:
131; CHECK: cleanuppad
132; CHECK: call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %a)
David Majnemer8a1c45d2015-12-12 05:38:55 +0000133; CHECK: cleanupret from %cp3 unwind to caller
Andrew Kaylor50e4e862015-09-04 23:39:40 +0000134; CHECK: }
135;
136define void @f3() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
137entry:
138 %a = alloca %struct.S2, align 1
139 invoke void @g() to label %invoke.cont unwind label %ehcleanup
140
141invoke.cont: ; preds = %entry
142 br label %try.cont
143
144ehcleanup: ; preds = %entry
David Majnemer8a1c45d2015-12-12 05:38:55 +0000145 %0 = cleanuppad within none []
146 cleanupret from %0 unwind label %catch.dispatch
Andrew Kaylor50e4e862015-09-04 23:39:40 +0000147
148catch.dispatch: ; preds = %ehcleanup
David Majnemer8a1c45d2015-12-12 05:38:55 +0000149 %cs1 = catchswitch within none [label %catch] unwind label %ehcleanup.1
Andrew Kaylor50e4e862015-09-04 23:39:40 +0000150
151catch: ; preds = %catch.dispatch
David Majnemer8a1c45d2015-12-12 05:38:55 +0000152 %cp2 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
153 catchret from %cp2 to label %catchret.dest
Andrew Kaylor50e4e862015-09-04 23:39:40 +0000154
155catchret.dest: ; preds = %catch
156 br label %try.cont
157
158try.cont: ; preds = %catchret.dest, %invoke.cont
159 ret void
160
David Majnemer8a1c45d2015-12-12 05:38:55 +0000161ehcleanup.1:
162 %cp3 = cleanuppad within none []
Andrew Kaylor50e4e862015-09-04 23:39:40 +0000163 call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %a)
David Majnemer8a1c45d2015-12-12 05:38:55 +0000164 cleanupret from %cp3 unwind to caller
Andrew Kaylor50e4e862015-09-04 23:39:40 +0000165}
166
167
168; This case arises when an object with an empty destructor may require cleanup
169; from either inside or outside of a try-block.
170;
171; void f4() {
172; S a;
173; g();
174; try {
175; g();
176; } catch (...) {}
177; }
178;
179; In this case, the cleanuppad should be eliminated, the invoke outside of the
David Majnemer8a1c45d2015-12-12 05:38:55 +0000180; catch block should be converted to a call (that is, that is, exception
181; handling continues with the parent frame of the caller).)
Andrew Kaylor50e4e862015-09-04 23:39:40 +0000182;
David Majnemer8a1c45d2015-12-12 05:38:55 +0000183; CHECK-LABEL: define void @f4()
Andrew Kaylor50e4e862015-09-04 23:39:40 +0000184; CHECK: entry:
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:
David Majnemer8a1c45d2015-12-12 05:38:55 +0000191; CHECK: catchswitch within none [label %catch] unwind to caller
Andrew Kaylor50e4e862015-09-04 23:39:40 +0000192; CHECK: catch:
David Majnemer8a1c45d2015-12-12 05:38:55 +0000193; CHECK: catchpad
Andrew Kaylor50e4e862015-09-04 23:39:40 +0000194; CHECK: catchret
Andrew Kaylor50e4e862015-09-04 23:39:40 +0000195; CHECK-NOT: cleanuppad
196; CHECK: }
197;
198define void @f4() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
199entry:
200 invoke void @g()
201 to label %invoke.cont unwind label %ehcleanup
202
203invoke.cont: ; preds = %entry
204 invoke void @g()
205 to label %try.cont unwind label %catch.dispatch
206
207catch.dispatch: ; preds = %invoke.cont
David Majnemer8a1c45d2015-12-12 05:38:55 +0000208 %cs1 = catchswitch within none [label %catch] unwind label %ehcleanup
Andrew Kaylor50e4e862015-09-04 23:39:40 +0000209
210catch: ; preds = %catch.dispatch
David Majnemer8a1c45d2015-12-12 05:38:55 +0000211 %0 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
212 catchret from %0 to label %try.cont
Andrew Kaylor50e4e862015-09-04 23:39:40 +0000213
214try.cont: ; preds = %catch, %invoke.cont
215 ret void
216
David Majnemer8a1c45d2015-12-12 05:38:55 +0000217ehcleanup:
218 %cp2 = cleanuppad within none []
219 cleanupret from %cp2 unwind to caller
Andrew Kaylor50e4e862015-09-04 23:39:40 +0000220}
221
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.
225;
David Majnemer8a1c45d2015-12-12 05:38:55 +0000226; CHECK-LABEL: define void @f5()
Andrew Kaylor50e4e862015-09-04 23:39:40 +0000227; CHECK: entry:
228; CHECK: invoke void @g()
229; CHECK: to label %try.cont unwind label %terminate
230; CHECK: terminate:
David Majnemer8a1c45d2015-12-12 05:38:55 +0000231; CHECK: terminatepad within none [i7 4] unwind to caller
Andrew Kaylor50e4e862015-09-04 23:39:40 +0000232; CHECK-NOT: cleanuppad
233; CHECK: try.cont:
234; CHECK: invoke void @g()
235; CHECK: to label %try.cont.1 unwind label %terminate.1
236; CHECK: terminate.1:
David Majnemer8a1c45d2015-12-12 05:38:55 +0000237; CHECK: terminatepad within none [i7 4] unwind label %ehcleanup.2
Andrew Kaylor50e4e862015-09-04 23:39:40 +0000238; CHECK-NOT: ehcleanup.1:
239; CHECK: ehcleanup.2:
240; CHECK: [[TMP:\%.+]] = cleanuppad
241; CHECK: call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %a)
David Majnemer8a1c45d2015-12-12 05:38:55 +0000242; CHECK: cleanupret from [[TMP]] unwind to caller
Andrew Kaylor50e4e862015-09-04 23:39:40 +0000243; CHECK: }
244define void @f5() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
245entry:
246 %a = alloca %struct.S2, align 1
247 invoke void @g()
248 to label %try.cont unwind label %terminate
249
250terminate: ; preds = %entry
David Majnemer8a1c45d2015-12-12 05:38:55 +0000251 terminatepad within none [i7 4] unwind label %ehcleanup
Andrew Kaylor50e4e862015-09-04 23:39:40 +0000252
253ehcleanup: ; preds = %terminate
David Majnemer8a1c45d2015-12-12 05:38:55 +0000254 %0 = cleanuppad within none []
255 cleanupret from %0 unwind to caller
Andrew Kaylor50e4e862015-09-04 23:39:40 +0000256
257try.cont: ; preds = %entry
258 invoke void @g()
259 to label %try.cont.1 unwind label %terminate.1
260
261terminate.1: ; preds = %try.cont
David Majnemer8a1c45d2015-12-12 05:38:55 +0000262 terminatepad within none [i7 4] unwind label %ehcleanup.1
Andrew Kaylor50e4e862015-09-04 23:39:40 +0000263
264ehcleanup.1: ; preds = %terminate.1
David Majnemer8a1c45d2015-12-12 05:38:55 +0000265 %1 = cleanuppad within none []
266 cleanupret from %1 unwind label %ehcleanup.2
Andrew Kaylor50e4e862015-09-04 23:39:40 +0000267
268ehcleanup.2: ; preds = %ehcleanup.1
David Majnemer8a1c45d2015-12-12 05:38:55 +0000269 %2 = cleanuppad within none []
Andrew Kaylor50e4e862015-09-04 23:39:40 +0000270 call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %a)
David Majnemer8a1c45d2015-12-12 05:38:55 +0000271 cleanupret from %2 unwind to caller
Andrew Kaylor50e4e862015-09-04 23:39:40 +0000272
273try.cont.1: ; preds = %try.cont
274 ret void
275}
276
277; This case tests simplification of an otherwise empty cleanup pad that contains
278; a PHI node.
279;
280; int f6() {
281; int state = 1;
282; try {
283; S a;
284; g();
285; state = 2;
286; g();
287; } catch (...) {
288; return state;
289; }
290; return 0;
291; }
292;
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.
295;
David Majnemer8a1c45d2015-12-12 05:38:55 +0000296; CHECK-LABEL: define i32 @f6()
Andrew Kaylor50e4e862015-09-04 23:39:40 +0000297; CHECK: entry:
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 ]
305; CHECK: }
306define i32 @f6() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
307entry:
308 invoke void @g()
309 to label %invoke.cont unwind label %ehcleanup
310
311invoke.cont: ; preds = %entry
312 invoke void @g()
313 to label %return unwind label %ehcleanup
314
315ehcleanup: ; preds = %invoke.cont, %entry
316 %state.0 = phi i32 [ 2, %invoke.cont ], [ 1, %entry ]
David Majnemer8a1c45d2015-12-12 05:38:55 +0000317 %0 = cleanuppad within none []
318 cleanupret from %0 unwind label %catch.dispatch
Andrew Kaylor50e4e862015-09-04 23:39:40 +0000319
320catch.dispatch: ; preds = %ehcleanup
David Majnemer8a1c45d2015-12-12 05:38:55 +0000321 %cs1 = catchswitch within none [label %catch] unwind to caller
Andrew Kaylor50e4e862015-09-04 23:39:40 +0000322
323catch: ; preds = %catch.dispatch
David Majnemer8a1c45d2015-12-12 05:38:55 +0000324 %1 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
325 catchret from %1 to label %return
Andrew Kaylor50e4e862015-09-04 23:39:40 +0000326
327return: ; preds = %invoke.cont, %catch
328 %retval.0 = phi i32 [ %state.0, %catch ], [ 0, %invoke.cont ]
329 ret i32 %retval.0
330}
331
332; This case tests another variation of simplification of an otherwise empty
333; cleanup pad that contains a PHI node.
334;
335; int f7() {
336; int state = 1;
337; try {
338; g();
339; state = 2;
340; S a;
341; g();
342; state = 3;
343; g();
344; } catch (...) {
345; return state;
346; }
347; return 0;
348; }
349;
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.
352;
David Majnemer8a1c45d2015-12-12 05:38:55 +0000353; CHECK-LABEL: define i32 @f7()
Andrew Kaylor50e4e862015-09-04 23:39:40 +0000354; CHECK: entry:
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 ]
364; CHECK: }
365define i32 @f7() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
366entry:
367 invoke void @g()
368 to label %invoke.cont unwind label %catch.dispatch
369
370invoke.cont: ; preds = %entry
371 invoke void @g()
372 to label %invoke.cont.1 unwind label %ehcleanup
373
374invoke.cont.1: ; preds = %invoke.cont
375 invoke void @g()
376 to label %return unwind label %ehcleanup
377
378ehcleanup: ; preds = %invoke.cont.1, %invoke.cont
379 %state.0 = phi i32 [ 3, %invoke.cont.1 ], [ 2, %invoke.cont ]
David Majnemer8a1c45d2015-12-12 05:38:55 +0000380 %0 = cleanuppad within none []
381 cleanupret from %0 unwind label %catch.dispatch
Andrew Kaylor50e4e862015-09-04 23:39:40 +0000382
383catch.dispatch: ; preds = %ehcleanup, %entry
384 %state.1 = phi i32 [ %state.0, %ehcleanup ], [ 1, %entry ]
David Majnemer8a1c45d2015-12-12 05:38:55 +0000385 %cs1 = catchswitch within none [label %catch] unwind to caller
Andrew Kaylor50e4e862015-09-04 23:39:40 +0000386
387catch: ; preds = %catch.dispatch
David Majnemer8a1c45d2015-12-12 05:38:55 +0000388 %1 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
389 catchret from %1 to label %return
Andrew Kaylor50e4e862015-09-04 23:39:40 +0000390
391return: ; preds = %invoke.cont.1, %catch
392 %retval.0 = phi i32 [ %state.1, %catch ], [ 0, %invoke.cont.1 ]
393 ret i32 %retval.0
394}
395
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.
399;
400; Conceptually, the case being modeled is something like this:
401;
402; int f8() {
403; int x = 1;
404; try {
405; S a;
406; g();
407; x = 2;
408; retry:
409; g();
410; return
411; } catch (...) {
412; use_x(x);
413; }
414; goto retry;
415; }
416;
417; While that C++ syntax isn't legal, the IR below is.
418;
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
421; PHI node itself.
422;
David Majnemer8a1c45d2015-12-12 05:38:55 +0000423; CHECK-LABEL: define void @f8()
Andrew Kaylor50e4e862015-09-04 23:39:40 +0000424; CHECK: entry:
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 ]
432; CHECK: }
433define void @f8() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
434entry:
435 invoke void @g()
436 to label %invoke.cont unwind label %ehcleanup
437
438invoke.cont: ; preds = %entry
439 invoke void @g()
440 to label %return unwind label %ehcleanup
441
442ehcleanup: ; preds = %invoke.cont, %entry
443 %x = phi i32 [ 2, %invoke.cont ], [ 1, %entry ]
David Majnemer8a1c45d2015-12-12 05:38:55 +0000444 %0 = cleanuppad within none []
445 cleanupret from %0 unwind label %catch.dispatch
Andrew Kaylor50e4e862015-09-04 23:39:40 +0000446
447catch.dispatch: ; preds = %ehcleanup, %catch.cont
David Majnemer8a1c45d2015-12-12 05:38:55 +0000448 %cs1 = catchswitch within none [label %catch] unwind to caller
Andrew Kaylor50e4e862015-09-04 23:39:40 +0000449
450catch: ; preds = %catch.dispatch
David Majnemer8a1c45d2015-12-12 05:38:55 +0000451 %1 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
Andrew Kaylor50e4e862015-09-04 23:39:40 +0000452 call void @use_x(i32 %x)
David Majnemer8a1c45d2015-12-12 05:38:55 +0000453 catchret from %1 to label %catch.cont
Andrew Kaylor50e4e862015-09-04 23:39:40 +0000454
455catch.cont: ; preds = %catch
456 invoke void @g()
457 to label %return unwind label %catch.dispatch
458
459return: ; preds = %invoke.cont, %catch.cont
460 ret void
461}
462
463%struct.S = type { i8 }
464%struct.S2 = type { i8 }
465declare void @"\01??1S2@@QEAA@XZ"(%struct.S2*)
466declare void @g()
467declare void @use_x(i32 %x)
468
469declare i32 @__CxxFrameHandler3(...)
470