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 4target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" 5 6; Test cases designed for the nosync function attribute. 7; FIXME's are used to indicate problems and missing attributes. 8 9; struct RT { 10; char A; 11; int B[10][20]; 12; char C; 13; }; 14; struct ST { 15; int X; 16; double Y; 17; struct RT Z; 18; }; 19; 20; int *foo(struct ST *s) { 21; return &s[1].Z.B[5][13]; 22; } 23 24; TEST 1 25; non-convergent and readnone implies nosync 26%struct.RT = type { i8, [10 x [20 x i32]], i8 } 27%struct.ST = type { i32, double, %struct.RT } 28 29;. 30; CHECK: @a = common global i32 0, align 4 31;. 32define ptr @foo(ptr %s) nounwind optsize ssp memory(none) uwtable { 33; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind optsize ssp willreturn memory(none) uwtable 34; CHECK-LABEL: define {{[^@]+}}@foo 35; CHECK-SAME: (ptr nofree readnone "no-capture-maybe-returned" [[S:%.*]]) #[[ATTR0:[0-9]+]] { 36; CHECK-NEXT: entry: 37; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [[STRUCT_ST:%.*]], ptr [[S]], i64 1, i32 2, i32 1, i64 5, i64 13 38; CHECK-NEXT: ret ptr [[ARRAYIDX]] 39; 40entry: 41 %arrayidx = getelementptr inbounds %struct.ST, ptr %s, i64 1, i32 2, i32 1, i64 5, i64 13 42 ret ptr %arrayidx 43} 44 45; TEST 2 46; atomic load with monotonic ordering 47; int load_monotonic(_Atomic int *num) { 48; int n = atomic_load_explicit(num, memory_order_relaxed); 49; return n; 50; } 51 52define i32 @load_monotonic(ptr nocapture readonly %arg) norecurse nounwind uwtable { 53; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) uwtable 54; CHECK-LABEL: define {{[^@]+}}@load_monotonic 55; CHECK-SAME: (ptr nofree noundef nonnull readonly align 4 captures(none) dereferenceable(4) [[ARG:%.*]]) #[[ATTR1:[0-9]+]] { 56; CHECK-NEXT: [[I:%.*]] = load atomic i32, ptr [[ARG]] monotonic, align 4 57; CHECK-NEXT: ret i32 [[I]] 58; 59 %i = load atomic i32, ptr %arg monotonic, align 4 60 ret i32 %i 61} 62 63 64; TEST 3 65; atomic store with monotonic ordering. 66; void store_monotonic(_Atomic int *num) { 67; atomic_load_explicit(num, memory_order_relaxed); 68; } 69 70define void @store_monotonic(ptr nocapture %arg) norecurse nounwind uwtable { 71; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) uwtable 72; CHECK-LABEL: define {{[^@]+}}@store_monotonic 73; CHECK-SAME: (ptr nofree noundef nonnull writeonly align 4 captures(none) dereferenceable(4) [[ARG:%.*]]) #[[ATTR1]] { 74; CHECK-NEXT: store atomic i32 10, ptr [[ARG]] monotonic, align 4 75; CHECK-NEXT: ret void 76; 77 store atomic i32 10, ptr %arg monotonic, align 4 78 ret void 79} 80 81; TEST 4 - negative, should not deduce nosync 82; atomic load with acquire ordering. 83; int load_acquire(_Atomic int *num) { 84; int n = atomic_load_explicit(num, memory_order_acquire); 85; return n; 86; } 87 88define i32 @load_acquire(ptr nocapture readonly %arg) norecurse nounwind uwtable { 89; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) uwtable 90; CHECK-LABEL: define {{[^@]+}}@load_acquire 91; CHECK-SAME: (ptr nofree noundef nonnull readonly align 4 captures(none) dereferenceable(4) [[ARG:%.*]]) #[[ATTR2:[0-9]+]] { 92; CHECK-NEXT: [[I:%.*]] = load atomic i32, ptr [[ARG]] acquire, align 4 93; CHECK-NEXT: ret i32 [[I]] 94; 95 %i = load atomic i32, ptr %arg acquire, align 4 96 ret i32 %i 97} 98 99; TEST 5 - negative, should not deduce nosync 100; atomic load with release ordering 101; void load_release(_Atomic int *num) { 102; atomic_store_explicit(num, 10, memory_order_release); 103; } 104 105define void @load_release(ptr nocapture %arg) norecurse nounwind uwtable { 106; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) uwtable 107; CHECK-LABEL: define {{[^@]+}}@load_release 108; CHECK-SAME: (ptr nofree noundef writeonly align 4 captures(none) [[ARG:%.*]]) #[[ATTR2]] { 109; CHECK-NEXT: store atomic volatile i32 10, ptr [[ARG]] release, align 4 110; CHECK-NEXT: ret void 111; 112 store atomic volatile i32 10, ptr %arg release, align 4 113 ret void 114} 115 116; TEST 6 - negative volatile, relaxed atomic 117 118define void @load_volatile_release(ptr nocapture %arg) norecurse nounwind uwtable { 119; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) uwtable 120; CHECK-LABEL: define {{[^@]+}}@load_volatile_release 121; CHECK-SAME: (ptr nofree noundef writeonly align 4 captures(none) [[ARG:%.*]]) #[[ATTR2]] { 122; CHECK-NEXT: store atomic volatile i32 10, ptr [[ARG]] release, align 4 123; CHECK-NEXT: ret void 124; 125 store atomic volatile i32 10, ptr %arg release, align 4 126 ret void 127} 128 129; TEST 7 - negative, should not deduce nosync 130; volatile store. 131; void volatile_store(volatile int *num) { 132; *num = 14; 133; } 134 135define void @volatile_store(ptr %arg) norecurse nounwind uwtable { 136; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) uwtable 137; CHECK-LABEL: define {{[^@]+}}@volatile_store 138; CHECK-SAME: (ptr nofree noundef align 4 [[ARG:%.*]]) #[[ATTR2]] { 139; CHECK-NEXT: store volatile i32 14, ptr [[ARG]], align 4 140; CHECK-NEXT: ret void 141; 142 store volatile i32 14, ptr %arg, align 4 143 ret void 144} 145 146; TEST 8 - negative, should not deduce nosync 147; volatile load. 148; int volatile_load(volatile int *num) { 149; int n = *num; 150; return n; 151; } 152 153define i32 @volatile_load(ptr %arg) norecurse nounwind uwtable { 154; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) uwtable 155; CHECK-LABEL: define {{[^@]+}}@volatile_load 156; CHECK-SAME: (ptr nofree noundef align 4 [[ARG:%.*]]) #[[ATTR2]] { 157; CHECK-NEXT: [[I:%.*]] = load volatile i32, ptr [[ARG]], align 4 158; CHECK-NEXT: ret i32 [[I]] 159; 160 %i = load volatile i32, ptr %arg, align 4 161 ret i32 %i 162} 163 164; TEST 9 165 166; CHECK: Function Attrs: noinline nosync nounwind uwtable 167declare void @nosync_function() noinline nounwind uwtable nosync 168 169define void @call_nosync_function() noinline nounwind uwtable { 170; CHECK: Function Attrs: noinline nosync nounwind uwtable 171; CHECK-LABEL: define {{[^@]+}}@call_nosync_function 172; CHECK-SAME: () #[[ATTR3:[0-9]+]] { 173; CHECK-NEXT: tail call void @nosync_function() #[[ATTR4:[0-9]+]] 174; CHECK-NEXT: ret void 175; 176 tail call void @nosync_function() noinline nounwind uwtable 177 ret void 178} 179 180; TEST 10 - negative, should not deduce nosync 181 182; CHECK: Function Attrs: noinline nounwind uwtable 183declare void @might_sync() noinline nounwind uwtable 184 185define void @call_might_sync() noinline nounwind uwtable { 186; CHECK: Function Attrs: noinline nounwind uwtable 187; CHECK-LABEL: define {{[^@]+}}@call_might_sync 188; CHECK-SAME: () #[[ATTR4]] { 189; CHECK-NEXT: tail call void @might_sync() #[[ATTR4]] 190; CHECK-NEXT: ret void 191; 192 tail call void @might_sync() noinline nounwind uwtable 193 ret void 194} 195 196; TEST 11 - positive, should deduce nosync 197; volatile operation in same scc but dead. Call volatile_load defined in TEST 8. 198 199define i32 @scc1(ptr %arg) noinline nounwind uwtable { 200; CHECK: Function Attrs: nofree noinline nounwind memory(argmem: readwrite) uwtable 201; CHECK-LABEL: define {{[^@]+}}@scc1 202; CHECK-SAME: (ptr nofree [[ARG:%.*]]) #[[ATTR5:[0-9]+]] { 203; CHECK-NEXT: tail call void @scc2(ptr nofree [[ARG]]) #[[ATTR20:[0-9]+]] 204; CHECK-NEXT: [[VAL:%.*]] = tail call i32 @volatile_load(ptr nofree noundef align 4 [[ARG]]) #[[ATTR20]] 205; CHECK-NEXT: ret i32 [[VAL]] 206; 207 tail call void @scc2(ptr %arg) 208 %val = tail call i32 @volatile_load(ptr %arg) 209 ret i32 %val 210} 211 212define void @scc2(ptr %arg) noinline nounwind uwtable { 213; CHECK: Function Attrs: nofree noinline nounwind memory(argmem: readwrite) uwtable 214; CHECK-LABEL: define {{[^@]+}}@scc2 215; CHECK-SAME: (ptr nofree [[ARG:%.*]]) #[[ATTR5]] { 216; CHECK-NEXT: [[I:%.*]] = tail call i32 @scc1(ptr nofree [[ARG]]) #[[ATTR20]] 217; CHECK-NEXT: ret void 218; 219 %i = tail call i32 @scc1(ptr %arg) 220 ret void 221} 222 223; TEST 12 - fences, negative 224; 225; void foo1(int *a, std::atomic<bool> flag){ 226; *a = 100; 227; atomic_thread_fence(std::memory_order_release); 228; flag.store(true, std::memory_order_relaxed); 229; } 230; 231; void bar(int *a, std::atomic<bool> flag){ 232; while(!flag.load(std::memory_order_relaxed)) 233; ; 234; 235; atomic_thread_fence(std::memory_order_acquire); 236; int b = *a; 237; } 238 239%"struct.std::atomic" = type { %"struct.std::__atomic_base" } 240%"struct.std::__atomic_base" = type { i8 } 241 242define void @foo1(ptr %arg, ptr %arg1) { 243; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn 244; CHECK-LABEL: define {{[^@]+}}@foo1 245; CHECK-SAME: (ptr nofree noundef nonnull writeonly align 4 captures(none) dereferenceable(4) [[ARG:%.*]], ptr nofree noundef nonnull writeonly captures(none) dereferenceable(1) [[ARG1:%.*]]) #[[ATTR6:[0-9]+]] { 246; CHECK-NEXT: store i32 100, ptr [[ARG]], align 4 247; CHECK-NEXT: fence release 248; CHECK-NEXT: store atomic i8 1, ptr [[ARG1]] monotonic, align 1 249; CHECK-NEXT: ret void 250; 251 store i32 100, ptr %arg, align 4 252 fence release 253 store atomic i8 1, ptr %arg1 monotonic, align 1 254 ret void 255} 256 257define void @bar(ptr %arg, ptr %arg1) { 258; CHECK: Function Attrs: nofree norecurse nounwind 259; CHECK-LABEL: define {{[^@]+}}@bar 260; CHECK-SAME: (ptr nofree readnone captures(none) [[ARG:%.*]], ptr nofree nonnull readonly captures(none) dereferenceable(1) [[ARG1:%.*]]) #[[ATTR7:[0-9]+]] { 261; CHECK-NEXT: br label [[BB2:%.*]] 262; CHECK: bb2: 263; CHECK-NEXT: [[I3:%.*]] = load atomic i8, ptr [[ARG1]] monotonic, align 1 264; CHECK-NEXT: [[I4:%.*]] = and i8 [[I3]], 1 265; CHECK-NEXT: [[I5:%.*]] = icmp eq i8 [[I4]], 0 266; CHECK-NEXT: br i1 [[I5]], label [[BB2]], label [[BB6:%.*]] 267; CHECK: bb6: 268; CHECK-NEXT: fence acquire 269; CHECK-NEXT: ret void 270; 271 br label %bb2 272 273bb2: 274 %i3 = load atomic i8, ptr %arg1 monotonic, align 1 275 %i4 = and i8 %i3, 1 276 %i5 = icmp eq i8 %i4, 0 277 br i1 %i5, label %bb2, label %bb6 278 279bb6: 280 fence acquire 281 ret void 282} 283 284; TEST 13 - Fence syncscope("singlethread") seq_cst 285define void @foo1_singlethread(ptr %arg, ptr %arg1) { 286; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn 287; CHECK-LABEL: define {{[^@]+}}@foo1_singlethread 288; CHECK-SAME: (ptr nofree noundef nonnull writeonly align 4 captures(none) dereferenceable(4) [[ARG:%.*]], ptr nofree noundef nonnull writeonly captures(none) dereferenceable(1) [[ARG1:%.*]]) #[[ATTR8:[0-9]+]] { 289; CHECK-NEXT: store i32 100, ptr [[ARG]], align 4 290; CHECK-NEXT: fence syncscope("singlethread") release 291; CHECK-NEXT: store atomic i8 1, ptr [[ARG1]] monotonic, align 1 292; CHECK-NEXT: ret void 293; 294 store i32 100, ptr %arg, align 4 295 fence syncscope("singlethread") release 296 store atomic i8 1, ptr %arg1 monotonic, align 1 297 ret void 298} 299 300define void @bar_singlethread(ptr %arg, ptr %arg1) { 301; CHECK: Function Attrs: nofree norecurse nosync nounwind 302; CHECK-LABEL: define {{[^@]+}}@bar_singlethread 303; CHECK-SAME: (ptr nofree readnone captures(none) [[ARG:%.*]], ptr nofree nonnull readonly captures(none) dereferenceable(1) [[ARG1:%.*]]) #[[ATTR9:[0-9]+]] { 304; CHECK-NEXT: br label [[BB2:%.*]] 305; CHECK: bb2: 306; CHECK-NEXT: [[I3:%.*]] = load atomic i8, ptr [[ARG1]] monotonic, align 1 307; CHECK-NEXT: [[I4:%.*]] = and i8 [[I3]], 1 308; CHECK-NEXT: [[I5:%.*]] = icmp eq i8 [[I4]], 0 309; CHECK-NEXT: br i1 [[I5]], label [[BB2]], label [[BB6:%.*]] 310; CHECK: bb6: 311; CHECK-NEXT: fence syncscope("singlethread") acquire 312; CHECK-NEXT: ret void 313; 314 br label %bb2 315 316bb2: 317 %i3 = load atomic i8, ptr %arg1 monotonic, align 1 318 %i4 = and i8 %i3, 1 319 %i5 = icmp eq i8 %i4, 0 320 br i1 %i5, label %bb2, label %bb6 321 322bb6: 323 fence syncscope("singlethread") acquire 324 ret void 325} 326 327declare void @llvm.memcpy.p0.p0.i32(ptr %dest, ptr %src, i32 %len, i1 %isvolatile) 328declare void @llvm.memset.p0.i32(ptr %dest, i8 %val, i32 %len, i1 %isvolatile) 329 330; TEST 14 - negative, checking volatile intrinsics. 331 332; It is odd to add nocapture but a result of the llvm.memcpy nocapture. 333; 334define i32 @memcpy_volatile(ptr %ptr1, ptr %ptr2) { 335; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) 336; CHECK-LABEL: define {{[^@]+}}@memcpy_volatile 337; CHECK-SAME: (ptr nofree writeonly captures(none) [[PTR1:%.*]], ptr nofree readonly captures(none) [[PTR2:%.*]]) #[[ATTR12:[0-9]+]] { 338; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr nofree writeonly captures(none) [[PTR1]], ptr nofree readonly captures(none) [[PTR2]], i32 noundef 8, i1 noundef true) #[[ATTR21:[0-9]+]] 339; CHECK-NEXT: ret i32 4 340; 341 call void @llvm.memcpy.p0.p0.i32(ptr %ptr1, ptr %ptr2, i32 8, i1 true) 342 ret i32 4 343} 344 345; TEST 15 - positive, non-volatile intrinsic. 346 347; It is odd to add nocapture but a result of the llvm.memset nocapture. 348; 349define i32 @memset_non_volatile(ptr %ptr1, i8 %val) { 350; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) 351; CHECK-LABEL: define {{[^@]+}}@memset_non_volatile 352; CHECK-SAME: (ptr nofree writeonly captures(none) [[PTR1:%.*]], i8 [[VAL:%.*]]) #[[ATTR13:[0-9]+]] { 353; CHECK-NEXT: call void @llvm.memset.p0.i32(ptr nofree writeonly captures(none) [[PTR1]], i8 [[VAL]], i32 noundef 8, i1 noundef false) #[[ATTR22:[0-9]+]] 354; CHECK-NEXT: ret i32 4 355; 356 call void @llvm.memset.p0.i32(ptr %ptr1, i8 %val, i32 8, i1 false) 357 ret i32 4 358} 359 360; TEST 16 - negative, inline assembly. 361 362define i32 @inline_asm_test(i32 %x) { 363; CHECK-LABEL: define {{[^@]+}}@inline_asm_test 364; CHECK-SAME: (i32 [[X:%.*]]) { 365; CHECK-NEXT: [[I:%.*]] = call i32 asm sideeffect "bswap $0", "=r,r"(i32 [[X]]) 366; CHECK-NEXT: ret i32 4 367; 368 %i = call i32 asm sideeffect "bswap $0", "=r,r"(i32 %x) 369 ret i32 4 370} 371 372declare void @readnone_test() convergent readnone 373 374; TEST 17 - negative. Convergent 375define void @convergent_readnone() { 376; CHECK: Function Attrs: memory(none) 377; CHECK-LABEL: define {{[^@]+}}@convergent_readnone 378; CHECK-SAME: () #[[ATTR15:[0-9]+]] { 379; CHECK-NEXT: call void @readnone_test() 380; CHECK-NEXT: ret void 381; 382 call void @readnone_test() 383 ret void 384} 385 386; CHECK: Function Attrs: nounwind 387declare void @llvm.x86.sse2.clflush(ptr) 388@a = common global i32 0, align 4 389 390; TEST 18 - negative. Synchronizing intrinsic 391 392define void @i_totally_sync() { 393; CHECK: Function Attrs: nounwind 394; CHECK-LABEL: define {{[^@]+}}@i_totally_sync 395; CHECK-SAME: () #[[ATTR16:[0-9]+]] { 396; CHECK-NEXT: tail call void @llvm.x86.sse2.clflush(ptr noundef nonnull align 4 dereferenceable(4) @a) 397; CHECK-NEXT: ret void 398; 399 tail call void @llvm.x86.sse2.clflush(ptr @a) 400 ret void 401} 402 403declare float @llvm.cos.f32(float %val) readnone 404 405; TEST 19 - positive, readnone & non-convergent intrinsic. 406 407define i32 @cos_test(float %x) { 408; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 409; CHECK-LABEL: define {{[^@]+}}@cos_test 410; CHECK-SAME: (float [[X:%.*]]) #[[ATTR18:[0-9]+]] { 411; CHECK-NEXT: ret i32 4 412; 413 %i = call float @llvm.cos.f32(float %x) 414 ret i32 4 415} 416 417define float @cos_test2(float %x) { 418; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 419; CHECK-LABEL: define {{[^@]+}}@cos_test2 420; CHECK-SAME: (float [[X:%.*]]) #[[ATTR18]] { 421; CHECK-NEXT: [[C:%.*]] = call nofpclass(inf) float @llvm.cos.f32(float [[X]]) #[[ATTR23:[0-9]+]] 422; CHECK-NEXT: ret float [[C]] 423; 424 %c = call float @llvm.cos.f32(float %x) 425 ret float %c 426} 427 428declare void @unknown() 429define void @nosync_convergent_callee_test() { 430; CHECK: Function Attrs: nosync memory(none) 431; CHECK-LABEL: define {{[^@]+}}@nosync_convergent_callee_test 432; CHECK-SAME: () #[[ATTR19:[0-9]+]] { 433; CHECK-NEXT: call void @unknown() #[[ATTR24:[0-9]+]] 434; CHECK-NEXT: ret void 435; 436 call void @unknown() nosync convergent readnone 437 ret void 438} 439;. 440; CHECK: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind optsize ssp willreturn memory(none) uwtable } 441; CHECK: attributes #[[ATTR1]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) uwtable } 442; CHECK: attributes #[[ATTR2]] = { mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) uwtable } 443; CHECK: attributes #[[ATTR3]] = { noinline nosync nounwind uwtable } 444; CHECK: attributes #[[ATTR4]] = { noinline nounwind uwtable } 445; CHECK: attributes #[[ATTR5]] = { nofree noinline nounwind memory(argmem: readwrite) uwtable } 446; CHECK: attributes #[[ATTR6]] = { mustprogress nofree norecurse nounwind willreturn } 447; CHECK: attributes #[[ATTR7]] = { nofree norecurse nounwind } 448; CHECK: attributes #[[ATTR8]] = { mustprogress nofree norecurse nosync nounwind willreturn } 449; CHECK: attributes #[[ATTR9]] = { nofree norecurse nosync nounwind } 450; CHECK: attributes #[[ATTR10:[0-9]+]] = { nocallback nofree nounwind willreturn memory(argmem: readwrite) } 451; CHECK: attributes #[[ATTR11:[0-9]+]] = { nocallback nofree nounwind willreturn memory(argmem: write) } 452; CHECK: attributes #[[ATTR12]] = { mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) } 453; CHECK: attributes #[[ATTR13]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) } 454; CHECK: attributes #[[ATTR14:[0-9]+]] = { convergent memory(none) } 455; CHECK: attributes #[[ATTR15]] = { memory(none) } 456; CHECK: attributes #[[ATTR16]] = { nounwind } 457; CHECK: attributes #[[ATTR17:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } 458; CHECK: attributes #[[ATTR18]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) } 459; CHECK: attributes #[[ATTR19]] = { nosync memory(none) } 460; CHECK: attributes #[[ATTR20]] = { nofree nounwind } 461; CHECK: attributes #[[ATTR21]] = { nofree willreturn } 462; CHECK: attributes #[[ATTR22]] = { nofree willreturn memory(write) } 463; CHECK: attributes #[[ATTR23]] = { nofree nosync willreturn } 464; CHECK: attributes #[[ATTR24]] = { convergent nosync memory(none) } 465;. 466;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: 467; CGSCC: {{.*}} 468; TUNIT: {{.*}} 469