1; RUN: opt %s -inline -S | FileCheck %s
2
3declare void @external_func()
4declare void @abort()
5
6@exception_inner = external global i8
7@exception_outer = external global i8
8@condition = external global i1
9
10
11; Check for a bug in which multiple "resume" instructions in the
12; inlined function caused "catch i8* @exception_outer" to appear
13; multiple times in the resulting landingpad.
14
15define internal void @inner_multiple_resume() {
16  invoke void @external_func()
17      to label %cont unwind label %lpad
18cont:
19  ret void
20lpad:
21  %lp = landingpad i32 personality i8* null
22      catch i8* @exception_inner
23  %cond = load i1* @condition
24  br i1 %cond, label %resume1, label %resume2
25resume1:
26  resume i32 1
27resume2:
28  resume i32 2
29}
30
31define void @outer_multiple_resume() {
32  invoke void @inner_multiple_resume()
33      to label %cont unwind label %lpad
34cont:
35  ret void
36lpad:
37  %lp = landingpad i32 personality i8* null
38      catch i8* @exception_outer
39  resume i32 %lp
40}
41; CHECK: define void @outer_multiple_resume()
42; CHECK: %lp.i = landingpad
43; CHECK-NEXT: catch i8* @exception_inner
44; CHECK-NEXT: catch i8* @exception_outer
45; Check that there isn't another "catch" clause:
46; CHECK-NEXT: load
47
48
49; Check for a bug in which having a "resume" and a "call" in the
50; inlined function caused "catch i8* @exception_outer" to appear
51; multiple times in the resulting landingpad.
52
53define internal void @inner_resume_and_call() {
54  call void @external_func()
55  invoke void @external_func()
56      to label %cont unwind label %lpad
57cont:
58  ret void
59lpad:
60  %lp = landingpad i32 personality i8* null
61      catch i8* @exception_inner
62  resume i32 %lp
63}
64
65define void @outer_resume_and_call() {
66  invoke void @inner_resume_and_call()
67      to label %cont unwind label %lpad
68cont:
69  ret void
70lpad:
71  %lp = landingpad i32 personality i8* null
72      catch i8* @exception_outer
73  resume i32 %lp
74}
75; CHECK: define void @outer_resume_and_call()
76; CHECK: %lp.i = landingpad
77; CHECK-NEXT: catch i8* @exception_inner
78; CHECK-NEXT: catch i8* @exception_outer
79; Check that there isn't another "catch" clause:
80; CHECK-NEXT: br
81
82
83; Check what happens if the inlined function contains an "invoke" but
84; no "resume".  In this case, the inlined landingpad does not need to
85; include the "catch i8* @exception_outer" clause from the outer
86; function (since the outer function's landingpad will not be
87; reachable), but it's OK to include this clause.
88
89define internal void @inner_no_resume_or_call() {
90  invoke void @external_func()
91      to label %cont unwind label %lpad
92cont:
93  ret void
94lpad:
95  %lp = landingpad i32 personality i8* null
96      catch i8* @exception_inner
97  ; A landingpad might have no "resume" if a C++ destructor aborts.
98  call void @abort() noreturn nounwind
99  unreachable
100}
101
102define void @outer_no_resume_or_call() {
103  invoke void @inner_no_resume_or_call()
104      to label %cont unwind label %lpad
105cont:
106  ret void
107lpad:
108  %lp = landingpad i32 personality i8* null
109      catch i8* @exception_outer
110  resume i32 %lp
111}
112; CHECK: define void @outer_no_resume_or_call()
113; CHECK: %lp.i = landingpad
114; CHECK-NEXT: catch i8* @exception_inner
115; CHECK-NEXT: catch i8* @exception_outer
116; Check that there isn't another "catch" clause:
117; CHECK-NEXT: call void @abort()
118