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