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