1; RUN: opt -mtriple=x86_64-linux-gnu -dwarfehprepare < %s -S | FileCheck %s
2
3; Check basic functionality of IR-to-IR DWARF EH preparation. This should
4; eliminate resumes. This pass requires a TargetMachine, so we put it under X86
5; and provide an x86 triple.
6
7@int_typeinfo = global i8 0
8
9declare void @might_throw()
10declare void @cleanup()
11
12define i32 @simple_cleanup_catch() {
13  invoke void @might_throw()
14          to label %cont unwind label %lpad
15
16; CHECK-LABEL: define i32 @simple_cleanup_catch()
17; CHECK: invoke void @might_throw()
18
19cont:
20  ret i32 0
21
22; CHECK: ret i32 0
23
24lpad:
25  %ehvals = landingpad { i8*, i32 } personality i32 (...)* @__gxx_personality_v0
26      cleanup
27      catch i8* @int_typeinfo
28  %ehptr = extractvalue { i8*, i32 } %ehvals, 0
29  %ehsel = extractvalue { i8*, i32 } %ehvals, 1
30  call void @cleanup()
31  %int_sel = call i32 @llvm.eh.typeid.for(i8* @int_typeinfo)
32  %int_match = icmp eq i32 %ehsel, %int_sel
33  br i1 %int_match, label %catch_int, label %eh.resume
34
35; CHECK: lpad:
36; CHECK: landingpad { i8*, i32 } personality i32 (...)* @__gxx_personality_v0
37; CHECK: call void @cleanup()
38; CHECK: call i32 @llvm.eh.typeid.for
39; CHECK: br i1
40
41catch_int:
42  ret i32 1
43
44; CHECK: catch_int:
45; CHECK: ret i32 1
46
47eh.resume:
48  %tmp_ehvals = insertvalue { i8*, i32 } undef, i8* %ehptr, 0
49  %new_ehvals = insertvalue { i8*, i32 } %tmp_ehvals, i32 %ehsel, 1
50  resume { i8*, i32 } %new_ehvals
51
52; CHECK: eh.resume:
53; CHECK-NEXT: call void @_Unwind_Resume(i8* %ehptr)
54}
55
56
57define i32 @catch_no_resume() {
58  invoke void @might_throw()
59          to label %cont unwind label %lpad
60
61cont:
62  ret i32 0
63
64lpad:
65  %ehvals = landingpad { i8*, i32 } personality i32 (...)* @__gxx_personality_v0
66      catch i8* @int_typeinfo
67  %ehptr = extractvalue { i8*, i32 } %ehvals, 0
68  %ehsel = extractvalue { i8*, i32 } %ehvals, 1
69  %int_sel = call i32 @llvm.eh.typeid.for(i8* @int_typeinfo)
70  %int_match = icmp eq i32 %ehsel, %int_sel
71  br i1 %int_match, label %catch_int, label %eh.resume
72
73catch_int:
74  ret i32 1
75
76eh.resume:
77  %tmp_ehvals = insertvalue { i8*, i32 } undef, i8* %ehptr, 0
78  %new_ehvals = insertvalue { i8*, i32 } %tmp_ehvals, i32 %ehsel, 1
79  resume { i8*, i32 } %new_ehvals
80}
81
82; Check that we can prune the unreachable resume instruction.
83
84; CHECK-LABEL: define i32 @catch_no_resume() {
85; CHECK: invoke void @might_throw()
86; CHECK: ret i32 0
87; CHECK: lpad:
88; CHECK: landingpad { i8*, i32 } personality i32 (...)* @__gxx_personality_v0
89; CHECK-NOT: br i1
90; CHECK: ret i32 1
91; CHECK-NOT: call void @_Unwind_Resume
92; CHECK: {{^[}]}}
93
94
95define i32 @catch_cleanup_merge() {
96  invoke void @might_throw()
97          to label %inner_invoke unwind label %outer_lpad
98inner_invoke:
99  invoke void @might_throw()
100          to label %cont unwind label %inner_lpad
101cont:
102  ret i32 0
103
104outer_lpad:
105  %ehvals1 = landingpad { i8*, i32 } personality i32 (...)* @__gxx_personality_v0
106      catch i8* @int_typeinfo
107  br label %catch.dispatch
108
109inner_lpad:
110  %ehvals2 = landingpad { i8*, i32 } personality i32 (...)* @__gxx_personality_v0
111      cleanup
112      catch i8* @int_typeinfo
113  call void @cleanup()
114  br label %catch.dispatch
115
116catch.dispatch:
117  %ehvals = phi { i8*, i32 } [ %ehvals1, %outer_lpad ], [ %ehvals2, %inner_lpad ]
118  %ehptr = extractvalue { i8*, i32 } %ehvals, 0
119  %ehsel = extractvalue { i8*, i32 } %ehvals, 1
120  %int_sel = call i32 @llvm.eh.typeid.for(i8* @int_typeinfo)
121  %int_match = icmp eq i32 %ehsel, %int_sel
122  br i1 %int_match, label %catch_int, label %eh.resume
123
124catch_int:
125  ret i32 1
126
127eh.resume:
128  %tmp_ehvals = insertvalue { i8*, i32 } undef, i8* %ehptr, 0
129  %new_ehvals = insertvalue { i8*, i32 } %tmp_ehvals, i32 %ehsel, 1
130  resume { i8*, i32 } %new_ehvals
131}
132
133; We can't prune this merge because one landingpad is a cleanup pad.
134
135; CHECK-LABEL: define i32 @catch_cleanup_merge()
136; CHECK: invoke void @might_throw()
137; CHECK: invoke void @might_throw()
138; CHECK: ret i32 0
139;
140; CHECK: outer_lpad:
141; CHECK: landingpad { i8*, i32 } personality i32 (...)* @__gxx_personality_v0
142; CHECK: br label %catch.dispatch
143;
144; CHECK: inner_lpad:
145; CHECK: landingpad { i8*, i32 } personality i32 (...)* @__gxx_personality_v0
146; CHECK: call void @cleanup()
147; CHECK: br label %catch.dispatch
148;
149; CHECK: catch.dispatch:
150; CHECK: call i32 @llvm.eh.typeid.for
151; CHECK: br i1
152; CHECK: catch_int:
153; CHECK: ret i32 1
154; CHECK: eh.resume:
155; CHECK-NEXT: call void @_Unwind_Resume(i8* %ehptr)
156
157declare i32 @__gxx_personality_v0(...)
158declare i32 @llvm.eh.typeid.for(i8*)
159