llvm-project/llvm/test/Transforms/Attributor/call-simplify-pointer-info.ll
Johannes Doerfert 8266d47cd1
[Attributor] Improve AAUnderlyingObjects (#104835)
- Allocas and GlobalValues cannot be simplified, so we should not try.
- If we never used any assumed state, the AAUnderlyingObjects doesn't
require an additional update.
- If we have seen an object (or it's underlying object) before, we do
not need to inspect it anymore.

The original logic for "SeenObjects" was flawed and caused us to add
intermediate values to the underlying object list if a PHI or select
instruction referenced the same underlying object twice. The test
changes are all instances of this situation and we now correctly derive
`memory(none)` for the functions that only access stack memory.

---------

Co-authored-by: Shilei Tian <i@tianshilei.me>
2024-08-20 12:05:20 -07:00

295 lines
15 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=TUNIT
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CGSCC
;
define internal i8 @read_arg(ptr %p) {
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
; CGSCC-LABEL: define {{[^@]+}}@read_arg
; CGSCC-SAME: (ptr nocapture nofree noundef nonnull readonly dereferenceable(1022) [[P:%.*]]) #[[ATTR0:[0-9]+]] {
; CGSCC-NEXT: entry:
; CGSCC-NEXT: [[L:%.*]] = load i8, ptr [[P]], align 1
; CGSCC-NEXT: ret i8 [[L]]
;
entry:
%l = load i8, ptr %p, align 1
ret i8 %l
}
define internal i8 @read_arg_index(ptr %p, i64 %index) {
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
; CGSCC-LABEL: define {{[^@]+}}@read_arg_index
; CGSCC-SAME: (ptr nocapture nofree noundef nonnull readonly align 16 dereferenceable(1024) [[P:%.*]]) #[[ATTR0]] {
; CGSCC-NEXT: entry:
; CGSCC-NEXT: [[G:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 2
; CGSCC-NEXT: [[L:%.*]] = load i8, ptr [[G]], align 1
; CGSCC-NEXT: ret i8 [[L]]
;
entry:
%g = getelementptr inbounds i8, ptr %p, i64 %index
%l = load i8, ptr %g, align 1
ret i8 %l
}
define i8 @call_simplifiable_1() {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@call_simplifiable_1
; TUNIT-SAME: () #[[ATTR0:[0-9]+]] {
; TUNIT-NEXT: entry:
; TUNIT-NEXT: [[BYTES:%.*]] = alloca [1024 x i8], align 16
; TUNIT-NEXT: [[I0:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BYTES]], i64 0, i64 2
; TUNIT-NEXT: ret i8 2
;
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@call_simplifiable_1
; CGSCC-SAME: () #[[ATTR1:[0-9]+]] {
; CGSCC-NEXT: entry:
; CGSCC-NEXT: [[BYTES:%.*]] = alloca [1024 x i8], align 16
; CGSCC-NEXT: [[I0:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BYTES]], i64 0, i64 2
; CGSCC-NEXT: store i8 2, ptr [[I0]], align 2
; CGSCC-NEXT: [[R:%.*]] = call i8 @read_arg(ptr nocapture nofree noundef nonnull readonly align 2 dereferenceable(1022) [[I0]]) #[[ATTR3:[0-9]+]]
; CGSCC-NEXT: ret i8 [[R]]
;
entry:
%Bytes = alloca [1024 x i8], align 16
%i0 = getelementptr inbounds [1024 x i8], ptr %Bytes, i64 0, i64 2
store i8 2, ptr %i0, align 1
%r = call i8 @read_arg(ptr %i0)
ret i8 %r
}
;;; Same as read_arg, but we need a copy to form distinct leaves in the callgraph.
define internal i8 @read_arg_1(ptr %p) {
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
; CGSCC-LABEL: define {{[^@]+}}@read_arg_1
; CGSCC-SAME: (ptr nocapture nofree noundef nonnull readonly dereferenceable(1) [[P:%.*]]) #[[ATTR0]] {
; CGSCC-NEXT: entry:
; CGSCC-NEXT: [[L:%.*]] = load i8, ptr [[P]], align 1
; CGSCC-NEXT: ret i8 [[L]]
;
entry:
%l = load i8, ptr %p, align 1
ret i8 %l
}
define internal i8 @sum_two_same_loads(ptr %p) {
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(argmem: read)
; CGSCC-LABEL: define {{[^@]+}}@sum_two_same_loads
; CGSCC-SAME: (ptr nocapture nofree noundef nonnull readonly dereferenceable(1022) [[P:%.*]]) #[[ATTR2:[0-9]+]] {
; CGSCC-NEXT: [[X:%.*]] = call i8 @read_arg_1(ptr nocapture nofree noundef nonnull readonly dereferenceable(1022) [[P]]) #[[ATTR3]]
; CGSCC-NEXT: [[Y:%.*]] = call i8 @read_arg_1(ptr nocapture nofree noundef nonnull readonly dereferenceable(1022) [[P]]) #[[ATTR3]]
; CGSCC-NEXT: [[Z:%.*]] = add nsw i8 [[X]], [[Y]]
; CGSCC-NEXT: ret i8 [[Z]]
;
%x = call i8 @read_arg_1(ptr %p)
%y = call i8 @read_arg_1(ptr %p)
%z = add nsw i8 %x, %y
ret i8 %z
}
define i8 @call_simplifiable_2() {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@call_simplifiable_2
; TUNIT-SAME: () #[[ATTR0]] {
; TUNIT-NEXT: entry:
; TUNIT-NEXT: [[BYTES:%.*]] = alloca [1024 x i8], align 16
; TUNIT-NEXT: [[I0:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BYTES]], i64 0, i64 2
; TUNIT-NEXT: [[I1:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BYTES]], i64 0, i64 3
; TUNIT-NEXT: ret i8 4
;
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@call_simplifiable_2
; CGSCC-SAME: () #[[ATTR1]] {
; CGSCC-NEXT: entry:
; CGSCC-NEXT: [[BYTES:%.*]] = alloca [1024 x i8], align 16
; CGSCC-NEXT: [[I0:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BYTES]], i64 0, i64 2
; CGSCC-NEXT: store i8 2, ptr [[I0]], align 2
; CGSCC-NEXT: [[I1:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BYTES]], i64 0, i64 3
; CGSCC-NEXT: store i8 3, ptr [[I1]], align 1
; CGSCC-NEXT: [[R:%.*]] = call i8 @sum_two_same_loads(ptr nocapture nofree noundef nonnull readonly align 2 dereferenceable(1022) [[I0]]) #[[ATTR3]]
; CGSCC-NEXT: ret i8 [[R]]
;
entry:
%Bytes = alloca [1024 x i8], align 16
%i0 = getelementptr inbounds [1024 x i8], ptr %Bytes, i64 0, i64 2
store i8 2, ptr %i0
%i1 = getelementptr inbounds [1024 x i8], ptr %Bytes, i64 0, i64 3
store i8 3, ptr %i1
%r = call i8 @sum_two_same_loads(ptr %i0)
ret i8 %r
}
define i8 @call_simplifiable_3() {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@call_simplifiable_3
; TUNIT-SAME: () #[[ATTR0]] {
; TUNIT-NEXT: entry:
; TUNIT-NEXT: [[BYTES:%.*]] = alloca [1024 x i8], align 16
; TUNIT-NEXT: [[I2:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BYTES]], i64 0, i64 2
; TUNIT-NEXT: ret i8 2
;
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@call_simplifiable_3
; CGSCC-SAME: () #[[ATTR1]] {
; CGSCC-NEXT: entry:
; CGSCC-NEXT: [[BYTES:%.*]] = alloca [1024 x i8], align 16
; CGSCC-NEXT: [[I2:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BYTES]], i64 0, i64 2
; CGSCC-NEXT: store i8 2, ptr [[I2]], align 2
; CGSCC-NEXT: [[R:%.*]] = call i8 @read_arg_index(ptr nocapture nofree noundef nonnull readonly align 16 dereferenceable(1024) [[BYTES]]) #[[ATTR3]]
; CGSCC-NEXT: ret i8 [[R]]
;
entry:
%Bytes = alloca [1024 x i8], align 16
%i0 = getelementptr inbounds [1024 x i8], ptr %Bytes, i64 0, i64 0
%i2 = getelementptr inbounds [1024 x i8], ptr %Bytes, i64 0, i64 2
store i8 2, ptr %i2, align 1
%r = call i8 @read_arg_index(ptr %i0, i64 2)
ret i8 %r
}
;;; Same as read_arg, but we need a copy to form distinct leaves in the callgraph.
define internal i8 @read_arg_2(ptr %p) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
; TUNIT-LABEL: define {{[^@]+}}@read_arg_2
; TUNIT-SAME: (ptr nocapture nofree noundef nonnull readonly dereferenceable(971) [[P:%.*]]) #[[ATTR1:[0-9]+]] {
; TUNIT-NEXT: entry:
; TUNIT-NEXT: [[L:%.*]] = load i8, ptr [[P]], align 1
; TUNIT-NEXT: ret i8 [[L]]
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
; CGSCC-LABEL: define {{[^@]+}}@read_arg_2
; CGSCC-SAME: (ptr nocapture nofree noundef nonnull readonly dereferenceable(1) [[P:%.*]]) #[[ATTR0]] {
; CGSCC-NEXT: entry:
; CGSCC-NEXT: [[L:%.*]] = load i8, ptr [[P]], align 1
; CGSCC-NEXT: ret i8 [[L]]
;
entry:
%l = load i8, ptr %p, align 1
ret i8 %l
}
define internal i8 @sum_two_different_loads(ptr %p, ptr %q) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
; TUNIT-LABEL: define {{[^@]+}}@sum_two_different_loads
; TUNIT-SAME: (ptr nocapture nofree nonnull readonly dereferenceable(972) [[P:%.*]], ptr nocapture nofree noundef nonnull readonly dereferenceable(971) [[Q:%.*]]) #[[ATTR1]] {
; TUNIT-NEXT: [[X:%.*]] = call i8 @read_arg_2(ptr nocapture nofree noundef nonnull readonly dereferenceable(972) [[P]]) #[[ATTR2:[0-9]+]]
; TUNIT-NEXT: [[Y:%.*]] = call i8 @read_arg_2(ptr nocapture nofree noundef nonnull readonly dereferenceable(971) [[Q]]) #[[ATTR2]]
; TUNIT-NEXT: [[Z:%.*]] = add nsw i8 [[X]], [[Y]]
; TUNIT-NEXT: ret i8 [[Z]]
;
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(argmem: read)
; CGSCC-LABEL: define {{[^@]+}}@sum_two_different_loads
; CGSCC-SAME: (ptr nocapture nofree noundef nonnull readonly dereferenceable(972) [[P:%.*]], ptr nocapture nofree noundef nonnull readonly dereferenceable(971) [[Q:%.*]]) #[[ATTR2]] {
; CGSCC-NEXT: [[X:%.*]] = call i8 @read_arg_2(ptr nocapture nofree noundef nonnull readonly dereferenceable(972) [[P]]) #[[ATTR3]]
; CGSCC-NEXT: [[Y:%.*]] = call i8 @read_arg_2(ptr nocapture nofree noundef nonnull readonly dereferenceable(971) [[Q]]) #[[ATTR3]]
; CGSCC-NEXT: [[Z:%.*]] = add nsw i8 [[X]], [[Y]]
; CGSCC-NEXT: ret i8 [[Z]]
;
%x = call i8 @read_arg_2(ptr %p)
%y = call i8 @read_arg_2(ptr %q)
%z = add nsw i8 %x, %y
ret i8 %z
}
define i8 @call_partially_simplifiable_1() {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@call_partially_simplifiable_1
; TUNIT-SAME: () #[[ATTR0]] {
; TUNIT-NEXT: entry:
; TUNIT-NEXT: [[BYTES:%.*]] = alloca [1024 x i8], align 16
; TUNIT-NEXT: [[I2:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BYTES]], i64 0, i64 2
; TUNIT-NEXT: store i8 2, ptr [[I2]], align 2
; TUNIT-NEXT: [[I3:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BYTES]], i64 0, i64 3
; TUNIT-NEXT: store i8 3, ptr [[I3]], align 1
; TUNIT-NEXT: [[I4:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BYTES]], i64 0, i64 4
; TUNIT-NEXT: [[R:%.*]] = call i8 @sum_two_different_loads(ptr nocapture nofree noundef nonnull readonly align 2 dereferenceable(1022) [[I2]], ptr nocapture nofree noundef nonnull readonly dereferenceable(1021) [[I3]]) #[[ATTR3:[0-9]+]]
; TUNIT-NEXT: ret i8 [[R]]
;
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@call_partially_simplifiable_1
; CGSCC-SAME: () #[[ATTR1]] {
; CGSCC-NEXT: entry:
; CGSCC-NEXT: [[BYTES:%.*]] = alloca [1024 x i8], align 16
; CGSCC-NEXT: [[I2:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BYTES]], i64 0, i64 2
; CGSCC-NEXT: store i8 2, ptr [[I2]], align 2
; CGSCC-NEXT: [[I3:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BYTES]], i64 0, i64 3
; CGSCC-NEXT: store i8 3, ptr [[I3]], align 1
; CGSCC-NEXT: [[I4:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BYTES]], i64 0, i64 4
; CGSCC-NEXT: store i8 4, ptr [[I4]], align 4
; CGSCC-NEXT: [[R:%.*]] = call i8 @sum_two_different_loads(ptr nocapture nofree noundef nonnull readonly align 2 dereferenceable(1022) [[I2]], ptr nocapture nofree noundef nonnull readonly dereferenceable(1021) [[I3]]) #[[ATTR3]]
; CGSCC-NEXT: ret i8 [[R]]
;
entry:
%Bytes = alloca [1024 x i8], align 16
%i2 = getelementptr inbounds [1024 x i8], ptr %Bytes, i64 0, i64 2
store i8 2, ptr %i2
%i3 = getelementptr inbounds [1024 x i8], ptr %Bytes, i64 0, i64 3
store i8 3, ptr %i3
%i4 = getelementptr inbounds [1024 x i8], ptr %Bytes, i64 0, i64 4
;;; This store is redundant, hence removed.
store i8 4, ptr %i4
%r = call i8 @sum_two_different_loads(ptr %i2, ptr %i3)
ret i8 %r
}
define i8 @call_partially_simplifiable_2(i1 %cond) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@call_partially_simplifiable_2
; TUNIT-SAME: (i1 [[COND:%.*]]) #[[ATTR0]] {
; TUNIT-NEXT: entry:
; TUNIT-NEXT: [[BYTES:%.*]] = alloca [1024 x i8], align 16
; TUNIT-NEXT: [[I51:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BYTES]], i64 0, i64 51
; TUNIT-NEXT: [[I52:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BYTES]], i64 0, i64 52
; TUNIT-NEXT: store i8 2, ptr [[I52]], align 4
; TUNIT-NEXT: [[I53:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BYTES]], i64 0, i64 53
; TUNIT-NEXT: store i8 3, ptr [[I53]], align 1
; TUNIT-NEXT: [[I54:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BYTES]], i64 0, i64 54
; TUNIT-NEXT: [[SEL:%.*]] = select i1 [[COND]], ptr [[I51]], ptr [[I52]]
; TUNIT-NEXT: [[R:%.*]] = call i8 @sum_two_different_loads(ptr nocapture nofree nonnull readonly dereferenceable(972) [[SEL]], ptr nocapture nofree noundef nonnull readonly dereferenceable(971) [[I53]]) #[[ATTR3]]
; TUNIT-NEXT: ret i8 [[R]]
;
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@call_partially_simplifiable_2
; CGSCC-SAME: (i1 [[COND:%.*]]) #[[ATTR1]] {
; CGSCC-NEXT: entry:
; CGSCC-NEXT: [[BYTES:%.*]] = alloca [1024 x i8], align 16
; CGSCC-NEXT: [[I51:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BYTES]], i64 0, i64 51
; CGSCC-NEXT: [[I52:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BYTES]], i64 0, i64 52
; CGSCC-NEXT: store i8 2, ptr [[I52]], align 4
; CGSCC-NEXT: [[I53:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BYTES]], i64 0, i64 53
; CGSCC-NEXT: store i8 3, ptr [[I53]], align 1
; CGSCC-NEXT: [[I54:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BYTES]], i64 0, i64 54
; CGSCC-NEXT: store i8 4, ptr [[I54]], align 2
; CGSCC-NEXT: [[SEL:%.*]] = select i1 [[COND]], ptr [[I51]], ptr [[I52]]
; CGSCC-NEXT: [[R:%.*]] = call i8 @sum_two_different_loads(ptr nocapture nofree noundef nonnull readonly dereferenceable(972) [[SEL]], ptr nocapture nofree noundef nonnull readonly dereferenceable(971) [[I53]]) #[[ATTR3]]
; CGSCC-NEXT: ret i8 [[R]]
;
entry:
%Bytes = alloca [1024 x i8], align 16
%i51 = getelementptr inbounds [1024 x i8], ptr %Bytes, i64 0, i64 51
%i52 = getelementptr inbounds [1024 x i8], ptr %Bytes, i64 0, i64 52
store i8 2, ptr %i52
%i53 = getelementptr inbounds [1024 x i8], ptr %Bytes, i64 0, i64 53
store i8 3, ptr %i53
%i54 = getelementptr inbounds [1024 x i8], ptr %Bytes, i64 0, i64 54
;;; This store is redundant, hence removed. Not affected by the select.
store i8 4, ptr %i54
%sel = select i1 %cond, ptr %i51, ptr %i52
%r = call i8 @sum_two_different_loads(ptr %sel, ptr %i53)
ret i8 %r
}
;.
; TUNIT: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
; TUNIT: attributes #[[ATTR1]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) }
; TUNIT: attributes #[[ATTR2]] = { nofree nosync nounwind willreturn memory(read) }
; TUNIT: attributes #[[ATTR3]] = { nofree norecurse nosync nounwind willreturn memory(read) }
;.
; CGSCC: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) }
; CGSCC: attributes #[[ATTR1]] = { mustprogress nofree nosync nounwind willreturn memory(none) }
; CGSCC: attributes #[[ATTR2]] = { mustprogress nofree nosync nounwind willreturn memory(argmem: read) }
; CGSCC: attributes #[[ATTR3]] = { nofree willreturn memory(read) }
;.