
This PR removes the old `nocapture` attribute, replacing it with the new `captures` attribute introduced in #116990. This change is intended to be essentially NFC, replacing existing uses of `nocapture` with `captures(none)` without adding any new analysis capabilities. Making use of non-`none` values is left for a followup. Some notes: * `nocapture` will be upgraded to `captures(none)` by the bitcode reader. * `nocapture` will also be upgraded by the textual IR reader. This is to make it easier to use old IR files and somewhat reduce the test churn in this PR. * Helper APIs like `doesNotCapture()` will check for `captures(none)`. * MLIR import will convert `captures(none)` into an `llvm.nocapture` attribute. The representation in the LLVM IR dialect should be updated separately.
673 lines
28 KiB
LLVM
673 lines
28 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 readonly captures(none) [[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 nofree nonnull readonly captures(none) [[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 readonly captures(none) [[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 nofree nonnull readonly captures(none) [[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 readonly captures(none) [[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 nofree nonnull readonly captures(none) [[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 writeonly captures(none) initializes((0, 4)) [[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 nofree nonnull writeonly captures(none) [[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 writeonly captures(none) initializes((0, 4)) [[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 nofree writeonly captures(none) [[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 readonly captures(none) [[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 nofree readonly captures(none) [[PTR:%.*]]) #[[ATTR1]] {
|
|
; ATTRIBUTOR-NEXT: entry:
|
|
; ATTRIBUTOR-NEXT: [[C:%.*]] = call i32 @test_only_read_arg(ptr nofree readonly captures(none) [[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 norecurse nosync nounwind willreturn memory(argmem: readwrite)
|
|
; FNATTRS-LABEL: define void @test_memcpy_argonly
|
|
; FNATTRS-SAME: (ptr writeonly captures(none) initializes((0, 32)) [[DST:%.*]], ptr readonly captures(none) [[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 nofree writeonly captures(none) [[DST:%.*]], ptr nofree readonly captures(none) [[SRC:%.*]]) #[[ATTR8:[0-9]+]] {
|
|
; ATTRIBUTOR-NEXT: entry:
|
|
; ATTRIBUTOR-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr writeonly captures(none) [[DST]], ptr readonly captures(none) [[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 norecurse nosync nounwind willreturn memory(readwrite, inaccessiblemem: none)
|
|
; FNATTRS-LABEL: define void @test_memcpy_src_global
|
|
; FNATTRS-SAME: (ptr writeonly captures(none) initializes((0, 32)) [[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 nofree writeonly captures(none) [[DST:%.*]]) #[[ATTR10:[0-9]+]] {
|
|
; ATTRIBUTOR-NEXT: entry:
|
|
; ATTRIBUTOR-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr writeonly captures(none) [[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 norecurse nosync nounwind willreturn memory(readwrite, inaccessiblemem: none)
|
|
; FNATTRS-LABEL: define void @test_memcpy_dst_global
|
|
; FNATTRS-SAME: (ptr readonly captures(none) [[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 nofree readonly captures(none) [[SRC:%.*]]) #[[ATTR10]] {
|
|
; ATTRIBUTOR-NEXT: entry:
|
|
; ATTRIBUTOR-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr writeonly @arr, ptr readonly captures(none) [[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 readonly captures(none) [[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 nofree nonnull readonly captures(none) [[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 readonly captures(none) [[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 nofree nonnull readonly captures(none) [[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 writeonly captures(none) initializes((0, 4)) [[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 nofree nonnull writeonly captures(none) [[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 readonly captures(none) [[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 nofree nonnull readonly captures(none) [[P:%.*]]) #[[ATTR15:[0-9]+]] {
|
|
; ATTRIBUTOR-NEXT: [[PVAL:%.*]] = load ptr, ptr [[P]], align 8
|
|
; ATTRIBUTOR-NEXT: call void @test_recursive_argmem_read(ptr nofree readonly captures(none) [[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 captures(none) [[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 nofree nonnull captures(none) [[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 nofree captures(none) [[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 readonly captures(none) [[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 nofree nonnull readonly captures(none) [[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 nofree nonnull readonly captures(none) [[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 readonly captures(none) [[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 nofree nonnull readonly captures(none) [[P:%.*]]) #[[ATTR15]] {
|
|
; ATTRIBUTOR-NEXT: [[PVAL:%.*]] = load ptr, ptr [[P]], align 8
|
|
; ATTRIBUTOR-NEXT: call void @test_scc_argmem_read_2(ptr nofree readonly captures(none) [[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 readonly captures(none) [[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 nofree readonly captures(none) [[P:%.*]]) #[[ATTR15]] {
|
|
; ATTRIBUTOR-NEXT: call void @test_scc_argmem_read_1(ptr nofree readonly captures(none) [[P]]) #[[ATTR15]]
|
|
; ATTRIBUTOR-NEXT: ret void
|
|
;
|
|
call void @test_scc_argmem_read_1(ptr %p)
|
|
ret void
|
|
}
|
|
|
|
define i64 @select_same_obj(i1 %c, ptr %p, i64 %x) {
|
|
; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
|
|
; FNATTRS-LABEL: define i64 @select_same_obj
|
|
; FNATTRS-SAME: (i1 [[C:%.*]], ptr readonly captures(none) [[P:%.*]], i64 [[X:%.*]]) #[[ATTR1]] {
|
|
; FNATTRS-NEXT: entry:
|
|
; FNATTRS-NEXT: [[P2:%.*]] = getelementptr i8, ptr [[P]], i64 [[X]]
|
|
; FNATTRS-NEXT: [[P3:%.*]] = select i1 [[C]], ptr [[P]], ptr [[P2]]
|
|
; FNATTRS-NEXT: [[R:%.*]] = load i64, ptr [[P3]], align 4
|
|
; FNATTRS-NEXT: ret i64 [[R]]
|
|
;
|
|
; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
|
|
; ATTRIBUTOR-LABEL: define i64 @select_same_obj
|
|
; ATTRIBUTOR-SAME: (i1 [[C:%.*]], ptr nofree readonly captures(none) [[P:%.*]], i64 [[X:%.*]]) #[[ATTR0]] {
|
|
; ATTRIBUTOR-NEXT: entry:
|
|
; ATTRIBUTOR-NEXT: [[P2:%.*]] = getelementptr i8, ptr [[P]], i64 [[X]]
|
|
; ATTRIBUTOR-NEXT: [[P3:%.*]] = select i1 [[C]], ptr [[P]], ptr [[P2]]
|
|
; ATTRIBUTOR-NEXT: [[R:%.*]] = load i64, ptr [[P3]], align 4
|
|
; ATTRIBUTOR-NEXT: ret i64 [[R]]
|
|
;
|
|
entry:
|
|
%p2 = getelementptr i8, ptr %p, i64 %x
|
|
%p3 = select i1 %c, ptr %p, ptr %p2
|
|
%r = load i64, ptr %p3
|
|
ret i64 %r
|
|
}
|
|
|
|
; FIXME: This could be `memory(argmem: read)`.
|
|
define i64 @select_different_obj(i1 %c, ptr %p, ptr %p2) {
|
|
; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read, inaccessiblemem: none)
|
|
; FNATTRS-LABEL: define i64 @select_different_obj
|
|
; FNATTRS-SAME: (i1 [[C:%.*]], ptr readonly captures(none) [[P:%.*]], ptr readonly captures(none) [[P2:%.*]]) #[[ATTR3]] {
|
|
; FNATTRS-NEXT: entry:
|
|
; FNATTRS-NEXT: [[P3:%.*]] = select i1 [[C]], ptr [[P]], ptr [[P2]]
|
|
; FNATTRS-NEXT: [[R:%.*]] = load i64, ptr [[P3]], align 4
|
|
; FNATTRS-NEXT: ret i64 [[R]]
|
|
;
|
|
; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
|
|
; ATTRIBUTOR-LABEL: define i64 @select_different_obj
|
|
; ATTRIBUTOR-SAME: (i1 [[C:%.*]], ptr nofree readonly captures(none) [[P:%.*]], ptr nofree readonly captures(none) [[P2:%.*]]) #[[ATTR0]] {
|
|
; ATTRIBUTOR-NEXT: entry:
|
|
; ATTRIBUTOR-NEXT: [[P3:%.*]] = select i1 [[C]], ptr [[P]], ptr [[P2]]
|
|
; ATTRIBUTOR-NEXT: [[R:%.*]] = load i64, ptr [[P3]], align 4
|
|
; ATTRIBUTOR-NEXT: ret i64 [[R]]
|
|
;
|
|
entry:
|
|
%p3 = select i1 %c, ptr %p, ptr %p2
|
|
%r = load i64, ptr %p3
|
|
ret i64 %r
|
|
}
|
|
|
|
define i64 @phi_same_obj(i1 %c, ptr %p, i64 %x) {
|
|
; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
|
|
; FNATTRS-LABEL: define i64 @phi_same_obj
|
|
; FNATTRS-SAME: (i1 [[C:%.*]], ptr readonly captures(none) [[P:%.*]], i64 [[X:%.*]]) #[[ATTR1]] {
|
|
; FNATTRS-NEXT: entry:
|
|
; FNATTRS-NEXT: [[P2:%.*]] = getelementptr i8, ptr [[P]], i64 [[X]]
|
|
; FNATTRS-NEXT: br i1 [[C]], label [[IF:%.*]], label [[JOIN:%.*]]
|
|
; FNATTRS: if:
|
|
; FNATTRS-NEXT: br label [[JOIN]]
|
|
; FNATTRS: join:
|
|
; FNATTRS-NEXT: [[P3:%.*]] = phi ptr [ [[P]], [[IF]] ], [ [[P2]], [[ENTRY:%.*]] ]
|
|
; FNATTRS-NEXT: [[R:%.*]] = load i64, ptr [[P3]], align 4
|
|
; FNATTRS-NEXT: ret i64 [[R]]
|
|
;
|
|
; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
|
|
; ATTRIBUTOR-LABEL: define i64 @phi_same_obj
|
|
; ATTRIBUTOR-SAME: (i1 [[C:%.*]], ptr nofree readonly captures(none) [[P:%.*]], i64 [[X:%.*]]) #[[ATTR1]] {
|
|
; ATTRIBUTOR-NEXT: entry:
|
|
; ATTRIBUTOR-NEXT: [[P2:%.*]] = getelementptr i8, ptr [[P]], i64 [[X]]
|
|
; ATTRIBUTOR-NEXT: br i1 [[C]], label [[IF:%.*]], label [[JOIN:%.*]]
|
|
; ATTRIBUTOR: if:
|
|
; ATTRIBUTOR-NEXT: br label [[JOIN]]
|
|
; ATTRIBUTOR: join:
|
|
; ATTRIBUTOR-NEXT: [[P3:%.*]] = phi ptr [ [[P]], [[IF]] ], [ [[P2]], [[ENTRY:%.*]] ]
|
|
; ATTRIBUTOR-NEXT: [[R:%.*]] = load i64, ptr [[P3]], align 4
|
|
; ATTRIBUTOR-NEXT: ret i64 [[R]]
|
|
;
|
|
entry:
|
|
%p2 = getelementptr i8, ptr %p, i64 %x
|
|
br i1 %c, label %if, label %join
|
|
if:
|
|
br label %join
|
|
join:
|
|
%p3 = phi ptr [ %p, %if ], [ %p2, %entry ]
|
|
%r = load i64, ptr %p3
|
|
ret i64 %r
|
|
}
|
|
|
|
; FIXME: This could be `memory(argmem: read)`.
|
|
define i64 @phi_different_obj(i1 %c, ptr %p, ptr %p2) {
|
|
; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read, inaccessiblemem: none)
|
|
; FNATTRS-LABEL: define i64 @phi_different_obj
|
|
; FNATTRS-SAME: (i1 [[C:%.*]], ptr readonly captures(none) [[P:%.*]], ptr readonly captures(none) [[P2:%.*]]) #[[ATTR3]] {
|
|
; FNATTRS-NEXT: entry:
|
|
; FNATTRS-NEXT: br i1 [[C]], label [[IF:%.*]], label [[JOIN:%.*]]
|
|
; FNATTRS: if:
|
|
; FNATTRS-NEXT: br label [[JOIN]]
|
|
; FNATTRS: join:
|
|
; FNATTRS-NEXT: [[P3:%.*]] = phi ptr [ [[P]], [[IF]] ], [ [[P2]], [[ENTRY:%.*]] ]
|
|
; FNATTRS-NEXT: [[R:%.*]] = load i64, ptr [[P3]], align 4
|
|
; FNATTRS-NEXT: ret i64 [[R]]
|
|
;
|
|
; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
|
|
; ATTRIBUTOR-LABEL: define i64 @phi_different_obj
|
|
; ATTRIBUTOR-SAME: (i1 [[C:%.*]], ptr nofree readonly captures(none) [[P:%.*]], ptr nofree readonly captures(none) [[P2:%.*]]) #[[ATTR1]] {
|
|
; ATTRIBUTOR-NEXT: entry:
|
|
; ATTRIBUTOR-NEXT: br i1 [[C]], label [[IF:%.*]], label [[JOIN:%.*]]
|
|
; ATTRIBUTOR: if:
|
|
; ATTRIBUTOR-NEXT: br label [[JOIN]]
|
|
; ATTRIBUTOR: join:
|
|
; ATTRIBUTOR-NEXT: [[P3:%.*]] = phi ptr [ [[P]], [[IF]] ], [ [[P2]], [[ENTRY:%.*]] ]
|
|
; ATTRIBUTOR-NEXT: [[R:%.*]] = load i64, ptr [[P3]], align 4
|
|
; ATTRIBUTOR-NEXT: ret i64 [[R]]
|
|
;
|
|
entry:
|
|
br i1 %c, label %if, label %join
|
|
if:
|
|
br label %join
|
|
join:
|
|
%p3 = phi ptr [ %p, %if ], [ %p2, %entry ]
|
|
%r = load i64, ptr %p3
|
|
ret i64 %r
|
|
}
|
|
|
|
; An `alloca` that won't be handled by `getModRefInfoMask`
|
|
define i64 @alloca_with_phis(i64 %arg, i1 %cmp) {
|
|
; COMMON: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
|
|
; COMMON-LABEL: define i64 @alloca_with_phis
|
|
; COMMON-SAME: (i64 [[ARG:%.*]], i1 [[CMP:%.*]]) #[[ATTR0]] {
|
|
; COMMON-NEXT: bb:
|
|
; COMMON-NEXT: [[I:%.*]] = alloca i64, align 8
|
|
; COMMON-NEXT: store i64 [[ARG]], ptr [[I]], align 4
|
|
; COMMON-NEXT: br i1 [[CMP]], label [[BB1:%.*]], label [[BB4:%.*]]
|
|
; COMMON: bb1:
|
|
; COMMON-NEXT: br i1 [[CMP]], label [[BB8:%.*]], label [[BB2:%.*]]
|
|
; COMMON: bb2:
|
|
; COMMON-NEXT: br i1 [[CMP]], label [[BB8]], label [[BB3:%.*]]
|
|
; COMMON: bb3:
|
|
; COMMON-NEXT: br i1 [[CMP]], label [[BB8]], label [[BB6:%.*]]
|
|
; COMMON: bb4:
|
|
; COMMON-NEXT: br i1 [[CMP]], label [[BB8]], label [[BB5:%.*]]
|
|
; COMMON: bb5:
|
|
; COMMON-NEXT: br i1 [[CMP]], label [[BB8]], label [[BB6]]
|
|
; COMMON: bb6:
|
|
; COMMON-NEXT: [[I7:%.*]] = phi ptr [ [[I]], [[BB3]] ], [ [[I]], [[BB5]] ]
|
|
; COMMON-NEXT: br label [[BB8]]
|
|
; COMMON: bb8:
|
|
; COMMON-NEXT: [[I9:%.*]] = phi ptr [ [[I]], [[BB1]] ], [ [[I]], [[BB2]] ], [ [[I]], [[BB3]] ], [ [[I]], [[BB4]] ], [ [[I]], [[BB5]] ], [ [[I7]], [[BB6]] ]
|
|
; COMMON-NEXT: [[RET:%.*]] = load i64, ptr [[I9]], align 4
|
|
; COMMON-NEXT: ret i64 [[RET]]
|
|
;
|
|
bb:
|
|
%i = alloca i64
|
|
store i64 %arg, ptr %i
|
|
br i1 %cmp, label %bb1, label %bb4
|
|
|
|
bb1: ; preds = %bb
|
|
br i1 %cmp, label %bb8, label %bb2
|
|
|
|
bb2: ; preds = %bb1
|
|
br i1 %cmp, label %bb8, label %bb3
|
|
|
|
bb3: ; preds = %bb2
|
|
br i1 %cmp, label %bb8, label %bb6
|
|
|
|
bb4: ; preds = %bb
|
|
br i1 %cmp, label %bb8, label %bb5
|
|
|
|
bb5: ; preds = %bb4
|
|
br i1 %cmp, label %bb8, label %bb6
|
|
|
|
bb6: ; preds = %bb5, %bb3
|
|
%i7 = phi ptr [ %i, %bb3 ], [ %i, %bb5 ]
|
|
br label %bb8
|
|
|
|
bb8: ; preds = %bb6, %bb5, %bb4, %bb3, %bb2, %bb1
|
|
%i9 = phi ptr [ %i, %bb1 ], [ %i, %bb2 ], [ %i, %bb3 ], [ %i, %bb4 ], [ %i, %bb5 ], [ %i7, %bb6 ]
|
|
%ret = load i64, ptr %i9
|
|
ret i64 %ret
|
|
}
|