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 5target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" 6 7; Test cases specifically designed for the "nofree" function attribute. 8; We use FIXME's to indicate problems and missing attributes. 9 10; Free functions 11declare void @free(ptr nocapture) local_unnamed_addr #1 12declare noalias ptr @realloc(ptr nocapture, i64) local_unnamed_addr #0 13declare void @_ZdaPv(ptr) local_unnamed_addr #2 14 15 16; TEST 1 (positive case) 17define void @only_return() #0 { 18; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable 19; CHECK-LABEL: define {{[^@]+}}@only_return 20; CHECK-SAME: () #[[ATTR3:[0-9]+]] { 21; CHECK-NEXT: ret void 22; 23 ret void 24} 25 26 27; TEST 2 (negative case) 28; Only free 29; void only_free(char* p) { 30; free(p); 31; } 32 33define void @only_free(ptr nocapture %0) local_unnamed_addr #0 { 34; CHECK: Function Attrs: noinline nounwind uwtable 35; CHECK-LABEL: define {{[^@]+}}@only_free 36; CHECK-SAME: (ptr captures(none) [[TMP0:%.*]]) local_unnamed_addr #[[ATTR1:[0-9]+]] { 37; CHECK-NEXT: tail call void @free(ptr captures(none) [[TMP0]]) #[[ATTR0:[0-9]+]] 38; CHECK-NEXT: ret void 39; 40 tail call void @free(ptr %0) #1 41 ret void 42} 43 44 45; TEST 3 (negative case) 46; Free occurs in same scc. 47; void free_in_scc1(char*p){ 48; free_in_scc2(p); 49; } 50; void free_in_scc2(char*p){ 51; free_in_scc1(p); 52; free(p); 53; } 54 55 56define void @free_in_scc1(ptr nocapture %0) local_unnamed_addr #0 { 57; CHECK: Function Attrs: noinline nounwind uwtable 58; CHECK-LABEL: define {{[^@]+}}@free_in_scc1 59; CHECK-SAME: (ptr captures(none) [[TMP0:%.*]]) local_unnamed_addr #[[ATTR1]] { 60; CHECK-NEXT: tail call void @free_in_scc2(ptr captures(none) [[TMP0]]) #[[ATTR0]] 61; CHECK-NEXT: ret void 62; 63 tail call void @free_in_scc2(ptr %0) #1 64 ret void 65} 66 67 68define void @free_in_scc2(ptr nocapture %0) local_unnamed_addr #0 { 69; CHECK: Function Attrs: noinline nounwind uwtable 70; CHECK-LABEL: define {{[^@]+}}@free_in_scc2 71; CHECK-SAME: (ptr captures(none) [[TMP0:%.*]]) local_unnamed_addr #[[ATTR1]] { 72; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[TMP0]], null 73; CHECK-NEXT: br i1 [[CMP]], label [[REC:%.*]], label [[CALL:%.*]] 74; CHECK: call: 75; CHECK-NEXT: tail call void @free(ptr nonnull captures(none) [[TMP0]]) #[[ATTR0]] 76; CHECK-NEXT: br label [[END:%.*]] 77; CHECK: rec: 78; CHECK-NEXT: tail call void @free_in_scc1(ptr captures(none) [[TMP0]]) #[[ATTR0]] 79; CHECK-NEXT: br label [[END]] 80; CHECK: end: 81; CHECK-NEXT: ret void 82; 83 %cmp = icmp eq ptr %0, null 84 br i1 %cmp, label %rec, label %call 85call: 86 tail call void @free(ptr %0) #1 87 br label %end 88rec: 89 tail call void @free_in_scc1(ptr %0) 90 br label %end 91end: 92 ret void 93} 94 95 96; TEST 4 (positive case) 97; Free doesn't occur. 98; void mutual_recursion1(){ 99; mutual_recursion2(); 100; } 101; void mutual_recursion2(){ 102; mutual_recursion1(); 103; } 104 105 106define void @mutual_recursion1() #0 { 107; TUNIT: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable 108; TUNIT-LABEL: define {{[^@]+}}@mutual_recursion1 109; TUNIT-SAME: () #[[ATTR4:[0-9]+]] { 110; TUNIT-NEXT: ret void 111; 112; CGSCC: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable 113; CGSCC-LABEL: define {{[^@]+}}@mutual_recursion1 114; CGSCC-SAME: () #[[ATTR3]] { 115; CGSCC-NEXT: ret void 116; 117 call void @mutual_recursion2() 118 ret void 119} 120 121define void @mutual_recursion2() #0 { 122; TUNIT: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable 123; TUNIT-LABEL: define {{[^@]+}}@mutual_recursion2 124; TUNIT-SAME: () #[[ATTR4]] { 125; TUNIT-NEXT: ret void 126; 127; CGSCC: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable 128; CGSCC-LABEL: define {{[^@]+}}@mutual_recursion2 129; CGSCC-SAME: () #[[ATTR3]] { 130; CGSCC-NEXT: ret void 131; 132 call void @mutual_recursion1() 133 ret void 134} 135 136 137; TEST 5 138; C++ delete operation (negative case) 139; void delete_op (char p[]){ 140; delete [] p; 141; } 142 143define void @_Z9delete_opPc(ptr %0) local_unnamed_addr #0 { 144; CHECK: Function Attrs: noinline nounwind uwtable 145; CHECK-LABEL: define {{[^@]+}}@_Z9delete_opPc 146; CHECK-SAME: (ptr [[TMP0:%.*]]) local_unnamed_addr #[[ATTR1]] { 147; CHECK-NEXT: [[TMP2:%.*]] = icmp eq ptr [[TMP0]], null 148; CHECK-NEXT: br i1 [[TMP2]], label [[TMP4:%.*]], label [[TMP3:%.*]] 149; CHECK: 3: 150; CHECK-NEXT: tail call void @_ZdaPv(ptr nonnull [[TMP0]]) #[[ATTR2:[0-9]+]] 151; CHECK-NEXT: br label [[TMP4]] 152; CHECK: 4: 153; CHECK-NEXT: ret void 154; 155 %2 = icmp eq ptr %0, null 156 br i1 %2, label %4, label %3 157 158; <label>:3: ; preds = %1 159 tail call void @_ZdaPv(ptr nonnull %0) #2 160 br label %4 161 162; <label>:4: ; preds = %3, %1 163 ret void 164} 165 166 167; TEST 6 (negative case) 168; Call realloc 169define noalias ptr @call_realloc(ptr nocapture %0, i64 %1) local_unnamed_addr #0 { 170; CHECK: Function Attrs: noinline nounwind uwtable 171; CHECK-LABEL: define {{[^@]+}}@call_realloc 172; CHECK-SAME: (ptr captures(none) [[TMP0:%.*]], i64 [[TMP1:%.*]]) local_unnamed_addr #[[ATTR1]] { 173; CHECK-NEXT: [[RET:%.*]] = tail call ptr @realloc(ptr captures(none) [[TMP0]], i64 [[TMP1]]) #[[ATTR2]] 174; CHECK-NEXT: ret ptr [[RET]] 175; 176 %ret = tail call ptr @realloc(ptr %0, i64 %1) #2 177 ret ptr %ret 178} 179 180 181; TEST 7 (positive case) 182; Call function declaration with "nofree" 183 184 185; CHECK: Function Attrs: nofree noinline nounwind memory(none) uwtable 186declare void @nofree_function() nofree readnone #0 187 188define void @call_nofree_function() #0 { 189; TUNIT: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable 190; TUNIT-LABEL: define {{[^@]+}}@call_nofree_function 191; TUNIT-SAME: () #[[ATTR4]] { 192; TUNIT-NEXT: ret void 193; 194; CGSCC: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable 195; CGSCC-LABEL: define {{[^@]+}}@call_nofree_function 196; CGSCC-SAME: () #[[ATTR5:[0-9]+]] { 197; CGSCC-NEXT: ret void 198; 199 tail call void @nofree_function() 200 ret void 201} 202 203; TEST 8 (negative case) 204; Call function declaration without "nofree" 205 206 207; CHECK: Function Attrs: noinline nounwind uwtable 208declare void @maybe_free() #0 209 210 211define void @call_maybe_free() #0 { 212; CHECK: Function Attrs: noinline nounwind uwtable 213; CHECK-LABEL: define {{[^@]+}}@call_maybe_free 214; CHECK-SAME: () #[[ATTR1]] { 215; CHECK-NEXT: tail call void @maybe_free() #[[ATTR0]] 216; CHECK-NEXT: ret void 217; 218 tail call void @maybe_free() 219 ret void 220} 221 222 223; TEST 9 (negative case) 224; Call both of above functions 225 226define void @call_both() #0 { 227; CHECK: Function Attrs: noinline nounwind uwtable 228; CHECK-LABEL: define {{[^@]+}}@call_both 229; CHECK-SAME: () #[[ATTR1]] { 230; CHECK-NEXT: tail call void @maybe_free() #[[ATTR0]] 231; CHECK-NEXT: ret void 232; 233 tail call void @maybe_free() 234 tail call void @nofree_function() 235 ret void 236} 237 238 239; TEST 10 (positive case) 240; Call intrinsic function 241; CHECK: Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) 242declare float @llvm.floor.f32(float) 243 244define void @call_floor(float %a) #0 { 245; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable 246; CHECK-LABEL: define {{[^@]+}}@call_floor 247; CHECK-SAME: (float [[A:%.*]]) #[[ATTR3]] { 248; CHECK-NEXT: ret void 249; 250 tail call float @llvm.floor.f32(float %a) 251 ret void 252} 253 254define float @call_floor2(float %a) #0 { 255; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable 256; CHECK-LABEL: define {{[^@]+}}@call_floor2 257; CHECK-SAME: (float [[A:%.*]]) #[[ATTR3]] { 258; CHECK-NEXT: [[C:%.*]] = tail call nofpclass(sub) float @llvm.floor.f32(float [[A]]) #[[ATTR14:[0-9]+]] 259; CHECK-NEXT: ret float [[C]] 260; 261 %c = tail call float @llvm.floor.f32(float %a) 262 ret float %c 263} 264 265; TEST 11 (positive case) 266; Check propagation. 267 268define void @f1() #0 { 269; TUNIT: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable 270; TUNIT-LABEL: define {{[^@]+}}@f1 271; TUNIT-SAME: () #[[ATTR4]] { 272; TUNIT-NEXT: ret void 273; 274; CGSCC: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable 275; CGSCC-LABEL: define {{[^@]+}}@f1 276; CGSCC-SAME: () #[[ATTR5]] { 277; CGSCC-NEXT: ret void 278; 279 tail call void @nofree_function() 280 ret void 281} 282 283define void @f2() #0 { 284; TUNIT: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable 285; TUNIT-LABEL: define {{[^@]+}}@f2 286; TUNIT-SAME: () #[[ATTR4]] { 287; TUNIT-NEXT: ret void 288; 289; CGSCC: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable 290; CGSCC-LABEL: define {{[^@]+}}@f2 291; CGSCC-SAME: () #[[ATTR5]] { 292; CGSCC-NEXT: ret void 293; 294 tail call void @f1() 295 ret void 296} 297 298; TEST 12 NoFree argument - positive. 299define double @test12(ptr nocapture readonly %a) { 300; CHECK: Function Attrs: nofree nounwind 301; CHECK-LABEL: define {{[^@]+}}@test12 302; CHECK-SAME: (ptr nofree noundef nonnull readonly align 8 captures(none) dereferenceable(8) [[A:%.*]]) #[[ATTR7:[0-9]+]] { 303; CHECK-NEXT: entry: 304; CHECK-NEXT: [[TMP0:%.*]] = load double, ptr [[A]], align 8 305; CHECK-NEXT: [[CALL:%.*]] = tail call double @cos(double [[TMP0]]) #[[ATTR8:[0-9]+]] 306; CHECK-NEXT: ret double [[CALL]] 307; 308entry: 309 %0 = load double, ptr %a, align 8 310 %call = tail call double @cos(double %0) #2 311 ret double %call 312} 313 314declare double @cos(double) nobuiltin nounwind nofree 315 316; FIXME: %a should be nofree. 317; TEST 13 NoFree argument - positive. 318define noalias ptr @test13(ptr nocapture readonly %a) { 319; CHECK: Function Attrs: nounwind 320; CHECK-LABEL: define {{[^@]+}}@test13 321; CHECK-SAME: (ptr nofree noundef nonnull readonly align 8 captures(none) dereferenceable(8) [[A:%.*]]) #[[ATTR0]] { 322; CHECK-NEXT: entry: 323; CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr [[A]], align 8 324; CHECK-NEXT: [[CALL:%.*]] = tail call noalias ptr @malloc(i64 [[TMP0]]) #[[ATTR2]] 325; CHECK-NEXT: ret ptr [[CALL]] 326; 327entry: 328 %0 = load i64, ptr %a, align 8 329 %call = tail call noalias ptr @malloc(i64 %0) #2 330 ret ptr %call 331} 332 333define void @test14(ptr nocapture %0, ptr nocapture %1) { 334; CHECK: Function Attrs: nounwind 335; CHECK-LABEL: define {{[^@]+}}@test14 336; CHECK-SAME: (ptr captures(none) [[TMP0:%.*]], ptr nofree readnone captures(none) [[TMP1:%.*]]) #[[ATTR0]] { 337; CHECK-NEXT: tail call void @free(ptr captures(none) [[TMP0]]) #[[ATTR0]] 338; CHECK-NEXT: ret void 339; 340 tail call void @free(ptr %0) #1 341 ret void 342} 343 344; UTC_ARGS: --enable 345 346define void @nonnull_assume_pos(ptr %arg1, ptr %arg2, ptr %arg3, ptr %arg4) { 347; ATTRIBUTOR-LABEL: define {{[^@]+}}@nonnull_assume_pos 348; ATTRIBUTOR-SAME: (ptr nofree [[ARG1:%.*]], ptr [[ARG2:%.*]], ptr nofree [[ARG3:%.*]], ptr [[ARG4:%.*]]) 349; ATTRIBUTOR-NEXT: call void @llvm.assume(i1 true) #11 [ "nofree"(ptr [[ARG1]]), "nofree"(ptr [[ARG3]]) ] 350; ATTRIBUTOR-NEXT: call void @unknown(ptr nofree [[ARG1]], ptr [[ARG2]], ptr nofree [[ARG3]], ptr [[ARG4]]) 351; ATTRIBUTOR-NEXT: ret void 352; 353; CHECK-LABEL: define {{[^@]+}}@nonnull_assume_pos 354; CHECK-SAME: (ptr nofree [[ARG1:%.*]], ptr [[ARG2:%.*]], ptr nofree [[ARG3:%.*]], ptr [[ARG4:%.*]]) { 355; CHECK-NEXT: call void @llvm.assume(i1 noundef true) #[[ATTR15:[0-9]+]] [ "nofree"(ptr [[ARG1]]), "nofree"(ptr [[ARG3]]) ] 356; CHECK-NEXT: call void @unknown(ptr nofree [[ARG1]], ptr [[ARG2]], ptr nofree [[ARG3]], ptr [[ARG4]]) 357; CHECK-NEXT: ret void 358; 359 call void @llvm.assume(i1 true) ["nofree"(ptr %arg1), "nofree"(ptr %arg3)] 360 call void @unknown(ptr %arg1, ptr %arg2, ptr %arg3, ptr %arg4) 361 ret void 362} 363define void @nonnull_assume_neg(ptr %arg1, ptr %arg2, ptr %arg3, ptr %arg4) { 364; ATTRIBUTOR-LABEL: define {{[^@]+}}@nonnull_assume_neg 365; ATTRIBUTOR-SAME: (ptr [[ARG1:%.*]], ptr [[ARG2:%.*]], ptr [[ARG3:%.*]], ptr [[ARG4:%.*]]) 366; ATTRIBUTOR-NEXT: call void @unknown(ptr [[ARG1]], ptr [[ARG2]], ptr [[ARG3]], ptr [[ARG4]]) 367; ATTRIBUTOR-NEXT: call void @llvm.assume(i1 true) [ "nofree"(ptr [[ARG1]]), "nofree"(ptr [[ARG3]]) ] 368; ATTRIBUTOR-NEXT: ret void 369; 370; CHECK-LABEL: define {{[^@]+}}@nonnull_assume_neg 371; CHECK-SAME: (ptr [[ARG1:%.*]], ptr [[ARG2:%.*]], ptr [[ARG3:%.*]], ptr [[ARG4:%.*]]) { 372; CHECK-NEXT: call void @unknown(ptr [[ARG1]], ptr [[ARG2]], ptr [[ARG3]], ptr [[ARG4]]) 373; CHECK-NEXT: call void @llvm.assume(i1 noundef true) [ "nofree"(ptr [[ARG1]]), "nofree"(ptr [[ARG3]]) ] 374; CHECK-NEXT: ret void 375; 376 call void @unknown(ptr %arg1, ptr %arg2, ptr %arg3, ptr %arg4) 377 call void @llvm.assume(i1 true) ["nofree"(ptr %arg1), "nofree"(ptr %arg3)] 378 ret void 379} 380define void @nonnull_assume_call(ptr %arg1, ptr %arg2, ptr %arg3, ptr %arg4) { 381; ATTRIBUTOR-LABEL: define {{[^@]+}}@nonnull_assume_call 382; ATTRIBUTOR-SAME: (ptr [[ARG1:%.*]], ptr [[ARG2:%.*]], ptr [[ARG3:%.*]], ptr [[ARG4:%.*]]) 383; ATTRIBUTOR-NEXT: call void @unknown(ptr [[ARG1]], ptr [[ARG2]], ptr [[ARG3]], ptr [[ARG4]]) 384; ATTRIBUTOR-NEXT: call void @use_i8_ptr(ptr noalias readnone [[ARG1]]) 385; ATTRIBUTOR-NEXT: call void @use_i8_ptr(ptr noalias readnone [[ARG2]]) 386; ATTRIBUTOR-NEXT: call void @llvm.assume(i1 true) [ "nofree"(ptr [[ARG1]]), "nofree"(ptr [[ARG3]]) ] 387; ATTRIBUTOR-NEXT: call void @use_i8_ptr(ptr noalias nofree readnone [[ARG3]]) 388; ATTRIBUTOR-NEXT: call void @use_i8_ptr(ptr noalias readnone [[ARG4]]) 389; ATTRIBUTOR-NEXT: call void @use_i8_ptr_ret(ptr noalias nofree readnone [[ARG1]]) 390; ATTRIBUTOR-NEXT: call void @use_i8_ptr_ret(ptr noalias readnone [[ARG2]]) 391; ATTRIBUTOR-NEXT: call void @llvm.assume(i1 true) [ "nofree"(ptr [[ARG1]]), "nofree"(ptr [[ARG4]]) ] 392; ATTRIBUTOR-NEXT: call void @use_i8_ptr_ret(ptr noalias nofree readnone [[ARG3]]) 393; ATTRIBUTOR-NEXT: call void @use_i8_ptr_ret(ptr noalias nofree readnone [[ARG4]]) 394; ATTRIBUTOR-NEXT: ret void 395; 396; CHECK-LABEL: define {{[^@]+}}@nonnull_assume_call 397; CHECK-SAME: (ptr [[ARG1:%.*]], ptr [[ARG2:%.*]], ptr [[ARG3:%.*]], ptr [[ARG4:%.*]]) { 398; CHECK-NEXT: call void @unknown(ptr [[ARG1]], ptr [[ARG2]], ptr [[ARG3]], ptr [[ARG4]]) 399; CHECK-NEXT: call void @use_i8_ptr(ptr noalias nofree readnone captures(none) [[ARG1]]) #[[ATTR0]] 400; CHECK-NEXT: call void @use_i8_ptr(ptr noalias nofree readnone captures(none) [[ARG2]]) #[[ATTR0]] 401; CHECK-NEXT: call void @llvm.assume(i1 noundef true) [ "nofree"(ptr [[ARG1]]), "nofree"(ptr [[ARG3]]) ] 402; CHECK-NEXT: call void @use_i8_ptr(ptr noalias nofree readnone captures(none) [[ARG3]]) #[[ATTR0]] 403; CHECK-NEXT: call void @use_i8_ptr(ptr noalias nofree readnone captures(none) [[ARG4]]) #[[ATTR0]] 404; CHECK-NEXT: call void @use_i8_ptr_ret(ptr noalias nofree readnone captures(none) [[ARG1]]) #[[ATTR0]] 405; CHECK-NEXT: call void @use_i8_ptr_ret(ptr noalias nofree readnone captures(none) [[ARG2]]) #[[ATTR0]] 406; CHECK-NEXT: call void @llvm.assume(i1 noundef true) [ "nofree"(ptr [[ARG1]]), "nofree"(ptr [[ARG4]]) ] 407; CHECK-NEXT: call void @use_i8_ptr_ret(ptr noalias nofree readnone captures(none) [[ARG3]]) #[[ATTR0]] 408; CHECK-NEXT: call void @use_i8_ptr_ret(ptr noalias nofree readnone captures(none) [[ARG4]]) #[[ATTR0]] 409; CHECK-NEXT: ret void 410; 411 call void @unknown(ptr %arg1, ptr %arg2, ptr %arg3, ptr %arg4) 412 call void @use_i8_ptr(ptr %arg1) 413 call void @use_i8_ptr(ptr %arg2) 414 call void @llvm.assume(i1 true) ["nofree"(ptr %arg1), "nofree"(ptr %arg3)] 415 call void @use_i8_ptr(ptr %arg3) 416 call void @use_i8_ptr(ptr %arg4) 417 call void @use_i8_ptr_ret(ptr %arg1) 418 call void @use_i8_ptr_ret(ptr %arg2) 419 call void @llvm.assume(i1 true) ["nofree"(ptr %arg1), "nofree"(ptr %arg4)] 420 call void @use_i8_ptr_ret(ptr %arg3) 421 call void @use_i8_ptr_ret(ptr %arg4) 422 ret void 423} 424 425; FIXME: function is nofree 426define weak void @implied_nofree1() readnone { 427; CHECK: Function Attrs: nosync memory(none) 428; CHECK-LABEL: define {{[^@]+}}@implied_nofree1 429; CHECK-SAME: () #[[ATTR9:[0-9]+]] { 430; CHECK-NEXT: ret void 431; 432 ret void 433} 434; FIXME: function is nofree 435define weak void @implied_nofree2() readonly { 436; CHECK: Function Attrs: nosync memory(read) 437; CHECK-LABEL: define {{[^@]+}}@implied_nofree2 438; CHECK-SAME: () #[[ATTR10:[0-9]+]] { 439; CHECK-NEXT: ret void 440; 441 ret void 442} 443define weak void @implied_nofree3(ptr readnone %a) { 444; CHECK-LABEL: define {{[^@]+}}@implied_nofree3 445; CHECK-SAME: (ptr nofree readnone [[A:%.*]]) { 446; CHECK-NEXT: ret void 447; 448 ret void 449} 450define weak void @implied_nofree4(ptr readonly %a) { 451; CHECK-LABEL: define {{[^@]+}}@implied_nofree4 452; CHECK-SAME: (ptr nofree readonly [[A:%.*]]) { 453; CHECK-NEXT: ret void 454; 455 ret void 456} 457; FIXME: %a is nofree 458define weak void @implied_nofree5(ptr %a) readonly { 459; CHECK: Function Attrs: nosync memory(read) 460; CHECK-LABEL: define {{[^@]+}}@implied_nofree5 461; CHECK-SAME: (ptr [[A:%.*]]) #[[ATTR10]] { 462; CHECK-NEXT: ret void 463; 464 ret void 465} 466define weak void @implied_nofree6(ptr %a) nofree { 467; CHECK: Function Attrs: nofree 468; CHECK-LABEL: define {{[^@]+}}@implied_nofree6 469; CHECK-SAME: (ptr nofree [[A:%.*]]) #[[ATTR11:[0-9]+]] { 470; CHECK-NEXT: ret void 471; 472 ret void 473} 474 475declare void @llvm.assume(i1) 476declare void @unknown(ptr, ptr, ptr, ptr) 477declare void @use_i8_ptr(ptr nocapture readnone) nounwind 478declare void @use_i8_ptr_ret(ptr nocapture readnone) nounwind willreturn 479 480declare noalias ptr @malloc(i64) 481 482attributes #0 = { nounwind uwtable noinline } 483attributes #1 = { nounwind } 484attributes #2 = { nobuiltin nounwind } 485;. 486; TUNIT: attributes #[[ATTR0]] = { nounwind } 487; TUNIT: attributes #[[ATTR1]] = { noinline nounwind uwtable } 488; TUNIT: attributes #[[ATTR2]] = { nobuiltin nounwind } 489; TUNIT: attributes #[[ATTR3]] = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable } 490; TUNIT: attributes #[[ATTR4]] = { mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable } 491; TUNIT: attributes #[[ATTR5:[0-9]+]] = { nofree noinline nounwind memory(none) uwtable } 492; TUNIT: attributes #[[ATTR6:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } 493; TUNIT: attributes #[[ATTR7]] = { nofree nounwind } 494; TUNIT: attributes #[[ATTR8]] = { nobuiltin nofree nounwind } 495; TUNIT: attributes #[[ATTR9]] = { nosync memory(none) } 496; TUNIT: attributes #[[ATTR10]] = { nosync memory(read) } 497; TUNIT: attributes #[[ATTR11]] = { nofree } 498; TUNIT: attributes #[[ATTR12:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: write) } 499; TUNIT: attributes #[[ATTR13:[0-9]+]] = { nounwind willreturn } 500; TUNIT: attributes #[[ATTR14]] = { nofree nosync willreturn } 501; TUNIT: attributes #[[ATTR15]] = { nofree willreturn memory(write) } 502;. 503; CGSCC: attributes #[[ATTR0]] = { nounwind } 504; CGSCC: attributes #[[ATTR1]] = { noinline nounwind uwtable } 505; CGSCC: attributes #[[ATTR2]] = { nobuiltin nounwind } 506; CGSCC: attributes #[[ATTR3]] = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable } 507; CGSCC: attributes #[[ATTR4:[0-9]+]] = { nofree noinline nounwind memory(none) uwtable } 508; CGSCC: attributes #[[ATTR5]] = { mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable } 509; CGSCC: attributes #[[ATTR6:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } 510; CGSCC: attributes #[[ATTR7]] = { nofree nounwind } 511; CGSCC: attributes #[[ATTR8]] = { nobuiltin nofree nounwind } 512; CGSCC: attributes #[[ATTR9]] = { nosync memory(none) } 513; CGSCC: attributes #[[ATTR10]] = { nosync memory(read) } 514; CGSCC: attributes #[[ATTR11]] = { nofree } 515; CGSCC: attributes #[[ATTR12:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: write) } 516; CGSCC: attributes #[[ATTR13:[0-9]+]] = { nounwind willreturn } 517; CGSCC: attributes #[[ATTR14]] = { nofree nosync willreturn } 518; CGSCC: attributes #[[ATTR15]] = { nofree willreturn memory(write) } 519;. 520