1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-attributes 2; RUN: opt -passes=function-attrs -S %s | FileCheck %s 3 4@g = global i32 20 5 6define void @test_no_read_or_write() { 7; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind readnone willreturn 8; CHECK-LABEL: @test_no_read_or_write( 9; CHECK-NEXT: entry: 10; CHECK-NEXT: ret void 11; 12entry: 13 ret void 14} 15 16define i32 @test_only_read_arg(i32* %ptr) { 17; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nosync nounwind readonly willreturn 18; CHECK-LABEL: @test_only_read_arg( 19; CHECK-NEXT: entry: 20; CHECK-NEXT: [[L:%.*]] = load i32, i32* [[PTR:%.*]], align 4 21; CHECK-NEXT: ret i32 [[L]] 22; 23entry: 24 %l = load i32, i32* %ptr 25 ret i32 %l 26} 27 28define i32 @test_read_global() { 29; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind readonly willreturn 30; CHECK-LABEL: @test_read_global( 31; CHECK-NEXT: entry: 32; CHECK-NEXT: [[L:%.*]] = load i32, i32* @g, align 4 33; CHECK-NEXT: ret i32 [[L]] 34; 35entry: 36 %l = load i32, i32* @g 37 ret i32 %l 38} 39 40define i32 @test_read_loaded_ptr(i32** %ptr) { 41; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind readonly willreturn 42; CHECK-LABEL: @test_read_loaded_ptr( 43; CHECK-NEXT: entry: 44; CHECK-NEXT: [[L:%.*]] = load i32*, i32** [[PTR:%.*]], align 8 45; CHECK-NEXT: [[L_2:%.*]] = load i32, i32* [[L]], align 4 46; CHECK-NEXT: ret i32 [[L_2]] 47; 48entry: 49 %l = load i32*, i32** %ptr 50 %l.2 = load i32, i32* %l 51 ret i32 %l.2 52} 53 54define void @test_only_write_arg(i32* %ptr) { 55; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nosync nounwind willreturn writeonly 56; CHECK-LABEL: @test_only_write_arg( 57; CHECK-NEXT: entry: 58; CHECK-NEXT: store i32 0, i32* [[PTR:%.*]], align 4 59; CHECK-NEXT: ret void 60; 61entry: 62 store i32 0, i32* %ptr 63 ret void 64} 65 66define void @test_write_global() { 67; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn writeonly 68; CHECK-LABEL: @test_write_global( 69; CHECK-NEXT: entry: 70; CHECK-NEXT: store i32 0, i32* @g, align 4 71; CHECK-NEXT: ret void 72; 73entry: 74 store i32 0, i32* @g 75 ret void 76} 77 78declare void @fn_may_access_memory() 79 80define void @test_call_may_access_memory() { 81; CHECK-LABEL: @test_call_may_access_memory( 82; CHECK-NEXT: entry: 83; CHECK-NEXT: call void @fn_may_access_memory() 84; CHECK-NEXT: ret void 85; 86entry: 87 call void @fn_may_access_memory() 88 ret void 89} 90 91declare i32 @fn_readnone() readnone 92 93define void @test_call_readnone(i32* %ptr) { 94; CHECK: Function Attrs: argmemonly writeonly 95; CHECK-LABEL: @test_call_readnone( 96; CHECK-NEXT: entry: 97; CHECK-NEXT: [[C:%.*]] = call i32 @fn_readnone() 98; CHECK-NEXT: store i32 [[C]], i32* [[PTR:%.*]], align 4 99; CHECK-NEXT: ret void 100; 101entry: 102 %c = call i32 @fn_readnone() 103 store i32 %c, i32* %ptr 104 ret void 105} 106 107declare i32 @fn_argmemonly(i32*) argmemonly 108 109define i32 @test_call_argmemonly(i32* %ptr) { 110; CHECK-LABEL: @test_call_argmemonly( 111; CHECK-NEXT: entry: 112; CHECK-NEXT: [[C:%.*]] = call i32 @fn_argmemonly(i32* [[PTR:%.*]]) 113; CHECK-NEXT: ret i32 [[C]] 114; 115entry: 116 %c = call i32 @fn_argmemonly(i32* %ptr) 117 ret i32 %c 118} 119 120define i32 @test_call_fn_where_argmemonly_can_be_inferred(i32* %ptr) { 121; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nosync nounwind readonly willreturn 122; CHECK-LABEL: @test_call_fn_where_argmemonly_can_be_inferred( 123; CHECK-NEXT: entry: 124; CHECK-NEXT: [[C:%.*]] = call i32 @test_only_read_arg(i32* [[PTR:%.*]]) 125; CHECK-NEXT: ret i32 [[C]] 126; 127entry: 128 %c = call i32 @test_only_read_arg(i32* %ptr) 129 ret i32 %c 130} 131 132define void @test_memcpy_argonly(i8* %dst, i8* %src) { 133; CHECK: Function Attrs: argmemonly mustprogress nofree nosync nounwind willreturn 134; CHECK-LABEL: @test_memcpy_argonly( 135; CHECK-NEXT: entry: 136; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[DST:%.*]], i8* [[SRC:%.*]], i64 32, i1 false) 137; CHECK-NEXT: ret void 138; 139entry: 140 call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dst, i8* %src, i64 32, i1 false) 141 ret void 142} 143 144declare void @llvm.memcpy.p0i8.p0i8.i64(i8*, i8*, i64, i1) 145 146@arr = global [32 x i8] zeroinitializer 147 148define void @test_memcpy_src_global(i8* %dst) { 149; CHECK: Function Attrs: mustprogress nofree nosync nounwind willreturn 150; CHECK-LABEL: @test_memcpy_src_global( 151; CHECK-NEXT: entry: 152; CHECK-NEXT: [[BC:%.*]] = bitcast [32 x i8]* @arr to i8* 153; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[DST:%.*]], i8* [[BC]], i64 32, i1 false) 154; CHECK-NEXT: ret void 155; 156entry: 157 %bc = bitcast [32 x i8]* @arr to i8* 158 call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dst, i8* %bc, i64 32, i1 false) 159 ret void 160} 161 162define void @test_memcpy_dst_global(i8* %src) { 163; CHECK: Function Attrs: mustprogress nofree nosync nounwind willreturn 164; CHECK-LABEL: @test_memcpy_dst_global( 165; CHECK-NEXT: entry: 166; CHECK-NEXT: [[BC:%.*]] = bitcast [32 x i8]* @arr to i8* 167; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[BC]], i8* [[SRC:%.*]], i64 32, i1 false) 168; CHECK-NEXT: ret void 169; 170entry: 171 %bc = bitcast [32 x i8]* @arr to i8* 172 call void @llvm.memcpy.p0i8.p0i8.i64(i8* %bc, i8* %src, i64 32, i1 false) 173 ret void 174} 175 176define i32 @test_read_arg_access_alloca(i32* %ptr) { 177; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nosync nounwind readonly willreturn 178; CHECK-LABEL: @test_read_arg_access_alloca( 179; CHECK-NEXT: entry: 180; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 181; CHECK-NEXT: [[L:%.*]] = load i32, i32* [[PTR:%.*]], align 4 182; CHECK-NEXT: store i32 [[L]], i32* [[A]], align 4 183; CHECK-NEXT: [[L_2:%.*]] = load i32, i32* [[A]], align 4 184; CHECK-NEXT: ret i32 [[L_2]] 185; 186entry: 187 %a = alloca i32 188 %l = load i32, i32* %ptr 189 store i32 %l, i32* %a 190 %l.2 = load i32, i32* %a 191 ret i32 %l.2 192} 193