Skip to content

Commit

Permalink
[BasicAA] Fix aliasGEP/DecomposeGEPExpression for scalable type.
Browse files Browse the repository at this point in the history
Summary:
Don't attempt to analyze the decomposed GEP for scalable type.
GEP index scale is not compile-time constant for scalable type.
Be conservative, return MayAlias.

Explicitly call TypeSize::getFixedSize() to assert on places where
scalable type doesn't make sense.

Add unit tests to check functionality of -basicaa for scalable type.

This patch is needed for D76944.

Reviewers: sdesmalen, efriedma, spatel, bjope, ctetreau

Reviewed By: efriedma

Subscribers: tschuett, hiraditya, rkruppe, psnobl, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D77828
  • Loading branch information
huihzhang committed Apr 10, 2020
1 parent f78fcd6 commit 6c989d0
Show file tree
Hide file tree
Showing 3 changed files with 245 additions and 5 deletions.
2 changes: 2 additions & 0 deletions llvm/include/llvm/Analysis/BasicAliasAnalysis.h
Expand Up @@ -142,6 +142,8 @@ class BasicAAResult : public AAResultBase<BasicAAResult> {
APInt OtherOffset;
// Scaled variable (non-constant) indices.
SmallVector<VariableGEPIndex, 4> VarIndices;
// Is GEP index scale compile-time constant.
bool HasCompileTimeConstantScale;
};

/// Tracks phi nodes we have visited.
Expand Down
29 changes: 24 additions & 5 deletions llvm/lib/Analysis/BasicAliasAnalysis.cpp
Expand Up @@ -531,6 +531,15 @@ bool BasicAAResult::DecomposeGEPExpression(const Value *V,
return false;
}

// Don't attempt to analyze GEPs if index scale is not a compile-time
// constant.
Type *SrcEleTy = GEPOp->getSourceElementType();
if (SrcEleTy->isVectorTy() && SrcEleTy->getVectorIsScalable()) {
Decomposed.Base = V;
Decomposed.HasCompileTimeConstantScale = false;
return false;
}

unsigned AS = GEPOp->getPointerAddressSpace();
// Walk the indices of the GEP, accumulating them into BaseOff/VarIndices.
gep_type_iterator GTI = gep_type_begin(GEPOp);
Expand All @@ -557,15 +566,16 @@ bool BasicAAResult::DecomposeGEPExpression(const Value *V,
if (CIdx->isZero())
continue;
Decomposed.OtherOffset +=
(DL.getTypeAllocSize(GTI.getIndexedType()) *
CIdx->getValue().sextOrSelf(MaxPointerSize))
.sextOrTrunc(MaxPointerSize);
(DL.getTypeAllocSize(GTI.getIndexedType()).getFixedSize() *
CIdx->getValue().sextOrSelf(MaxPointerSize))
.sextOrTrunc(MaxPointerSize);
continue;
}

GepHasConstantOffset = false;

APInt Scale(MaxPointerSize, DL.getTypeAllocSize(GTI.getIndexedType()));
APInt Scale(MaxPointerSize,
DL.getTypeAllocSize(GTI.getIndexedType()).getFixedSize());
unsigned ZExtBits = 0, SExtBits = 0;

