Files
clang-p2996/llvm/test/Transforms/FunctionAttrs/argmemonly.ll
Florian Hahn e5822ded56 [FunctionAttrs] Infer argmemonly .
This patch adds initial argmemonly inference, by checking the underlying
objects of locations returned by MemoryLocation.

I think this should cover most cases, except function calls to other
argmemonly functions.

I'm not sure if there's a reason why we don't infer those yet.

Additional argmemonly can improve codegen in some cases. It also makes
it easier to come up with a C reproducer for 7662d1687b (already fixed,
but I'm trying to see if C/C++ fuzzing could help to uncover similar
issues.)

Compile-time impact:
NewPM-O3: +0.01%
NewPM-ReleaseThinLTO: +0.03%
NewPM-ReleaseLTO+g: +0.05%

https://llvm-compile-time-tracker.com/compare.php?from=067c035012fc061ad6378458774ac2df117283c6&to=fe209d4aab5b593bd62d18c0876732ddcca1614d&stat=instructions

Reviewed By: nikic

Differential Revision: https://reviews.llvm.org/D121415
2022-03-16 10:24:33 +00:00

193 lines
5.6 KiB
LLVM

; 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
}