Files
clang-p2996/llvm/test/Transforms/FunctionAttrs/argmemonly.ll
Nikita Popov 86f3dc83e1 [FunctionAttrs] Consider recursive argmem effects (PR63936)
When inspecting the function body, we can't simply ignore effects
of functions in the SCC entirely, because an argmem access of a
recursive call might result in an access to another location in
the callee.

Fix this by separately tracking memory effects that would occur if
the SCC accesses argmem, and then later add those.

Fixes https://github.com/llvm/llvm-project/issues/63936.

Differential Revision: https://reviews.llvm.org/D155956
2023-08-14 14:39:54 +02:00

492 lines
20 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-attributes --version 2
; RUN: opt -passes=function-attrs -S < %s | FileCheck --check-prefixes=COMMON,FNATTRS %s
; RUN: opt -passes=attributor-light -S < %s | FileCheck --check-prefixes=COMMON,ATTRIBUTOR %s
@g = global i32 20
define void @test_no_read_or_write() {
; COMMON: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; COMMON-LABEL: define void @test_no_read_or_write
; COMMON-SAME: () #[[ATTR0:[0-9]+]] {
; COMMON-NEXT: entry:
; COMMON-NEXT: ret void
;
entry:
ret void
}
define i32 @test_only_read_arg(ptr %ptr) {
; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
; FNATTRS-LABEL: define i32 @test_only_read_arg
; FNATTRS-SAME: (ptr nocapture readonly [[PTR:%.*]]) #[[ATTR1:[0-9]+]] {
; FNATTRS-NEXT: entry:
; FNATTRS-NEXT: [[L:%.*]] = load i32, ptr [[PTR]], align 4
; FNATTRS-NEXT: ret i32 [[L]]
;
; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
; ATTRIBUTOR-LABEL: define i32 @test_only_read_arg
; ATTRIBUTOR-SAME: (ptr nocapture nofree nonnull readonly [[PTR:%.*]]) #[[ATTR1:[0-9]+]] {
; ATTRIBUTOR-NEXT: entry:
; ATTRIBUTOR-NEXT: [[L:%.*]] = load i32, ptr [[PTR]], align 4
; ATTRIBUTOR-NEXT: ret i32 [[L]]
;
entry:
%l = load i32, ptr %ptr
ret i32 %l
}
define i32 @test_only_read_arg_already_has_argmemonly(ptr %ptr) argmemonly {
; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
; FNATTRS-LABEL: define i32 @test_only_read_arg_already_has_argmemonly
; FNATTRS-SAME: (ptr nocapture readonly [[PTR:%.*]]) #[[ATTR1]] {
; FNATTRS-NEXT: entry:
; FNATTRS-NEXT: [[L:%.*]] = load i32, ptr [[PTR]], align 4
; FNATTRS-NEXT: ret i32 [[L]]
;
; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
; ATTRIBUTOR-LABEL: define i32 @test_only_read_arg_already_has_argmemonly
; ATTRIBUTOR-SAME: (ptr nocapture nofree nonnull readonly [[PTR:%.*]]) #[[ATTR1]] {
; ATTRIBUTOR-NEXT: entry:
; ATTRIBUTOR-NEXT: [[L:%.*]] = load i32, ptr [[PTR]], align 4
; ATTRIBUTOR-NEXT: ret i32 [[L]]
;
entry:
%l = load i32, ptr %ptr
ret i32 %l
}
define i32 @test_read_global() {
; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read, argmem: none, inaccessiblemem: none)
; FNATTRS-LABEL: define i32 @test_read_global
; FNATTRS-SAME: () #[[ATTR2:[0-9]+]] {
; FNATTRS-NEXT: entry:
; FNATTRS-NEXT: [[L:%.*]] = load i32, ptr @g, align 4
; FNATTRS-NEXT: ret i32 [[L]]
;
; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read)
; ATTRIBUTOR-LABEL: define i32 @test_read_global
; ATTRIBUTOR-SAME: () #[[ATTR2:[0-9]+]] {
; ATTRIBUTOR-NEXT: entry:
; ATTRIBUTOR-NEXT: [[L:%.*]] = load i32, ptr @g, align 4
; ATTRIBUTOR-NEXT: ret i32 [[L]]
;
entry:
%l = load i32, ptr @g
ret i32 %l
}
define i32 @test_read_loaded_ptr(ptr %ptr) {
; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read, inaccessiblemem: none)
; FNATTRS-LABEL: define i32 @test_read_loaded_ptr
; FNATTRS-SAME: (ptr nocapture readonly [[PTR:%.*]]) #[[ATTR3:[0-9]+]] {
; FNATTRS-NEXT: entry:
; FNATTRS-NEXT: [[L:%.*]] = load ptr, ptr [[PTR]], align 8
; FNATTRS-NEXT: [[L_2:%.*]] = load i32, ptr [[L]], align 4
; FNATTRS-NEXT: ret i32 [[L_2]]
;
; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read)
; ATTRIBUTOR-LABEL: define i32 @test_read_loaded_ptr
; ATTRIBUTOR-SAME: (ptr nocapture nofree nonnull readonly [[PTR:%.*]]) #[[ATTR2]] {
; ATTRIBUTOR-NEXT: entry:
; ATTRIBUTOR-NEXT: [[L:%.*]] = load ptr, ptr [[PTR]], align 8
; ATTRIBUTOR-NEXT: [[L_2:%.*]] = load i32, ptr [[L]], align 4
; ATTRIBUTOR-NEXT: ret i32 [[L_2]]
;
entry:
%l = load ptr, ptr %ptr
%l.2 = load i32, ptr %l
ret i32 %l.2
}
define void @test_only_write_arg(ptr %ptr) {
; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
; FNATTRS-LABEL: define void @test_only_write_arg
; FNATTRS-SAME: (ptr nocapture writeonly [[PTR:%.*]]) #[[ATTR4:[0-9]+]] {
; FNATTRS-NEXT: entry:
; FNATTRS-NEXT: store i32 0, ptr [[PTR]], align 4
; FNATTRS-NEXT: ret void
;
; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
; ATTRIBUTOR-LABEL: define void @test_only_write_arg
; ATTRIBUTOR-SAME: (ptr nocapture nofree nonnull writeonly [[PTR:%.*]]) #[[ATTR3:[0-9]+]] {
; ATTRIBUTOR-NEXT: entry:
; ATTRIBUTOR-NEXT: store i32 0, ptr [[PTR]], align 4
; ATTRIBUTOR-NEXT: ret void
;
entry:
store i32 0, ptr %ptr
ret void
}
define void @test_write_global() {
; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write, argmem: none, inaccessiblemem: none)
; FNATTRS-LABEL: define void @test_write_global
; FNATTRS-SAME: () #[[ATTR5:[0-9]+]] {
; FNATTRS-NEXT: entry:
; FNATTRS-NEXT: store i32 0, ptr @g, align 4
; FNATTRS-NEXT: ret void
;
; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write)
; ATTRIBUTOR-LABEL: define void @test_write_global
; ATTRIBUTOR-SAME: () #[[ATTR4:[0-9]+]] {
; ATTRIBUTOR-NEXT: entry:
; ATTRIBUTOR-NEXT: store i32 0, ptr @g, align 4
; ATTRIBUTOR-NEXT: ret void
;
entry:
store i32 0, ptr @g
ret void
}
declare void @fn_may_access_memory()
define void @test_call_may_access_memory() {
; COMMON-LABEL: define void @test_call_may_access_memory() {
; COMMON-NEXT: entry:
; COMMON-NEXT: call void @fn_may_access_memory()
; COMMON-NEXT: ret void
;
entry:
call void @fn_may_access_memory()
ret void
}
declare i32 @fn_readnone() readnone
define void @test_call_readnone(ptr %ptr) {
; FNATTRS: Function Attrs: memory(argmem: write)
; FNATTRS-LABEL: define void @test_call_readnone
; FNATTRS-SAME: (ptr nocapture writeonly [[PTR:%.*]]) #[[ATTR7:[0-9]+]] {
; FNATTRS-NEXT: entry:
; FNATTRS-NEXT: [[C:%.*]] = call i32 @fn_readnone()
; FNATTRS-NEXT: store i32 [[C]], ptr [[PTR]], align 4
; FNATTRS-NEXT: ret void
;
; ATTRIBUTOR: Function Attrs: nosync memory(argmem: write)
; ATTRIBUTOR-LABEL: define void @test_call_readnone
; ATTRIBUTOR-SAME: (ptr nocapture nofree writeonly [[PTR:%.*]]) #[[ATTR6:[0-9]+]] {
; ATTRIBUTOR-NEXT: entry:
; ATTRIBUTOR-NEXT: [[C:%.*]] = call i32 @fn_readnone() #[[ATTR18:[0-9]+]]
; ATTRIBUTOR-NEXT: store i32 [[C]], ptr [[PTR]], align 4
; ATTRIBUTOR-NEXT: ret void
;
entry:
%c = call i32 @fn_readnone()
store i32 %c, ptr %ptr
ret void
}
declare i32 @fn_argmemonly(ptr) argmemonly
define i32 @test_call_argmemonly(ptr %ptr) {
; FNATTRS: Function Attrs: memory(argmem: readwrite)
; FNATTRS-LABEL: define i32 @test_call_argmemonly
; FNATTRS-SAME: (ptr [[PTR:%.*]]) #[[ATTR8:[0-9]+]] {
; FNATTRS-NEXT: entry:
; FNATTRS-NEXT: [[C:%.*]] = call i32 @fn_argmemonly(ptr [[PTR]])
; FNATTRS-NEXT: ret i32 [[C]]
;
; ATTRIBUTOR: Function Attrs: memory(argmem: readwrite)
; ATTRIBUTOR-LABEL: define i32 @test_call_argmemonly
; ATTRIBUTOR-SAME: (ptr [[PTR:%.*]]) #[[ATTR7:[0-9]+]] {
; ATTRIBUTOR-NEXT: entry:
; ATTRIBUTOR-NEXT: [[C:%.*]] = call i32 @fn_argmemonly(ptr [[PTR]])
; ATTRIBUTOR-NEXT: ret i32 [[C]]
;
entry:
%c = call i32 @fn_argmemonly(ptr %ptr)
ret i32 %c
}
define i32 @test_call_fn_where_argmemonly_can_be_inferred(ptr %ptr) {
; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
; FNATTRS-LABEL: define i32 @test_call_fn_where_argmemonly_can_be_inferred
; FNATTRS-SAME: (ptr nocapture readonly [[PTR:%.*]]) #[[ATTR1]] {
; FNATTRS-NEXT: entry:
; FNATTRS-NEXT: [[C:%.*]] = call i32 @test_only_read_arg(ptr [[PTR]])
; FNATTRS-NEXT: ret i32 [[C]]
;
; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
; ATTRIBUTOR-LABEL: define i32 @test_call_fn_where_argmemonly_can_be_inferred
; ATTRIBUTOR-SAME: (ptr nocapture nofree readonly [[PTR:%.*]]) #[[ATTR1]] {
; ATTRIBUTOR-NEXT: entry:
; ATTRIBUTOR-NEXT: [[C:%.*]] = call i32 @test_only_read_arg(ptr nocapture nofree readonly [[PTR]]) #[[ATTR19:[0-9]+]]
; ATTRIBUTOR-NEXT: ret i32 [[C]]
;
entry:
%c = call i32 @test_only_read_arg(ptr %ptr)
ret i32 %c
}
define void @test_memcpy_argonly(ptr %dst, ptr %src) {
; FNATTRS: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(argmem: readwrite)
; FNATTRS-LABEL: define void @test_memcpy_argonly
; FNATTRS-SAME: (ptr nocapture writeonly [[DST:%.*]], ptr nocapture readonly [[SRC:%.*]]) #[[ATTR9:[0-9]+]] {
; FNATTRS-NEXT: entry:
; FNATTRS-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr [[DST]], ptr [[SRC]], i64 32, i1 false)
; FNATTRS-NEXT: ret void
;
; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite)
; ATTRIBUTOR-LABEL: define void @test_memcpy_argonly
; ATTRIBUTOR-SAME: (ptr nocapture nofree writeonly [[DST:%.*]], ptr nocapture nofree readonly [[SRC:%.*]]) #[[ATTR8:[0-9]+]] {
; ATTRIBUTOR-NEXT: entry:
; ATTRIBUTOR-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr nocapture writeonly [[DST]], ptr nocapture readonly [[SRC]], i64 32, i1 false) #[[ATTR20:[0-9]+]]
; ATTRIBUTOR-NEXT: ret void
;
entry:
call void @llvm.memcpy.p0.p0.i64(ptr %dst, ptr %src, i64 32, i1 false)
ret void
}
declare void @llvm.memcpy.p0.p0.i64(ptr, ptr, i64, i1)
@arr = global [32 x i8] zeroinitializer
define void @test_memcpy_src_global(ptr %dst) {
; FNATTRS: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(readwrite, inaccessiblemem: none)
; FNATTRS-LABEL: define void @test_memcpy_src_global
; FNATTRS-SAME: (ptr nocapture writeonly [[DST:%.*]]) #[[ATTR11:[0-9]+]] {
; FNATTRS-NEXT: entry:
; FNATTRS-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr [[DST]], ptr @arr, i64 32, i1 false)
; FNATTRS-NEXT: ret void
;
; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn
; ATTRIBUTOR-LABEL: define void @test_memcpy_src_global
; ATTRIBUTOR-SAME: (ptr nocapture nofree writeonly [[DST:%.*]]) #[[ATTR10:[0-9]+]] {
; ATTRIBUTOR-NEXT: entry:
; ATTRIBUTOR-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr nocapture writeonly [[DST]], ptr readonly @arr, i64 32, i1 false) #[[ATTR20]]
; ATTRIBUTOR-NEXT: ret void
;
entry:
call void @llvm.memcpy.p0.p0.i64(ptr %dst, ptr @arr, i64 32, i1 false)
ret void
}
define void @test_memcpy_dst_global(ptr %src) {
; FNATTRS: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(readwrite, inaccessiblemem: none)
; FNATTRS-LABEL: define void @test_memcpy_dst_global
; FNATTRS-SAME: (ptr nocapture readonly [[SRC:%.*]]) #[[ATTR11]] {
; FNATTRS-NEXT: entry:
; FNATTRS-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr @arr, ptr [[SRC]], i64 32, i1 false)
; FNATTRS-NEXT: ret void
;
; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn
; ATTRIBUTOR-LABEL: define void @test_memcpy_dst_global
; ATTRIBUTOR-SAME: (ptr nocapture nofree readonly [[SRC:%.*]]) #[[ATTR10]] {
; ATTRIBUTOR-NEXT: entry:
; ATTRIBUTOR-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr writeonly @arr, ptr nocapture readonly [[SRC]], i64 32, i1 false) #[[ATTR20]]
; ATTRIBUTOR-NEXT: ret void
;
entry:
call void @llvm.memcpy.p0.p0.i64(ptr @arr, ptr %src, i64 32, i1 false)
ret void
}
define i32 @test_read_arg_access_alloca(ptr %ptr) {
; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
; FNATTRS-LABEL: define i32 @test_read_arg_access_alloca
; FNATTRS-SAME: (ptr nocapture readonly [[PTR:%.*]]) #[[ATTR1]] {
; FNATTRS-NEXT: entry:
; FNATTRS-NEXT: [[A:%.*]] = alloca i32, align 4
; FNATTRS-NEXT: [[L:%.*]] = load i32, ptr [[PTR]], align 4
; FNATTRS-NEXT: store i32 [[L]], ptr [[A]], align 4
; FNATTRS-NEXT: [[L_2:%.*]] = load i32, ptr [[A]], align 4
; FNATTRS-NEXT: ret i32 [[L_2]]
;
; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite)
; ATTRIBUTOR-LABEL: define i32 @test_read_arg_access_alloca
; ATTRIBUTOR-SAME: (ptr nocapture nofree nonnull readonly [[PTR:%.*]]) #[[ATTR8]] {
; ATTRIBUTOR-NEXT: entry:
; ATTRIBUTOR-NEXT: [[A:%.*]] = alloca i32, align 4
; ATTRIBUTOR-NEXT: [[L:%.*]] = load i32, ptr [[PTR]], align 4
; ATTRIBUTOR-NEXT: store i32 [[L]], ptr [[A]], align 4
; ATTRIBUTOR-NEXT: [[L_2:%.*]] = load i32, ptr [[A]], align 4
; ATTRIBUTOR-NEXT: ret i32 [[L_2]]
;
entry:
%a = alloca i32
%l = load i32, ptr %ptr
store i32 %l, ptr %a
%l.2 = load i32, ptr %a
ret i32 %l.2
}
declare void @fn_inaccessiblememonly() inaccessiblememonly
define void @test_inaccessiblememonly() {
; FNATTRS: Function Attrs: memory(inaccessiblemem: readwrite)
; FNATTRS-LABEL: define void @test_inaccessiblememonly
; FNATTRS-SAME: () #[[ATTR12:[0-9]+]] {
; FNATTRS-NEXT: call void @fn_inaccessiblememonly()
; FNATTRS-NEXT: ret void
;
; ATTRIBUTOR: Function Attrs: memory(inaccessiblemem: readwrite)
; ATTRIBUTOR-LABEL: define void @test_inaccessiblememonly
; ATTRIBUTOR-SAME: () #[[ATTR11:[0-9]+]] {
; ATTRIBUTOR-NEXT: call void @fn_inaccessiblememonly()
; ATTRIBUTOR-NEXT: ret void
;
call void @fn_inaccessiblememonly()
ret void
}
define void @test_inaccessiblememonly_readonly() {
; FNATTRS: Function Attrs: nofree memory(inaccessiblemem: read)
; FNATTRS-LABEL: define void @test_inaccessiblememonly_readonly
; FNATTRS-SAME: () #[[ATTR13:[0-9]+]] {
; FNATTRS-NEXT: call void @fn_inaccessiblememonly() #[[ATTR19:[0-9]+]]
; FNATTRS-NEXT: ret void
;
; ATTRIBUTOR: Function Attrs: nosync memory(inaccessiblemem: read)
; ATTRIBUTOR-LABEL: define void @test_inaccessiblememonly_readonly
; ATTRIBUTOR-SAME: () #[[ATTR12:[0-9]+]] {
; ATTRIBUTOR-NEXT: call void @fn_inaccessiblememonly() #[[ATTR21:[0-9]+]]
; ATTRIBUTOR-NEXT: ret void
;
call void @fn_inaccessiblememonly() readonly
ret void
}
define void @test_inaccessibleorargmemonly_readonly(ptr %arg) {
; FNATTRS: Function Attrs: nofree memory(argmem: read, inaccessiblemem: read)
; FNATTRS-LABEL: define void @test_inaccessibleorargmemonly_readonly
; FNATTRS-SAME: (ptr nocapture readonly [[ARG:%.*]]) #[[ATTR14:[0-9]+]] {
; FNATTRS-NEXT: [[TMP1:%.*]] = load i32, ptr [[ARG]], align 4
; FNATTRS-NEXT: call void @fn_inaccessiblememonly() #[[ATTR19]]
; FNATTRS-NEXT: ret void
;
; ATTRIBUTOR: Function Attrs: nosync memory(argmem: read, inaccessiblemem: read)
; ATTRIBUTOR-LABEL: define void @test_inaccessibleorargmemonly_readonly
; ATTRIBUTOR-SAME: (ptr nocapture nofree nonnull readonly [[ARG:%.*]]) #[[ATTR13:[0-9]+]] {
; ATTRIBUTOR-NEXT: [[TMP1:%.*]] = load i32, ptr [[ARG]], align 4
; ATTRIBUTOR-NEXT: call void @fn_inaccessiblememonly() #[[ATTR21]]
; ATTRIBUTOR-NEXT: ret void
;
load i32, ptr %arg
call void @fn_inaccessiblememonly() readonly
ret void
}
define void @test_inaccessibleorargmemonly_readwrite(ptr %arg) {
; FNATTRS: Function Attrs: memory(argmem: write, inaccessiblemem: read)
; FNATTRS-LABEL: define void @test_inaccessibleorargmemonly_readwrite
; FNATTRS-SAME: (ptr nocapture writeonly [[ARG:%.*]]) #[[ATTR15:[0-9]+]] {
; FNATTRS-NEXT: store i32 0, ptr [[ARG]], align 4
; FNATTRS-NEXT: call void @fn_inaccessiblememonly() #[[ATTR19]]
; FNATTRS-NEXT: ret void
;
; ATTRIBUTOR: Function Attrs: nosync memory(argmem: readwrite, inaccessiblemem: readwrite)
; ATTRIBUTOR-LABEL: define void @test_inaccessibleorargmemonly_readwrite
; ATTRIBUTOR-SAME: (ptr nocapture nofree nonnull writeonly [[ARG:%.*]]) #[[ATTR14:[0-9]+]] {
; ATTRIBUTOR-NEXT: store i32 0, ptr [[ARG]], align 4
; ATTRIBUTOR-NEXT: call void @fn_inaccessiblememonly() #[[ATTR21]]
; ATTRIBUTOR-NEXT: ret void
;
store i32 0, ptr %arg
call void @fn_inaccessiblememonly() readonly
ret void
}
define void @test_recursive_argmem_read(ptr %p) {
; FNATTRS: Function Attrs: nofree nosync nounwind memory(read, inaccessiblemem: none)
; FNATTRS-LABEL: define void @test_recursive_argmem_read
; FNATTRS-SAME: (ptr nocapture readonly [[P:%.*]]) #[[ATTR16:[0-9]+]] {
; FNATTRS-NEXT: [[PVAL:%.*]] = load ptr, ptr [[P]], align 8
; FNATTRS-NEXT: call void @test_recursive_argmem_read(ptr [[PVAL]])
; FNATTRS-NEXT: ret void
;
; ATTRIBUTOR: Function Attrs: nofree nosync nounwind memory(read)
; ATTRIBUTOR-LABEL: define void @test_recursive_argmem_read
; ATTRIBUTOR-SAME: (ptr nocapture nofree nonnull readonly [[P:%.*]]) #[[ATTR15:[0-9]+]] {
; ATTRIBUTOR-NEXT: [[PVAL:%.*]] = load ptr, ptr [[P]], align 8
; ATTRIBUTOR-NEXT: call void @test_recursive_argmem_read(ptr nocapture nofree readonly [[PVAL]]) #[[ATTR15]]
; ATTRIBUTOR-NEXT: ret void
;
%pval = load ptr, ptr %p
call void @test_recursive_argmem_read(ptr %pval)
ret void
}
define void @test_recursive_argmem_readwrite(ptr %p) {
; FNATTRS: Function Attrs: nofree nosync nounwind memory(readwrite, inaccessiblemem: none)
; FNATTRS-LABEL: define void @test_recursive_argmem_readwrite
; FNATTRS-SAME: (ptr nocapture [[P:%.*]]) #[[ATTR17:[0-9]+]] {
; FNATTRS-NEXT: [[PVAL:%.*]] = load ptr, ptr [[P]], align 8
; FNATTRS-NEXT: store i32 0, ptr [[P]], align 4
; FNATTRS-NEXT: call void @test_recursive_argmem_readwrite(ptr [[PVAL]])
; FNATTRS-NEXT: ret void
;
; ATTRIBUTOR: Function Attrs: nofree nosync nounwind
; ATTRIBUTOR-LABEL: define void @test_recursive_argmem_readwrite
; ATTRIBUTOR-SAME: (ptr nocapture nofree nonnull [[P:%.*]]) #[[ATTR16:[0-9]+]] {
; ATTRIBUTOR-NEXT: [[PVAL:%.*]] = load ptr, ptr [[P]], align 8
; ATTRIBUTOR-NEXT: store i32 0, ptr [[P]], align 4
; ATTRIBUTOR-NEXT: call void @test_recursive_argmem_readwrite(ptr nocapture nofree [[PVAL]]) #[[ATTR16]]
; ATTRIBUTOR-NEXT: ret void
;
%pval = load ptr, ptr %p
store i32 0, ptr %p
call void @test_recursive_argmem_readwrite(ptr %pval)
ret void
}
define void @test_recursive_argmem_read_alloca(ptr %p) {
; FNATTRS: Function Attrs: nofree nosync nounwind memory(argmem: read)
; FNATTRS-LABEL: define void @test_recursive_argmem_read_alloca
; FNATTRS-SAME: (ptr nocapture readonly [[P:%.*]]) #[[ATTR18:[0-9]+]] {
; FNATTRS-NEXT: [[A:%.*]] = alloca ptr, align 8
; FNATTRS-NEXT: [[TMP1:%.*]] = load i32, ptr [[P]], align 4
; FNATTRS-NEXT: call void @test_recursive_argmem_read_alloca(ptr [[A]])
; FNATTRS-NEXT: ret void
;
; ATTRIBUTOR: Function Attrs: nofree nosync nounwind memory(argmem: read)
; ATTRIBUTOR-LABEL: define void @test_recursive_argmem_read_alloca
; ATTRIBUTOR-SAME: (ptr nocapture nofree nonnull readonly [[P:%.*]]) #[[ATTR17:[0-9]+]] {
; ATTRIBUTOR-NEXT: [[A:%.*]] = alloca ptr, align 8
; ATTRIBUTOR-NEXT: [[TMP1:%.*]] = load i32, ptr [[P]], align 4
; ATTRIBUTOR-NEXT: call void @test_recursive_argmem_read_alloca(ptr nocapture nofree nonnull readonly [[A]]) #[[ATTR15]]
; ATTRIBUTOR-NEXT: ret void
;
%a = alloca ptr
load i32, ptr %p
call void @test_recursive_argmem_read_alloca(ptr %a)
ret void
}
define void @test_scc_argmem_read_1(ptr %p) {
; FNATTRS: Function Attrs: nofree nosync nounwind memory(read, inaccessiblemem: none)
; FNATTRS-LABEL: define void @test_scc_argmem_read_1
; FNATTRS-SAME: (ptr nocapture readonly [[P:%.*]]) #[[ATTR16]] {
; FNATTRS-NEXT: [[PVAL:%.*]] = load ptr, ptr [[P]], align 8
; FNATTRS-NEXT: call void @test_scc_argmem_read_2(ptr [[PVAL]])
; FNATTRS-NEXT: ret void
;
; ATTRIBUTOR: Function Attrs: nofree nosync nounwind memory(read)
; ATTRIBUTOR-LABEL: define void @test_scc_argmem_read_1
; ATTRIBUTOR-SAME: (ptr nocapture nofree nonnull readonly [[P:%.*]]) #[[ATTR15]] {
; ATTRIBUTOR-NEXT: [[PVAL:%.*]] = load ptr, ptr [[P]], align 8
; ATTRIBUTOR-NEXT: call void @test_scc_argmem_read_2(ptr nocapture nofree readonly [[PVAL]]) #[[ATTR15]]
; ATTRIBUTOR-NEXT: ret void
;
%pval = load ptr, ptr %p
call void @test_scc_argmem_read_2(ptr %pval)
ret void
}
define void @test_scc_argmem_read_2(ptr %p) {
; FNATTRS: Function Attrs: nofree nosync nounwind memory(read, inaccessiblemem: none)
; FNATTRS-LABEL: define void @test_scc_argmem_read_2
; FNATTRS-SAME: (ptr nocapture readonly [[P:%.*]]) #[[ATTR16]] {
; FNATTRS-NEXT: call void @test_scc_argmem_read_1(ptr [[P]])
; FNATTRS-NEXT: ret void
;
; ATTRIBUTOR: Function Attrs: nofree nosync nounwind memory(read)
; ATTRIBUTOR-LABEL: define void @test_scc_argmem_read_2
; ATTRIBUTOR-SAME: (ptr nocapture nofree readonly [[P:%.*]]) #[[ATTR15]] {
; ATTRIBUTOR-NEXT: call void @test_scc_argmem_read_1(ptr nocapture nofree readonly [[P]]) #[[ATTR15]]
; ATTRIBUTOR-NEXT: ret void
;
call void @test_scc_argmem_read_1(ptr %p)
ret void
}