Files
clang-p2996/llvm/test/Analysis/ScalarEvolution/scev-aa.ll
Nikita Popov 57d57b1afd [AAEval] Make compatible with opaque pointers
With opaque pointers, we cannot use the pointer element type to
determine the LocationSize for the AA query. Instead, -aa-eval
tests are now required to have an explicit load or store for any
pointer they want to compute alias results for, and the load/store
types are used to determine the location size.

This may affect ordering of results, and sorting within one result,
as the type is not considered part of the sorted string anymore.

To somewhat minimize the churn, printing still uses faux typed
pointer notation.
2022-03-16 10:02:11 +01:00

349 lines
10 KiB
LLVM

; RUN: opt -disable-output < %s -aa-pipeline=scev-aa -passes=aa-eval -print-all-alias-modref-info \
; RUN: 2>&1 | FileCheck %s
; At the time of this writing, -basic-aa misses the example of the form
; A[i+(j+1)] != A[i+j], which can arise from multi-dimensional array references,
; and the example of the form A[0] != A[i+1], where i+1 is known to be positive.
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64"
; p[i] and p[i+1] don't alias.
; CHECK-LABEL: Function: loop
; CHECK: NoAlias: double* %pi, double* %pi.next
define void @loop(double* nocapture %p, i64 %n) nounwind {
entry:
%j = icmp sgt i64 %n, 0
br i1 %j, label %bb, label %return
bb:
%i = phi i64 [ 0, %entry ], [ %i.next, %bb ]
%pi = getelementptr double, double* %p, i64 %i
%i.next = add i64 %i, 1
%pi.next = getelementptr double, double* %p, i64 %i.next
%x = load double, double* %pi
%y = load double, double* %pi.next
%z = fmul double %x, %y
store double %z, double* %pi
%exitcond = icmp eq i64 %i.next, %n
br i1 %exitcond, label %return, label %bb
return:
ret void
}
; Slightly more involved: p[j][i], p[j][i+1], and p[j+1][i] don't alias.
; CHECK-LABEL: Function: nestedloop
; CHECK: NoAlias: double* %pi.j, double* %pi.next.j
; CHECK: NoAlias: double* %pi.j, double* %pi.j.next
; CHECK: NoAlias: double* %pi.j.next, double* %pi.next.j
define void @nestedloop(double* nocapture %p, i64 %m) nounwind {
entry:
%k = icmp sgt i64 %m, 0
br i1 %k, label %guard, label %return
guard:
%l = icmp sgt i64 91, 0
br i1 %l, label %outer.loop, label %return
outer.loop:
%j = phi i64 [ 0, %guard ], [ %j.next, %outer.latch ]
br label %bb
bb:
%i = phi i64 [ 0, %outer.loop ], [ %i.next, %bb ]
%i.next = add i64 %i, 1
%e = add i64 %i, %j
%pi.j = getelementptr double, double* %p, i64 %e
%f = add i64 %i.next, %j
%pi.next.j = getelementptr double, double* %p, i64 %f
%x = load double, double* %pi.j
%y = load double, double* %pi.next.j
%z = fmul double %x, %y
store double %z, double* %pi.j
%o = add i64 %j, 91
%g = add i64 %i, %o
%pi.j.next = getelementptr double, double* %p, i64 %g
%a = load double, double* %pi.j.next
%b = fmul double %x, %a
store double %b, double* %pi.j.next
%exitcond = icmp eq i64 %i.next, 91
br i1 %exitcond, label %outer.latch, label %bb
outer.latch:
%j.next = add i64 %j, 91
%h = icmp eq i64 %j.next, %m
br i1 %h, label %return, label %outer.loop
return:
ret void
}
; Even more involved: same as nestedloop, but with a variable extent.
; When n is 1, p[j+1][i] does alias p[j][i+1], and there's no way to
; prove whether n will be greater than 1, so that relation will always
; by MayAlias. The loop is guarded by a n > 0 test though, so
; p[j+1][i] and p[j][i] can theoretically be determined to be NoAlias,
; however the analysis currently doesn't do that.
; TODO: Make the analysis smarter and turn that MayAlias into a NoAlias.
; CHECK-LABEL: Function: nestedloop_more
; CHECK: NoAlias: double* %pi.j, double* %pi.next.j
; CHECK: MayAlias: double* %pi.j, double* %pi.j.next
define void @nestedloop_more(double* nocapture %p, i64 %n, i64 %m) nounwind {
entry:
%k = icmp sgt i64 %m, 0
br i1 %k, label %guard, label %return
guard:
%l = icmp sgt i64 %n, 0
br i1 %l, label %outer.loop, label %return
outer.loop:
%j = phi i64 [ 0, %guard ], [ %j.next, %outer.latch ]
br label %bb
bb:
%i = phi i64 [ 0, %outer.loop ], [ %i.next, %bb ]
%i.next = add i64 %i, 1
%e = add i64 %i, %j
%pi.j = getelementptr double, double* %p, i64 %e
%f = add i64 %i.next, %j
%pi.next.j = getelementptr double, double* %p, i64 %f
%x = load double, double* %pi.j
%y = load double, double* %pi.next.j
%z = fmul double %x, %y
store double %z, double* %pi.j
%o = add i64 %j, %n
%g = add i64 %i, %o
%pi.j.next = getelementptr double, double* %p, i64 %g
%a = load double, double* %pi.j.next
%b = fmul double %x, %a
store double %b, double* %pi.j.next
%exitcond = icmp eq i64 %i.next, %n
br i1 %exitcond, label %outer.latch, label %bb
outer.latch:
%j.next = add i64 %j, %n
%h = icmp eq i64 %j.next, %m
br i1 %h, label %return, label %outer.loop
return:
ret void
}
; ScalarEvolution expands field offsets into constants, which allows it to
; do aggressive analysis. Contrast this with BasicAA, which works by
; recognizing GEP idioms.
%struct.A = type { %struct.B, i32, i32 }
%struct.B = type { double }
; CHECK-LABEL: Function: foo
; CHECK-DAG: NoAlias: %struct.B* %B, i32* %Z
; CHECK-DAG: NoAlias: %struct.B* %B, %struct.B* %C
; CHECK-DAG: MustAlias: %struct.B* %C, i32* %Z
; CHECK-DAG: NoAlias: %struct.B* %B, i32* %X
; CHECK-DAG: MustAlias: i32* %X, i32* %Z
; CHECK-DAG: MustAlias: %struct.B* %C, i32* %Y
; CHECK-DAG: MustAlias: i32* %X, i32* %Y
define void @foo() {
entry:
%A = alloca %struct.A
%B = getelementptr %struct.A, %struct.A* %A, i32 0, i32 0
%Q = bitcast %struct.B* %B to %struct.A*
%Z = getelementptr %struct.A, %struct.A* %Q, i32 0, i32 1
%C = getelementptr %struct.B, %struct.B* %B, i32 1
%X = bitcast %struct.B* %C to i32*
%Y = getelementptr %struct.A, %struct.A* %A, i32 0, i32 1
load %struct.B, %struct.B* %B
load %struct.B, %struct.B* %C
load i32, i32* %X
load i32, i32* %Y
load i32, i32* %Z
ret void
}
; CHECK-LABEL: Function: bar
; CHECK-DAG: NoAlias: %struct.B* %N, i32* %P
; CHECK-DAG: NoAlias: %struct.B* %N, %struct.B* %R
; CHECK-DAG: MustAlias: i32* %P, %struct.B* %R
; CHECK-DAG: NoAlias: %struct.B* %N, i32* %W
; CHECK-DAG: MustAlias: i32* %P, i32* %W
; CHECK-DAG: MustAlias: %struct.B* %R, i32* %V
; CHECK-DAG: MustAlias: i32* %V, i32* %W
define void @bar() {
%M = alloca %struct.A
%N = getelementptr %struct.A, %struct.A* %M, i32 0, i32 0
%O = bitcast %struct.B* %N to %struct.A*
%P = getelementptr %struct.A, %struct.A* %O, i32 0, i32 1
%R = getelementptr %struct.B, %struct.B* %N, i32 1
%W = bitcast %struct.B* %R to i32*
%V = getelementptr %struct.A, %struct.A* %M, i32 0, i32 1
load %struct.B, %struct.B* %N
load %struct.B, %struct.B* %R
load i32, i32* %P
load i32, i32* %V
load i32, i32* %W
ret void
}
; CHECK: Function: nonnegative: 2 pointers, 0 call sites
; CHECK: NoAlias: i64* %arrayidx, i64* %p
define void @nonnegative(i64* %p) nounwind {
entry:
br label %for.body
for.body: ; preds = %entry, %for.body
%i = phi i64 [ %inc, %for.body ], [ 0, %entry ] ; <i64> [#uses=2]
%inc = add nsw i64 %i, 1 ; <i64> [#uses=2]
%arrayidx = getelementptr inbounds i64, i64* %p, i64 %inc
store i64 0, i64* %arrayidx
%tmp6 = load i64, i64* %p ; <i64> [#uses=1]
%cmp = icmp slt i64 %inc, %tmp6 ; <i1> [#uses=1]
br i1 %cmp, label %for.body, label %for.end
for.end: ; preds = %for.body, %entry
ret void
}
; CHECK-LABEL: Function: test_no_dom: 3 pointers, 0 call sites
; CHECK: MayAlias: double* %addr1, double* %data
; CHECK: NoAlias: double* %addr2, double* %data
; CHECK: MayAlias: double* %addr1, double* %addr2
; In this case, checking %addr1 and %add2 involves two addrecs in two
; different loops where neither dominates the other. This used to crash
; because we expected the arguments to an AddExpr to have a strict
; dominance order.
define void @test_no_dom(double* %data) {
entry:
load double, double* %data
br label %for.body
for.body:
%indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.latch ]
%indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
br i1 undef, label %subloop1, label %subloop2
subloop1:
%iv1 = phi i32 [0, %for.body], [%iv1.next, %subloop1]
%iv1.next = add i32 %iv1, 1
%addr1 = getelementptr double, double* %data, i32 %iv1
store double 0.0, double* %addr1
%cmp1 = icmp slt i32 %iv1, 200
br i1 %cmp1, label %subloop1, label %for.latch
subloop2:
%iv2 = phi i32 [400, %for.body], [%iv2.next, %subloop2]
%iv2.next = add i32 %iv2, 1
%addr2 = getelementptr double, double* %data, i32 %iv2
store double 0.0, double* %addr2
%cmp2 = icmp slt i32 %iv2, 600
br i1 %cmp2, label %subloop2, label %for.latch
for.latch:
br label %for.body
for.end:
ret void
}
declare double* @get_addr(i32 %i)
; CHECK-LABEL: Function: test_no_dom2: 3 pointers, 2 call sites
; CHECK: MayAlias: double* %addr1, double* %data
; CHECK: MayAlias: double* %addr2, double* %data
; CHECK: MayAlias: double* %addr1, double* %addr2
; In this case, checking %addr1 and %add2 involves two addrecs in two
; different loops where neither dominates the other. This is analogous
; to test_no_dom, but involves SCEVUnknown as opposed to SCEVAddRecExpr.
define void @test_no_dom2(double* %data) {
entry:
load double, double* %data
br label %for.body
for.body:
%indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.latch ]
%indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
br i1 undef, label %subloop1, label %subloop2
subloop1:
%iv1 = phi i32 [0, %for.body], [%iv1.next, %subloop1]
%iv1.next = add i32 %iv1, 1
%addr1 = call double* @get_addr(i32 %iv1)
store double 0.0, double* %addr1
%cmp1 = icmp slt i32 %iv1, 200
br i1 %cmp1, label %subloop1, label %for.latch
subloop2:
%iv2 = phi i32 [400, %for.body], [%iv2.next, %subloop2]
%iv2.next = add i32 %iv2, 1
%addr2 = call double* @get_addr(i32 %iv2)
store double 0.0, double* %addr2
%cmp2 = icmp slt i32 %iv2, 600
br i1 %cmp2, label %subloop2, label %for.latch
for.latch:
br label %for.body
for.end:
ret void
}
; CHECK-LABEL: Function: test_dom: 3 pointers, 0 call sites
; CHECK: MayAlias: double* %addr1, double* %data
; CHECK: NoAlias: double* %addr2, double* %data
; CHECK: NoAlias: double* %addr1, double* %addr2
; This is a variant of test_non_dom where the second subloop is
; dominated by the first. As a result of that, we can nest the
; addrecs and cancel out the %data base pointer.
define void @test_dom(double* %data) {
entry:
load double, double* %data
br label %for.body
for.body:
%indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.latch ]
%indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
br label %subloop1
subloop1:
%iv1 = phi i32 [0, %for.body], [%iv1.next, %subloop1]
%iv1.next = add i32 %iv1, 1
%addr1 = getelementptr double, double* %data, i32 %iv1
store double 0.0, double* %addr1
%cmp1 = icmp slt i32 %iv1, 200
br i1 %cmp1, label %subloop1, label %subloop2
subloop2:
%iv2 = phi i32 [400, %subloop1], [%iv2.next, %subloop2]
%iv2.next = add i32 %iv2, 1
%addr2 = getelementptr double, double* %data, i32 %iv2
store double 0.0, double* %addr2
%cmp2 = icmp slt i32 %iv2, 600
br i1 %cmp2, label %subloop2, label %for.latch
for.latch:
br label %for.body
for.end:
ret void
}