1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-attributes 2; RUN: opt < %s -passes=function-attrs -S | FileCheck %s 3 4target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" 5 6; Base case, empty function 7define void @test1() { 8; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 9; CHECK-LABEL: @test1( 10; CHECK-NEXT: ret void 11; 12 ret void 13} 14 15; Show the bottom up walk 16define void @test2() { 17; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 18; CHECK-LABEL: @test2( 19; CHECK-NEXT: call void @test1() 20; CHECK-NEXT: ret void 21; 22 call void @test1() 23 ret void 24} 25 26declare void @unknown() convergent 27 28; Negative case with convergent function 29define void @test3() convergent { 30; CHECK: Function Attrs: convergent 31; CHECK-LABEL: @test3( 32; CHECK-NEXT: call void @unknown() 33; CHECK-NEXT: ret void 34; 35 call void @unknown() 36 ret void 37} 38 39define i32 @test4(i32 %a, i32 %b) { 40; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 41; CHECK-LABEL: @test4( 42; CHECK-NEXT: [[ADD:%.*]] = add i32 [[A:%.*]], [[B:%.*]] 43; CHECK-NEXT: ret i32 [[A]] 44; 45 %add = add i32 %a, %b 46 ret i32 %a 47} 48 49; negative case - explicit sync 50define void @test5(ptr %p) { 51; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) 52; CHECK-LABEL: @test5( 53; CHECK-NEXT: store atomic i8 0, ptr [[P:%.*]] seq_cst, align 1 54; CHECK-NEXT: ret void 55; 56 store atomic i8 0, ptr %p seq_cst, align 1 57 ret void 58} 59 60; negative case - explicit sync 61define i8 @test6(ptr %p) { 62; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) 63; CHECK-LABEL: @test6( 64; CHECK-NEXT: [[V:%.*]] = load atomic i8, ptr [[P:%.*]] seq_cst, align 1 65; CHECK-NEXT: ret i8 [[V]] 66; 67 %v = load atomic i8, ptr %p seq_cst, align 1 68 ret i8 %v 69} 70 71; negative case - explicit sync 72define void @test7(ptr %p) { 73; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) 74; CHECK-LABEL: @test7( 75; CHECK-NEXT: [[TMP1:%.*]] = atomicrmw add ptr [[P:%.*]], i8 0 seq_cst, align 1 76; CHECK-NEXT: ret void 77; 78 atomicrmw add ptr %p, i8 0 seq_cst, align 1 79 ret void 80} 81 82; negative case - explicit sync 83define void @test8(ptr %p) { 84; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn 85; CHECK-LABEL: @test8( 86; CHECK-NEXT: fence seq_cst 87; CHECK-NEXT: ret void 88; 89 fence seq_cst 90 ret void 91} 92 93; singlethread fences are okay 94define void @test9(ptr %p) { 95; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn 96; CHECK-LABEL: @test9( 97; CHECK-NEXT: fence syncscope("singlethread") seq_cst 98; CHECK-NEXT: ret void 99; 100 fence syncscope("singlethread") seq_cst 101 ret void 102} 103 104; atomic load with monotonic ordering 105define i32 @load_monotonic(ptr nocapture readonly %0) norecurse nounwind uwtable { 106; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) uwtable 107; CHECK-LABEL: @load_monotonic( 108; CHECK-NEXT: [[TMP2:%.*]] = load atomic i32, ptr [[TMP0:%.*]] monotonic, align 4 109; CHECK-NEXT: ret i32 [[TMP2]] 110; 111 %2 = load atomic i32, ptr %0 monotonic, align 4 112 ret i32 %2 113} 114 115; atomic store with monotonic ordering. 116define void @store_monotonic(ptr nocapture %0) norecurse nounwind uwtable { 117; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) uwtable 118; CHECK-LABEL: @store_monotonic( 119; CHECK-NEXT: store atomic i32 10, ptr [[TMP0:%.*]] monotonic, align 4 120; CHECK-NEXT: ret void 121; 122 store atomic i32 10, ptr %0 monotonic, align 4 123 ret void 124} 125 126; negative, should not deduce nosync 127; atomic load with acquire ordering. 128define i32 @load_acquire(ptr nocapture readonly %0) norecurse nounwind uwtable { 129; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) uwtable 130; CHECK-LABEL: @load_acquire( 131; CHECK-NEXT: [[TMP2:%.*]] = load atomic i32, ptr [[TMP0:%.*]] acquire, align 4 132; CHECK-NEXT: ret i32 [[TMP2]] 133; 134 %2 = load atomic i32, ptr %0 acquire, align 4 135 ret i32 %2 136} 137 138define i32 @load_unordered(ptr nocapture readonly %0) norecurse nounwind uwtable { 139; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) uwtable 140; CHECK-LABEL: @load_unordered( 141; CHECK-NEXT: [[TMP2:%.*]] = load atomic i32, ptr [[TMP0:%.*]] unordered, align 4 142; CHECK-NEXT: ret i32 [[TMP2]] 143; 144 %2 = load atomic i32, ptr %0 unordered, align 4 145 ret i32 %2 146} 147 148; atomic store with unordered ordering. 149define void @store_unordered(ptr nocapture %0) norecurse nounwind uwtable { 150; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) uwtable 151; CHECK-LABEL: @store_unordered( 152; CHECK-NEXT: store atomic i32 10, ptr [[TMP0:%.*]] unordered, align 4 153; CHECK-NEXT: ret void 154; 155 store atomic i32 10, ptr %0 unordered, align 4 156 ret void 157} 158 159 160; negative, should not deduce nosync 161; atomic load with release ordering 162define void @load_release(ptr nocapture %0) norecurse nounwind uwtable { 163; CHECK: Function Attrs: nofree norecurse nounwind memory(argmem: readwrite, inaccessiblemem: readwrite) uwtable 164; CHECK-LABEL: @load_release( 165; CHECK-NEXT: store atomic volatile i32 10, ptr [[TMP0:%.*]] release, align 4 166; CHECK-NEXT: ret void 167; 168 store atomic volatile i32 10, ptr %0 release, align 4 169 ret void 170} 171 172; negative volatile, relaxed atomic 173define void @load_volatile_release(ptr nocapture %0) norecurse nounwind uwtable { 174; CHECK: Function Attrs: nofree norecurse nounwind memory(argmem: readwrite, inaccessiblemem: readwrite) uwtable 175; CHECK-LABEL: @load_volatile_release( 176; CHECK-NEXT: store atomic volatile i32 10, ptr [[TMP0:%.*]] release, align 4 177; CHECK-NEXT: ret void 178; 179 store atomic volatile i32 10, ptr %0 release, align 4 180 ret void 181} 182 183; volatile store. 184define void @volatile_store(ptr %0) norecurse nounwind uwtable { 185; CHECK: Function Attrs: nofree norecurse nounwind memory(argmem: readwrite, inaccessiblemem: readwrite) uwtable 186; CHECK-LABEL: @volatile_store( 187; CHECK-NEXT: store volatile i32 14, ptr [[TMP0:%.*]], align 4 188; CHECK-NEXT: ret void 189; 190 store volatile i32 14, ptr %0, align 4 191 ret void 192} 193 194; negative, should not deduce nosync 195; volatile load. 196define i32 @volatile_load(ptr %0) norecurse nounwind uwtable { 197; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite, inaccessiblemem: readwrite) uwtable 198; CHECK-LABEL: @volatile_load( 199; CHECK-NEXT: [[TMP2:%.*]] = load volatile i32, ptr [[TMP0:%.*]], align 4 200; CHECK-NEXT: ret i32 [[TMP2]] 201; 202 %2 = load volatile i32, ptr %0, align 4 203 ret i32 %2 204} 205 206; CHECK: Function Attrs: noinline nosync nounwind uwtable 207; CHECK-NEXT: declare void @nosync_function() 208declare void @nosync_function() noinline nounwind uwtable nosync 209 210define void @call_nosync_function() nounwind uwtable noinline { 211; CHECK: Function Attrs: noinline nosync nounwind uwtable 212; CHECK-LABEL: @call_nosync_function( 213; CHECK-NEXT: tail call void @nosync_function() #[[ATTR11:[0-9]+]] 214; CHECK-NEXT: ret void 215; 216 tail call void @nosync_function() noinline nounwind uwtable 217 ret void 218} 219 220; CHECK: Function Attrs: noinline nounwind uwtable 221; CHECK-NEXT: declare void @might_sync() 222declare void @might_sync() noinline nounwind uwtable 223 224define void @call_might_sync() nounwind uwtable noinline { 225; CHECK: Function Attrs: noinline nounwind uwtable 226; CHECK-LABEL: @call_might_sync( 227; CHECK-NEXT: tail call void @might_sync() #[[ATTR11]] 228; CHECK-NEXT: ret void 229; 230 tail call void @might_sync() noinline nounwind uwtable 231 ret void 232} 233 234declare void @llvm.memcpy(ptr %dest, ptr %src, i32 %len, i1 %isvolatile) 235declare void @llvm.memset(ptr %dest, i8 %val, i32 %len, i1 %isvolatile) 236 237; negative, checking volatile intrinsics. 238define i32 @memcpy_volatile(ptr %ptr1, ptr %ptr2) { 239; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) 240; CHECK-LABEL: @memcpy_volatile( 241; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr [[PTR1:%.*]], ptr [[PTR2:%.*]], i32 8, i1 true) 242; CHECK-NEXT: ret i32 4 243; 244 call void @llvm.memcpy(ptr %ptr1, ptr %ptr2, i32 8, i1 1) 245 ret i32 4 246} 247 248; positive, non-volatile intrinsic. 249define i32 @memset_non_volatile(ptr %ptr1, i8 %val) { 250; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) 251; CHECK-LABEL: @memset_non_volatile( 252; CHECK-NEXT: call void @llvm.memset.p0.i32(ptr [[PTR1:%.*]], i8 [[VAL:%.*]], i32 8, i1 false) 253; CHECK-NEXT: ret i32 4 254; 255 call void @llvm.memset(ptr %ptr1, i8 %val, i32 8, i1 0) 256 ret i32 4 257} 258 259; negative, inline assembly. 260define i32 @inline_asm_test(i32 %x) { 261; CHECK-LABEL: @inline_asm_test( 262; CHECK-NEXT: [[TMP1:%.*]] = call i32 asm "bswap $0", "=r,r"(i32 [[X:%.*]]) 263; CHECK-NEXT: ret i32 4 264; 265 call i32 asm "bswap $0", "=r,r"(i32 %x) 266 ret i32 4 267} 268 269declare void @readnone_test() convergent readnone 270 271; negative. Convergent 272define void @convergent_readnone(){ 273; CHECK: Function Attrs: nofree nosync memory(none) 274; CHECK-LABEL: @convergent_readnone( 275; CHECK-NEXT: call void @readnone_test() 276; CHECK-NEXT: ret void 277; 278 call void @readnone_test() 279 ret void 280} 281 282; CHECK: Function Attrs: nounwind 283; CHECK-NEXT: declare void @llvm.x86.sse2.clflush(ptr) 284declare void @llvm.x86.sse2.clflush(ptr) 285@a = common global i32 0, align 4 286 287; negative. Synchronizing intrinsic 288define void @i_totally_sync() { 289; CHECK: Function Attrs: nounwind 290; CHECK-LABEL: @i_totally_sync( 291; CHECK-NEXT: tail call void @llvm.x86.sse2.clflush(ptr @a) 292; CHECK-NEXT: ret void 293; 294 tail call void @llvm.x86.sse2.clflush(ptr @a) 295 ret void 296} 297 298declare float @llvm.cos(float %val) readnone 299 300define float @cos_test(float %x) { 301; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 302; CHECK-LABEL: @cos_test( 303; CHECK-NEXT: [[C:%.*]] = call float @llvm.cos.f32(float [[X:%.*]]) 304; CHECK-NEXT: ret float [[C]] 305; 306 %c = call float @llvm.cos(float %x) 307 ret float %c 308} 309