
Relative to the previous attempt this includes two fixes: * Adjust callCapturesBefore() to not skip captures(ret: address, provenance) arguments, as these will not count as a capture at the call-site. * When visiting uses during stack slot optimization, don't skip the ModRef check for passthru captures. Calls can both modref and be passthru for captures. ------ This extends CaptureTracking to support inferring non-trivial CaptureInfos. The focus of this patch is to only support FunctionAttrs, other users of CaptureTracking will be updated in followups. The key API changes here are: * DetermineUseCaptureKind() now returns a UseCaptureInfo where the UseCC component specifies what is captured at that Use and the ResultCC component specifies what may be captured via the return value of the User. Usually only one or the other will be used (corresponding to previous MAY_CAPTURE or PASSTHROUGH results), but both may be set for call captures. * The CaptureTracking::captures() extension point is passed this UseCaptureInfo as well and then can decide what to do with it by returning an Action, which is one of: Stop: stop traversal. ContinueIgnoringReturn: continue traversal but don't follow the instruction return value. Continue: continue traversal and follow the instruction return value if it has additional CaptureComponents. For now, this patch retains the (unsound) special logic for comparison of null with a dereferenceable pointer. I'd like to switch key code to take advantage of address/address_is_null before dropping it. This PR mainly intends to introduce necessary API changes and basic inference support, there are various possible improvements marked with TODOs.
789 lines
37 KiB
LLVM
789 lines
37 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 readonly captures(none) [[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 nofree readonly captures(none) [[Y1_2:%.*]], ptr [[Z1_2:%.*]]) {
|
|
; ATTRIBUTOR-NEXT: call void (ptr, ptr, ...) @test1_1(ptr [[X1_2]], ptr nofree readonly captures(none) [[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 nofree readonly captures(none) [[Y1_2:%.*]], ptr [[Z1_2:%.*]]) {
|
|
; ATTRIBUTOR-CGSCC-NEXT: call void (ptr, ptr, ...) @test1_1(ptr [[X1_2]], ptr nofree readonly captures(none) [[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 captures(ret: address, provenance) [[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 captures(address) [[P:%.*]], ptr readnone captures(address) [[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 readonly captures(none) [[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 readonly captures(none) [[P:%.*]]) #[[ATTR3:[0-9]+]] {
|
|
; ATTRIBUTOR-NEXT: call void @test4_1(ptr readonly captures(none) [[P]]) #[[ATTR3]]
|
|
; ATTRIBUTOR-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-CGSCC: Function Attrs: nosync memory(read)
|
|
; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@test4_2
|
|
; ATTRIBUTOR-CGSCC-SAME: (ptr readonly captures(none) [[P:%.*]]) #[[ATTR3:[0-9]+]] {
|
|
; ATTRIBUTOR-CGSCC-NEXT: call void @test4_1(ptr readonly captures(none) [[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 writeonly captures(none) initializes((0, 8)) [[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 nofree nonnull writeonly captures(none) [[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 nofree nonnull writeonly captures(none) [[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 writeonly captures(none) initializes((0, 8)) [[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 nofree nonnull writeonly captures(none) [[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 nofree nonnull writeonly captures(none) [[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 inalloca(i32) captures(none) [[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 nofree nonnull writeonly inalloca(i32) captures(none) [[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 nofree nonnull writeonly inalloca(i32) captures(none) [[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 preallocated(i32) captures(none) [[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 nofree nonnull writeonly preallocated(i32) captures(none) [[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 nofree nonnull writeonly preallocated(i32) captures(none) [[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 captures(ret: address, provenance) [[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 captures(none) [[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 nofree writeonly captures(none) [[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 norecurse 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 norecurse 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 readnone captures(none) [[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 nofree readnone captures(none) [[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 nofree readnone captures(none) [[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 readnone captures(none) [[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 nofree readnone captures(none) [[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 nofree readnone captures(none) [[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 readnone captures(none) [[P:%.*]], ptr readonly captures(none) [[F:%.*]]) {
|
|
; FNATTRS-NEXT: call void [[F]](ptr readnone captures(none) [[P]])
|
|
; FNATTRS-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@fptr_test1a
|
|
; ATTRIBUTOR-SAME: (ptr nofree captures(none) [[P:%.*]], ptr nofree nonnull captures(none) [[F:%.*]]) {
|
|
; ATTRIBUTOR-NEXT: call void [[F]](ptr nofree readnone captures(none) [[P]])
|
|
; ATTRIBUTOR-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@fptr_test1a
|
|
; ATTRIBUTOR-CGSCC-SAME: (ptr nofree captures(none) [[P:%.*]], ptr nofree nonnull captures(none) [[F:%.*]]) {
|
|
; ATTRIBUTOR-CGSCC-NEXT: call void [[F]](ptr nofree readnone captures(none) [[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 readonly captures(none) [[F:%.*]]) {
|
|
; FNATTRS-NEXT: call void [[F]](ptr readnone [[P]])
|
|
; FNATTRS-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@fptr_test1b
|
|
; ATTRIBUTOR-SAME: (ptr nofree [[P:%.*]], ptr nofree nonnull captures(none) [[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 nofree nonnull captures(none) [[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 readonly captures(none) [[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 nofree nonnull readonly captures(none) [[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 nofree nonnull readonly captures(none) [[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 readonly captures(none) [[P:%.*]], ptr readonly captures(none) [[F:%.*]]) {
|
|
; FNATTRS-NEXT: call void [[F]](ptr readonly captures(none) [[P]])
|
|
; FNATTRS-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@fptr_test2a
|
|
; ATTRIBUTOR-SAME: (ptr nofree captures(none) [[P:%.*]], ptr nofree nonnull captures(none) [[F:%.*]]) {
|
|
; ATTRIBUTOR-NEXT: call void [[F]](ptr nofree readonly captures(none) [[P]])
|
|
; ATTRIBUTOR-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@fptr_test2a
|
|
; ATTRIBUTOR-CGSCC-SAME: (ptr nofree captures(none) [[P:%.*]], ptr nofree nonnull captures(none) [[F:%.*]]) {
|
|
; ATTRIBUTOR-CGSCC-NEXT: call void [[F]](ptr nofree readonly captures(none) [[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 readonly captures(none) [[F:%.*]]) {
|
|
; FNATTRS-NEXT: call void [[F]](ptr readonly [[P]])
|
|
; FNATTRS-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@fptr_test2b
|
|
; ATTRIBUTOR-SAME: (ptr nofree [[P:%.*]], ptr nofree nonnull captures(none) [[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 nofree nonnull captures(none) [[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 readonly captures(none) [[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 nofree nonnull readonly captures(none) [[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 nofree nonnull readonly captures(none) [[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 captures(none) [[P:%.*]]) {
|
|
; FNATTRS-NEXT: call void @readnone_param(ptr [[P]]) [ "deopt"() ]
|
|
; FNATTRS-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@op_bundle_readnone_deopt
|
|
; ATTRIBUTOR-SAME: (ptr nofree captures(none) [[P:%.*]]) {
|
|
; ATTRIBUTOR-NEXT: call void @readnone_param(ptr nofree captures(none) [[P]]) [ "deopt"() ]
|
|
; ATTRIBUTOR-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@op_bundle_readnone_deopt
|
|
; ATTRIBUTOR-CGSCC-SAME: (ptr nofree captures(none) [[P:%.*]]) {
|
|
; ATTRIBUTOR-CGSCC-NEXT: call void @readnone_param(ptr nofree captures(none) [[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 captures(none) [[P:%.*]]) {
|
|
; FNATTRS-NEXT: call void @readnone_param(ptr [[P]]) [ "unknown"() ]
|
|
; FNATTRS-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@op_bundle_readnone_unknown
|
|
; ATTRIBUTOR-SAME: (ptr nofree captures(none) [[P:%.*]]) {
|
|
; ATTRIBUTOR-NEXT: call void @readnone_param(ptr nofree captures(none) [[P]]) [ "unknown"() ]
|
|
; ATTRIBUTOR-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@op_bundle_readnone_unknown
|
|
; ATTRIBUTOR-CGSCC-SAME: (ptr nofree captures(none) [[P:%.*]]) {
|
|
; ATTRIBUTOR-CGSCC-NEXT: call void @readnone_param(ptr nofree captures(none) [[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 readonly captures(none) [[P:%.*]]) {
|
|
; FNATTRS-NEXT: call void @readonly_param(ptr [[P]]) [ "deopt"() ]
|
|
; FNATTRS-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@op_bundle_readonly_deopt
|
|
; ATTRIBUTOR-SAME: (ptr nofree captures(none) [[P:%.*]]) {
|
|
; ATTRIBUTOR-NEXT: call void @readonly_param(ptr nofree captures(none) [[P]]) [ "deopt"() ]
|
|
; ATTRIBUTOR-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@op_bundle_readonly_deopt
|
|
; ATTRIBUTOR-CGSCC-SAME: (ptr nofree captures(none) [[P:%.*]]) {
|
|
; ATTRIBUTOR-CGSCC-NEXT: call void @readonly_param(ptr nofree captures(none) [[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 captures(none) [[P:%.*]]) {
|
|
; FNATTRS-NEXT: call void @readonly_param(ptr [[P]]) [ "unknown"() ]
|
|
; FNATTRS-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@op_bundle_readonly_unknown
|
|
; ATTRIBUTOR-SAME: (ptr nofree captures(none) [[P:%.*]]) {
|
|
; ATTRIBUTOR-NEXT: call void @readonly_param(ptr nofree captures(none) [[P]]) [ "unknown"() ]
|
|
; ATTRIBUTOR-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@op_bundle_readonly_unknown
|
|
; ATTRIBUTOR-CGSCC-SAME: (ptr nofree captures(none) [[P:%.*]]) {
|
|
; ATTRIBUTOR-CGSCC-NEXT: call void @readonly_param(ptr nofree captures(none) [[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 readonly captures(none) 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 nofree nonnull readonly captures(none) 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 nofree nonnull readonly captures(none) 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 readnone captures(none) 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 nofree nonnull readnone captures(none) 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 nofree nonnull readnone captures(none) dereferenceable(4) [[P:%.*]]) #[[ATTR1]] {
|
|
; ATTRIBUTOR-CGSCC-NEXT: ret void
|
|
;
|
|
ret void
|
|
}
|
|
|
|
declare void @byval_param(ptr byval(i32) %p)
|
|
|
|
define void @call_byval_param(ptr %p) {
|
|
; FNATTRS-LABEL: define {{[^@]+}}@call_byval_param
|
|
; FNATTRS-SAME: (ptr readonly captures(none) [[P:%.*]]) {
|
|
; FNATTRS-NEXT: call void @byval_param(ptr byval(i32) [[P]])
|
|
; FNATTRS-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@call_byval_param
|
|
; ATTRIBUTOR-SAME: (ptr readonly captures(none) [[P:%.*]]) {
|
|
; ATTRIBUTOR-NEXT: call void @byval_param(ptr readonly byval(i32) captures(none) [[P]])
|
|
; ATTRIBUTOR-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@call_byval_param
|
|
; ATTRIBUTOR-CGSCC-SAME: (ptr readonly captures(none) [[P:%.*]]) {
|
|
; ATTRIBUTOR-CGSCC-NEXT: call void @byval_param(ptr readonly byval(i32) captures(none) [[P]])
|
|
; ATTRIBUTOR-CGSCC-NEXT: ret void
|
|
;
|
|
call void @byval_param(ptr byval(i32) %p)
|
|
ret void
|
|
}
|
|
|
|
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
|
|
; COMMON: {{.*}}
|