This patch adds a lightweight instance of Attributor that only deduces attributes. This is just an initial version with the goal to have a version that only focuses on attributes to replace the function-attrs pass. The initial version has a few open issues pending until default enablement, the main one probably being compile time. The main additional functionality this will provide in general is propagating attributes to call sites. Open issues: * compile time The current version increase O3 +2.67% and ThinLTO +6.18% when replacing FunctionAttr https://llvm-compile-time-tracker.com/compare.php?from=c4bb3e073548cf436d5fa0406e3ae75e94684dec&to=d992630a69c79a2587d736e6a88f448850413bd1&stat=instructions%3Au Both are with an additional change to preserve more analysis, like FunctionAttrs CGSCC run. * some missed attribute inference Reviewed By: jdoerfert Differential Revision: https://reviews.llvm.org/D152081
257 lines
9.4 KiB
LLVM
257 lines
9.4 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
|
|
; RUN: opt < %s -aa-pipeline=basic-aa -passes='cgscc(function-attrs),rpo-function-attrs' -S | FileCheck --check-prefixes=COMMON,FNATTRS %s
|
|
; RUN: opt -passes=attributor-light -S < %s | FileCheck --check-prefixes=COMMON,ATTRIBUTOR %s
|
|
|
|
|
|
define i32 @leaf() {
|
|
; COMMON: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
|
|
; COMMON-LABEL: define {{[^@]+}}@leaf
|
|
; COMMON-SAME: () #[[ATTR0:[0-9]+]] {
|
|
; COMMON-NEXT: ret i32 1
|
|
;
|
|
ret i32 1
|
|
}
|
|
|
|
define i32 @self_rec() {
|
|
; FNATTRS: Function Attrs: nofree nosync nounwind memory(none)
|
|
; FNATTRS-LABEL: define {{[^@]+}}@self_rec
|
|
; FNATTRS-SAME: () #[[ATTR1:[0-9]+]] {
|
|
; FNATTRS-NEXT: [[A:%.*]] = call i32 @self_rec()
|
|
; FNATTRS-NEXT: ret i32 4
|
|
;
|
|
; ATTRIBUTOR: Function Attrs: nofree nosync nounwind memory(none)
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@self_rec
|
|
; ATTRIBUTOR-SAME: () #[[ATTR1:[0-9]+]] {
|
|
; ATTRIBUTOR-NEXT: [[A:%.*]] = call i32 @self_rec() #[[ATTR1]]
|
|
; ATTRIBUTOR-NEXT: ret i32 4
|
|
;
|
|
%a = call i32 @self_rec()
|
|
ret i32 4
|
|
}
|
|
|
|
define i32 @indirect_rec() {
|
|
; FNATTRS: Function Attrs: nofree nosync nounwind memory(none)
|
|
; FNATTRS-LABEL: define {{[^@]+}}@indirect_rec
|
|
; FNATTRS-SAME: () #[[ATTR1]] {
|
|
; FNATTRS-NEXT: [[A:%.*]] = call i32 @indirect_rec2()
|
|
; FNATTRS-NEXT: ret i32 [[A]]
|
|
;
|
|
; ATTRIBUTOR: Function Attrs: nofree nosync nounwind memory(none)
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@indirect_rec
|
|
; ATTRIBUTOR-SAME: () #[[ATTR1]] {
|
|
; ATTRIBUTOR-NEXT: [[A:%.*]] = call i32 @indirect_rec2() #[[ATTR1]]
|
|
; ATTRIBUTOR-NEXT: ret i32 [[A]]
|
|
;
|
|
%a = call i32 @indirect_rec2()
|
|
ret i32 %a
|
|
}
|
|
|
|
define i32 @indirect_rec2() {
|
|
; FNATTRS: Function Attrs: nofree nosync nounwind memory(none)
|
|
; FNATTRS-LABEL: define {{[^@]+}}@indirect_rec2
|
|
; FNATTRS-SAME: () #[[ATTR1]] {
|
|
; FNATTRS-NEXT: [[A:%.*]] = call i32 @indirect_rec()
|
|
; FNATTRS-NEXT: ret i32 [[A]]
|
|
;
|
|
; ATTRIBUTOR: Function Attrs: nofree nosync nounwind memory(none)
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@indirect_rec2
|
|
; ATTRIBUTOR-SAME: () #[[ATTR1]] {
|
|
; ATTRIBUTOR-NEXT: [[A:%.*]] = call i32 @indirect_rec() #[[ATTR1]]
|
|
; ATTRIBUTOR-NEXT: ret i32 [[A]]
|
|
;
|
|
%a = call i32 @indirect_rec()
|
|
ret i32 %a
|
|
}
|
|
|
|
define i32 @extern() {
|
|
; FNATTRS: Function Attrs: nofree nosync memory(none)
|
|
; FNATTRS-LABEL: define {{[^@]+}}@extern
|
|
; FNATTRS-SAME: () #[[ATTR2:[0-9]+]] {
|
|
; FNATTRS-NEXT: [[A:%.*]] = call i32 @k()
|
|
; FNATTRS-NEXT: ret i32 [[A]]
|
|
;
|
|
; ATTRIBUTOR: Function Attrs: nosync memory(none)
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@extern
|
|
; ATTRIBUTOR-SAME: () #[[ATTR2:[0-9]+]] {
|
|
; ATTRIBUTOR-NEXT: [[A:%.*]] = call i32 @k()
|
|
; ATTRIBUTOR-NEXT: ret i32 [[A]]
|
|
;
|
|
%a = call i32 @k()
|
|
ret i32 %a
|
|
}
|
|
|
|
declare i32 @k() readnone
|
|
|
|
define void @intrinsic(ptr %dest, ptr %src, i32 %len) {
|
|
; FNATTRS: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(argmem: readwrite)
|
|
; FNATTRS-LABEL: define {{[^@]+}}@intrinsic
|
|
; FNATTRS-SAME: (ptr nocapture writeonly [[DEST:%.*]], ptr nocapture readonly [[SRC:%.*]], i32 [[LEN:%.*]]) #[[ATTR4:[0-9]+]] {
|
|
; FNATTRS-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr [[DEST]], ptr [[SRC]], i32 [[LEN]], i1 false)
|
|
; FNATTRS-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite)
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@intrinsic
|
|
; ATTRIBUTOR-SAME: (ptr nocapture nofree writeonly [[DEST:%.*]], ptr nocapture nofree readonly [[SRC:%.*]], i32 [[LEN:%.*]]) #[[ATTR4:[0-9]+]] {
|
|
; ATTRIBUTOR-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr nocapture writeonly [[DEST]], ptr nocapture readonly [[SRC]], i32 [[LEN]], i1 false) #[[ATTR7:[0-9]+]]
|
|
; ATTRIBUTOR-NEXT: ret void
|
|
;
|
|
call void @llvm.memcpy.p0.p0.i32(ptr %dest, ptr %src, i32 %len, i1 false)
|
|
ret void
|
|
}
|
|
|
|
declare void @llvm.memcpy.p0.p0.i32(ptr, ptr, i32, i1)
|
|
|
|
define internal i32 @called_by_norecurse() {
|
|
; FNATTRS: Function Attrs: nofree norecurse nosync memory(none)
|
|
; FNATTRS-LABEL: define {{[^@]+}}@called_by_norecurse
|
|
; FNATTRS-SAME: () #[[ATTR6:[0-9]+]] {
|
|
; FNATTRS-NEXT: [[A:%.*]] = call i32 @k()
|
|
; FNATTRS-NEXT: ret i32 [[A]]
|
|
;
|
|
; ATTRIBUTOR: Function Attrs: nosync memory(none)
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@called_by_norecurse
|
|
; ATTRIBUTOR-SAME: () #[[ATTR2]] {
|
|
; ATTRIBUTOR-NEXT: [[A:%.*]] = call i32 @k()
|
|
; ATTRIBUTOR-NEXT: ret i32 [[A]]
|
|
;
|
|
%a = call i32 @k()
|
|
ret i32 %a
|
|
}
|
|
|
|
define void @m() norecurse {
|
|
; FNATTRS: Function Attrs: nofree norecurse nosync memory(none)
|
|
; FNATTRS-LABEL: define {{[^@]+}}@m
|
|
; FNATTRS-SAME: () #[[ATTR6]] {
|
|
; FNATTRS-NEXT: [[A:%.*]] = call i32 @called_by_norecurse()
|
|
; FNATTRS-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR: Function Attrs: norecurse nosync memory(none)
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@m
|
|
; ATTRIBUTOR-SAME: () #[[ATTR6:[0-9]+]] {
|
|
; ATTRIBUTOR-NEXT: [[A:%.*]] = call i32 @called_by_norecurse() #[[ATTR2]]
|
|
; ATTRIBUTOR-NEXT: ret void
|
|
;
|
|
%a = call i32 @called_by_norecurse()
|
|
ret void
|
|
}
|
|
|
|
define internal i32 @called_by_norecurse_indirectly() {
|
|
; FNATTRS: Function Attrs: nofree norecurse nosync memory(none)
|
|
; FNATTRS-LABEL: define {{[^@]+}}@called_by_norecurse_indirectly
|
|
; FNATTRS-SAME: () #[[ATTR6]] {
|
|
; FNATTRS-NEXT: [[A:%.*]] = call i32 @k()
|
|
; FNATTRS-NEXT: ret i32 [[A]]
|
|
;
|
|
; ATTRIBUTOR: Function Attrs: nosync memory(none)
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@called_by_norecurse_indirectly
|
|
; ATTRIBUTOR-SAME: () #[[ATTR2]] {
|
|
; ATTRIBUTOR-NEXT: [[A:%.*]] = call i32 @k()
|
|
; ATTRIBUTOR-NEXT: ret i32 [[A]]
|
|
;
|
|
%a = call i32 @k()
|
|
ret i32 %a
|
|
}
|
|
|
|
define internal void @o() {
|
|
; FNATTRS: Function Attrs: nofree norecurse nosync memory(none)
|
|
; FNATTRS-LABEL: define {{[^@]+}}@o
|
|
; FNATTRS-SAME: () #[[ATTR6]] {
|
|
; FNATTRS-NEXT: [[A:%.*]] = call i32 @called_by_norecurse_indirectly()
|
|
; FNATTRS-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR: Function Attrs: nosync memory(none)
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@o
|
|
; ATTRIBUTOR-SAME: () #[[ATTR2]] {
|
|
; ATTRIBUTOR-NEXT: [[A:%.*]] = call i32 @called_by_norecurse_indirectly() #[[ATTR2]]
|
|
; ATTRIBUTOR-NEXT: ret void
|
|
;
|
|
%a = call i32 @called_by_norecurse_indirectly()
|
|
ret void
|
|
}
|
|
|
|
define void @p() norecurse {
|
|
; FNATTRS: Function Attrs: nofree norecurse nosync memory(none)
|
|
; FNATTRS-LABEL: define {{[^@]+}}@p
|
|
; FNATTRS-SAME: () #[[ATTR6]] {
|
|
; FNATTRS-NEXT: call void @o()
|
|
; FNATTRS-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR: Function Attrs: norecurse nosync memory(none)
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@p
|
|
; ATTRIBUTOR-SAME: () #[[ATTR6]] {
|
|
; ATTRIBUTOR-NEXT: call void @o() #[[ATTR2]]
|
|
; ATTRIBUTOR-NEXT: ret void
|
|
;
|
|
call void @o()
|
|
ret void
|
|
}
|
|
|
|
define internal i32 @escapes_as_parameter(ptr %p) {
|
|
; FNATTRS: Function Attrs: nofree nosync memory(none)
|
|
; FNATTRS-LABEL: define {{[^@]+}}@escapes_as_parameter
|
|
; FNATTRS-SAME: (ptr nocapture readnone [[P:%.*]]) #[[ATTR2]] {
|
|
; FNATTRS-NEXT: [[A:%.*]] = call i32 @k()
|
|
; FNATTRS-NEXT: ret i32 [[A]]
|
|
;
|
|
; ATTRIBUTOR: Function Attrs: nosync memory(none)
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@escapes_as_parameter
|
|
; ATTRIBUTOR-SAME: (ptr nocapture nofree readnone [[P:%.*]]) #[[ATTR2]] {
|
|
; ATTRIBUTOR-NEXT: [[A:%.*]] = call i32 @k()
|
|
; ATTRIBUTOR-NEXT: ret i32 [[A]]
|
|
;
|
|
%a = call i32 @k()
|
|
ret i32 %a
|
|
}
|
|
|
|
define internal void @q() {
|
|
; FNATTRS: Function Attrs: nofree norecurse nosync memory(none)
|
|
; FNATTRS-LABEL: define {{[^@]+}}@q
|
|
; FNATTRS-SAME: () #[[ATTR6]] {
|
|
; FNATTRS-NEXT: [[A:%.*]] = call i32 @escapes_as_parameter(ptr @escapes_as_parameter)
|
|
; FNATTRS-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR: Function Attrs: norecurse nosync memory(none)
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@q
|
|
; ATTRIBUTOR-SAME: () #[[ATTR6]] {
|
|
; ATTRIBUTOR-NEXT: [[A:%.*]] = call i32 @escapes_as_parameter(ptr nonnull @escapes_as_parameter) #[[ATTR2]]
|
|
; ATTRIBUTOR-NEXT: ret void
|
|
;
|
|
%a = call i32 @escapes_as_parameter(ptr @escapes_as_parameter)
|
|
ret void
|
|
}
|
|
|
|
define void @r() norecurse {
|
|
; FNATTRS: Function Attrs: nofree norecurse nosync memory(none)
|
|
; FNATTRS-LABEL: define {{[^@]+}}@r
|
|
; FNATTRS-SAME: () #[[ATTR6]] {
|
|
; FNATTRS-NEXT: call void @q()
|
|
; FNATTRS-NEXT: ret void
|
|
;
|
|
; ATTRIBUTOR: Function Attrs: norecurse nosync memory(none)
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@r
|
|
; ATTRIBUTOR-SAME: () #[[ATTR6]] {
|
|
; ATTRIBUTOR-NEXT: call void @q() #[[ATTR2]]
|
|
; ATTRIBUTOR-NEXT: ret void
|
|
;
|
|
call void @q()
|
|
ret void
|
|
}
|
|
;.
|
|
; FNATTRS: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
|
|
; FNATTRS: attributes #[[ATTR1]] = { nofree nosync nounwind memory(none) }
|
|
; FNATTRS: attributes #[[ATTR2]] = { nofree nosync memory(none) }
|
|
; FNATTRS: attributes #[[ATTR3:[0-9]+]] = { memory(none) }
|
|
; FNATTRS: attributes #[[ATTR4]] = { mustprogress nofree nosync nounwind willreturn memory(argmem: readwrite) }
|
|
; FNATTRS: attributes #[[ATTR5:[0-9]+]] = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }
|
|
; FNATTRS: attributes #[[ATTR6]] = { nofree norecurse nosync memory(none) }
|
|
;.
|
|
; ATTRIBUTOR: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
|
|
; ATTRIBUTOR: attributes #[[ATTR1]] = { nofree nosync nounwind memory(none) }
|
|
; ATTRIBUTOR: attributes #[[ATTR2]] = { nosync memory(none) }
|
|
; ATTRIBUTOR: attributes #[[ATTR3:[0-9]+]] = { memory(none) }
|
|
; ATTRIBUTOR: attributes #[[ATTR4]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) }
|
|
; ATTRIBUTOR: attributes #[[ATTR5:[0-9]+]] = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }
|
|
; ATTRIBUTOR: attributes #[[ATTR6]] = { norecurse nosync memory(none) }
|
|
; ATTRIBUTOR: attributes #[[ATTR7]] = { nofree willreturn }
|
|
;.
|