• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1; RUN: opt < %s -simplifycfg -S | FileCheck %s
2
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 within none []
35  cleanupret from %0 unwind label %ehcleanup.1
36
37ehcleanup.1:                                      ; preds = %ehcleanup
38  %1 = cleanuppad within none []
39  cleanupret from %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 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
68; CHECK: catch:
69; CHECK:   catchpad
70; CHECK:   catchret
71; 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
83  %0 = cleanuppad within none []
84  call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %b)
85  cleanupret from %0 unwind label %catch.dispatch
86
87catch.dispatch:                                   ; preds = %ehcleanup
88  %cs1 = catchswitch within none [label %catch] unwind label %ehcleanup.1
89
90catch:                                            ; preds = %catch.dispatch
91  %1 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
92  catchret from %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
100ehcleanup.1:
101  %2 = cleanuppad within none []
102  cleanupret from %2 unwind to caller
103}
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;
121; CHECK-LABEL: define void @f3()
122; CHECK: entry:
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
127; CHECK: catch:
128; CHECK:   catchpad within %cs1 [i8* null, i32 64, i8* null]
129; CHECK:   catchret
130; CHECK: ehcleanup.1:
131; CHECK:   cleanuppad
132; CHECK:   call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %a)
133; CHECK:   cleanupret from %cp3 unwind to caller
134; 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
145  %0 = cleanuppad within none []
146  cleanupret from %0 unwind label %catch.dispatch
147
148catch.dispatch:                                   ; preds = %ehcleanup
149  %cs1 = catchswitch within none [label %catch] unwind label %ehcleanup.1
150
151catch:                                            ; preds = %catch.dispatch
152  %cp2 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
153  catchret from %cp2 to label %catchret.dest
154
155catchret.dest:                                    ; preds = %catch
156  br label %try.cont
157
158try.cont:                                         ; preds = %catchret.dest, %invoke.cont
159  ret void
160
161ehcleanup.1:
162  %cp3 = cleanuppad within none []
163  call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %a)
164  cleanupret from %cp3 unwind to caller
165}
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
180; catch block should be converted to a call (that is, that is, exception
181; handling continues with the parent frame of the caller).)
182;
183; CHECK-LABEL: define void @f4()
184; 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:
191; CHECK:   catchswitch within none [label %catch] unwind to caller
192; CHECK: catch:
193; CHECK:   catchpad
194; CHECK:   catchret
195; 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
208  %cs1 = catchswitch within none [label %catch] unwind label %ehcleanup
209
210catch:                                            ; preds = %catch.dispatch
211  %0 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
212  catchret from %0 to label %try.cont
213
214try.cont:                                         ; preds = %catch, %invoke.cont
215  ret void
216
217ehcleanup:
218  %cp2 = cleanuppad within none []
219  cleanupret from %cp2 unwind to caller
220}
221
222; This case tests simplification of an otherwise empty cleanup pad that contains
223; a PHI node.
224;
225; int f6() {
226;   int state = 1;
227;   try {
228;     S a;
229;     g();
230;     state = 2;
231;     g();
232;   } catch (...) {
233;     return state;
234;   }
235;   return 0;
236; }
237;
238; In this case, the cleanup pad should be eliminated and the PHI node in the
239; cleanup pad should be sunk into the catch dispatch block.
240;
241; CHECK-LABEL: define i32 @f6()
242; CHECK: entry:
243; CHECK:   invoke void @g()
244; CHECK: invoke.cont:
245; CHECK:   invoke void @g()
246; CHECK-NOT: ehcleanup:
247; CHECK-NOT:   cleanuppad
248; CHECK: catch.dispatch:
249; CHECK:   %state.0 = phi i32 [ 2, %invoke.cont ], [ 1, %entry ]
250; CHECK: }
251define i32 @f6() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
252entry:
253  invoke void @g()
254          to label %invoke.cont unwind label %ehcleanup
255
256invoke.cont:                                      ; preds = %entry
257  invoke void @g()
258          to label %return unwind label %ehcleanup
259
260ehcleanup:                                        ; preds = %invoke.cont, %entry
261  %state.0 = phi i32 [ 2, %invoke.cont ], [ 1, %entry ]
262  %0 = cleanuppad within none []
263  cleanupret from %0 unwind label %catch.dispatch
264
265catch.dispatch:                                   ; preds = %ehcleanup
266  %cs1 = catchswitch within none [label %catch] unwind to caller
267
268catch:                                            ; preds = %catch.dispatch
269  %1 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
270  catchret from %1 to label %return
271
272return:                                           ; preds = %invoke.cont, %catch
273  %retval.0 = phi i32 [ %state.0, %catch ], [ 0, %invoke.cont ]
274  ret i32 %retval.0
275}
276
277; This case tests another variation of simplification of an otherwise empty
278; cleanup pad that contains a PHI node.
279;
280; int f7() {
281;   int state = 1;
282;   try {
283;     g();
284;     state = 2;
285;     S a;
286;     g();
287;     state = 3;
288;     g();
289;   } catch (...) {
290;     return state;
291;   }
292;   return 0;
293; }
294;
295; In this case, the cleanup pad should be eliminated and the PHI node in the
296; cleanup pad should be merged with the PHI node in the catch dispatch block.
297;
298; CHECK-LABEL: define i32 @f7()
299; CHECK: entry:
300; CHECK:   invoke void @g()
301; CHECK: invoke.cont:
302; CHECK:   invoke void @g()
303; CHECK: invoke.cont.1:
304; CHECK:   invoke void @g()
305; CHECK-NOT: ehcleanup:
306; CHECK-NOT:   cleanuppad
307; CHECK: catch.dispatch:
308; CHECK:   %state.1 = phi i32 [ 1, %entry ], [ 3, %invoke.cont.1 ], [ 2, %invoke.cont ]
309; CHECK: }
310define i32 @f7() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
311entry:
312  invoke void @g()
313          to label %invoke.cont unwind label %catch.dispatch
314
315invoke.cont:                                      ; preds = %entry
316  invoke void @g()
317          to label %invoke.cont.1 unwind label %ehcleanup
318
319invoke.cont.1:                                    ; preds = %invoke.cont
320  invoke void @g()
321          to label %return unwind label %ehcleanup
322
323ehcleanup:                                        ; preds = %invoke.cont.1, %invoke.cont
324  %state.0 = phi i32 [ 3, %invoke.cont.1 ], [ 2, %invoke.cont ]
325  %0 = cleanuppad within none []
326  cleanupret from %0 unwind label %catch.dispatch
327
328catch.dispatch:                                   ; preds = %ehcleanup, %entry
329  %state.1 = phi i32 [ %state.0, %ehcleanup ], [ 1, %entry ]
330  %cs1 = catchswitch within none [label %catch] unwind to caller
331
332catch:                                            ; preds = %catch.dispatch
333  %1 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
334  catchret from %1 to label %return
335
336return:                                           ; preds = %invoke.cont.1, %catch
337  %retval.0 = phi i32 [ %state.1, %catch ], [ 0, %invoke.cont.1 ]
338  ret i32 %retval.0
339}
340
341; This case tests a scenario where an empty cleanup pad is not dominated by all
342; of the predecessors of its successor, but the successor references a PHI node
343; in the empty cleanup pad.
344;
345; Conceptually, the case being modeled is something like this:
346;
347; int f8() {
348;   int x = 1;
349;   try {
350;     S a;
351;     g();
352;     x = 2;
353; retry:
354;     g();
355;     return
356;   } catch (...) {
357;     use_x(x);
358;   }
359;   goto retry;
360; }
361;
362; While that C++ syntax isn't legal, the IR below is.
363;
364; In this case, the PHI node that is sunk from ehcleanup to catch.dispatch
365; should have an incoming value entry for path from 'foo' that references the
366; PHI node itself.
367;
368; CHECK-LABEL: define void @f8()
369; CHECK: entry:
370; CHECK:   invoke void @g()
371; CHECK: invoke.cont:
372; CHECK:   invoke void @g()
373; CHECK-NOT: ehcleanup:
374; CHECK-NOT:   cleanuppad
375; CHECK: catch.dispatch:
376; CHECK:   %x = phi i32 [ 2, %invoke.cont ], [ 1, %entry ], [ %x, %catch.cont ]
377; CHECK: }
378define void @f8() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
379entry:
380  invoke void @g()
381          to label %invoke.cont unwind label %ehcleanup
382
383invoke.cont:                                      ; preds = %entry
384  invoke void @g()
385          to label %return unwind label %ehcleanup
386
387ehcleanup:                                        ; preds = %invoke.cont, %entry
388  %x = phi i32 [ 2, %invoke.cont ], [ 1, %entry ]
389  %0 = cleanuppad within none []
390  cleanupret from %0 unwind label %catch.dispatch
391
392catch.dispatch:                                   ; preds = %ehcleanup, %catch.cont
393  %cs1 = catchswitch within none [label %catch] unwind to caller
394
395catch:                                            ; preds = %catch.dispatch
396  %1 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
397  call void @use_x(i32 %x)
398  catchret from %1 to label %catch.cont
399
400catch.cont:                                       ; preds = %catch
401  invoke void @g()
402          to label %return unwind label %catch.dispatch
403
404return:                                           ; preds = %invoke.cont, %catch.cont
405  ret void
406}
407; CHECK-LABEL: define i32 @f9()
408; CHECK: entry:
409; CHECK:   invoke void @"\01??1S2@@QEAA@XZ"(
410; CHECK-NOT:   cleanuppad
411; CHECK: catch.dispatch:
412; CHECK: }
413define i32 @f9() personality i32 (...)* @__CxxFrameHandler3 {
414entry:
415  %s = alloca i8, align 1
416  call void @llvm.lifetime.start(i64 1, i8* nonnull %s)
417  %bc = bitcast i8* %s to %struct.S2*
418  invoke void @"\01??1S2@@QEAA@XZ"(%struct.S2* %bc)
419          to label %try.cont unwind label %ehcleanup
420
421ehcleanup:
422  %cleanup.pad = cleanuppad within none []
423  call void @llvm.lifetime.end(i64 1, i8* nonnull %s)
424  cleanupret from %cleanup.pad unwind label %catch.dispatch
425
426catch.dispatch:
427  %catch.switch = catchswitch within none [label %catch] unwind to caller
428
429catch:
430  %catch.pad = catchpad within %catch.switch [i8* null, i32 0, i8* null]
431  catchret from %catch.pad to label %try.cont
432
433try.cont:
434  ret i32 0
435}
436
437; CHECK-LABEL: define void @f10(
438define void @f10(i32 %V) personality i32 (...)* @__CxxFrameHandler3 {
439entry:
440  invoke void @g()
441          to label %unreachable unwind label %cleanup
442; CHECK:       call void @g()
443; CHECK-NEXT:  unreachable
444
445unreachable:
446  unreachable
447
448cleanup:
449  %cp = cleanuppad within none []
450  switch i32 %V, label %cleanupret1 [
451    i32 0, label %cleanupret2
452  ]
453
454cleanupret1:
455  cleanupret from %cp unwind to caller
456
457cleanupret2:
458  cleanupret from %cp unwind to caller
459}
460
461%struct.S = type { i8 }
462%struct.S2 = type { i8 }
463declare void @"\01??1S2@@QEAA@XZ"(%struct.S2*)
464declare void @g()
465declare void @use_x(i32 %x)
466
467declare i32 @__CxxFrameHandler3(...)
468
469declare void @llvm.lifetime.start(i64, i8* nocapture)
470declare void @llvm.lifetime.end(i64, i8* nocapture)
471