blob: d04c567e5037915b2e5776b42c2a3dcc204e5666 [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
34 %0 = cleanuppad []
35 cleanupret %0 unwind label %ehcleanup.1
36
37ehcleanup.1: ; preds = %ehcleanup
38 %1 = cleanuppad []
39 cleanupret %1 unwind to caller
40}
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:
63; CHECK: cleanuppad
64; CHECK: call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %b)
65; CHECK: cleanupret %0 unwind label %catch.dispatch
66; CHECK: catch.dispatch:
67; CHECK: catchpad
68; CHECK: catch:
69; CHECK: catchret
70; CHECK: catchendblock: ; preds = %catch.dispatch
71; CHECK: catchendpad unwind to caller
72; CHECK-NOT: cleanuppad
73; CHECK: }
74;
75define void @f2() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
76entry:
77 %b = alloca %struct.S2, align 1
78 invoke void @g() to label %invoke.cont unwind label %ehcleanup
79
80invoke.cont: ; preds = %entry
81 br label %try.cont
82
83ehcleanup: ; preds = %entry
84 %0 = cleanuppad []
85 call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %b)
86 cleanupret %0 unwind label %catch.dispatch
87
88catch.dispatch: ; preds = %ehcleanup
Reid Klecknerb005d282015-09-16 20:16:27 +000089 %1 = catchpad [i8* null, i32 u0x40, i8* null] to label %catch unwind label %catchendblock
Andrew Kaylor50e4e862015-09-04 23:39:40 +000090
91catch: ; preds = %catch.dispatch
92 catchret %1 to label %catchret.dest
93
94catchret.dest: ; preds = %catch
95 br label %try.cont
96
97try.cont: ; preds = %catchret.dest, %invoke.cont
98 ret void
99
100catchendblock: ; preds = %catch.dispatch
101 catchendpad unwind label %ehcleanup.1
102
103ehcleanup.1: ; preds = %catchendblock
104 %2 = cleanuppad []
105 cleanupret %2 unwind to caller
106}
107
108
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.
112;
113; void f3() {
114; S2 a;
115; try {
116; S b;
117; g();
118; } catch (...) {}
119; }
120;
121; In this case the inner cleanup pad should be eliminated and the invoke of g()
122; should unwind directly to the catchpad.
123;
124; CHECK: define void @f3()
125; CHECK: entry:
126; CHECK: invoke void @g()
127; CHECK: to label %try.cont unwind label %catch.dispatch
128; CHECK: catch.dispatch:
Reid Klecknerb005d282015-09-16 20:16:27 +0000129; CHECK: catchpad [i8* null, i32 64, i8* null]
Reid Kleckner5dbee7b2015-09-11 17:27:52 +0000130; CHECK-NEXT: to label %catch unwind label %catchendblock
Andrew Kaylor50e4e862015-09-04 23:39:40 +0000131; CHECK: catch:
132; CHECK: catchret
133; CHECK: catchendblock:
134; CHECK: catchendpad unwind label %ehcleanup.1
135; CHECK: ehcleanup.1:
136; CHECK: cleanuppad
137; CHECK: call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %a)
138; CHECK: cleanupret %1 unwind to caller
139; CHECK: }
140;
141define void @f3() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
142entry:
143 %a = alloca %struct.S2, align 1
144 invoke void @g() to label %invoke.cont unwind label %ehcleanup
145
146invoke.cont: ; preds = %entry
147 br label %try.cont
148
149ehcleanup: ; preds = %entry
150 %0 = cleanuppad []
151 cleanupret %0 unwind label %catch.dispatch
152
153catch.dispatch: ; preds = %ehcleanup
Reid Klecknerb005d282015-09-16 20:16:27 +0000154 %1 = catchpad [i8* null, i32 u0x40, i8* null] to label %catch unwind label %catchendblock
Andrew Kaylor50e4e862015-09-04 23:39:40 +0000155
156catch: ; preds = %catch.dispatch
157 catchret %1 to label %catchret.dest
158
159catchret.dest: ; preds = %catch
160 br label %try.cont
161
162try.cont: ; preds = %catchret.dest, %invoke.cont
163 ret void
164
165catchendblock: ; preds = %catch.dispatch
166 catchendpad unwind label %ehcleanup.1
167
168ehcleanup.1: ; preds = %catchendblock
169 %2 = cleanuppad []
170 call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %a)
171 cleanupret %2 unwind to caller
172}
173
174
175; This case arises when an object with an empty destructor may require cleanup
176; from either inside or outside of a try-block.
177;
178; void f4() {
179; S a;
180; g();
181; try {
182; g();
183; } catch (...) {}
184; }
185;
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).)
190;
191; CHECK: define void @f4()
192; CHECK: entry:
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:
199; CHECK: catchpad
200; CHECK: catch:
201; CHECK: catchret
202; CHECK: catchendblock:
203; CHECK: catchendpad unwind to caller
204; CHECK-NOT: cleanuppad
205; CHECK: }
206;
207define void @f4() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
208entry:
209 invoke void @g()
210 to label %invoke.cont unwind label %ehcleanup
211
212invoke.cont: ; preds = %entry
213 invoke void @g()
214 to label %try.cont unwind label %catch.dispatch
215
216catch.dispatch: ; preds = %invoke.cont
Reid Klecknerb005d282015-09-16 20:16:27 +0000217 %0 = catchpad [i8* null, i32 u0x40, i8* null] to label %catch unwind label %catchendblock
Andrew Kaylor50e4e862015-09-04 23:39:40 +0000218
219catch: ; preds = %catch.dispatch
220 catchret %0 to label %try.cont
221
222try.cont: ; preds = %catch, %invoke.cont
223 ret void
224
225catchendblock: ; preds = %catch.dispatch
226 catchendpad unwind label %ehcleanup
227
228ehcleanup: ; preds = %catchendblock, %entry
229 %1 = cleanuppad []
230 cleanupret %1 unwind to caller
231}
232
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.
236;
237; CHECK: define void @f5()
238; CHECK: entry:
239; CHECK: invoke void @g()
240; CHECK: to label %try.cont unwind label %terminate
241; CHECK: terminate:
242; CHECK: terminatepad [i7 4] unwind to caller
243; CHECK-NOT: cleanuppad
244; CHECK: try.cont:
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
254; CHECK: }
255define void @f5() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
256entry:
257 %a = alloca %struct.S2, align 1
258 invoke void @g()
259 to label %try.cont unwind label %terminate
260
261terminate: ; preds = %entry
262 terminatepad [i7 4] unwind label %ehcleanup
263
264ehcleanup: ; preds = %terminate
265 %0 = cleanuppad []
266 cleanupret %0 unwind to caller
267
268try.cont: ; preds = %entry
269 invoke void @g()
270 to label %try.cont.1 unwind label %terminate.1
271
272terminate.1: ; preds = %try.cont
273 terminatepad [i7 4] unwind label %ehcleanup.1
274
275ehcleanup.1: ; preds = %terminate.1
276 %1 = cleanuppad []
277 cleanupret %1 unwind label %ehcleanup.2
278
279ehcleanup.2: ; preds = %ehcleanup.1
280 %2 = cleanuppad []
281 call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %a)
282 cleanupret %2 unwind to caller
283
284try.cont.1: ; preds = %try.cont
285 ret void
286}
287
288; This case tests simplification of an otherwise empty cleanup pad that contains
289; a PHI node.
290;
291; int f6() {
292; int state = 1;
293; try {
294; S a;
295; g();
296; state = 2;
297; g();
298; } catch (...) {
299; return state;
300; }
301; return 0;
302; }
303;
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.
306;
307; CHECK: define i32 @f6()
308; CHECK: entry:
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 ]
316; CHECK: }
317define i32 @f6() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
318entry:
319 invoke void @g()
320 to label %invoke.cont unwind label %ehcleanup
321
322invoke.cont: ; preds = %entry
323 invoke void @g()
324 to label %return unwind label %ehcleanup
325
326ehcleanup: ; preds = %invoke.cont, %entry
327 %state.0 = phi i32 [ 2, %invoke.cont ], [ 1, %entry ]
328 %0 = cleanuppad []
329 cleanupret %0 unwind label %catch.dispatch
330
331catch.dispatch: ; preds = %ehcleanup
Reid Klecknerb005d282015-09-16 20:16:27 +0000332 %1 = catchpad [i8* null, i32 u0x40, i8* null] to label %catch unwind label %catchendblock
Andrew Kaylor50e4e862015-09-04 23:39:40 +0000333
334catch: ; preds = %catch.dispatch
335 catchret %1 to label %return
336
337catchendblock: ; preds = %catch.dispatch
338 catchendpad unwind to caller
339
340return: ; preds = %invoke.cont, %catch
341 %retval.0 = phi i32 [ %state.0, %catch ], [ 0, %invoke.cont ]
342 ret i32 %retval.0
343}
344
345; This case tests another variation of simplification of an otherwise empty
346; cleanup pad that contains a PHI node.
347;
348; int f7() {
349; int state = 1;
350; try {
351; g();
352; state = 2;
353; S a;
354; g();
355; state = 3;
356; g();
357; } catch (...) {
358; return state;
359; }
360; return 0;
361; }
362;
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.
365;
366; CHECK: define i32 @f7()
367; CHECK: entry:
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 ]
377; CHECK: }
378define i32 @f7() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
379entry:
380 invoke void @g()
381 to label %invoke.cont unwind label %catch.dispatch
382
383invoke.cont: ; preds = %entry
384 invoke void @g()
385 to label %invoke.cont.1 unwind label %ehcleanup
386
387invoke.cont.1: ; preds = %invoke.cont
388 invoke void @g()
389 to label %return unwind label %ehcleanup
390
391ehcleanup: ; preds = %invoke.cont.1, %invoke.cont
392 %state.0 = phi i32 [ 3, %invoke.cont.1 ], [ 2, %invoke.cont ]
393 %0 = cleanuppad []
394 cleanupret %0 unwind label %catch.dispatch
395
396catch.dispatch: ; preds = %ehcleanup, %entry
397 %state.1 = phi i32 [ %state.0, %ehcleanup ], [ 1, %entry ]
Reid Klecknerb005d282015-09-16 20:16:27 +0000398 %1 = catchpad [i8* null, i32 u0x40, i8* null] to label %catch unwind label %catchendblock
Andrew Kaylor50e4e862015-09-04 23:39:40 +0000399
400catch: ; preds = %catch.dispatch
401 catchret %1 to label %return
402
403catchendblock: ; preds = %catch.dispatch
404 catchendpad unwind to caller
405
406return: ; preds = %invoke.cont.1, %catch
407 %retval.0 = phi i32 [ %state.1, %catch ], [ 0, %invoke.cont.1 ]
408 ret i32 %retval.0
409}
410
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.
414;
415; Conceptually, the case being modeled is something like this:
416;
417; int f8() {
418; int x = 1;
419; try {
420; S a;
421; g();
422; x = 2;
423; retry:
424; g();
425; return
426; } catch (...) {
427; use_x(x);
428; }
429; goto retry;
430; }
431;
432; While that C++ syntax isn't legal, the IR below is.
433;
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
436; PHI node itself.
437;
438; CHECK: define void @f8()
439; CHECK: entry:
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 ]
447; CHECK: }
448define void @f8() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
449entry:
450 invoke void @g()
451 to label %invoke.cont unwind label %ehcleanup
452
453invoke.cont: ; preds = %entry
454 invoke void @g()
455 to label %return unwind label %ehcleanup
456
457ehcleanup: ; preds = %invoke.cont, %entry
458 %x = phi i32 [ 2, %invoke.cont ], [ 1, %entry ]
459 %0 = cleanuppad []
460 cleanupret %0 unwind label %catch.dispatch
461
462catch.dispatch: ; preds = %ehcleanup, %catch.cont
Reid Klecknerb005d282015-09-16 20:16:27 +0000463 %1 = catchpad [i8* null, i32 u0x40, i8* null] to label %catch unwind label %catchendblock
Andrew Kaylor50e4e862015-09-04 23:39:40 +0000464
465catch: ; preds = %catch.dispatch
466 call void @use_x(i32 %x)
467 catchret %1 to label %catch.cont
468
469catchendblock: ; preds = %catch.dispatch
470 catchendpad unwind to caller
471
472catch.cont: ; preds = %catch
473 invoke void @g()
474 to label %return unwind label %catch.dispatch
475
476return: ; preds = %invoke.cont, %catch.cont
477 ret void
478}
479
480%struct.S = type { i8 }
481%struct.S2 = type { i8 }
482declare void @"\01??1S2@@QEAA@XZ"(%struct.S2*)
483declare void @g()
484declare void @use_x(i32 %x)
485
486declare i32 @__CxxFrameHandler3(...)
487