| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-attributes |
| ; RUN: opt -passes=function-attrs -S %s | FileCheck %s |
| |
| @g = global i32 20 |
| |
| define void @test_no_read_or_write() { |
| ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind readnone willreturn |
| ; CHECK-LABEL: @test_no_read_or_write( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| ret void |
| } |
| |
| define i32 @test_only_read_arg(i32* %ptr) { |
| ; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nosync nounwind readonly willreturn |
| ; CHECK-LABEL: @test_only_read_arg( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[L:%.*]] = load i32, i32* [[PTR:%.*]], align 4 |
| ; CHECK-NEXT: ret i32 [[L]] |
| ; |
| entry: |
| %l = load i32, i32* %ptr |
| ret i32 %l |
| } |
| |
| define i32 @test_read_global() { |
| ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind readonly willreturn |
| ; CHECK-LABEL: @test_read_global( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[L:%.*]] = load i32, i32* @g, align 4 |
| ; CHECK-NEXT: ret i32 [[L]] |
| ; |
| entry: |
| %l = load i32, i32* @g |
| ret i32 %l |
| } |
| |
| define i32 @test_read_loaded_ptr(i32** %ptr) { |
| ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind readonly willreturn |
| ; CHECK-LABEL: @test_read_loaded_ptr( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[L:%.*]] = load i32*, i32** [[PTR:%.*]], align 8 |
| ; CHECK-NEXT: [[L_2:%.*]] = load i32, i32* [[L]], align 4 |
| ; CHECK-NEXT: ret i32 [[L_2]] |
| ; |
| entry: |
| %l = load i32*, i32** %ptr |
| %l.2 = load i32, i32* %l |
| ret i32 %l.2 |
| } |
| |
| define void @test_only_write_arg(i32* %ptr) { |
| ; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nosync nounwind willreturn writeonly |
| ; CHECK-LABEL: @test_only_write_arg( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: store i32 0, i32* [[PTR:%.*]], align 4 |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| store i32 0, i32* %ptr |
| ret void |
| } |
| |
| define void @test_write_global() { |
| ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn writeonly |
| ; CHECK-LABEL: @test_write_global( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: store i32 0, i32* @g, align 4 |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| store i32 0, i32* @g |
| ret void |
| } |
| |
| declare void @fn_may_access_memory() |
| |
| define void @test_call_may_access_memory() { |
| ; CHECK-LABEL: @test_call_may_access_memory( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: call void @fn_may_access_memory() |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| call void @fn_may_access_memory() |
| ret void |
| } |
| |
| declare i32 @fn_readnone() readnone |
| |
| define void @test_call_readnone(i32* %ptr) { |
| ; CHECK: Function Attrs: argmemonly writeonly |
| ; CHECK-LABEL: @test_call_readnone( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[C:%.*]] = call i32 @fn_readnone() |
| ; CHECK-NEXT: store i32 [[C]], i32* [[PTR:%.*]], align 4 |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %c = call i32 @fn_readnone() |
| store i32 %c, i32* %ptr |
| ret void |
| } |
| |
| declare i32 @fn_argmemonly(i32*) argmemonly |
| |
| define i32 @test_call_argmemonly(i32* %ptr) { |
| ; CHECK-LABEL: @test_call_argmemonly( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[C:%.*]] = call i32 @fn_argmemonly(i32* [[PTR:%.*]]) |
| ; CHECK-NEXT: ret i32 [[C]] |
| ; |
| entry: |
| %c = call i32 @fn_argmemonly(i32* %ptr) |
| ret i32 %c |
| } |
| |
| define i32 @test_call_fn_where_argmemonly_can_be_inferred(i32* %ptr) { |
| ; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nosync nounwind readonly willreturn |
| ; CHECK-LABEL: @test_call_fn_where_argmemonly_can_be_inferred( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[C:%.*]] = call i32 @test_only_read_arg(i32* [[PTR:%.*]]) |
| ; CHECK-NEXT: ret i32 [[C]] |
| ; |
| entry: |
| %c = call i32 @test_only_read_arg(i32* %ptr) |
| ret i32 %c |
| } |
| |
| define void @test_memcpy_argonly(i8* %dst, i8* %src) { |
| ; CHECK: Function Attrs: argmemonly mustprogress nofree nosync nounwind willreturn |
| ; CHECK-LABEL: @test_memcpy_argonly( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[DST:%.*]], i8* [[SRC:%.*]], i64 32, i1 false) |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dst, i8* %src, i64 32, i1 false) |
| ret void |
| } |
| |
| declare void @llvm.memcpy.p0i8.p0i8.i64(i8*, i8*, i64, i1) |
| |
| @arr = global [32 x i8] zeroinitializer |
| |
| define void @test_memcpy_src_global(i8* %dst) { |
| ; CHECK: Function Attrs: mustprogress nofree nosync nounwind willreturn |
| ; CHECK-LABEL: @test_memcpy_src_global( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[BC:%.*]] = bitcast [32 x i8]* @arr to i8* |
| ; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[DST:%.*]], i8* [[BC]], i64 32, i1 false) |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %bc = bitcast [32 x i8]* @arr to i8* |
| call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dst, i8* %bc, i64 32, i1 false) |
| ret void |
| } |
| |
| define void @test_memcpy_dst_global(i8* %src) { |
| ; CHECK: Function Attrs: mustprogress nofree nosync nounwind willreturn |
| ; CHECK-LABEL: @test_memcpy_dst_global( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[BC:%.*]] = bitcast [32 x i8]* @arr to i8* |
| ; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[BC]], i8* [[SRC:%.*]], i64 32, i1 false) |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %bc = bitcast [32 x i8]* @arr to i8* |
| call void @llvm.memcpy.p0i8.p0i8.i64(i8* %bc, i8* %src, i64 32, i1 false) |
| ret void |
| } |
| |
| define i32 @test_read_arg_access_alloca(i32* %ptr) { |
| ; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nosync nounwind readonly willreturn |
| ; CHECK-LABEL: @test_read_arg_access_alloca( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 |
| ; CHECK-NEXT: [[L:%.*]] = load i32, i32* [[PTR:%.*]], align 4 |
| ; CHECK-NEXT: store i32 [[L]], i32* [[A]], align 4 |
| ; CHECK-NEXT: [[L_2:%.*]] = load i32, i32* [[A]], align 4 |
| ; CHECK-NEXT: ret i32 [[L_2]] |
| ; |
| entry: |
| %a = alloca i32 |
| %l = load i32, i32* %ptr |
| store i32 %l, i32* %a |
| %l.2 = load i32, i32* %a |
| ret i32 %l.2 |
| } |