xref: /llvm-project/llvm/test/Transforms/Attributor/nounwind.ll (revision cd3a4c31bc9694d160de54c6a4daa53e152cb463)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
2; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal  -attributor-annotate-decl-cs  -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
3; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal  -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
4
5; TEST 1
6define i32 @foo1() {
7; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
8; CHECK-LABEL: define {{[^@]+}}@foo1
9; CHECK-SAME: () #[[ATTR0:[0-9]+]] {
10; CHECK-NEXT:    ret i32 1
11;
12  ret i32 1
13}
14
15declare void @unknown()
16define void @foo2() nounwind {
17; CHECK: Function Attrs: nounwind
18; CHECK-LABEL: define {{[^@]+}}@foo2
19; CHECK-SAME: () #[[ATTR1:[0-9]+]] {
20; CHECK-NEXT:    call void @unknown()
21; CHECK-NEXT:    ret void
22;
23  call void @unknown()
24  ret void
25}
26
27; TEST 2
28define i32 @scc1_foo() {
29; TUNIT: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
30; TUNIT-LABEL: define {{[^@]+}}@scc1_foo
31; TUNIT-SAME: () #[[ATTR2:[0-9]+]] {
32; TUNIT-NEXT:    ret i32 1
33;
34; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
35; CGSCC-LABEL: define {{[^@]+}}@scc1_foo
36; CGSCC-SAME: () #[[ATTR0]] {
37; CGSCC-NEXT:    ret i32 1
38;
39  %1 = call i32 @scc1_bar()
40  ret i32 1
41}
42
43
44; TEST 3
45define i32 @scc1_bar() {
46; TUNIT: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
47; TUNIT-LABEL: define {{[^@]+}}@scc1_bar
48; TUNIT-SAME: () #[[ATTR2]] {
49; TUNIT-NEXT:    ret i32 1
50;
51; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
52; CGSCC-LABEL: define {{[^@]+}}@scc1_bar
53; CGSCC-SAME: () #[[ATTR0]] {
54; CGSCC-NEXT:    ret i32 1
55;
56  %1 = call i32 @scc1_foo()
57  ret i32 1
58}
59
60declare i32 @non_nounwind()
61
62; TEST 4
63define void @call_non_nounwind(){
64; CHECK-LABEL: define {{[^@]+}}@call_non_nounwind() {
65; CHECK-NEXT:    [[TMP1:%.*]] = tail call i32 @non_nounwind()
66; CHECK-NEXT:    ret void
67;
68  tail call i32 @non_nounwind()
69  ret void
70}
71
72; TEST 5 - throw
73; int maybe_throw(bool canThrow) {
74;   if (canThrow)
75;     throw;
76;   else
77;     return -1;
78; }
79
80define i32 @maybe_throw(i1 zeroext %0) {
81; CHECK-LABEL: define {{[^@]+}}@maybe_throw
82; CHECK-SAME: (i1 noundef zeroext [[TMP0:%.*]]) {
83; CHECK-NEXT:    br i1 [[TMP0]], label [[TMP2:%.*]], label [[TMP3:%.*]]
84; CHECK:       2:
85; CHECK-NEXT:    tail call void @__cxa_rethrow()
86; CHECK-NEXT:    unreachable
87; CHECK:       3:
88; CHECK-NEXT:    ret i32 -1
89;
90  br i1 %0, label %2, label %3
91
922:                                                ; preds = %1
93  tail call void @__cxa_rethrow() #1
94  unreachable
95
963:                                                ; preds = %1
97  ret i32 -1
98}
99
100declare void @__cxa_rethrow()
101
102; TEST 6 - catch
103; int catch_thing() {
104;   try {
105;       int a = doThing(true);
106;   }
107;   catch(...) { return -1; }
108;   return 1;
109; }
110
111define i32 @catch_thing() personality ptr @__gxx_personality_v0 {
112; CHECK-LABEL: define {{[^@]+}}@catch_thing() personality ptr @__gxx_personality_v0 {
113; CHECK-NEXT:    invoke void @__cxa_rethrow()
114; CHECK-NEXT:            to label [[TMP1:%.*]] unwind label [[TMP2:%.*]]
115; CHECK:       1:
116; CHECK-NEXT:    unreachable
117; CHECK:       2:
118; CHECK-NEXT:    [[TMP3:%.*]] = landingpad { ptr, i32 }
119; CHECK-NEXT:            catch ptr null
120; CHECK-NEXT:    [[TMP4:%.*]] = extractvalue { ptr, i32 } [[TMP3]], 0
121; CHECK-NEXT:    [[TMP5:%.*]] = tail call ptr @__cxa_begin_catch(ptr [[TMP4]])
122; CHECK-NEXT:    tail call void @__cxa_end_catch()
123; CHECK-NEXT:    ret i32 -1
124;
125  invoke void @__cxa_rethrow() #1
126  to label %1 unwind label %2
127
1281:                                                ; preds = %0
129  unreachable
130
1312:                                                ; preds = %0
132  %3 = landingpad { ptr, i32 }
133  catch ptr null
134  %4 = extractvalue { ptr, i32 } %3, 0
135  %5 = tail call ptr @__cxa_begin_catch(ptr %4) #2
136  tail call void @__cxa_end_catch()
137  ret i32 -1
138}
139
140define i32 @catch_thing_user() {
141; TUNIT-LABEL: define {{[^@]+}}@catch_thing_user() {
142; TUNIT-NEXT:    [[CATCH_THING_CALL:%.*]] = call i32 @catch_thing()
143; TUNIT-NEXT:    ret i32 -1
144;
145; CGSCC-LABEL: define {{[^@]+}}@catch_thing_user() {
146; CGSCC-NEXT:    [[CATCH_THING_CALL:%.*]] = call noundef i32 @catch_thing()
147; CGSCC-NEXT:    ret i32 [[CATCH_THING_CALL]]
148;
149  %catch_thing_call = call i32 @catch_thing()
150  ret i32 %catch_thing_call
151}
152
153define void @two_potential_callees_pos1(i1 %c) {
154; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
155; TUNIT-LABEL: define {{[^@]+}}@two_potential_callees_pos1
156; TUNIT-SAME: (i1 [[C:%.*]]) #[[ATTR0]] {
157; TUNIT-NEXT:    ret void
158;
159; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn
160; CGSCC-LABEL: define {{[^@]+}}@two_potential_callees_pos1
161; CGSCC-SAME: (i1 [[C:%.*]]) #[[ATTR2:[0-9]+]] {
162; CGSCC-NEXT:    [[FP:%.*]] = select i1 [[C]], ptr @foo1, ptr @scc1_foo
163; CGSCC-NEXT:    [[TMP1:%.*]] = icmp eq ptr [[FP]], @scc1_foo
164; CGSCC-NEXT:    br i1 [[TMP1]], label [[TMP2:%.*]], label [[TMP3:%.*]]
165; CGSCC:       2:
166; CGSCC-NEXT:    call void @scc1_foo()
167; CGSCC-NEXT:    br label [[TMP6:%.*]]
168; CGSCC:       3:
169; CGSCC-NEXT:    br i1 true, label [[TMP4:%.*]], label [[TMP5:%.*]]
170; CGSCC:       4:
171; CGSCC-NEXT:    call void @foo1()
172; CGSCC-NEXT:    br label [[TMP6]]
173; CGSCC:       5:
174; CGSCC-NEXT:    unreachable
175; CGSCC:       6:
176; CGSCC-NEXT:    ret void
177;
178  %fp = select i1 %c, ptr @foo1, ptr @scc1_foo
179  call void %fp()
180  ret void
181}
182define void @two_potential_callees_pos2(i1 %c) {
183; CHECK: Function Attrs: nounwind
184; CHECK-LABEL: define {{[^@]+}}@two_potential_callees_pos2
185; CHECK-SAME: (i1 [[C:%.*]]) #[[ATTR1]] {
186; CHECK-NEXT:    [[FP:%.*]] = select i1 [[C]], ptr @foo2, ptr @scc1_foo
187; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq ptr [[FP]], @scc1_foo
188; CHECK-NEXT:    br i1 [[TMP1]], label [[TMP2:%.*]], label [[TMP3:%.*]]
189; CHECK:       2:
190; CHECK-NEXT:    call void @scc1_foo()
191; CHECK-NEXT:    br label [[TMP6:%.*]]
192; CHECK:       3:
193; CHECK-NEXT:    br i1 true, label [[TMP4:%.*]], label [[TMP5:%.*]]
194; CHECK:       4:
195; CHECK-NEXT:    call void @foo2()
196; CHECK-NEXT:    br label [[TMP6]]
197; CHECK:       5:
198; CHECK-NEXT:    unreachable
199; CHECK:       6:
200; CHECK-NEXT:    ret void
201;
202  %fp = select i1 %c, ptr @foo2, ptr @scc1_foo
203  call void %fp()
204  ret void
205}
206define void @two_potential_callees_neg(i1 %c) {
207; CHECK-LABEL: define {{[^@]+}}@two_potential_callees_neg
208; CHECK-SAME: (i1 [[C:%.*]]) {
209; CHECK-NEXT:    [[FP:%.*]] = select i1 [[C]], ptr @foo1, ptr @non_nounwind
210; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq ptr [[FP]], @non_nounwind
211; CHECK-NEXT:    br i1 [[TMP1]], label [[TMP2:%.*]], label [[TMP3:%.*]]
212; CHECK:       2:
213; CHECK-NEXT:    call void @non_nounwind()
214; CHECK-NEXT:    br label [[TMP6:%.*]]
215; CHECK:       3:
216; CHECK-NEXT:    br i1 true, label [[TMP4:%.*]], label [[TMP5:%.*]]
217; CHECK:       4:
218; CHECK-NEXT:    call void @foo1()
219; CHECK-NEXT:    br label [[TMP6]]
220; CHECK:       5:
221; CHECK-NEXT:    unreachable
222; CHECK:       6:
223; CHECK-NEXT:    ret void
224;
225  %fp = select i1 %c, ptr @foo1, ptr @non_nounwind
226  call void %fp()
227  ret void
228}
229
230declare i32 @__gxx_personality_v0(...)
231
232declare ptr @__cxa_begin_catch(ptr)
233
234declare void @__cxa_end_catch()
235;.
236; TUNIT: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
237; TUNIT: attributes #[[ATTR1]] = { nounwind }
238; TUNIT: attributes #[[ATTR2]] = { mustprogress nofree nosync nounwind willreturn memory(none) }
239;.
240; CGSCC: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
241; CGSCC: attributes #[[ATTR1]] = { nounwind }
242; CGSCC: attributes #[[ATTR2]] = { mustprogress nofree nosync nounwind willreturn }
243;.
244