| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-attributes | 
 | ; RUN: opt < %s -passes=function-attrs -S | FileCheck %s | 
 |  | 
 | target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" | 
 |  | 
 | ; Base case, empty function | 
 | define void @test1() { | 
 | ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) | 
 | ; CHECK-LABEL: @test1( | 
 | ; CHECK-NEXT:    ret void | 
 | ; | 
 |   ret void | 
 | } | 
 |  | 
 | ; Show the bottom up walk | 
 | define void @test2() { | 
 | ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) | 
 | ; CHECK-LABEL: @test2( | 
 | ; CHECK-NEXT:    call void @test1() | 
 | ; CHECK-NEXT:    ret void | 
 | ; | 
 |   call void @test1() | 
 |   ret void | 
 | } | 
 |  | 
 | declare void @unknown() convergent | 
 |  | 
 | ; Negative case with convergent function | 
 | define void @test3() convergent { | 
 | ; CHECK: Function Attrs: convergent | 
 | ; CHECK-LABEL: @test3( | 
 | ; CHECK-NEXT:    call void @unknown() | 
 | ; CHECK-NEXT:    ret void | 
 | ; | 
 |   call void @unknown() | 
 |   ret void | 
 | } | 
 |  | 
 | define i32 @test4(i32 %a, i32 %b) { | 
 | ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) | 
 | ; CHECK-LABEL: @test4( | 
 | ; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[A:%.*]], [[B:%.*]] | 
 | ; CHECK-NEXT:    ret i32 [[A]] | 
 | ; | 
 |   %add = add i32 %a, %b | 
 |   ret i32 %a | 
 | } | 
 |  | 
 | ; negative case - explicit sync | 
 | define void @test5(ptr %p) { | 
 | ; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) | 
 | ; CHECK-LABEL: @test5( | 
 | ; CHECK-NEXT:    store atomic i8 0, ptr [[P:%.*]] seq_cst, align 1 | 
 | ; CHECK-NEXT:    ret void | 
 | ; | 
 |   store atomic i8 0, ptr %p seq_cst, align 1 | 
 |   ret void | 
 | } | 
 |  | 
 | ; negative case - explicit sync | 
 | define i8 @test6(ptr %p) { | 
 | ; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) | 
 | ; CHECK-LABEL: @test6( | 
 | ; CHECK-NEXT:    [[V:%.*]] = load atomic i8, ptr [[P:%.*]] seq_cst, align 1 | 
 | ; CHECK-NEXT:    ret i8 [[V]] | 
 | ; | 
 |   %v = load atomic i8, ptr %p seq_cst, align 1 | 
 |   ret i8 %v | 
 | } | 
 |  | 
 | ; negative case - explicit sync | 
 | define void @test7(ptr %p) { | 
 | ; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) | 
 | ; CHECK-LABEL: @test7( | 
 | ; CHECK-NEXT:    [[TMP1:%.*]] = atomicrmw add ptr [[P:%.*]], i8 0 seq_cst, align 1 | 
 | ; CHECK-NEXT:    ret void | 
 | ; | 
 |   atomicrmw add ptr %p, i8 0 seq_cst, align 1 | 
 |   ret void | 
 | } | 
 |  | 
 | ; negative case - explicit sync | 
 | define void @test8(ptr %p) { | 
 | ; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn | 
 | ; CHECK-LABEL: @test8( | 
 | ; CHECK-NEXT:    fence seq_cst | 
 | ; CHECK-NEXT:    ret void | 
 | ; | 
 |   fence seq_cst | 
 |   ret void | 
 | } | 
 |  | 
 | ; singlethread fences are okay | 
 | define void @test9(ptr %p) { | 
 | ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn | 
 | ; CHECK-LABEL: @test9( | 
 | ; CHECK-NEXT:    fence syncscope("singlethread") seq_cst | 
 | ; CHECK-NEXT:    ret void | 
 | ; | 
 |   fence syncscope("singlethread") seq_cst | 
 |   ret void | 
 | } | 
 |  | 
 | ; atomic load with monotonic ordering | 
 | define i32 @load_monotonic(ptr nocapture readonly %0) norecurse nounwind uwtable { | 
 | ; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) uwtable | 
 | ; CHECK-LABEL: @load_monotonic( | 
 | ; CHECK-NEXT:    [[TMP2:%.*]] = load atomic i32, ptr [[TMP0:%.*]] monotonic, align 4 | 
 | ; CHECK-NEXT:    ret i32 [[TMP2]] | 
 | ; | 
 |   %2 = load atomic i32, ptr %0 monotonic, align 4 | 
 |   ret i32 %2 | 
 | } | 
 |  | 
 | ; atomic store with monotonic ordering. | 
 | define void @store_monotonic(ptr nocapture %0) norecurse nounwind uwtable { | 
 | ; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) uwtable | 
 | ; CHECK-LABEL: @store_monotonic( | 
 | ; CHECK-NEXT:    store atomic i32 10, ptr [[TMP0:%.*]] monotonic, align 4 | 
 | ; CHECK-NEXT:    ret void | 
 | ; | 
 |   store atomic i32 10, ptr %0 monotonic, align 4 | 
 |   ret void | 
 | } | 
 |  | 
 | ; negative, should not deduce nosync | 
 | ; atomic load with acquire ordering. | 
 | define i32 @load_acquire(ptr nocapture readonly %0) norecurse nounwind uwtable { | 
 | ; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) uwtable | 
 | ; CHECK-LABEL: @load_acquire( | 
 | ; CHECK-NEXT:    [[TMP2:%.*]] = load atomic i32, ptr [[TMP0:%.*]] acquire, align 4 | 
 | ; CHECK-NEXT:    ret i32 [[TMP2]] | 
 | ; | 
 |   %2 = load atomic i32, ptr %0 acquire, align 4 | 
 |   ret i32 %2 | 
 | } | 
 |  | 
 | define i32 @load_unordered(ptr nocapture readonly %0) norecurse nounwind uwtable { | 
 | ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) uwtable | 
 | ; CHECK-LABEL: @load_unordered( | 
 | ; CHECK-NEXT:    [[TMP2:%.*]] = load atomic i32, ptr [[TMP0:%.*]] unordered, align 4 | 
 | ; CHECK-NEXT:    ret i32 [[TMP2]] | 
 | ; | 
 |   %2 = load atomic i32, ptr %0 unordered, align 4 | 
 |   ret i32 %2 | 
 | } | 
 |  | 
 | ; atomic store with unordered ordering. | 
 | define void @store_unordered(ptr nocapture %0) norecurse nounwind uwtable { | 
 | ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) uwtable | 
 | ; CHECK-LABEL: @store_unordered( | 
 | ; CHECK-NEXT:    store atomic i32 10, ptr [[TMP0:%.*]] unordered, align 4 | 
 | ; CHECK-NEXT:    ret void | 
 | ; | 
 |   store atomic i32 10, ptr %0 unordered, align 4 | 
 |   ret void | 
 | } | 
 |  | 
 |  | 
 | ; negative, should not deduce nosync | 
 | ; atomic load with release ordering | 
 | define void @load_release(ptr nocapture %0) norecurse nounwind uwtable { | 
 | ; CHECK: Function Attrs: nofree norecurse nounwind memory(argmem: readwrite, inaccessiblemem: readwrite) uwtable | 
 | ; CHECK-LABEL: @load_release( | 
 | ; CHECK-NEXT:    store atomic volatile i32 10, ptr [[TMP0:%.*]] release, align 4 | 
 | ; CHECK-NEXT:    ret void | 
 | ; | 
 |   store atomic volatile i32 10, ptr %0 release, align 4 | 
 |   ret void | 
 | } | 
 |  | 
 | ; negative volatile, relaxed atomic | 
 | define void @load_volatile_release(ptr nocapture %0) norecurse nounwind uwtable { | 
 | ; CHECK: Function Attrs: nofree norecurse nounwind memory(argmem: readwrite, inaccessiblemem: readwrite) uwtable | 
 | ; CHECK-LABEL: @load_volatile_release( | 
 | ; CHECK-NEXT:    store atomic volatile i32 10, ptr [[TMP0:%.*]] release, align 4 | 
 | ; CHECK-NEXT:    ret void | 
 | ; | 
 |   store atomic volatile i32 10, ptr %0 release, align 4 | 
 |   ret void | 
 | } | 
 |  | 
 | ; volatile store. | 
 | define void @volatile_store(ptr %0) norecurse nounwind uwtable { | 
 | ; CHECK: Function Attrs: nofree norecurse nounwind memory(argmem: readwrite, inaccessiblemem: readwrite) uwtable | 
 | ; CHECK-LABEL: @volatile_store( | 
 | ; CHECK-NEXT:    store volatile i32 14, ptr [[TMP0:%.*]], align 4 | 
 | ; CHECK-NEXT:    ret void | 
 | ; | 
 |   store volatile i32 14, ptr %0, align 4 | 
 |   ret void | 
 | } | 
 |  | 
 | ; negative, should not deduce nosync | 
 | ; volatile load. | 
 | define i32 @volatile_load(ptr %0) norecurse nounwind uwtable { | 
 | ; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite, inaccessiblemem: readwrite) uwtable | 
 | ; CHECK-LABEL: @volatile_load( | 
 | ; CHECK-NEXT:    [[TMP2:%.*]] = load volatile i32, ptr [[TMP0:%.*]], align 4 | 
 | ; CHECK-NEXT:    ret i32 [[TMP2]] | 
 | ; | 
 |   %2 = load volatile i32, ptr %0, align 4 | 
 |   ret i32 %2 | 
 | } | 
 |  | 
 | ; CHECK: Function Attrs: noinline nosync nounwind uwtable | 
 | ; CHECK-NEXT: declare void @nosync_function() | 
 | declare void @nosync_function() noinline nounwind uwtable nosync | 
 |  | 
 | define void @call_nosync_function() nounwind uwtable noinline { | 
 | ; CHECK: Function Attrs: noinline nosync nounwind uwtable | 
 | ; CHECK-LABEL: @call_nosync_function( | 
 | ; CHECK-NEXT:    tail call void @nosync_function() #[[ATTR11:[0-9]+]] | 
 | ; CHECK-NEXT:    ret void | 
 | ; | 
 |   tail call void @nosync_function() noinline nounwind uwtable | 
 |   ret void | 
 | } | 
 |  | 
 | ; CHECK: Function Attrs: noinline nounwind uwtable | 
 | ; CHECK-NEXT: declare void @might_sync() | 
 | declare void @might_sync() noinline nounwind uwtable | 
 |  | 
 | define void @call_might_sync() nounwind uwtable noinline { | 
 | ; CHECK: Function Attrs: noinline nounwind uwtable | 
 | ; CHECK-LABEL: @call_might_sync( | 
 | ; CHECK-NEXT:    tail call void @might_sync() #[[ATTR11]] | 
 | ; CHECK-NEXT:    ret void | 
 | ; | 
 |   tail call void @might_sync() noinline nounwind uwtable | 
 |   ret void | 
 | } | 
 |  | 
 | declare void @llvm.memcpy(ptr %dest, ptr %src, i32 %len, i1 %isvolatile) | 
 | declare void @llvm.memset(ptr %dest, i8 %val, i32 %len, i1 %isvolatile) | 
 |  | 
 | ; negative, checking volatile intrinsics. | 
 | define i32 @memcpy_volatile(ptr %ptr1, ptr %ptr2) { | 
 | ; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite, inaccessiblemem: readwrite) | 
 | ; CHECK-LABEL: @memcpy_volatile( | 
 | ; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i32(ptr [[PTR1:%.*]], ptr [[PTR2:%.*]], i32 8, i1 true) | 
 | ; CHECK-NEXT:    ret i32 4 | 
 | ; | 
 |   call void @llvm.memcpy(ptr %ptr1, ptr %ptr2, i32 8, i1 1) | 
 |   ret i32 4 | 
 | } | 
 |  | 
 | ; positive, non-volatile intrinsic. | 
 | define i32 @memset_non_volatile(ptr %ptr1, i8 %val) { | 
 | ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) | 
 | ; CHECK-LABEL: @memset_non_volatile( | 
 | ; CHECK-NEXT:    call void @llvm.memset.p0.i32(ptr [[PTR1:%.*]], i8 [[VAL:%.*]], i32 8, i1 false) | 
 | ; CHECK-NEXT:    ret i32 4 | 
 | ; | 
 |   call void @llvm.memset(ptr %ptr1, i8 %val, i32 8, i1 0) | 
 |   ret i32 4 | 
 | } | 
 |  | 
 | ; negative, inline assembly. | 
 | define i32 @inline_asm_test(i32 %x) { | 
 | ; CHECK-LABEL: @inline_asm_test( | 
 | ; CHECK-NEXT:    [[TMP1:%.*]] = call i32 asm "bswap $0", "=r,r"(i32 [[X:%.*]]) | 
 | ; CHECK-NEXT:    ret i32 4 | 
 | ; | 
 |   call i32 asm "bswap $0", "=r,r"(i32 %x) | 
 |   ret i32 4 | 
 | } | 
 |  | 
 | declare void @readnone_test() convergent readnone | 
 |  | 
 | ; negative. Convergent | 
 | define void @convergent_readnone(){ | 
 | ; CHECK: Function Attrs: nofree nosync memory(none) | 
 | ; CHECK-LABEL: @convergent_readnone( | 
 | ; CHECK-NEXT:    call void @readnone_test() | 
 | ; CHECK-NEXT:    ret void | 
 | ; | 
 |   call void @readnone_test() | 
 |   ret void | 
 | } | 
 |  | 
 | ; CHECK: Function Attrs: nounwind | 
 | ; CHECK-NEXT: declare void @llvm.x86.sse2.clflush(ptr) | 
 | declare void @llvm.x86.sse2.clflush(ptr) | 
 | @a = common global i32 0, align 4 | 
 |  | 
 | ; negative. Synchronizing intrinsic | 
 | define void @i_totally_sync() { | 
 | ; CHECK: Function Attrs: nounwind | 
 | ; CHECK-LABEL: @i_totally_sync( | 
 | ; CHECK-NEXT:    tail call void @llvm.x86.sse2.clflush(ptr @a) | 
 | ; CHECK-NEXT:    ret void | 
 | ; | 
 |   tail call void @llvm.x86.sse2.clflush(ptr @a) | 
 |   ret void | 
 | } | 
 |  | 
 | declare float @llvm.cos(float %val) readnone | 
 |  | 
 | define float @cos_test(float %x) { | 
 | ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) | 
 | ; CHECK-LABEL: @cos_test( | 
 | ; CHECK-NEXT:    [[C:%.*]] = call float @llvm.cos.f32(float [[X:%.*]]) | 
 | ; CHECK-NEXT:    ret float [[C]] | 
 | ; | 
 |   %c = call float @llvm.cos(float %x) | 
 |   ret float %c | 
 | } |