1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-attributes 2; RUN: opt -passes=function-attrs -S %s | FileCheck --check-prefixes=COMMON,FNATTRS %s 3; RUN: opt -passes=attributor-light -S %s | FileCheck --check-prefixes=COMMON,ATTRIBUTOR %s 4 5define void @mustprogress_readnone() mustprogress { 6; FNATTRS: Function Attrs: mustprogress nofree norecurse noreturn nosync nounwind willreturn memory(none) 7; FNATTRS-LABEL: @mustprogress_readnone( 8; FNATTRS-NEXT: entry: 9; FNATTRS-NEXT: br label [[WHILE_BODY:%.*]] 10; FNATTRS: while.body: 11; FNATTRS-NEXT: br label [[WHILE_BODY]] 12; 13; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse noreturn nosync nounwind memory(none) 14; ATTRIBUTOR-LABEL: @mustprogress_readnone( 15; ATTRIBUTOR-NEXT: entry: 16; ATTRIBUTOR-NEXT: br label [[WHILE_BODY:%.*]] 17; ATTRIBUTOR: while.body: 18; ATTRIBUTOR-NEXT: br label [[WHILE_BODY]] 19; 20entry: 21 br label %while.body 22 23while.body: 24 br label %while.body 25} 26 27define i32 @mustprogress_load(ptr %ptr) mustprogress { 28; FNATTRS: Function Attrs: mustprogress nofree norecurse noreturn nosync nounwind willreturn memory(argmem: read) 29; FNATTRS-LABEL: @mustprogress_load( 30; FNATTRS-NEXT: entry: 31; FNATTRS-NEXT: br label [[WHILE_BODY:%.*]] 32; FNATTRS: while.body: 33; FNATTRS-NEXT: [[R:%.*]] = load i32, ptr [[PTR:%.*]], align 4 34; FNATTRS-NEXT: br label [[WHILE_BODY]] 35; 36; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse noreturn nosync nounwind memory(argmem: read) 37; ATTRIBUTOR-LABEL: @mustprogress_load( 38; ATTRIBUTOR-NEXT: entry: 39; ATTRIBUTOR-NEXT: br label [[WHILE_BODY:%.*]] 40; ATTRIBUTOR: while.body: 41; ATTRIBUTOR-NEXT: [[R:%.*]] = load i32, ptr [[PTR:%.*]], align 4 42; ATTRIBUTOR-NEXT: br label [[WHILE_BODY]] 43; 44entry: 45 br label %while.body 46 47while.body: 48 %r = load i32, ptr %ptr 49 br label %while.body 50} 51 52define void @mustprogress_store(ptr %ptr) mustprogress { 53; COMMON: Function Attrs: mustprogress nofree norecurse noreturn nosync nounwind memory(argmem: write) 54; COMMON-LABEL: @mustprogress_store( 55; COMMON-NEXT: entry: 56; COMMON-NEXT: br label [[WHILE_BODY:%.*]] 57; COMMON: while.body: 58; COMMON-NEXT: store i32 0, ptr [[PTR:%.*]], align 4 59; COMMON-NEXT: br label [[WHILE_BODY]] 60; 61entry: 62 br label %while.body 63 64while.body: 65 store i32 0, ptr %ptr 66 br label %while.body 67} 68 69declare void @unknown_fn() 70 71define void @mustprogress_call_unknown_fn() mustprogress { 72; COMMON: Function Attrs: mustprogress 73; COMMON-LABEL: @mustprogress_call_unknown_fn( 74; COMMON-NEXT: call void @unknown_fn() 75; COMMON-NEXT: ret void 76; 77 call void @unknown_fn() 78 ret void 79} 80 81define i32 @mustprogress_call_known_functions(ptr %ptr) mustprogress { 82; FNATTRS: Function Attrs: mustprogress nofree norecurse noreturn nosync nounwind willreturn memory(argmem: read) 83; FNATTRS-LABEL: @mustprogress_call_known_functions( 84; FNATTRS-NEXT: call void @mustprogress_readnone() 85; FNATTRS-NEXT: [[R:%.*]] = call i32 @mustprogress_load(ptr [[PTR:%.*]]) 86; FNATTRS-NEXT: ret i32 [[R]] 87; 88; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) 89; ATTRIBUTOR-LABEL: @mustprogress_call_known_functions( 90; ATTRIBUTOR-NEXT: call void @mustprogress_readnone() #[[ATTR9:[0-9]+]] 91; ATTRIBUTOR-NEXT: [[R:%.*]] = call i32 @mustprogress_load(ptr nofree readonly captures(none) [[PTR:%.*]]) #[[ATTR12:[0-9]+]] 92; ATTRIBUTOR-NEXT: ret i32 [[R]] 93; 94 call void @mustprogress_readnone() 95 %r = call i32 @mustprogress_load(ptr %ptr) 96 ret i32 %r 97} 98 99declare i32 @__gxx_personality_v0(...) 100 101define i64 @mustprogress_mayunwind() mustprogress personality ptr @__gxx_personality_v0 { 102; FNATTRS: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none) 103; FNATTRS-LABEL: @mustprogress_mayunwind( 104; FNATTRS-NEXT: [[A:%.*]] = invoke i64 @fn_noread() 105; FNATTRS-NEXT: to label [[A:%.*]] unwind label [[B:%.*]] 106; FNATTRS: A: 107; FNATTRS-NEXT: ret i64 10 108; FNATTRS: B: 109; FNATTRS-NEXT: [[VAL:%.*]] = landingpad { ptr, i32 } 110; FNATTRS-NEXT: catch ptr null 111; FNATTRS-NEXT: ret i64 0 112; 113; ATTRIBUTOR: Function Attrs: mustprogress nosync nounwind willreturn memory(none) 114; ATTRIBUTOR-LABEL: @mustprogress_mayunwind( 115; ATTRIBUTOR-NEXT: [[A:%.*]] = invoke i64 @fn_noread() #[[ATTR13:[0-9]+]] 116; ATTRIBUTOR-NEXT: to label [[A:%.*]] unwind label [[B:%.*]] 117; ATTRIBUTOR: A: 118; ATTRIBUTOR-NEXT: ret i64 10 119; ATTRIBUTOR: B: 120; ATTRIBUTOR-NEXT: [[VAL:%.*]] = landingpad { ptr, i32 } 121; ATTRIBUTOR-NEXT: catch ptr null 122; ATTRIBUTOR-NEXT: ret i64 0 123; 124 %a = invoke i64 @fn_noread() 125 to label %A unwind label %B 126A: 127 ret i64 10 128 129B: 130 %val = landingpad { ptr, i32 } 131 catch ptr null 132 ret i64 0 133} 134 135; Function without loops or non-willreturn calls will return. 136define void @willreturn_no_loop(i1 %c, ptr %p) { 137; FNATTRS: Function Attrs: mustprogress willreturn 138; FNATTRS-LABEL: @willreturn_no_loop( 139; FNATTRS-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]] 140; FNATTRS: if: 141; FNATTRS-NEXT: [[TMP1:%.*]] = load atomic i32, ptr [[P:%.*]] seq_cst, align 4 142; FNATTRS-NEXT: call void @fn_willreturn() 143; FNATTRS-NEXT: br label [[END:%.*]] 144; FNATTRS: else: 145; FNATTRS-NEXT: store atomic i32 0, ptr [[P]] seq_cst, align 4 146; FNATTRS-NEXT: br label [[END]] 147; FNATTRS: end: 148; FNATTRS-NEXT: ret void 149; 150; ATTRIBUTOR: Function Attrs: mustprogress willreturn 151; ATTRIBUTOR-LABEL: @willreturn_no_loop( 152; ATTRIBUTOR-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]] 153; ATTRIBUTOR: if: 154; ATTRIBUTOR-NEXT: [[TMP1:%.*]] = load atomic i32, ptr [[P:%.*]] seq_cst, align 4 155; ATTRIBUTOR-NEXT: call void @fn_willreturn() #[[ATTR11:[0-9]+]] 156; ATTRIBUTOR-NEXT: br label [[END:%.*]] 157; ATTRIBUTOR: else: 158; ATTRIBUTOR-NEXT: store atomic i32 0, ptr [[P]] seq_cst, align 4 159; ATTRIBUTOR-NEXT: br label [[END]] 160; ATTRIBUTOR: end: 161; ATTRIBUTOR-NEXT: ret void 162; 163 br i1 %c, label %if, label %else 164 165if: 166 load atomic i32, ptr %p seq_cst, align 4 167 call void @fn_willreturn() 168 br label %end 169 170else: 171 store atomic i32 0, ptr %p seq_cst, align 4 172 br label %end 173 174end: 175 ret void 176} 177 178; Calls a function that is not guaranteed to return, not willreturn. 179define void @willreturn_non_returning_function(i1 %c, ptr %p) { 180; COMMON-LABEL: @willreturn_non_returning_function( 181; COMMON-NEXT: call void @unknown_fn() 182; COMMON-NEXT: ret void 183; 184 call void @unknown_fn() 185 ret void 186} 187 188; Infinite loop without mustprogress, will not return. 189define void @willreturn_loop() { 190; COMMON: Function Attrs: nofree norecurse noreturn nosync nounwind memory(none) 191; COMMON-LABEL: @willreturn_loop( 192; COMMON-NEXT: br label [[LOOP:%.*]] 193; COMMON: loop: 194; COMMON-NEXT: br label [[LOOP]] 195; 196 br label %loop 197 198loop: 199 br label %loop 200} 201 202; Finite loop. Could be willreturn but not detected. 203; FIXME 204define void @willreturn_finite_loop() { 205; COMMON: Function Attrs: nofree norecurse nosync nounwind memory(none) 206; COMMON-LABEL: @willreturn_finite_loop( 207; COMMON-NEXT: entry: 208; COMMON-NEXT: br label [[LOOP:%.*]] 209; COMMON: loop: 210; COMMON-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[I_INC:%.*]], [[LOOP]] ] 211; COMMON-NEXT: [[I_INC]] = add nuw i32 [[I]], 1 212; COMMON-NEXT: [[C:%.*]] = icmp ne i32 [[I_INC]], 100 213; COMMON-NEXT: br i1 [[C]], label [[LOOP]], label [[END:%.*]] 214; COMMON: end: 215; COMMON-NEXT: ret void 216; 217entry: 218 br label %loop 219 220loop: 221 %i = phi i32 [ 0, %entry], [ %i.inc, %loop ] 222 %i.inc = add nuw i32 %i, 1 223 %c = icmp ne i32 %i.inc, 100 224 br i1 %c, label %loop, label %end 225 226end: 227 ret void 228} 229 230; Infinite recursion without mustprogress, will not return. 231define void @willreturn_recursion() { 232; FNATTRS: Function Attrs: nofree nosync nounwind memory(none) 233; FNATTRS-LABEL: @willreturn_recursion( 234; FNATTRS-NEXT: tail call void @willreturn_recursion() 235; FNATTRS-NEXT: ret void 236; 237; ATTRIBUTOR: Function Attrs: nofree nosync nounwind memory(none) 238; ATTRIBUTOR-LABEL: @willreturn_recursion( 239; ATTRIBUTOR-NEXT: tail call void @willreturn_recursion() #[[ATTR9]] 240; ATTRIBUTOR-NEXT: ret void 241; 242 tail call void @willreturn_recursion() 243 ret void 244} 245 246; Irreducible infinite loop, will not return. 247define void @willreturn_irreducible(i1 %c) { 248; COMMON: Function Attrs: nofree norecurse noreturn nosync nounwind memory(none) 249; COMMON-LABEL: @willreturn_irreducible( 250; COMMON-NEXT: br i1 [[C:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] 251; COMMON: bb1: 252; COMMON-NEXT: br label [[BB2]] 253; COMMON: bb2: 254; COMMON-NEXT: br label [[BB1]] 255; 256 br i1 %c, label %bb1, label %bb2 257 258bb1: 259 br label %bb2 260 261bb2: 262 br label %bb1 263} 264 265define linkonce i32 @square(i32) { 266; COMMON-LABEL: @square( 267; COMMON-NEXT: [[TMP2:%.*]] = mul nsw i32 [[TMP0:%.*]], [[TMP0]] 268; COMMON-NEXT: ret i32 [[TMP2]] 269; 270 %2 = mul nsw i32 %0, %0 271 ret i32 %2 272} 273 274declare i64 @fn_noread() readnone 275declare void @fn_willreturn() willreturn 276