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.
421 lines
14 KiB
LLVM
421 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-prefixes=CHECK,NO-PHI-VALUES
|
|
; RUN: opt < %s -aa-pipeline=basic-aa -passes='require<phi-values>,aa-eval' -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s --check-prefixes=CHECK,PHI-VALUES
|
|
|
|
; 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(float *%src1, float * noalias %src2, i32 %n) nounwind {
|
|
entry:
|
|
load float, float* %src1
|
|
load float, float* %src2
|
|
br label %loop
|
|
|
|
loop:
|
|
%phi = phi float* [ %src2, %entry ], [ %next, %loop ]
|
|
%idx = phi i32 [ 0, %entry ], [ %idxn, %loop ]
|
|
%next = getelementptr inbounds float, float* %phi, i32 1
|
|
%g = getelementptr inbounds float, float* %src1, i32 3
|
|
%l = load float, float* %phi
|
|
load float, float* %next
|
|
%a = fadd float %l, 1.0
|
|
store float %a, float* %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* %0, [2 x i32]* %tab
|
|
; CHECK: PartialAlias (off -4): i32* %arrayidx, [2 x i32]* %tab
|
|
; CHECK: NoAlias: i8* %0, i32* %arrayidx
|
|
; CHECK: MustAlias: i32* %arrayidx1, [2 x i32]* %tab
|
|
; CHECK: MustAlias: i8* %0, i32* %arrayidx1
|
|
; CHECK: NoAlias: i32* %arrayidx, i32* %arrayidx1
|
|
; CHECK: MayAlias: i32* %incdec.ptr.i, [2 x i32]* %tab
|
|
; CHECK: NoAlias: i8* %0, i32* %incdec.ptr.i
|
|
; CHECK: MayAlias: i32* %arrayidx, i32* %incdec.ptr.i
|
|
; CHECK: NoAlias: i32* %arrayidx1, i32* %incdec.ptr.i
|
|
; CHECK: MayAlias: i32* %p.addr.05.i, [2 x i32]* %tab
|
|
; CHECK: MayAlias: i8* %0, i32* %p.addr.05.i
|
|
; CHECK: MayAlias: i32* %arrayidx, i32* %p.addr.05.i
|
|
; CHECK: MayAlias: i32* %arrayidx1, i32* %p.addr.05.i
|
|
; 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], [2 x i32]* %tab
|
|
%0 = bitcast [2 x i32]* %tab to i8*
|
|
%ignore2 = load i8, i8* %0
|
|
%arrayidx = getelementptr inbounds [2 x i32], [2 x i32]* %tab, i32 0, i32 1
|
|
store i32 0, i32* %arrayidx, align 4
|
|
%arrayidx1 = getelementptr inbounds [2 x i32], [2 x i32]* %tab, i32 0, i32 0
|
|
store i32 0, i32* %arrayidx1, align 4
|
|
%1 = add i32 1, 1
|
|
%cmp4.i = icmp slt i32 %1, 2
|
|
br i1 %cmp4.i, label %while.body.i, label %f.exit
|
|
|
|
while.body.i: ; preds = %while.body.i, %entry
|
|
%2 = phi i32 [ 1, %while.body.i ], [ %1, %entry ]
|
|
%foo.06.i = phi i32 [ %sub.i, %while.body.i ], [ 2, %entry ]
|
|
%p.addr.05.i = phi i32* [ %incdec.ptr.i, %while.body.i ], [ %arrayidx1, %entry ]
|
|
%sub.i = sub nsw i32 %foo.06.i, %2
|
|
%incdec.ptr.i = getelementptr inbounds i32, i32* %p.addr.05.i, i32 1
|
|
%ignore3 = load i32, i32* %incdec.ptr.i
|
|
store i32 %sub.i, i32* %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
|
|
%3 = load i32, i32* %arrayidx1, align 4
|
|
%cmp = icmp eq i32 %3, 2
|
|
%4 = load i32, i32* %arrayidx, align 4
|
|
%cmp4 = icmp eq i32 %4, 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* %0, [10 x i32]* %tab
|
|
; CHECK: MustAlias: i32* %arrayidx, [10 x i32]* %tab
|
|
; CHECK: MustAlias: i8* %0, i32* %arrayidx
|
|
; CHECK: PartialAlias (off -36): i32* %arrayidx1, [10 x i32]* %tab
|
|
; CHECK: NoAlias: i8* %0, i32* %arrayidx1
|
|
; CHECK: NoAlias: i32* %arrayidx, i32* %arrayidx1
|
|
; CHECK: MayAlias: i32* %incdec.ptr.i, [10 x i32]* %tab
|
|
; CHECK: MayAlias: i8* %0, i32* %incdec.ptr.i
|
|
; CHECK: MayAlias: i32* %arrayidx, i32* %incdec.ptr.i
|
|
; CHECK: MayAlias: i32* %arrayidx1, i32* %incdec.ptr.i
|
|
; CHECK: MayAlias: i32* %p.addr.05.i, [10 x i32]* %tab
|
|
; CHECK: MayAlias: i8* %0, i32* %p.addr.05.i
|
|
; CHECK: MayAlias: i32* %arrayidx, i32* %p.addr.05.i
|
|
; 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], [10 x i32]* %tab
|
|
%0 = bitcast [10 x i32]* %tab to i8*
|
|
%ignore2 = load i8, i8* %0
|
|
%arrayidx = getelementptr inbounds [10 x i32], [10 x i32]* %tab, i32 0, i32 0
|
|
store i32 0, i32* %arrayidx, align 4
|
|
%arrayidx1 = getelementptr inbounds [10 x i32], [10 x i32]* %tab, i32 0, i32 9
|
|
store i32 0, i32* %arrayidx1, align 4
|
|
%1 = add i32 1, 1
|
|
%cmp4.i = icmp slt i32 %1, 2
|
|
br i1 %cmp4.i, label %while.body.i, label %f.exit
|
|
|
|
while.body.i: ; preds = %while.body.i, %entry
|
|
%2 = phi i32 [ 1, %while.body.i ], [ %1, %entry ]
|
|
%foo.06.i = phi i32 [ %sub.i, %while.body.i ], [ 2, %entry ]
|
|
%p.addr.05.i = phi i32* [ %incdec.ptr.i, %while.body.i ], [ %arrayidx1, %entry ]
|
|
%sub.i = sub nsw i32 %foo.06.i, %2
|
|
%incdec.ptr.i = getelementptr inbounds i32, i32* %p.addr.05.i, i32 -1
|
|
%ignore3 = load i32, i32* %incdec.ptr.i
|
|
store i32 %sub.i, i32* %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
|
|
%3 = load i32, i32* %arrayidx1, align 4
|
|
%cmp = icmp eq i32 %3, 2
|
|
%4 = load i32, i32* %arrayidx, align 4
|
|
%cmp4 = icmp eq i32 %4, 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], [3 x i16]* %int_arr.10
|
|
%_tmp1 = getelementptr inbounds [3 x i16], [3 x i16]* %int_arr.10, i16 0, i16 2
|
|
load i16, i16* %_tmp1
|
|
br label %bb1
|
|
|
|
bb1: ; preds = %bb1, %0
|
|
%i.7.0 = phi i16 [ 2, %0 ], [ %_tmp5, %bb1 ]
|
|
%ls1.9.0 = phi i16* [ %_tmp1, %0 ], [ %_tmp7, %bb1 ]
|
|
store i16 %i.7.0, i16* %ls1.9.0, align 1
|
|
%_tmp5 = add nsw i16 %i.7.0, -1
|
|
%_tmp7 = getelementptr i16, i16* %ls1.9.0, i16 -1
|
|
load i16, i16* %_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], [3 x i16]* %int_arr.10, i16 0, i16 1
|
|
%_tmp12 = load i16, i16* %_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, i8* noalias %p.base) {
|
|
entry:
|
|
%a = alloca i8
|
|
load i8, i8* %p.base
|
|
load i8, i8* %a
|
|
br label %loop
|
|
|
|
loop:
|
|
%p = phi i8* [ %p.base, %entry ], [ %p.next, %loop ]
|
|
%offset = call i16 @call(i32 0)
|
|
%p.next = getelementptr inbounds i8, i8* %p, i16 %offset
|
|
load i8, i8* %p
|
|
load i8, i8* %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 i32* @symmetry(i32* %p.base, i1 %c) {
|
|
entry:
|
|
load i32, i32* %p.base
|
|
br label %loop
|
|
|
|
loop:
|
|
%p = phi i32* [ %p.base, %entry ], [ %p.next, %loop ]
|
|
%p.next = getelementptr inbounds i32, i32* %p, i32 1
|
|
load i32, i32* %p
|
|
load i32, i32* %p.next
|
|
br i1 %c, label %loop, label %exit
|
|
|
|
exit:
|
|
%result = phi i32* [ %p.next, %loop ]
|
|
load i32, i32* %result
|
|
ret i32* %result
|
|
}
|
|
|
|
; CHECK-LABEL: Function: nested_loop
|
|
; CHECK: NoAlias: i8* %a, i8* %p.base
|
|
; CHECK: NoAlias: i8* %a, i8* %p.outer
|
|
; NO-PHI-VALUES: MayAlias: i8* %a, i8* %p.inner
|
|
; PHI-VALUES: NoAlias: 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, i8* noalias %p.base) {
|
|
entry:
|
|
%a = alloca i8
|
|
load i8, i8* %p.base
|
|
load i8, i8* %a
|
|
br label %outer_loop
|
|
|
|
outer_loop:
|
|
%p.outer = phi i8* [ %p.base, %entry ], [ %p.outer.next, %outer_loop_latch ]
|
|
load i8, i8* %p.outer
|
|
br label %inner_loop
|
|
|
|
inner_loop:
|
|
%p.inner = phi i8* [ %p.outer, %outer_loop ], [ %p.inner.next, %inner_loop ]
|
|
%p.inner.next = getelementptr inbounds i8, i8* %p.inner, i64 1
|
|
load i8, i8* %p.inner
|
|
load i8, i8* %p.inner.next
|
|
br i1 %c, label %inner_loop, label %outer_loop_latch
|
|
|
|
outer_loop_latch:
|
|
%p.outer.next = getelementptr inbounds i8, i8* %p.inner, i64 10
|
|
load i8, i8* %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, i8* noalias %p.base) {
|
|
entry:
|
|
%a = alloca i8
|
|
load i8, i8* %p.base
|
|
load i8, i8* %a
|
|
br label %outer_loop
|
|
|
|
outer_loop:
|
|
%p.outer = phi i8* [ %p.base, %entry ], [ %p.outer.next, %outer_loop_latch ]
|
|
%p.outer.next = getelementptr inbounds i8, i8* %p.outer, i64 10
|
|
load i8, i8* %p.outer
|
|
load i8, i8* %p.outer.next
|
|
br label %inner_loop
|
|
|
|
inner_loop:
|
|
%p.inner = phi i8* [ %p.outer.next, %outer_loop ], [ %p.inner.next, %inner_loop ]
|
|
%p.inner.next = getelementptr inbounds i8, i8* %p.inner, i64 1
|
|
load i8, i8* %p.inner
|
|
load i8, i8* %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
|
|
; NO-PHI-VALUES: NoAlias: i8* %a, i8* %p.inner
|
|
; PHI-VALUES: MayAlias: i8* %a, i8* %p.inner
|
|
; CHECK: NoAlias: i8* %a, i8* %p.inner.next
|
|
define void @nested_loop3(i1 %c, i1 %c2, i8* noalias %p.base) {
|
|
entry:
|
|
%a = alloca i8
|
|
load i8, i8* %p.base
|
|
load i8, i8* %a
|
|
br label %outer_loop
|
|
|
|
outer_loop:
|
|
%p.outer = phi i8* [ %p.base, %entry ], [ %p.outer.next, %outer_loop_latch ]
|
|
%p.outer.next = getelementptr inbounds i8, i8* %p.outer, i64 10
|
|
load i8, i8* %p.outer
|
|
load i8, i8* %p.outer.next
|
|
br label %inner_loop
|
|
|
|
inner_loop:
|
|
%p.inner = phi i8* [ %p.outer, %outer_loop ], [ %p.inner.next, %inner_loop ]
|
|
%p.inner.next = getelementptr inbounds i8, i8* %p.inner, i64 1
|
|
load i8, i8* %p.inner
|
|
load i8, i8* %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, i8* noalias %p.base) {
|
|
entry:
|
|
%a = alloca i8
|
|
load i8, i8* %p.base
|
|
load i8, i8* %a
|
|
br label %loop1
|
|
|
|
loop1:
|
|
%p1 = phi i8* [ %p.base, %entry ], [ %p1.next, %loop1 ]
|
|
%p1.next = getelementptr inbounds i8, i8* %p1, i64 10
|
|
load i8, i8* %p1
|
|
load i8, i8* %p1.next
|
|
br i1 %c, label %loop1, label %loop2
|
|
|
|
loop2:
|
|
%p2 = phi i8* [ %p1.next, %loop1 ], [ %p2.next, %loop2 ]
|
|
%p2.next = getelementptr inbounds i8, i8* %p2, i64 1
|
|
load i8, i8* %p2
|
|
load i8, i8* %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
|
|
; NO-PHI-VALUES: NoAlias: i8* %a, i8* %p2
|
|
; PHI-VALUES: MayAlias: i8* %a, i8* %p2
|
|
; CHECK: NoAlias: i8* %a, i8* %p2.next
|
|
define void @sibling_loop2(i1 %c, i1 %c2, i8* noalias %p.base) {
|
|
entry:
|
|
%a = alloca i8
|
|
load i8, i8* %p.base
|
|
load i8, i8* %a
|
|
br label %loop1
|
|
|
|
loop1:
|
|
%p1 = phi i8* [ %p.base, %entry ], [ %p1.next, %loop1 ]
|
|
%p1.next = getelementptr inbounds i8, i8* %p1, i64 10
|
|
load i8, i8* %p1
|
|
load i8, i8* %p1.next
|
|
br i1 %c, label %loop1, label %loop2
|
|
|
|
loop2:
|
|
%p2 = phi i8* [ %p1, %loop1 ], [ %p2.next, %loop2 ]
|
|
%p2.next = getelementptr inbounds i8, i8* %p2, i64 1
|
|
load i8, i8* %p2
|
|
load i8, i8* %p2.next
|
|
br i1 %c2, label %loop2, label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
declare i16 @call(i32)
|