This adds a writable attribute, which in conjunction with dereferenceable(N) states that a spurious store of N bytes is introduced on function entry. This implies that this many bytes are writable without trapping or introducing data races. See https://llvm.org/docs/Atomics.html#optimization-outside-atomic for why the second point is important. This attribute can be added to sret arguments. I believe Rust will also be able to use it for by-value (moved) arguments. Rust likely won't be able to use it for &mut arguments (tree borrows does not appear to allow spurious stores). In this patch the new attribute is only used by LICM scalar promotion. However, the actual motivation for this is to fix a correctness issue in call slot optimization, which needs this attribute to avoid optimization regressions. Followup to the discussion on D157499. Differential Revision: https://reviews.llvm.org/D158081
767 lines
35 KiB
LLVM
767 lines
35 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes
|
|
; RUN: opt < %s -passes=function-attrs -S | FileCheck --check-prefixes=COMMON,FNATTRS %s
|
|
; RUN: opt < %s -passes=attributor-light -S | FileCheck --check-prefixes=COMMON,ATTRIBUTOR %s
|
|
; RUN: opt < %s -passes=attributor-light-cgscc -S | FileCheck --check-prefixes=COMMON,ATTRIBUTOR-CGSCC %s
|
|
|
|
@x = global i32 0
|
|
|
|
declare void @test1_1(ptr %x1_1, ptr nocapture readonly %y1_1, ...)
|
|
|
|
define void @test1_2(ptr %x1_2, ptr %y1_2, ptr %z1_2) {
|
|
; FNATTRS-LABEL: define {{[^@]+}}@test1_2
|
|
; FNATTRS-SAME: (ptr [[X1_2:%.*]], ptr nocapture readonly [[Y1_2:%.*]], ptr [[Z1_2:%.*]]) {
|
|
; FNATTRS-NEXT: call void (ptr, ptr, ...) @test1_1(ptr [[X1_2]], ptr [[Y1_2]], ptr [[Z1_2]])
|
|
; FNATTRS-NEXT: store i32 0, ptr @x, align 4
|
|
; FNATTRS-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@test1_2
|
|
; ATTRIBUTOR-SAME: (ptr [[X1_2:%.*]], ptr nocapture nofree readonly [[Y1_2:%.*]], ptr [[Z1_2:%.*]]) {
|
|
; ATTRIBUTOR-NEXT: call void (ptr, ptr, ...) @test1_1(ptr [[X1_2]], ptr nocapture nofree readonly [[Y1_2]], ptr [[Z1_2]])
|
|
; ATTRIBUTOR-NEXT: store i32 0, ptr @x, align 4
|
|
; ATTRIBUTOR-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@test1_2
|
|
; ATTRIBUTOR-CGSCC-SAME: (ptr [[X1_2:%.*]], ptr nocapture nofree readonly [[Y1_2:%.*]], ptr [[Z1_2:%.*]]) {
|
|
; ATTRIBUTOR-CGSCC-NEXT: call void (ptr, ptr, ...) @test1_1(ptr [[X1_2]], ptr nocapture nofree readonly [[Y1_2]], ptr [[Z1_2]])
|
|
; ATTRIBUTOR-CGSCC-NEXT: store i32 0, ptr @x, align 4
|
|
; ATTRIBUTOR-CGSCC-NEXT: ret void
|
|
;
|
|
call void (ptr, ptr, ...) @test1_1(ptr %x1_2, ptr %y1_2, ptr %z1_2)
|
|
store i32 0, ptr @x
|
|
ret void
|
|
}
|
|
|
|
; TODO: Missing with attributor-light: argmem: none, inaccessiblemem: none
|
|
define ptr @test2(ptr %p) {
|
|
; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write, argmem: none, inaccessiblemem: none)
|
|
; FNATTRS-LABEL: define {{[^@]+}}@test2
|
|
; FNATTRS-SAME: (ptr readnone returned [[P:%.*]]) #[[ATTR0:[0-9]+]] {
|
|
; FNATTRS-NEXT: store i32 0, ptr @x, align 4
|
|
; FNATTRS-NEXT: ret ptr [[P]]
|
|
;
|
|
; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write)
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@test2
|
|
; ATTRIBUTOR-SAME: (ptr nofree readnone [[P:%.*]]) #[[ATTR0:[0-9]+]] {
|
|
; ATTRIBUTOR-NEXT: store i32 0, ptr @x, align 4
|
|
; ATTRIBUTOR-NEXT: ret ptr [[P]]
|
|
;
|
|
; ATTRIBUTOR-CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write)
|
|
; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@test2
|
|
; ATTRIBUTOR-CGSCC-SAME: (ptr nofree readnone [[P:%.*]]) #[[ATTR0:[0-9]+]] {
|
|
; ATTRIBUTOR-CGSCC-NEXT: store i32 0, ptr @x, align 4
|
|
; ATTRIBUTOR-CGSCC-NEXT: ret ptr [[P]]
|
|
;
|
|
store i32 0, ptr @x
|
|
ret ptr %p
|
|
}
|
|
|
|
define i1 @test3(ptr %p, ptr %q) {
|
|
; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
|
|
; FNATTRS-LABEL: define {{[^@]+}}@test3
|
|
; FNATTRS-SAME: (ptr readnone [[P:%.*]], ptr readnone [[Q:%.*]]) #[[ATTR1:[0-9]+]] {
|
|
; FNATTRS-NEXT: [[A:%.*]] = icmp ult ptr [[P]], [[Q]]
|
|
; FNATTRS-NEXT: ret i1 [[A]]
|
|
;
|
|
; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@test3
|
|
; ATTRIBUTOR-SAME: (ptr nofree readnone [[P:%.*]], ptr nofree readnone [[Q:%.*]]) #[[ATTR1:[0-9]+]] {
|
|
; ATTRIBUTOR-NEXT: [[A:%.*]] = icmp ult ptr [[P]], [[Q]]
|
|
; ATTRIBUTOR-NEXT: ret i1 [[A]]
|
|
;
|
|
; ATTRIBUTOR-CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
|
|
; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@test3
|
|
; ATTRIBUTOR-CGSCC-SAME: (ptr nofree readnone [[P:%.*]], ptr nofree readnone [[Q:%.*]]) #[[ATTR1:[0-9]+]] {
|
|
; ATTRIBUTOR-CGSCC-NEXT: [[A:%.*]] = icmp ult ptr [[P]], [[Q]]
|
|
; ATTRIBUTOR-CGSCC-NEXT: ret i1 [[A]]
|
|
;
|
|
%A = icmp ult ptr %p, %q
|
|
ret i1 %A
|
|
}
|
|
|
|
declare void @test4_1(ptr nocapture) readonly
|
|
|
|
define void @test4_2(ptr %p) {
|
|
; FNATTRS: Function Attrs: nofree memory(read)
|
|
; FNATTRS-LABEL: define {{[^@]+}}@test4_2
|
|
; FNATTRS-SAME: (ptr nocapture readonly [[P:%.*]]) #[[ATTR3:[0-9]+]] {
|
|
; FNATTRS-NEXT: call void @test4_1(ptr [[P]])
|
|
; FNATTRS-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR: Function Attrs: nosync memory(read)
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@test4_2
|
|
; ATTRIBUTOR-SAME: (ptr nocapture readonly [[P:%.*]]) #[[ATTR3:[0-9]+]] {
|
|
; ATTRIBUTOR-NEXT: call void @test4_1(ptr nocapture readonly [[P]]) #[[ATTR3]]
|
|
; ATTRIBUTOR-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-CGSCC: Function Attrs: nosync memory(read)
|
|
; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@test4_2
|
|
; ATTRIBUTOR-CGSCC-SAME: (ptr nocapture readonly [[P:%.*]]) #[[ATTR3:[0-9]+]] {
|
|
; ATTRIBUTOR-CGSCC-NEXT: call void @test4_1(ptr nocapture readonly [[P]]) #[[ATTR3]]
|
|
; ATTRIBUTOR-CGSCC-NEXT: ret void
|
|
;
|
|
call void @test4_1(ptr %p)
|
|
ret void
|
|
}
|
|
|
|
; Missed optz'n: we could make %q readnone, but don't break test6!
|
|
define void @test5(ptr %p, ptr %q) {
|
|
; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
|
|
; FNATTRS-LABEL: define {{[^@]+}}@test5
|
|
; FNATTRS-SAME: (ptr nocapture writeonly [[P:%.*]], ptr [[Q:%.*]]) #[[ATTR4:[0-9]+]] {
|
|
; FNATTRS-NEXT: store ptr [[Q]], ptr [[P]], align 8
|
|
; FNATTRS-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@test5
|
|
; ATTRIBUTOR-SAME: (ptr nocapture nofree nonnull writeonly [[P:%.*]], ptr nofree writeonly [[Q:%.*]]) #[[ATTR4:[0-9]+]] {
|
|
; ATTRIBUTOR-NEXT: store ptr [[Q]], ptr [[P]], align 8
|
|
; ATTRIBUTOR-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
|
|
; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@test5
|
|
; ATTRIBUTOR-CGSCC-SAME: (ptr nocapture nofree nonnull writeonly [[P:%.*]], ptr nofree writeonly [[Q:%.*]]) #[[ATTR4:[0-9]+]] {
|
|
; ATTRIBUTOR-CGSCC-NEXT: store ptr [[Q]], ptr [[P]], align 8
|
|
; ATTRIBUTOR-CGSCC-NEXT: ret void
|
|
;
|
|
store ptr %q, ptr %p
|
|
ret void
|
|
}
|
|
|
|
declare void @test6_1()
|
|
|
|
; This is not a missed optz'n.
|
|
define void @test6_2(ptr %p, ptr %q) {
|
|
; FNATTRS-LABEL: define {{[^@]+}}@test6_2
|
|
; FNATTRS-SAME: (ptr nocapture writeonly [[P:%.*]], ptr [[Q:%.*]]) {
|
|
; FNATTRS-NEXT: store ptr [[Q]], ptr [[P]], align 8
|
|
; FNATTRS-NEXT: call void @test6_1()
|
|
; FNATTRS-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@test6_2
|
|
; ATTRIBUTOR-SAME: (ptr nocapture nofree nonnull writeonly [[P:%.*]], ptr nofree [[Q:%.*]]) {
|
|
; ATTRIBUTOR-NEXT: store ptr [[Q]], ptr [[P]], align 8
|
|
; ATTRIBUTOR-NEXT: call void @test6_1()
|
|
; ATTRIBUTOR-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@test6_2
|
|
; ATTRIBUTOR-CGSCC-SAME: (ptr nocapture nofree nonnull writeonly [[P:%.*]], ptr nofree [[Q:%.*]]) {
|
|
; ATTRIBUTOR-CGSCC-NEXT: store ptr [[Q]], ptr [[P]], align 8
|
|
; ATTRIBUTOR-CGSCC-NEXT: call void @test6_1()
|
|
; ATTRIBUTOR-CGSCC-NEXT: ret void
|
|
;
|
|
store ptr %q, ptr %p
|
|
call void @test6_1()
|
|
ret void
|
|
}
|
|
|
|
; inalloca parameters are always considered written
|
|
define void @test7_1(ptr inalloca(i32) %a) {
|
|
; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite)
|
|
; FNATTRS-LABEL: define {{[^@]+}}@test7_1
|
|
; FNATTRS-SAME: (ptr nocapture inalloca(i32) [[A:%.*]]) #[[ATTR5:[0-9]+]] {
|
|
; FNATTRS-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@test7_1
|
|
; ATTRIBUTOR-SAME: (ptr nocapture nofree nonnull writeonly inalloca(i32) [[A:%.*]]) #[[ATTR1]] {
|
|
; ATTRIBUTOR-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
|
|
; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@test7_1
|
|
; ATTRIBUTOR-CGSCC-SAME: (ptr nocapture nofree nonnull writeonly inalloca(i32) [[A:%.*]]) #[[ATTR1]] {
|
|
; ATTRIBUTOR-CGSCC-NEXT: ret void
|
|
;
|
|
ret void
|
|
}
|
|
|
|
; preallocated parameters are always considered written
|
|
define void @test7_2(ptr preallocated(i32) %a) {
|
|
; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite)
|
|
; FNATTRS-LABEL: define {{[^@]+}}@test7_2
|
|
; FNATTRS-SAME: (ptr nocapture preallocated(i32) [[A:%.*]]) #[[ATTR5]] {
|
|
; FNATTRS-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@test7_2
|
|
; ATTRIBUTOR-SAME: (ptr nocapture nofree nonnull writeonly preallocated(i32) [[A:%.*]]) #[[ATTR1]] {
|
|
; ATTRIBUTOR-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
|
|
; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@test7_2
|
|
; ATTRIBUTOR-CGSCC-SAME: (ptr nocapture nofree nonnull writeonly preallocated(i32) [[A:%.*]]) #[[ATTR1]] {
|
|
; ATTRIBUTOR-CGSCC-NEXT: ret void
|
|
;
|
|
ret void
|
|
}
|
|
|
|
define ptr @test8_1(ptr %p) {
|
|
; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
|
|
; FNATTRS-LABEL: define {{[^@]+}}@test8_1
|
|
; FNATTRS-SAME: (ptr readnone returned [[P:%.*]]) #[[ATTR1]] {
|
|
; FNATTRS-NEXT: entry:
|
|
; FNATTRS-NEXT: ret ptr [[P]]
|
|
;
|
|
; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@test8_1
|
|
; ATTRIBUTOR-SAME: (ptr nofree readnone [[P:%.*]]) #[[ATTR1]] {
|
|
; ATTRIBUTOR-NEXT: entry:
|
|
; ATTRIBUTOR-NEXT: ret ptr [[P]]
|
|
;
|
|
; ATTRIBUTOR-CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
|
|
; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@test8_1
|
|
; ATTRIBUTOR-CGSCC-SAME: (ptr nofree readnone [[P:%.*]]) #[[ATTR1]] {
|
|
; ATTRIBUTOR-CGSCC-NEXT: entry:
|
|
; ATTRIBUTOR-CGSCC-NEXT: ret ptr [[P]]
|
|
;
|
|
entry:
|
|
ret ptr %p
|
|
}
|
|
|
|
define void @test8_2(ptr %p) {
|
|
; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
|
|
; FNATTRS-LABEL: define {{[^@]+}}@test8_2
|
|
; FNATTRS-SAME: (ptr writeonly [[P:%.*]]) #[[ATTR4]] {
|
|
; FNATTRS-NEXT: entry:
|
|
; FNATTRS-NEXT: [[CALL:%.*]] = call ptr @test8_1(ptr [[P]])
|
|
; FNATTRS-NEXT: store i32 10, ptr [[CALL]], align 4
|
|
; FNATTRS-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write)
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@test8_2
|
|
; ATTRIBUTOR-SAME: (ptr nocapture nofree writeonly [[P:%.*]]) #[[ATTR0]] {
|
|
; ATTRIBUTOR-NEXT: entry:
|
|
; ATTRIBUTOR-NEXT: [[CALL:%.*]] = call ptr @test8_1(ptr nofree readnone [[P]]) #[[ATTR14:[0-9]+]]
|
|
; ATTRIBUTOR-NEXT: store i32 10, ptr [[CALL]], align 4
|
|
; ATTRIBUTOR-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(write)
|
|
; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@test8_2
|
|
; ATTRIBUTOR-CGSCC-SAME: (ptr nofree writeonly [[P:%.*]]) #[[ATTR5:[0-9]+]] {
|
|
; ATTRIBUTOR-CGSCC-NEXT: entry:
|
|
; ATTRIBUTOR-CGSCC-NEXT: [[CALL:%.*]] = call ptr @test8_1(ptr nofree readnone [[P]]) #[[ATTR14:[0-9]+]]
|
|
; ATTRIBUTOR-CGSCC-NEXT: store i32 10, ptr [[CALL]], align 4
|
|
; ATTRIBUTOR-CGSCC-NEXT: ret void
|
|
;
|
|
entry:
|
|
%call = call ptr @test8_1(ptr %p)
|
|
store i32 10, ptr %call, align 4
|
|
ret void
|
|
}
|
|
|
|
declare void @llvm.masked.scatter.v4i32.v4p0(<4 x i32>%val, <4 x ptr>, i32, <4 x i1>)
|
|
|
|
define void @test9(<4 x ptr> %ptrs, <4 x i32>%val) {
|
|
; FNATTRS: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(write)
|
|
; FNATTRS-LABEL: define {{[^@]+}}@test9
|
|
; FNATTRS-SAME: (<4 x ptr> [[PTRS:%.*]], <4 x i32> [[VAL:%.*]]) #[[ATTR7:[0-9]+]] {
|
|
; FNATTRS-NEXT: call void @llvm.masked.scatter.v4i32.v4p0(<4 x i32> [[VAL]], <4 x ptr> [[PTRS]], i32 4, <4 x i1> <i1 true, i1 false, i1 true, i1 false>)
|
|
; FNATTRS-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write)
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@test9
|
|
; ATTRIBUTOR-SAME: (<4 x ptr> [[PTRS:%.*]], <4 x i32> [[VAL:%.*]]) #[[ATTR0]] {
|
|
; ATTRIBUTOR-NEXT: call void @llvm.masked.scatter.v4i32.v4p0(<4 x i32> [[VAL]], <4 x ptr> [[PTRS]], i32 4, <4 x i1> <i1 true, i1 false, i1 true, i1 false>) #[[ATTR15:[0-9]+]]
|
|
; ATTRIBUTOR-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write)
|
|
; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@test9
|
|
; ATTRIBUTOR-CGSCC-SAME: (<4 x ptr> [[PTRS:%.*]], <4 x i32> [[VAL:%.*]]) #[[ATTR0]] {
|
|
; ATTRIBUTOR-CGSCC-NEXT: call void @llvm.masked.scatter.v4i32.v4p0(<4 x i32> [[VAL]], <4 x ptr> [[PTRS]], i32 4, <4 x i1> <i1 true, i1 false, i1 true, i1 false>) #[[ATTR15:[0-9]+]]
|
|
; ATTRIBUTOR-CGSCC-NEXT: ret void
|
|
;
|
|
call void @llvm.masked.scatter.v4i32.v4p0(<4 x i32>%val, <4 x ptr> %ptrs, i32 4, <4 x i1><i1 true, i1 false, i1 true, i1 false>)
|
|
ret void
|
|
}
|
|
|
|
declare <4 x i32> @llvm.masked.gather.v4i32.v4p0(<4 x ptr>, i32, <4 x i1>, <4 x i32>)
|
|
define <4 x i32> @test10(<4 x ptr> %ptrs) {
|
|
; FNATTRS: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(read)
|
|
; FNATTRS-LABEL: define {{[^@]+}}@test10
|
|
; FNATTRS-SAME: (<4 x ptr> [[PTRS:%.*]]) #[[ATTR9:[0-9]+]] {
|
|
; FNATTRS-NEXT: [[RES:%.*]] = call <4 x i32> @llvm.masked.gather.v4i32.v4p0(<4 x ptr> [[PTRS]], i32 4, <4 x i1> <i1 true, i1 false, i1 true, i1 false>, <4 x i32> undef)
|
|
; FNATTRS-NEXT: ret <4 x i32> [[RES]]
|
|
;
|
|
; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read)
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@test10
|
|
; ATTRIBUTOR-SAME: (<4 x ptr> [[PTRS:%.*]]) #[[ATTR7:[0-9]+]] {
|
|
; ATTRIBUTOR-NEXT: [[RES:%.*]] = call <4 x i32> @llvm.masked.gather.v4i32.v4p0(<4 x ptr> [[PTRS]], i32 4, <4 x i1> <i1 true, i1 false, i1 true, i1 false>, <4 x i32> undef) #[[ATTR16:[0-9]+]]
|
|
; ATTRIBUTOR-NEXT: ret <4 x i32> [[RES]]
|
|
;
|
|
; ATTRIBUTOR-CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read)
|
|
; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@test10
|
|
; ATTRIBUTOR-CGSCC-SAME: (<4 x ptr> [[PTRS:%.*]]) #[[ATTR8:[0-9]+]] {
|
|
; ATTRIBUTOR-CGSCC-NEXT: [[RES:%.*]] = call <4 x i32> @llvm.masked.gather.v4i32.v4p0(<4 x ptr> [[PTRS]], i32 4, <4 x i1> <i1 true, i1 false, i1 true, i1 false>, <4 x i32> undef) #[[ATTR16:[0-9]+]]
|
|
; ATTRIBUTOR-CGSCC-NEXT: ret <4 x i32> [[RES]]
|
|
;
|
|
%res = call <4 x i32> @llvm.masked.gather.v4i32.v4p0(<4 x ptr> %ptrs, i32 4, <4 x i1><i1 true, i1 false, i1 true, i1 false>, <4 x i32>undef)
|
|
ret <4 x i32> %res
|
|
}
|
|
|
|
declare <4 x i32> @test11_1(<4 x ptr>) argmemonly nounwind readonly
|
|
define <4 x i32> @test11_2(<4 x ptr> %ptrs) {
|
|
; FNATTRS: Function Attrs: nofree nounwind memory(argmem: read)
|
|
; FNATTRS-LABEL: define {{[^@]+}}@test11_2
|
|
; FNATTRS-SAME: (<4 x ptr> [[PTRS:%.*]]) #[[ATTR11:[0-9]+]] {
|
|
; FNATTRS-NEXT: [[RES:%.*]] = call <4 x i32> @test11_1(<4 x ptr> [[PTRS]])
|
|
; FNATTRS-NEXT: ret <4 x i32> [[RES]]
|
|
;
|
|
; ATTRIBUTOR: Function Attrs: nosync nounwind memory(argmem: read)
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@test11_2
|
|
; ATTRIBUTOR-SAME: (<4 x ptr> [[PTRS:%.*]]) #[[ATTR9:[0-9]+]] {
|
|
; ATTRIBUTOR-NEXT: [[RES:%.*]] = call <4 x i32> @test11_1(<4 x ptr> [[PTRS]]) #[[ATTR3]]
|
|
; ATTRIBUTOR-NEXT: ret <4 x i32> [[RES]]
|
|
;
|
|
; ATTRIBUTOR-CGSCC: Function Attrs: nosync nounwind memory(argmem: read)
|
|
; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@test11_2
|
|
; ATTRIBUTOR-CGSCC-SAME: (<4 x ptr> [[PTRS:%.*]]) #[[ATTR10:[0-9]+]] {
|
|
; ATTRIBUTOR-CGSCC-NEXT: [[RES:%.*]] = call <4 x i32> @test11_1(<4 x ptr> [[PTRS]]) #[[ATTR3]]
|
|
; ATTRIBUTOR-CGSCC-NEXT: ret <4 x i32> [[RES]]
|
|
;
|
|
%res = call <4 x i32> @test11_1(<4 x ptr> %ptrs)
|
|
ret <4 x i32> %res
|
|
}
|
|
|
|
declare <4 x i32> @test12_1(<4 x ptr>) argmemonly nounwind
|
|
define <4 x i32> @test12_2(<4 x ptr> %ptrs) {
|
|
; FNATTRS: Function Attrs: nounwind memory(argmem: readwrite)
|
|
; FNATTRS-LABEL: define {{[^@]+}}@test12_2
|
|
; FNATTRS-SAME: (<4 x ptr> [[PTRS:%.*]]) #[[ATTR12:[0-9]+]] {
|
|
; FNATTRS-NEXT: [[RES:%.*]] = call <4 x i32> @test12_1(<4 x ptr> [[PTRS]])
|
|
; FNATTRS-NEXT: ret <4 x i32> [[RES]]
|
|
;
|
|
; ATTRIBUTOR: Function Attrs: nounwind memory(argmem: readwrite)
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@test12_2
|
|
; ATTRIBUTOR-SAME: (<4 x ptr> [[PTRS:%.*]]) #[[ATTR10:[0-9]+]] {
|
|
; ATTRIBUTOR-NEXT: [[RES:%.*]] = call <4 x i32> @test12_1(<4 x ptr> [[PTRS]])
|
|
; ATTRIBUTOR-NEXT: ret <4 x i32> [[RES]]
|
|
;
|
|
; ATTRIBUTOR-CGSCC: Function Attrs: nounwind memory(argmem: readwrite)
|
|
; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@test12_2
|
|
; ATTRIBUTOR-CGSCC-SAME: (<4 x ptr> [[PTRS:%.*]]) #[[ATTR11:[0-9]+]] {
|
|
; ATTRIBUTOR-CGSCC-NEXT: [[RES:%.*]] = call <4 x i32> @test12_1(<4 x ptr> [[PTRS]])
|
|
; ATTRIBUTOR-CGSCC-NEXT: ret <4 x i32> [[RES]]
|
|
;
|
|
%res = call <4 x i32> @test12_1(<4 x ptr> %ptrs)
|
|
ret <4 x i32> %res
|
|
}
|
|
|
|
define i32 @volatile_load(ptr %p) {
|
|
; FNATTRS: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite, inaccessiblemem: readwrite)
|
|
; FNATTRS-LABEL: define {{[^@]+}}@volatile_load
|
|
; FNATTRS-SAME: (ptr [[P:%.*]]) #[[ATTR13:[0-9]+]] {
|
|
; FNATTRS-NEXT: [[LOAD:%.*]] = load volatile i32, ptr [[P]], align 4
|
|
; FNATTRS-NEXT: ret i32 [[LOAD]]
|
|
;
|
|
; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite)
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@volatile_load
|
|
; ATTRIBUTOR-SAME: (ptr nofree [[P:%.*]]) #[[ATTR11:[0-9]+]] {
|
|
; ATTRIBUTOR-NEXT: [[LOAD:%.*]] = load volatile i32, ptr [[P]], align 4
|
|
; ATTRIBUTOR-NEXT: ret i32 [[LOAD]]
|
|
;
|
|
; ATTRIBUTOR-CGSCC: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite)
|
|
; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@volatile_load
|
|
; ATTRIBUTOR-CGSCC-SAME: (ptr nofree [[P:%.*]]) #[[ATTR12:[0-9]+]] {
|
|
; ATTRIBUTOR-CGSCC-NEXT: [[LOAD:%.*]] = load volatile i32, ptr [[P]], align 4
|
|
; ATTRIBUTOR-CGSCC-NEXT: ret i32 [[LOAD]]
|
|
;
|
|
%load = load volatile i32, ptr %p
|
|
ret i32 %load
|
|
}
|
|
|
|
declare void @escape_readnone_ptr(ptr %addr, ptr readnone %ptr)
|
|
declare void @escape_readonly_ptr(ptr %addr, ptr readonly %ptr)
|
|
|
|
; The argument pointer %escaped_then_written cannot be marked readnone/only even
|
|
; though the only direct use, in @escape_readnone_ptr/@escape_readonly_ptr,
|
|
; is marked as readnone/only. However, the functions can write the pointer into
|
|
; %addr, causing the store to write to %escaped_then_written.
|
|
define void @unsound_readnone(ptr %ignored, ptr %escaped_then_written) {
|
|
; FNATTRS-LABEL: define {{[^@]+}}@unsound_readnone
|
|
; FNATTRS-SAME: (ptr nocapture readnone [[IGNORED:%.*]], ptr [[ESCAPED_THEN_WRITTEN:%.*]]) {
|
|
; FNATTRS-NEXT: [[ADDR:%.*]] = alloca ptr, align 8
|
|
; FNATTRS-NEXT: call void @escape_readnone_ptr(ptr [[ADDR]], ptr [[ESCAPED_THEN_WRITTEN]])
|
|
; FNATTRS-NEXT: [[ADDR_LD:%.*]] = load ptr, ptr [[ADDR]], align 8
|
|
; FNATTRS-NEXT: store i8 0, ptr [[ADDR_LD]], align 1
|
|
; FNATTRS-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@unsound_readnone
|
|
; ATTRIBUTOR-SAME: (ptr nocapture nofree readnone [[IGNORED:%.*]], ptr nofree [[ESCAPED_THEN_WRITTEN:%.*]]) {
|
|
; ATTRIBUTOR-NEXT: [[ADDR:%.*]] = alloca ptr, align 8
|
|
; ATTRIBUTOR-NEXT: call void @escape_readnone_ptr(ptr [[ADDR]], ptr nofree [[ESCAPED_THEN_WRITTEN]])
|
|
; ATTRIBUTOR-NEXT: [[ADDR_LD:%.*]] = load ptr, ptr [[ADDR]], align 8
|
|
; ATTRIBUTOR-NEXT: store i8 0, ptr [[ADDR_LD]], align 1
|
|
; ATTRIBUTOR-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@unsound_readnone
|
|
; ATTRIBUTOR-CGSCC-SAME: (ptr nocapture nofree readnone [[IGNORED:%.*]], ptr nofree [[ESCAPED_THEN_WRITTEN:%.*]]) {
|
|
; ATTRIBUTOR-CGSCC-NEXT: [[ADDR:%.*]] = alloca ptr, align 8
|
|
; ATTRIBUTOR-CGSCC-NEXT: call void @escape_readnone_ptr(ptr [[ADDR]], ptr nofree [[ESCAPED_THEN_WRITTEN]])
|
|
; ATTRIBUTOR-CGSCC-NEXT: [[ADDR_LD:%.*]] = load ptr, ptr [[ADDR]], align 8
|
|
; ATTRIBUTOR-CGSCC-NEXT: store i8 0, ptr [[ADDR_LD]], align 1
|
|
; ATTRIBUTOR-CGSCC-NEXT: ret void
|
|
;
|
|
%addr = alloca ptr
|
|
call void @escape_readnone_ptr(ptr %addr, ptr %escaped_then_written)
|
|
%addr.ld = load ptr, ptr %addr
|
|
store i8 0, ptr %addr.ld
|
|
ret void
|
|
}
|
|
|
|
define void @unsound_readonly(ptr %ignored, ptr %escaped_then_written) {
|
|
; FNATTRS-LABEL: define {{[^@]+}}@unsound_readonly
|
|
; FNATTRS-SAME: (ptr nocapture readnone [[IGNORED:%.*]], ptr [[ESCAPED_THEN_WRITTEN:%.*]]) {
|
|
; FNATTRS-NEXT: [[ADDR:%.*]] = alloca ptr, align 8
|
|
; FNATTRS-NEXT: call void @escape_readonly_ptr(ptr [[ADDR]], ptr [[ESCAPED_THEN_WRITTEN]])
|
|
; FNATTRS-NEXT: [[ADDR_LD:%.*]] = load ptr, ptr [[ADDR]], align 8
|
|
; FNATTRS-NEXT: store i8 0, ptr [[ADDR_LD]], align 1
|
|
; FNATTRS-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@unsound_readonly
|
|
; ATTRIBUTOR-SAME: (ptr nocapture nofree readnone [[IGNORED:%.*]], ptr nofree [[ESCAPED_THEN_WRITTEN:%.*]]) {
|
|
; ATTRIBUTOR-NEXT: [[ADDR:%.*]] = alloca ptr, align 8
|
|
; ATTRIBUTOR-NEXT: call void @escape_readonly_ptr(ptr [[ADDR]], ptr nofree [[ESCAPED_THEN_WRITTEN]])
|
|
; ATTRIBUTOR-NEXT: [[ADDR_LD:%.*]] = load ptr, ptr [[ADDR]], align 8
|
|
; ATTRIBUTOR-NEXT: store i8 0, ptr [[ADDR_LD]], align 1
|
|
; ATTRIBUTOR-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@unsound_readonly
|
|
; ATTRIBUTOR-CGSCC-SAME: (ptr nocapture nofree readnone [[IGNORED:%.*]], ptr nofree [[ESCAPED_THEN_WRITTEN:%.*]]) {
|
|
; ATTRIBUTOR-CGSCC-NEXT: [[ADDR:%.*]] = alloca ptr, align 8
|
|
; ATTRIBUTOR-CGSCC-NEXT: call void @escape_readonly_ptr(ptr [[ADDR]], ptr nofree [[ESCAPED_THEN_WRITTEN]])
|
|
; ATTRIBUTOR-CGSCC-NEXT: [[ADDR_LD:%.*]] = load ptr, ptr [[ADDR]], align 8
|
|
; ATTRIBUTOR-CGSCC-NEXT: store i8 0, ptr [[ADDR_LD]], align 1
|
|
; ATTRIBUTOR-CGSCC-NEXT: ret void
|
|
;
|
|
%addr = alloca ptr
|
|
call void @escape_readonly_ptr(ptr %addr, ptr %escaped_then_written)
|
|
%addr.ld = load ptr, ptr %addr
|
|
store i8 0, ptr %addr.ld
|
|
ret void
|
|
}
|
|
|
|
define void @fptr_test1a(ptr %p, ptr %f) {
|
|
; FNATTRS-LABEL: define {{[^@]+}}@fptr_test1a
|
|
; FNATTRS-SAME: (ptr nocapture readnone [[P:%.*]], ptr nocapture readonly [[F:%.*]]) {
|
|
; FNATTRS-NEXT: call void [[F]](ptr nocapture readnone [[P]])
|
|
; FNATTRS-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@fptr_test1a
|
|
; ATTRIBUTOR-SAME: (ptr nocapture nofree [[P:%.*]], ptr nocapture nofree nonnull [[F:%.*]]) {
|
|
; ATTRIBUTOR-NEXT: call void [[F]](ptr nocapture nofree readnone [[P]])
|
|
; ATTRIBUTOR-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@fptr_test1a
|
|
; ATTRIBUTOR-CGSCC-SAME: (ptr nocapture nofree [[P:%.*]], ptr nocapture nofree nonnull [[F:%.*]]) {
|
|
; ATTRIBUTOR-CGSCC-NEXT: call void [[F]](ptr nocapture nofree readnone [[P]])
|
|
; ATTRIBUTOR-CGSCC-NEXT: ret void
|
|
;
|
|
call void %f(ptr nocapture readnone %p)
|
|
ret void
|
|
}
|
|
|
|
; Can't infer readnone here because call might capture %p
|
|
define void @fptr_test1b(ptr %p, ptr %f) {
|
|
; FNATTRS-LABEL: define {{[^@]+}}@fptr_test1b
|
|
; FNATTRS-SAME: (ptr [[P:%.*]], ptr nocapture readonly [[F:%.*]]) {
|
|
; FNATTRS-NEXT: call void [[F]](ptr readnone [[P]])
|
|
; FNATTRS-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@fptr_test1b
|
|
; ATTRIBUTOR-SAME: (ptr nofree [[P:%.*]], ptr nocapture nofree nonnull [[F:%.*]]) {
|
|
; ATTRIBUTOR-NEXT: call void [[F]](ptr nofree readnone [[P]])
|
|
; ATTRIBUTOR-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@fptr_test1b
|
|
; ATTRIBUTOR-CGSCC-SAME: (ptr nofree [[P:%.*]], ptr nocapture nofree nonnull [[F:%.*]]) {
|
|
; ATTRIBUTOR-CGSCC-NEXT: call void [[F]](ptr nofree readnone [[P]])
|
|
; ATTRIBUTOR-CGSCC-NEXT: ret void
|
|
;
|
|
call void %f(ptr readnone %p)
|
|
ret void
|
|
}
|
|
|
|
define void @fptr_test1c(ptr %p, ptr %f) {
|
|
; FNATTRS: Function Attrs: nofree memory(read)
|
|
; FNATTRS-LABEL: define {{[^@]+}}@fptr_test1c
|
|
; FNATTRS-SAME: (ptr readnone [[P:%.*]], ptr nocapture readonly [[F:%.*]]) #[[ATTR3]] {
|
|
; FNATTRS-NEXT: call void [[F]](ptr readnone [[P]]) #[[ATTR2:[0-9]+]]
|
|
; FNATTRS-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR: Function Attrs: memory(read)
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@fptr_test1c
|
|
; ATTRIBUTOR-SAME: (ptr nofree readonly [[P:%.*]], ptr nocapture nofree nonnull readonly [[F:%.*]]) #[[ATTR2:[0-9]+]] {
|
|
; ATTRIBUTOR-NEXT: call void [[F]](ptr nofree readnone [[P]]) #[[ATTR2]]
|
|
; ATTRIBUTOR-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-CGSCC: Function Attrs: memory(read)
|
|
; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@fptr_test1c
|
|
; ATTRIBUTOR-CGSCC-SAME: (ptr nofree readonly [[P:%.*]], ptr nocapture nofree nonnull readonly [[F:%.*]]) #[[ATTR2:[0-9]+]] {
|
|
; ATTRIBUTOR-CGSCC-NEXT: call void [[F]](ptr nofree readnone [[P]]) #[[ATTR2]]
|
|
; ATTRIBUTOR-CGSCC-NEXT: ret void
|
|
;
|
|
call void %f(ptr readnone %p) readonly
|
|
ret void
|
|
}
|
|
|
|
define void @fptr_test2a(ptr %p, ptr %f) {
|
|
; FNATTRS-LABEL: define {{[^@]+}}@fptr_test2a
|
|
; FNATTRS-SAME: (ptr nocapture readonly [[P:%.*]], ptr nocapture readonly [[F:%.*]]) {
|
|
; FNATTRS-NEXT: call void [[F]](ptr nocapture readonly [[P]])
|
|
; FNATTRS-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@fptr_test2a
|
|
; ATTRIBUTOR-SAME: (ptr nocapture nofree [[P:%.*]], ptr nocapture nofree nonnull [[F:%.*]]) {
|
|
; ATTRIBUTOR-NEXT: call void [[F]](ptr nocapture nofree readonly [[P]])
|
|
; ATTRIBUTOR-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@fptr_test2a
|
|
; ATTRIBUTOR-CGSCC-SAME: (ptr nocapture nofree [[P:%.*]], ptr nocapture nofree nonnull [[F:%.*]]) {
|
|
; ATTRIBUTOR-CGSCC-NEXT: call void [[F]](ptr nocapture nofree readonly [[P]])
|
|
; ATTRIBUTOR-CGSCC-NEXT: ret void
|
|
;
|
|
call void %f(ptr nocapture readonly %p)
|
|
ret void
|
|
}
|
|
|
|
define void @fptr_test2b(ptr %p, ptr %f) {
|
|
; Can't infer readonly here because call might capture %p
|
|
; FNATTRS-LABEL: define {{[^@]+}}@fptr_test2b
|
|
; FNATTRS-SAME: (ptr [[P:%.*]], ptr nocapture readonly [[F:%.*]]) {
|
|
; FNATTRS-NEXT: call void [[F]](ptr readonly [[P]])
|
|
; FNATTRS-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@fptr_test2b
|
|
; ATTRIBUTOR-SAME: (ptr nofree [[P:%.*]], ptr nocapture nofree nonnull [[F:%.*]]) {
|
|
; ATTRIBUTOR-NEXT: call void [[F]](ptr nofree readonly [[P]])
|
|
; ATTRIBUTOR-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@fptr_test2b
|
|
; ATTRIBUTOR-CGSCC-SAME: (ptr nofree [[P:%.*]], ptr nocapture nofree nonnull [[F:%.*]]) {
|
|
; ATTRIBUTOR-CGSCC-NEXT: call void [[F]](ptr nofree readonly [[P]])
|
|
; ATTRIBUTOR-CGSCC-NEXT: ret void
|
|
;
|
|
call void %f(ptr readonly %p)
|
|
ret void
|
|
}
|
|
|
|
define void @fptr_test2c(ptr %p, ptr %f) {
|
|
; FNATTRS: Function Attrs: nofree memory(read)
|
|
; FNATTRS-LABEL: define {{[^@]+}}@fptr_test2c
|
|
; FNATTRS-SAME: (ptr readonly [[P:%.*]], ptr nocapture readonly [[F:%.*]]) #[[ATTR3]] {
|
|
; FNATTRS-NEXT: call void [[F]](ptr readonly [[P]]) #[[ATTR2]]
|
|
; FNATTRS-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR: Function Attrs: memory(read)
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@fptr_test2c
|
|
; ATTRIBUTOR-SAME: (ptr nofree readonly [[P:%.*]], ptr nocapture nofree nonnull readonly [[F:%.*]]) #[[ATTR2]] {
|
|
; ATTRIBUTOR-NEXT: call void [[F]](ptr nofree readonly [[P]]) #[[ATTR2]]
|
|
; ATTRIBUTOR-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-CGSCC: Function Attrs: memory(read)
|
|
; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@fptr_test2c
|
|
; ATTRIBUTOR-CGSCC-SAME: (ptr nofree readonly [[P:%.*]], ptr nocapture nofree nonnull readonly [[F:%.*]]) #[[ATTR2]] {
|
|
; ATTRIBUTOR-CGSCC-NEXT: call void [[F]](ptr nofree readonly [[P]]) #[[ATTR2]]
|
|
; ATTRIBUTOR-CGSCC-NEXT: ret void
|
|
;
|
|
call void %f(ptr readonly %p) readonly
|
|
ret void
|
|
}
|
|
|
|
define void @alloca_recphi() {
|
|
; FNATTRS: Function Attrs: nofree norecurse nosync nounwind memory(none)
|
|
; FNATTRS-LABEL: define {{[^@]+}}@alloca_recphi
|
|
; FNATTRS-SAME: () #[[ATTR14:[0-9]+]] {
|
|
; FNATTRS-NEXT: entry:
|
|
; FNATTRS-NEXT: [[A:%.*]] = alloca [8 x i32], align 4
|
|
; FNATTRS-NEXT: [[A_END:%.*]] = getelementptr i32, ptr [[A]], i64 8
|
|
; FNATTRS-NEXT: br label [[LOOP:%.*]]
|
|
; FNATTRS: loop:
|
|
; FNATTRS-NEXT: [[P:%.*]] = phi ptr [ [[A]], [[ENTRY:%.*]] ], [ [[P_NEXT:%.*]], [[LOOP]] ]
|
|
; FNATTRS-NEXT: store i32 0, ptr [[P]], align 4
|
|
; FNATTRS-NEXT: [[TMP0:%.*]] = load i32, ptr [[P]], align 4
|
|
; FNATTRS-NEXT: [[P_NEXT]] = getelementptr i32, ptr [[P]], i64 1
|
|
; FNATTRS-NEXT: [[C:%.*]] = icmp ne ptr [[P_NEXT]], [[A_END]]
|
|
; FNATTRS-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; FNATTRS: exit:
|
|
; FNATTRS-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR: Function Attrs: nofree norecurse nosync nounwind memory(none)
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@alloca_recphi
|
|
; ATTRIBUTOR-SAME: () #[[ATTR12:[0-9]+]] {
|
|
; ATTRIBUTOR-NEXT: entry:
|
|
; ATTRIBUTOR-NEXT: [[A:%.*]] = alloca [8 x i32], align 4
|
|
; ATTRIBUTOR-NEXT: [[A_END:%.*]] = getelementptr i32, ptr [[A]], i64 8
|
|
; ATTRIBUTOR-NEXT: br label [[LOOP:%.*]]
|
|
; ATTRIBUTOR: loop:
|
|
; ATTRIBUTOR-NEXT: [[P:%.*]] = phi ptr [ [[A]], [[ENTRY:%.*]] ], [ [[P_NEXT:%.*]], [[LOOP]] ]
|
|
; ATTRIBUTOR-NEXT: store i32 0, ptr [[P]], align 4
|
|
; ATTRIBUTOR-NEXT: [[TMP0:%.*]] = load i32, ptr [[P]], align 4
|
|
; ATTRIBUTOR-NEXT: [[P_NEXT]] = getelementptr i32, ptr [[P]], i64 1
|
|
; ATTRIBUTOR-NEXT: [[C:%.*]] = icmp ne ptr [[P_NEXT]], [[A_END]]
|
|
; ATTRIBUTOR-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; ATTRIBUTOR: exit:
|
|
; ATTRIBUTOR-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
|
|
; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@alloca_recphi
|
|
; ATTRIBUTOR-CGSCC-SAME: () #[[ATTR1]] {
|
|
; ATTRIBUTOR-CGSCC-NEXT: entry:
|
|
; ATTRIBUTOR-CGSCC-NEXT: [[A:%.*]] = alloca [8 x i32], align 4
|
|
; ATTRIBUTOR-CGSCC-NEXT: [[A_END:%.*]] = getelementptr i32, ptr [[A]], i64 8
|
|
; ATTRIBUTOR-CGSCC-NEXT: br label [[LOOP:%.*]]
|
|
; ATTRIBUTOR-CGSCC: loop:
|
|
; ATTRIBUTOR-CGSCC-NEXT: [[P:%.*]] = phi ptr [ [[A]], [[ENTRY:%.*]] ], [ [[P_NEXT:%.*]], [[LOOP]] ]
|
|
; ATTRIBUTOR-CGSCC-NEXT: store i32 0, ptr [[P]], align 4
|
|
; ATTRIBUTOR-CGSCC-NEXT: [[TMP0:%.*]] = load i32, ptr [[P]], align 4
|
|
; ATTRIBUTOR-CGSCC-NEXT: [[P_NEXT]] = getelementptr i32, ptr [[P]], i64 1
|
|
; ATTRIBUTOR-CGSCC-NEXT: [[C:%.*]] = icmp ne ptr [[P_NEXT]], [[A_END]]
|
|
; ATTRIBUTOR-CGSCC-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; ATTRIBUTOR-CGSCC: exit:
|
|
; ATTRIBUTOR-CGSCC-NEXT: ret void
|
|
;
|
|
entry:
|
|
%a = alloca [8 x i32]
|
|
%a.end = getelementptr i32, ptr %a, i64 8
|
|
br label %loop
|
|
|
|
loop:
|
|
%p = phi ptr [ %a, %entry ], [ %p.next, %loop ]
|
|
store i32 0, ptr %p
|
|
load i32, ptr %p
|
|
%p.next = getelementptr i32, ptr %p, i64 1
|
|
%c = icmp ne ptr %p.next, %a.end
|
|
br i1 %c, label %loop, label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
declare void @readnone_param(ptr nocapture readnone %p)
|
|
declare void @readonly_param(ptr nocapture readonly %p)
|
|
|
|
; FIXME: While this can't be readnone, this could be readonly.
|
|
define void @op_bundle_readnone_deopt(ptr %p) {
|
|
; FNATTRS-LABEL: define {{[^@]+}}@op_bundle_readnone_deopt
|
|
; FNATTRS-SAME: (ptr nocapture [[P:%.*]]) {
|
|
; FNATTRS-NEXT: call void @readnone_param(ptr [[P]]) [ "deopt"() ]
|
|
; FNATTRS-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@op_bundle_readnone_deopt
|
|
; ATTRIBUTOR-SAME: (ptr nocapture nofree [[P:%.*]]) {
|
|
; ATTRIBUTOR-NEXT: call void @readnone_param(ptr nocapture nofree [[P]]) [ "deopt"() ]
|
|
; ATTRIBUTOR-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@op_bundle_readnone_deopt
|
|
; ATTRIBUTOR-CGSCC-SAME: (ptr nocapture nofree [[P:%.*]]) {
|
|
; ATTRIBUTOR-CGSCC-NEXT: call void @readnone_param(ptr nocapture nofree [[P]]) [ "deopt"() ]
|
|
; ATTRIBUTOR-CGSCC-NEXT: ret void
|
|
;
|
|
call void @readnone_param(ptr %p) ["deopt"()]
|
|
ret void
|
|
}
|
|
|
|
define void @op_bundle_readnone_unknown(ptr %p) {
|
|
; FNATTRS-LABEL: define {{[^@]+}}@op_bundle_readnone_unknown
|
|
; FNATTRS-SAME: (ptr nocapture [[P:%.*]]) {
|
|
; FNATTRS-NEXT: call void @readnone_param(ptr [[P]]) [ "unknown"() ]
|
|
; FNATTRS-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@op_bundle_readnone_unknown
|
|
; ATTRIBUTOR-SAME: (ptr nocapture nofree [[P:%.*]]) {
|
|
; ATTRIBUTOR-NEXT: call void @readnone_param(ptr nocapture nofree [[P]]) [ "unknown"() ]
|
|
; ATTRIBUTOR-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@op_bundle_readnone_unknown
|
|
; ATTRIBUTOR-CGSCC-SAME: (ptr nocapture nofree [[P:%.*]]) {
|
|
; ATTRIBUTOR-CGSCC-NEXT: call void @readnone_param(ptr nocapture nofree [[P]]) [ "unknown"() ]
|
|
; ATTRIBUTOR-CGSCC-NEXT: ret void
|
|
;
|
|
call void @readnone_param(ptr %p) ["unknown"()]
|
|
ret void
|
|
}
|
|
|
|
define void @op_bundle_readonly_deopt(ptr %p) {
|
|
; FNATTRS-LABEL: define {{[^@]+}}@op_bundle_readonly_deopt
|
|
; FNATTRS-SAME: (ptr nocapture readonly [[P:%.*]]) {
|
|
; FNATTRS-NEXT: call void @readonly_param(ptr [[P]]) [ "deopt"() ]
|
|
; FNATTRS-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@op_bundle_readonly_deopt
|
|
; ATTRIBUTOR-SAME: (ptr nocapture nofree [[P:%.*]]) {
|
|
; ATTRIBUTOR-NEXT: call void @readonly_param(ptr nocapture nofree [[P]]) [ "deopt"() ]
|
|
; ATTRIBUTOR-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@op_bundle_readonly_deopt
|
|
; ATTRIBUTOR-CGSCC-SAME: (ptr nocapture nofree [[P:%.*]]) {
|
|
; ATTRIBUTOR-CGSCC-NEXT: call void @readonly_param(ptr nocapture nofree [[P]]) [ "deopt"() ]
|
|
; ATTRIBUTOR-CGSCC-NEXT: ret void
|
|
;
|
|
call void @readonly_param(ptr %p) ["deopt"()]
|
|
ret void
|
|
}
|
|
|
|
define void @op_bundle_readonly_unknown(ptr %p) {
|
|
; FNATTRS-LABEL: define {{[^@]+}}@op_bundle_readonly_unknown
|
|
; FNATTRS-SAME: (ptr nocapture [[P:%.*]]) {
|
|
; FNATTRS-NEXT: call void @readonly_param(ptr [[P]]) [ "unknown"() ]
|
|
; FNATTRS-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@op_bundle_readonly_unknown
|
|
; ATTRIBUTOR-SAME: (ptr nocapture nofree [[P:%.*]]) {
|
|
; ATTRIBUTOR-NEXT: call void @readonly_param(ptr nocapture nofree [[P]]) [ "unknown"() ]
|
|
; ATTRIBUTOR-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@op_bundle_readonly_unknown
|
|
; ATTRIBUTOR-CGSCC-SAME: (ptr nocapture nofree [[P:%.*]]) {
|
|
; ATTRIBUTOR-CGSCC-NEXT: call void @readonly_param(ptr nocapture nofree [[P]]) [ "unknown"() ]
|
|
; ATTRIBUTOR-CGSCC-NEXT: ret void
|
|
;
|
|
call void @readonly_param(ptr %p) ["unknown"()]
|
|
ret void
|
|
}
|
|
|
|
define i32 @writable_readonly(ptr writable dereferenceable(4) %p) {
|
|
; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
|
|
; FNATTRS-LABEL: define {{[^@]+}}@writable_readonly
|
|
; FNATTRS-SAME: (ptr nocapture readonly dereferenceable(4) [[P:%.*]]) #[[ATTR15:[0-9]+]] {
|
|
; FNATTRS-NEXT: [[V:%.*]] = load i32, ptr [[P]], align 4
|
|
; FNATTRS-NEXT: ret i32 [[V]]
|
|
;
|
|
; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@writable_readonly
|
|
; ATTRIBUTOR-SAME: (ptr nocapture nofree nonnull readonly dereferenceable(4) [[P:%.*]]) #[[ATTR13:[0-9]+]] {
|
|
; ATTRIBUTOR-NEXT: [[V:%.*]] = load i32, ptr [[P]], align 4
|
|
; ATTRIBUTOR-NEXT: ret i32 [[V]]
|
|
;
|
|
; ATTRIBUTOR-CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
|
|
; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@writable_readonly
|
|
; ATTRIBUTOR-CGSCC-SAME: (ptr nocapture nofree nonnull readonly dereferenceable(4) [[P:%.*]]) #[[ATTR13:[0-9]+]] {
|
|
; ATTRIBUTOR-CGSCC-NEXT: [[V:%.*]] = load i32, ptr [[P]], align 4
|
|
; ATTRIBUTOR-CGSCC-NEXT: ret i32 [[V]]
|
|
;
|
|
%v = load i32, ptr %p
|
|
ret i32 %v
|
|
}
|
|
|
|
define void @writable_readnone(ptr writable dereferenceable(4) %p) {
|
|
; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
|
|
; FNATTRS-LABEL: define {{[^@]+}}@writable_readnone
|
|
; FNATTRS-SAME: (ptr nocapture readnone dereferenceable(4) [[P:%.*]]) #[[ATTR1]] {
|
|
; FNATTRS-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@writable_readnone
|
|
; ATTRIBUTOR-SAME: (ptr nocapture nofree nonnull readnone dereferenceable(4) [[P:%.*]]) #[[ATTR1]] {
|
|
; ATTRIBUTOR-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
|
|
; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@writable_readnone
|
|
; ATTRIBUTOR-CGSCC-SAME: (ptr nocapture nofree nonnull readnone dereferenceable(4) [[P:%.*]]) #[[ATTR1]] {
|
|
; ATTRIBUTOR-CGSCC-NEXT: ret void
|
|
;
|
|
ret void
|
|
}
|
|
|
|
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
|
|
; COMMON: {{.*}}
|