// If the integer type is smaller than the pointer size, it is implicitly
Expand Down Expand Up @@ -1158,7 +1168,8 @@ static AliasResult aliasSameBasePointerGEPs(const GEPOperator *GEP1,
// partially overlap. We also need to check that the loaded size matches
// the element size, otherwise we could still have overlap.
Type *LastElementTy = GetElementPtrInst::getTypeAtIndex(Ty, (uint64_t)0);
const uint64_t ElementSize = DL.getTypeStoreSize(LastElementTy);
const uint64_t ElementSize =
DL.getTypeStoreSize(LastElementTy).getFixedSize();
if (V1Size != ElementSize || V2Size != ElementSize)
return MayAlias;

Expand Down Expand Up @@ -1316,12 +1327,20 @@ AliasResult BasicAAResult::aliasGEP(
unsigned MaxPointerSize = getMaxPointerSize(DL);
DecompGEP1.StructOffset = DecompGEP1.OtherOffset = APInt(MaxPointerSize, 0);
DecompGEP2.StructOffset = DecompGEP2.OtherOffset = APInt(MaxPointerSize, 0);
DecompGEP1.HasCompileTimeConstantScale =
DecompGEP2.HasCompileTimeConstantScale = true;

bool GEP1MaxLookupReached =
DecomposeGEPExpression(GEP1, DecompGEP1, DL, &AC, DT);
bool GEP2MaxLookupReached =
DecomposeGEPExpression(V2, DecompGEP2, DL, &AC, DT);

// Don't attempt to analyze the decomposed GEP if index scale is not a
// compile-time constant.
if (!DecompGEP1.HasCompileTimeConstantScale ||
!DecompGEP2.HasCompileTimeConstantScale)
return MayAlias;

APInt GEP1BaseOffset = DecompGEP1.StructOffset + DecompGEP1.OtherOffset;
APInt GEP2BaseOffset = DecompGEP2.StructOffset + DecompGEP2.OtherOffset;

Expand Down
219 changes: 219 additions & 0 deletions llvm/test/Analysis/BasicAA/vscale.ll
@@ -0,0 +1,219 @@
; RUN: opt < %s -basicaa -aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s

; getelementptr

; CHECK-LABEL: gep_alloca_const_offset_1
; CHECK-DAG: MustAlias: <vscale x 4 x i32>* %alloc, <vscale x 4 x i32>* %gep1
; CHECK-DAG: MayAlias: <vscale x 4 x i32>* %alloc, <vscale x 4 x i32>* %gep2
; CHECK-DAG: MayAlias: <vscale x 4 x i32>* %gep1, <vscale x 4 x i32>* %gep2
define void @gep_alloca_const_offset_1() {
%alloc = alloca <vscale x 4 x i32>
%gep1 = getelementptr <vscale x 4 x i32>, <vscale x 4 x i32>* %alloc, i64 0
%gep2 = getelementptr <vscale x 4 x i32>, <vscale x 4 x i32>* %alloc, i64 1
ret void
}

; CHECK-LABEL: gep_alloca_const_offset_2
; CHECK-DAG: MayAlias: <vscale x 4 x i32>* %alloc, <vscale x 4 x i32>* %gep1
; CHECK-DAG: MayAlias: <vscale x 4 x i32>* %alloc, <vscale x 4 x i32>* %gep2
; TODO: AliasResult for gep1,gep2 can be improved as MustAlias
; CHECK-DAG: MayAlias: <vscale x 4 x i32>* %gep1, <vscale x 4 x i32>* %gep2
define void @gep_alloca_const_offset_2() {
%alloc = alloca <vscale x 4 x i32>
%gep1 = getelementptr <vscale x 4 x i32>, <vscale x 4 x i32>* %alloc, i64 1
%gep2 = getelementptr <vscale x 4 x i32>, <vscale x 4 x i32>* %alloc, i64 1
ret void
}

; CHECK-LABEL: gep_alloca_const_offset_3
; CHECK-DAG: MustAlias: <vscale x 4 x i32>* %alloc, <vscale x 4 x i32>* %gep1
; CHECK-DAG: MayAlias: <vscale x 4 x i32>* %alloc, i32* %gep2
; CHECK-DAG: MayAlias: <vscale x 4 x i32>* %gep1, i32* %gep2
define void @gep_alloca_const_offset_3() {
%alloc = alloca <vscale x 4 x i32>
%gep1 = getelementptr <vscale x 4 x i32>, <vscale x 4 x i32>* %alloc, i64 0
%gep2 = getelementptr <vscale x 4 x i32>, <vscale x 4 x i32>* %alloc, i64 0, i64 1
ret void
}

; CHECK-LABEL: gep_alloca_const_offset_4
; CHECK-DAG: MustAlias: <vscale x 4 x i32>* %alloc, <vscale x 4 x i32>* %gep1
; CHECK-DAG: MustAlias: <vscale x 4 x i32>* %alloc, i32* %gep2
; CHECK-DAG: MustAlias: <vscale x 4 x i32>* %gep1, i32* %gep2
define void @gep_alloca_const_offset_4() {
%alloc = alloca <vscale x 4 x i32>
%gep1 = getelementptr <vscale x 4 x i32>, <vscale x 4 x i32>* %alloc, i64 0
%gep2 = getelementptr <vscale x 4 x i32>, <vscale x 4 x i32>* %alloc, i64 0, i64 0
ret void
}

; CHECK-LABEL: gep_alloca_symbolic_offset
; CHECK-DAG: MayAlias: <vscale x 4 x i32>* %alloc, <vscale x 4 x i32>* %gep1
; CHECK-DAG: MayAlias: <vscale x 4 x i32>* %alloc, <vscale x 4 x i32>* %gep2
; CHECK-DAG: MayAlias: <vscale x 4 x i32>* %gep1, <vscale x 4 x i32>* %gep2
define void @gep_alloca_symbolic_offset(i64 %idx1, i64 %idx2) {
%alloc = alloca <vscale x 4 x i32>
%gep1 = getelementptr <vscale x 4 x i32>, <vscale x 4 x i32>* %alloc, i64 %idx1
%gep2 = getelementptr <vscale x 4 x i32>, <vscale x 4 x i32>* %alloc, i64 %idx2
ret void
}

; CHECK-LABEL: gep_same_base_const_offset
; CHECK-DAG: MayAlias: <vscale x 4 x i32>* %p, i32* %gep1
; CHECK-DAG: MayAlias: <vscale x 4 x i32>* %p, i32* %gep2
; TODO: AliasResult for gep1,gep2 can be improved as NoAlias
; CHECK-DAG: MayAlias: i32* %gep1, i32* %gep2
define void @gep_same_base_const_offset(<vscale x 4 x i32>* %p) {
%gep1 = getelementptr <vscale x 4 x i32>, <vscale x 4 x i32>* %p, i64 1, i64 0
%gep2 = getelementptr <vscale x 4 x i32>, <vscale x 4 x i32>* %p, i64 1, i64 1
ret void
}

; CHECK-LABEL: gep_same_base_symbolic_offset
; CHECK-DAG: MayAlias: <vscale x 4 x i32>* %gep1, <vscale x 4 x i32>* %p
; CHECK-DAG: MayAlias: <vscale x 4 x i32>* %gep2, <vscale x 4 x i32>* %p
; CHECK-DAG: MayAlias: <vscale x 4 x i32>* %gep1, <vscale x 4 x i32>* %gep2
define void @gep_same_base_symbolic_offset(<vscale x 4 x i32>* %p, i64 %idx1, i64 %idx2) {
%gep1 = getelementptr <vscale x 4 x i32>, <vscale x 4 x i32>* %p, i64 %idx1
%gep2 = getelementptr <vscale x 4 x i32>, <vscale x 4 x i32>* %p, i64 %idx2
ret void
}

; CHECK-LABEL: gep_different_base_const_offset
; CHECK-DAG: MayAlias: <vscale x 4 x i32>* %gep1, <vscale x 4 x i32>* %p1
; CHECK-DAG: MayAlias: <vscale x 4 x i32>* %gep2, <vscale x 4 x i32>* %p2
; CHECK-DAG: NoAlias: <vscale x 4 x i32>* %p1, <vscale x 4 x i32>* %p2
; CHECK-DAG: NoAlias: <vscale x 4 x i32>* %gep1, <vscale x 4 x i32>* %p2
; CHECK-DAG: NoAlias: <vscale x 4 x i32>* %gep2, <vscale x 4 x i32>* %p1
; CHECK-DAG: NoAlias: <vscale x 4 x i32>* %gep1, <vscale x 4 x i32>* %gep2
define void @gep_different_base_const_offset(<vscale x 4 x i32>* noalias %p1, <vscale x 4 x i32>* noalias %p2) {
%gep1 = getelementptr <vscale x 4 x i32>, <vscale x 4 x i32>* %p1, i64 1
%gep2 = getelementptr <vscale x 4 x i32>, <vscale x 4 x i32>* %p2, i64 1
ret void
}

; getelementptr + bitcast

; CHECK-LABEL: gep_bitcast_1
; CHECK-DAG: MustAlias: <vscale x 4 x i32>* %p, i32* %p2
; CHECK-DAG: MayAlias: <vscale x 4 x i32>* %p, i32* %gep1
; CHECK-DAG: MayAlias: i32* %gep1, i32* %p2
; CHECK-DAG: MayAlias: <vscale x 4 x i32>* %p, i32* %gep2
; CHECK-DAG: MayAlias: i32* %gep1, i32* %gep2
; CHECK-DAG: NoAlias: i32* %gep2, i32* %p2
define void @gep_bitcast_1(<vscale x 4 x i32>* %p) {
%gep1 = getelementptr <vscale x 4 x i32>, <vscale x 4 x i32>* %p, i64 1, i64 0
%p2 = bitcast <vscale x 4 x i32>* %p to i32*
%gep2 = getelementptr i32, i32* %p2, i64 4
ret void
}

; CHECK-LABEL: gep_bitcast_2
; CHECK-DAG: MustAlias: <vscale x 4 x float>* %p2, <vscale x 4 x i32>* %p
; CHECK-DAG: MayAlias: <vscale x 4 x i32>* %p, i32* %gep1
; CHECK-DAG: MayAlias: <vscale x 4 x float>* %p2, i32* %gep1
; CHECK-DAG: MayAlias: <vscale x 4 x i32>* %p, float* %gep2
; CHECK-DAG: MayAlias: float* %gep2, i32* %gep1
; CHECK-DAG: MayAlias: <vscale x 4 x float>* %p2, float* %gep2
define void @gep_bitcast_2(<vscale x 4 x i32>* %p) {
%gep1 = getelementptr <vscale x 4 x i32>, <vscale x 4 x i32>* %p, i64 1, i64 0
%p2 = bitcast <vscale x 4 x i32>* %p to <vscale x 4 x float>*
%gep2 = getelementptr <vscale x 4 x float>, <vscale x 4 x float>* %p2, i64 1, i64 0
ret void
}

; getelementptr recursion

; CHECK-LABEL: gep_recursion_level_1
; CHECK-DAG: MayAlias: <vscale x 4 x i32>* %p, i32* %a
; CHECK-DAG: MayAlias: i32* %a, i32* %gep
; CHECK-DAG: MayAlias: i32* %a, i32* %gep_rec_1
; CHECK-DAG: MayAlias: <vscale x 4 x i32>* %p, i32* %gep
; CHECK-DAG: MayAlias: <vscale x 4 x i32>* %p, i32* %gep_rec_1
; CHECK-DAG: MayAlias: i32* %gep, i32* %gep_rec_1
define void @gep_recursion_level_1(i32* %a, <vscale x 4 x i32>* %p) {
%gep = getelementptr <vscale x 4 x i32>, <vscale x 4 x i32>* %p, i64 1, i64 2
%gep_rec_1 = getelementptr i32, i32* %gep, i64 1
ret void
}

; CHECK-LABEL: gep_recursion_level_1_bitcast
; CHECK-DAG: MustAlias: <vscale x 4 x i32>* %p, i32* %a
; CHECK-DAG: MayAlias: i32* %a, i32* %gep
; CHECK-DAG: MayAlias: i32* %a, i32* %gep_rec_1
; CHECK-DAG: MayAlias: <vscale x 4 x i32>* %p, i32* %gep
; CHECK-DAG: MayAlias: <vscale x 4 x i32>* %p, i32* %gep_rec_1
; CHECK-DAG: MayAlias: i32* %gep, i32* %gep_rec_1
define void @gep_recursion_level_1_bitcast(i32* %a) {
%p = bitcast i32* %a to <vscale x 4 x i32>*
%gep = getelementptr <vscale x 4 x i32>, <vscale x 4 x i32>* %p, i64 1, i64 2
%gep_rec_1 = getelementptr i32, i32* %gep, i64 1
ret void
}

; CHECK-LABEL: gep_recursion_level_2
; CHECK-DAG: MayAlias: <vscale x 4 x i32>* %p, i32* %a
; CHECK-DAG: MayAlias: i32* %a, i32* %gep
; CHECK-DAG: MayAlias: i32* %a, i32* %gep_rec_1
; CHECK-DAG: MayAlias: i32* %a, i32* %gep_rec_2
; CHECK-DAG: MayAlias: <vscale x 4 x i32>* %p, i32* %gep
; CHECK-DAG: MayAlias: <vscale x 4 x i32>* %p, i32* %gep_rec_1
; CHECK-DAG: MayAlias: <vscale x 4 x i32>* %p, i32* %gep_rec_2
; CHECK-DAG: MayAlias: i32* %gep, i32* %gep_rec_1
; CHECK-DAG: MayAlias: i32* %gep, i32* %gep_rec_2
; CHECK-DAG: MayAlias: i32* %gep_rec_1, i32* %gep_rec_2
define void @gep_recursion_level_2(i32* %a, <vscale x 4 x i32>* %p) {
%gep = getelementptr <vscale x 4 x i32>, <vscale x 4 x i32>* %p, i64 1, i64 2
%gep_rec_1 = getelementptr i32, i32* %gep, i64 1
%gep_rec_2 = getelementptr i32, i32* %gep_rec_1, i64 1
ret void
}

; CHECK-LABEL: gep_recursion_max_lookup_depth_reached
; CHECK-DAG: MayAlias: <vscale x 4 x i32>* %p, i32* %a
; CHECK-DAG: MayAlias: i32* %a, i32* %gep
; CHECK-DAG: MayAlias: i32* %a, i32* %gep_rec_1
; CHECK-DAG: MayAlias: i32* %a, i32* %gep_rec_2
; CHECK-DAG: MayAlias: i32* %a, i32* %gep_rec_3
; CHECK-DAG: MayAlias: i32* %a, i32* %gep_rec_4
; CHECK-DAG: MayAlias: i32* %a, i32* %gep_rec_5
; CHECK-DAG: MayAlias: i32* %a, i32* %gep_rec_6
; CHECK-DAG: MayAlias: <vscale x 4 x i32>* %p, i32* %gep
; CHECK-DAG: MayAlias: <vscale x 4 x i32>* %p, i32* %gep_rec_1
; CHECK-DAG: MayAlias: <vscale x 4 x i32>* %p, i32* %gep_rec_2
; CHECK-DAG: MayAlias: <vscale x 4 x i32>* %p, i32* %gep_rec_3
; CHECK-DAG: MayAlias: <vscale x 4 x i32>* %p, i32* %gep_rec_4
; CHECK-DAG: MayAlias: <vscale x 4 x i32>* %p, i32* %gep_rec_5
; CHECK-DAG: MayAlias: <vscale x 4 x i32>* %p, i32* %gep_rec_6
; CHECK-DAG: MayAlias: i32* %gep, i32* %gep_rec_1
; CHECK-DAG: MayAlias: i32* %gep, i32* %gep_rec_2
; CHECK-DAG: MayAlias: i32* %gep, i32* %gep_rec_3
; CHECK-DAG: MayAlias: i32* %gep, i32* %gep_rec_4
; CHECK-DAG: MayAlias: i32* %gep, i32* %gep_rec_5
; CHECK-DAG: MayAlias: i32* %gep, i32* %gep_rec_6
; CHECK-DAG: MayAlias: i32* %gep_rec_1, i32* %gep_rec_2
; CHECK-DAG: MayAlias: i32* %gep_rec_1, i32* %gep_rec_3
; CHECK-DAG: MayAlias: i32* %gep_rec_1, i32* %gep_rec_4
; CHECK-DAG: MayAlias: i32* %gep_rec_1, i32* %gep_rec_5
; CHECK-DAG: MayAlias: i32* %gep_rec_1, i32* %gep_rec_6
; CHECK-DAG: MayAlias: i32* %gep_rec_2, i32* %gep_rec_3
; CHECK-DAG: MayAlias: i32* %gep_rec_2, i32* %gep_rec_4
; CHECK-DAG: MayAlias: i32* %gep_rec_2, i32* %gep_rec_5
; CHECK-DAG: MayAlias: i32* %gep_rec_2, i32* %gep_rec_6
; CHECK-DAG: MayAlias: i32* %gep_rec_3, i32* %gep_rec_4
; CHECK-DAG: MayAlias: i32* %gep_rec_3, i32* %gep_rec_5
; CHECK-DAG: MayAlias: i32* %gep_rec_3, i32* %gep_rec_6
; CHECK-DAG: MayAlias: i32* %gep_rec_4, i32* %gep_rec_5
; CHECK-DAG: MayAlias: i32* %gep_rec_4, i32* %gep_rec_6
; CHECK-DAG: MayAlias: i32* %gep_rec_5, i32* %gep_rec_6
; GEP max lookup depth was set to 6.
define void @gep_recursion_max_lookup_depth_reached(i32* %a, <vscale x 4 x i32>* %p) {
%gep = getelementptr <vscale x 4 x i32>, <vscale x 4 x i32>* %p, i64 1, i64 2
%gep_rec_1 = getelementptr i32, i32* %gep, i64 1
%gep_rec_2 = getelementptr i32, i32* %gep_rec_1, i64 1
%gep_rec_3 = getelementptr i32, i32* %gep_rec_2, i64 1
%gep_rec_4 = getelementptr i32, i32* %gep_rec_3, i64 1
%gep_rec_5 = getelementptr i32, i32* %gep_rec_4, i64 1
%gep_rec_6 = getelementptr i32, i32* %gep_rec_5, i64 1
ret void
}

0 comments on commit 6c989d0

Please sign in to comment.