Nikita Popov 243acd5dcb [BasicAA] Remove support for PhiValues analysis
BasicAA currently has an optional dependency on the PhiValues
analysis. However, at least with our current pipeline setup, we
never actually make use of it. It's possible that this used to work
with the legacy pass manager, but I'm not sure of that either.

Given that this analysis has not actually been in use for a long
time, and nobody noticed or complained, I think we should drop
support for it and focus on one code path. It is worth noting that
analysis quality for the non-PhiValues case has significantly
improved in the meantime.

If we really wanted to make use of PhiValues, the right way would
probably be to pass it in via AAQI in places we want to use it,
rather than using an optional pass manager dependency (which are
an unpredictable PITA and should really only ever be used for
analyses that are only preserved and not used).

Differential Revision: https://reviews.llvm.org/D139719
2022-12-12 09:47:30 +01:00

427 lines
14 KiB
LLVM

; RUN: opt < %s -aa-pipeline=basic-aa -passes=aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s
; CHECK-LABEL: Function: simple: 5 pointers, 0 call sites
; CHECK: NoAlias: float* %src1, float* %src2
; CHECK: NoAlias: float* %phi, float* %src1
; CHECK: MayAlias: float* %phi, float* %src2
; CHECK: NoAlias: float* %next, float* %src1
; CHECK: MayAlias: float* %next, float* %src2
; CHECK: NoAlias: float* %next, float* %phi
; CHECK: NoAlias: float* %g, float* %src1
; CHECK: NoAlias: float* %g, float* %src2
; CHECK: NoAlias: float* %g, float* %phi
; CHECK: NoAlias: float* %g, float* %next
define void @simple(ptr %src1, ptr noalias %src2, i32 %n) nounwind {
entry:
load float, ptr %src1
load float, ptr %src2
br label %loop
loop:
%phi = phi ptr [ %src2, %entry ], [ %next, %loop ]
%idx = phi i32 [ 0, %entry ], [ %idxn, %loop ]
%next = getelementptr inbounds float, ptr %phi, i32 1
%g = getelementptr inbounds float, ptr %src1, i32 3
%l = load float, ptr %phi
load float, ptr %next
%a = fadd float %l, 1.0
store float %a, ptr %g
%idxn = add nsw nuw i32 %idx, 1
%cmp5 = icmp eq i32 %idxn, %n
br i1 %cmp5, label %end, label %loop
end:
ret void
}
; CHECK-LABEL: Function: notmust: 6 pointers, 0 call sites
; CHECK: MustAlias: i8* %tab, [2 x i32]* %tab
; CHECK: PartialAlias (off -4): i32* %arrayidx, [2 x i32]* %tab
; CHECK: NoAlias: i32* %arrayidx, i8* %tab
; CHECK: MustAlias: i32* %tab, [2 x i32]* %tab
; CHECK: MustAlias: i32* %tab, i8* %tab
; CHECK: NoAlias: i32* %arrayidx, i32* %tab
; CHECK: MayAlias: i32* %incdec.ptr.i, [2 x i32]* %tab
; CHECK: NoAlias: i32* %incdec.ptr.i, i8* %tab
; CHECK: MayAlias: i32* %arrayidx, i32* %incdec.ptr.i
; CHECK: NoAlias: i32* %incdec.ptr.i, i32* %tab
; CHECK: MayAlias: i32* %p.addr.05.i, [2 x i32]* %tab
; CHECK: MayAlias: i32* %p.addr.05.i, i8* %tab
; CHECK: MayAlias: i32* %arrayidx, i32* %p.addr.05.i
; CHECK: MayAlias: i32* %p.addr.05.i, i32* %tab
; CHECK: NoAlias: i32* %incdec.ptr.i, i32* %p.addr.05.i
define i32 @notmust() nounwind {
entry:
%tab = alloca [2 x i32], align 4
%ignore1 = load [2 x i32], ptr %tab
%ignore2 = load i8, ptr %tab
%arrayidx = getelementptr inbounds [2 x i32], ptr %tab, i32 0, i32 1
store i32 0, ptr %arrayidx, align 4
store i32 0, ptr %tab, align 4
%0 = add i32 1, 1
%cmp4.i = icmp slt i32 %0, 2
br i1 %cmp4.i, label %while.body.i, label %f.exit
while.body.i: ; preds = %while.body.i, %entry
%1 = phi i32 [ 1, %while.body.i ], [ %0, %entry ]
%foo.06.i = phi i32 [ %sub.i, %while.body.i ], [ 2, %entry ]
%p.addr.05.i = phi ptr [ %incdec.ptr.i, %while.body.i ], [ %tab, %entry ]
%sub.i = sub nsw i32 %foo.06.i, %1
%incdec.ptr.i = getelementptr inbounds i32, ptr %p.addr.05.i, i32 1
%ignore3 = load i32, ptr %incdec.ptr.i
store i32 %sub.i, ptr %p.addr.05.i, align 4
%cmp.i = icmp sgt i32 %sub.i, 1
br i1 %cmp.i, label %while.body.i, label %f.exit
f.exit: ; preds = %entry, %while.body.i
%2 = load i32, ptr %tab, align 4
%cmp = icmp eq i32 %2, 2
%3 = load i32, ptr %arrayidx, align 4
%cmp4 = icmp eq i32 %3, 1
%or.cond = and i1 %cmp, %cmp4
br i1 %or.cond, label %if.end, label %if.then
if.then: ; preds = %f.exit
unreachable
if.end: ; preds = %f.exit
ret i32 0
}
; CHECK-LABEL: Function: reverse: 6 pointers, 0 call sites
; CHECK: MustAlias: i8* %tab, [10 x i32]* %tab
; CHECK: MustAlias: i32* %tab, [10 x i32]* %tab
; CHECK: MustAlias: i32* %tab, i8* %tab
; CHECK: PartialAlias (off -36): i32* %arrayidx1, [10 x i32]* %tab
; CHECK: NoAlias: i32* %arrayidx1, i8* %tab
; CHECK: NoAlias: i32* %arrayidx1, i32* %tab
; CHECK: MayAlias: i32* %incdec.ptr.i, [10 x i32]* %tab
; CHECK: MayAlias: i32* %incdec.ptr.i, i8* %tab
; CHECK: MayAlias: i32* %incdec.ptr.i, i32* %tab
; CHECK: MayAlias: i32* %arrayidx1, i32* %incdec.ptr.i
; CHECK: MayAlias: i32* %p.addr.05.i, [10 x i32]* %tab
; CHECK: MayAlias: i32* %p.addr.05.i, i8* %tab
; CHECK: MayAlias: i32* %p.addr.05.i, i32* %tab
; CHECK: MayAlias: i32* %arrayidx1, i32* %p.addr.05.i
; CHECK: NoAlias: i32* %incdec.ptr.i, i32* %p.addr.05.i
define i32 @reverse() nounwind {
entry:
%tab = alloca [10 x i32], align 4
%ignore1 = load [10 x i32], ptr %tab
%ignore2 = load i8, ptr %tab
store i32 0, ptr %tab, align 4
%arrayidx1 = getelementptr inbounds [10 x i32], ptr %tab, i32 0, i32 9
store i32 0, ptr %arrayidx1, align 4
%0 = add i32 1, 1
%cmp4.i = icmp slt i32 %0, 2
br i1 %cmp4.i, label %while.body.i, label %f.exit
while.body.i: ; preds = %while.body.i, %entry
%1 = phi i32 [ 1, %while.body.i ], [ %0, %entry ]
%foo.06.i = phi i32 [ %sub.i, %while.body.i ], [ 2, %entry ]
%p.addr.05.i = phi ptr [ %incdec.ptr.i, %while.body.i ], [ %arrayidx1, %entry ]
%sub.i = sub nsw i32 %foo.06.i, %1
%incdec.ptr.i = getelementptr inbounds i32, ptr %p.addr.05.i, i32 -1
%ignore3 = load i32, ptr %incdec.ptr.i
store i32 %sub.i, ptr %p.addr.05.i, align 4
%cmp.i = icmp sgt i32 %sub.i, 1
br i1 %cmp.i, label %while.body.i, label %f.exit
f.exit: ; preds = %entry, %while.body.i
%2 = load i32, ptr %arrayidx1, align 4
%cmp = icmp eq i32 %2, 2
%3 = load i32, ptr %tab, align 4
%cmp4 = icmp eq i32 %3, 1
%or.cond = and i1 %cmp, %cmp4
br i1 %or.cond, label %if.end, label %if.then
if.then: ; preds = %f.exit
unreachable
if.end: ; preds = %f.exit
ret i32 0
}
; CHECK-LABEL: Function: negative: 5 pointers, 1 call sites
; CHECK: PartialAlias (off -4): i16* %_tmp1, [3 x i16]* %int_arr.10
; CHECK: MayAlias: [3 x i16]* %int_arr.10, i16* %ls1.9.0
; CHECK: MayAlias: i16* %_tmp1, i16* %ls1.9.0
; CHECK: MayAlias: i16* %_tmp7, [3 x i16]* %int_arr.10
; CHECK: MayAlias: i16* %_tmp1, i16* %_tmp7
; CHECK: NoAlias: i16* %_tmp7, i16* %ls1.9.0
; CHECK: PartialAlias (off -2): i16* %_tmp11, [3 x i16]* %int_arr.10
; CHECK: NoAlias: i16* %_tmp1, i16* %_tmp11
; CHECK: MayAlias: i16* %_tmp11, i16* %ls1.9.0
; CHECK: MayAlias: i16* %_tmp11, i16* %_tmp7
; CHECK: NoModRef: Ptr: [3 x i16]* %int_arr.10 <-> %_tmp16 = call i16 @call(i32 %_tmp13)
; CHECK: NoModRef: Ptr: i16* %_tmp1 <-> %_tmp16 = call i16 @call(i32 %_tmp13)
; CHECK: Both ModRef: Ptr: i16* %ls1.9.0 <-> %_tmp16 = call i16 @call(i32 %_tmp13)
; CHECK: Both ModRef: Ptr: i16* %_tmp7 <-> %_tmp16 = call i16 @call(i32 %_tmp13)
; CHECK: NoModRef: Ptr: i16* %_tmp11 <-> %_tmp16 = call i16 @call(i32 %_tmp13)
define i16 @negative(i16 %argc.5.par) {
%int_arr.10 = alloca [3 x i16], align 1
load [3 x i16], ptr %int_arr.10
%_tmp1 = getelementptr inbounds [3 x i16], ptr %int_arr.10, i16 0, i16 2
load i16, ptr %_tmp1
br label %bb1
bb1: ; preds = %bb1, %0
%i.7.0 = phi i16 [ 2, %0 ], [ %_tmp5, %bb1 ]
%ls1.9.0 = phi ptr [ %_tmp1, %0 ], [ %_tmp7, %bb1 ]
store i16 %i.7.0, ptr %ls1.9.0, align 1
%_tmp5 = add nsw i16 %i.7.0, -1
%_tmp7 = getelementptr i16, ptr %ls1.9.0, i16 -1
load i16, ptr %_tmp7
%_tmp9 = icmp sgt i16 %i.7.0, 0
br i1 %_tmp9, label %bb1, label %bb3
bb3: ; preds = %bb1
%_tmp11 = getelementptr inbounds [3 x i16], ptr %int_arr.10, i16 0, i16 1
%_tmp12 = load i16, ptr %_tmp11, align 1
%_tmp13 = sext i16 %_tmp12 to i32
%_tmp16 = call i16 @call(i32 %_tmp13)
%_tmp18.not = icmp eq i16 %_tmp12, 1
br i1 %_tmp18.not, label %bb5, label %bb4
bb4: ; preds = %bb3
ret i16 1
bb5: ; preds = %bb3, %bb4
ret i16 0
}
; CHECK-LABEL: Function: dynamic_offset
; CHECK: NoAlias: i8* %a, i8* %p.base
; CHECK: MayAlias: i8* %p, i8* %p.base
; CHECK: NoAlias: i8* %a, i8* %p
; CHECK: MayAlias: i8* %p.base, i8* %p.next
; CHECK: NoAlias: i8* %a, i8* %p.next
; CHECK: MayAlias: i8* %p, i8* %p.next
define void @dynamic_offset(i1 %c, ptr noalias %p.base) {
entry:
%a = alloca i8
load i8, ptr %p.base
load i8, ptr %a
br label %loop
loop:
%p = phi ptr [ %p.base, %entry ], [ %p.next, %loop ]
%offset = call i16 @call(i32 0)
%p.next = getelementptr inbounds i8, ptr %p, i16 %offset
load i8, ptr %p
load i8, ptr %p.next
br i1 %c, label %loop, label %exit
exit:
ret void
}
; TODO: Currently yields an asymmetric result.
; CHECK-LABEL: Function: symmetry
; CHECK: MayAlias: i32* %p, i32* %p.base
; CHECK: MayAlias: i32* %p.base, i32* %p.next
; CHECK: NoAlias: i32* %p, i32* %p.next
; CHECK: MayAlias: i32* %p.base, i32* %result
; CHECK: NoAlias: i32* %p, i32* %result
; CHECK: MustAlias: i32* %p.next, i32* %result
define ptr @symmetry(ptr %p.base, i1 %c) {
entry:
load i32, ptr %p.base
br label %loop
loop:
%p = phi ptr [ %p.base, %entry ], [ %p.next, %loop ]
%p.next = getelementptr inbounds i32, ptr %p, i32 1
load i32, ptr %p
load i32, ptr %p.next
br i1 %c, label %loop, label %exit
exit:
%result = phi ptr [ %p.next, %loop ]
load i32, ptr %result
ret ptr %result
}
; FIXME: %a and %p.inner do not alias.
; CHECK-LABEL: Function: nested_loop
; CHECK: NoAlias: i8* %a, i8* %p.base
; CHECK: NoAlias: i8* %a, i8* %p.outer
; CHECK: MayAlias: i8* %a, i8* %p.inner
; CHECK: NoAlias: i8* %a, i8* %p.inner.next
; CHECK: NoAlias: i8* %a, i8* %p.outer.next
define void @nested_loop(i1 %c, i1 %c2, ptr noalias %p.base) {
entry:
%a = alloca i8
load i8, ptr %p.base
load i8, ptr %a
br label %outer_loop
outer_loop:
%p.outer = phi ptr [ %p.base, %entry ], [ %p.outer.next, %outer_loop_latch ]
load i8, ptr %p.outer
br label %inner_loop
inner_loop:
%p.inner = phi ptr [ %p.outer, %outer_loop ], [ %p.inner.next, %inner_loop ]
%p.inner.next = getelementptr inbounds i8, ptr %p.inner, i64 1
load i8, ptr %p.inner
load i8, ptr %p.inner.next
br i1 %c, label %inner_loop, label %outer_loop_latch
outer_loop_latch:
%p.outer.next = getelementptr inbounds i8, ptr %p.inner, i64 10
load i8, ptr %p.outer.next
br i1 %c2, label %outer_loop, label %exit
exit:
ret void
}
; Same as the previous test case, but avoiding phi of phi.
; CHECK-LABEL: Function: nested_loop2
; CHECK: NoAlias: i8* %a, i8* %p.base
; CHECK: NoAlias: i8* %a, i8* %p.outer
; CHECK: NoAlias: i8* %a, i8* %p.outer.next
; CHECK: MayAlias: i8* %a, i8* %p.inner
; CHECK: NoAlias: i8* %a, i8* %p.inner.next
; TODO: (a, p.inner) could be NoAlias
define void @nested_loop2(i1 %c, i1 %c2, ptr noalias %p.base) {
entry:
%a = alloca i8
load i8, ptr %p.base
load i8, ptr %a
br label %outer_loop
outer_loop:
%p.outer = phi ptr [ %p.base, %entry ], [ %p.outer.next, %outer_loop_latch ]
%p.outer.next = getelementptr inbounds i8, ptr %p.outer, i64 10
load i8, ptr %p.outer
load i8, ptr %p.outer.next
br label %inner_loop
inner_loop:
%p.inner = phi ptr [ %p.outer.next, %outer_loop ], [ %p.inner.next, %inner_loop ]
%p.inner.next = getelementptr inbounds i8, ptr %p.inner, i64 1
load i8, ptr %p.inner
load i8, ptr %p.inner.next
br i1 %c, label %inner_loop, label %outer_loop_latch
outer_loop_latch:
br i1 %c2, label %outer_loop, label %exit
exit:
ret void
}
; CHECK-LABEL: Function: nested_loop3
; CHECK: NoAlias: i8* %a, i8* %p.base
; CHECK: NoAlias: i8* %a, i8* %p.outer
; CHECK: NoAlias: i8* %a, i8* %p.outer.next
; CHECK: NoAlias: i8* %a, i8* %p.inner
; CHECK: NoAlias: i8* %a, i8* %p.inner.next
define void @nested_loop3(i1 %c, i1 %c2, ptr noalias %p.base) {
entry:
%a = alloca i8
load i8, ptr %p.base
load i8, ptr %a
br label %outer_loop
outer_loop:
%p.outer = phi ptr [ %p.base, %entry ], [ %p.outer.next, %outer_loop_latch ]
%p.outer.next = getelementptr inbounds i8, ptr %p.outer, i64 10
load i8, ptr %p.outer
load i8, ptr %p.outer.next
br label %inner_loop
inner_loop:
%p.inner = phi ptr [ %p.outer, %outer_loop ], [ %p.inner.next, %inner_loop ]
%p.inner.next = getelementptr inbounds i8, ptr %p.inner, i64 1
load i8, ptr %p.inner
load i8, ptr %p.inner.next
br i1 %c, label %inner_loop, label %outer_loop_latch
outer_loop_latch:
br i1 %c2, label %outer_loop, label %exit
exit:
ret void
}
; CHECK-LABEL: Function: sibling_loop
; CHECK: NoAlias: i8* %a, i8* %p.base
; CHECK: NoAlias: i8* %a, i8* %p1
; CHECK: NoAlias: i8* %a, i8* %p1.next
; CHECK: MayAlias: i8* %a, i8* %p2
; CHECK: NoAlias: i8* %a, i8* %p2.next
; TODO: %p2 does not alias %a
define void @sibling_loop(i1 %c, i1 %c2, ptr noalias %p.base) {
entry:
%a = alloca i8
load i8, ptr %p.base
load i8, ptr %a
br label %loop1
loop1:
%p1 = phi ptr [ %p.base, %entry ], [ %p1.next, %loop1 ]
%p1.next = getelementptr inbounds i8, ptr %p1, i64 10
load i8, ptr %p1
load i8, ptr %p1.next
br i1 %c, label %loop1, label %loop2
loop2:
%p2 = phi ptr [ %p1.next, %loop1 ], [ %p2.next, %loop2 ]
%p2.next = getelementptr inbounds i8, ptr %p2, i64 1
load i8, ptr %p2
load i8, ptr %p2.next
br i1 %c2, label %loop2, label %exit
exit:
ret void
}
; CHECK-LABEL: Function: sibling_loop2
; CHECK: NoAlias: i8* %a, i8* %p.base
; CHECK: NoAlias: i8* %a, i8* %p1
; CHECK: NoAlias: i8* %a, i8* %p1.next
; CHECK: NoAlias: i8* %a, i8* %p2
; CHECK: NoAlias: i8* %a, i8* %p2.next
define void @sibling_loop2(i1 %c, i1 %c2, ptr noalias %p.base) {
entry:
%a = alloca i8
load i8, ptr %p.base
load i8, ptr %a
br label %loop1
loop1:
%p1 = phi ptr [ %p.base, %entry ], [ %p1.next, %loop1 ]
%p1.next = getelementptr inbounds i8, ptr %p1, i64 10
load i8, ptr %p1
load i8, ptr %p1.next
br i1 %c, label %loop1, label %loop2
loop2:
%p2 = phi ptr [ %p1, %loop1 ], [ %p2.next, %loop2 ]
%p2.next = getelementptr inbounds i8, ptr %p2, i64 1
load i8, ptr %p2
load i8, ptr %p2.next
br i1 %c2, label %loop2, label %exit
exit:
ret void
}
; CHECK: MustAlias: i8* %a, i8* %phi
define void @phi_contains_self() {
entry:
%a = alloca i32
load i8, ptr %a
br label %loop
loop:
%phi = phi ptr [ %phi, %loop ], [ %a, %entry ]
load i8, ptr %phi
br label %loop
}
declare i16 @call(i32)