diff --git a/llvm/include/llvm/Analysis/BasicAliasAnalysis.h b/llvm/include/llvm/Analysis/BasicAliasAnalysis.h --- a/llvm/include/llvm/Analysis/BasicAliasAnalysis.h +++ b/llvm/include/llvm/Analysis/BasicAliasAnalysis.h @@ -142,6 +142,8 @@ APInt OtherOffset; // Scaled variable (non-constant) indices. SmallVector VarIndices; + // Is GEP index scale compile-time constant. + bool HasCompileTimeConstantScale; }; /// Tracks phi nodes we have visited. diff --git a/llvm/lib/Analysis/BasicAliasAnalysis.cpp b/llvm/lib/Analysis/BasicAliasAnalysis.cpp --- a/llvm/lib/Analysis/BasicAliasAnalysis.cpp +++ b/llvm/lib/Analysis/BasicAliasAnalysis.cpp @@ -531,6 +531,15 @@ 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); @@ -557,15 +566,16 @@ 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 @@ -1158,7 +1168,8 @@ // 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; @@ -1316,12 +1327,20 @@ 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; diff --git a/llvm/test/Analysis/BasicAA/vscale.ll b/llvm/test/Analysis/BasicAA/vscale.ll new file mode 100644 --- /dev/null +++ b/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: * %alloc, * %gep1 +; CHECK-DAG: MayAlias: * %alloc, * %gep2 +; CHECK-DAG: MayAlias: * %gep1, * %gep2 +define void @gep_alloca_const_offset_1() { + %alloc = alloca + %gep1 = getelementptr , * %alloc, i64 0 + %gep2 = getelementptr , * %alloc, i64 1 + ret void +} + +; CHECK-LABEL: gep_alloca_const_offset_2 +; CHECK-DAG: MayAlias: * %alloc, * %gep1 +; CHECK-DAG: MayAlias: * %alloc, * %gep2 +; TODO: AliasResult for gep1,gep2 can be improved as MustAlias +; CHECK-DAG: MayAlias: * %gep1, * %gep2 +define void @gep_alloca_const_offset_2() { + %alloc = alloca + %gep1 = getelementptr , * %alloc, i64 1 + %gep2 = getelementptr , * %alloc, i64 1 + ret void +} + +; CHECK-LABEL: gep_alloca_const_offset_3 +; CHECK-DAG: MustAlias: * %alloc, * %gep1 +; CHECK-DAG: MayAlias: * %alloc, i32* %gep2 +; CHECK-DAG: MayAlias: * %gep1, i32* %gep2 +define void @gep_alloca_const_offset_3() { + %alloc = alloca + %gep1 = getelementptr , * %alloc, i64 0 + %gep2 = getelementptr , * %alloc, i64 0, i64 1 + ret void +} + +; CHECK-LABEL: gep_alloca_const_offset_4 +; CHECK-DAG: MustAlias: * %alloc, * %gep1 +; CHECK-DAG: MustAlias: * %alloc, i32* %gep2 +; CHECK-DAG: MustAlias: * %gep1, i32* %gep2 +define void @gep_alloca_const_offset_4() { + %alloc = alloca + %gep1 = getelementptr , * %alloc, i64 0 + %gep2 = getelementptr , * %alloc, i64 0, i64 0 + ret void +} + +; CHECK-LABEL: gep_alloca_symbolic_offset +; CHECK-DAG: MayAlias: * %alloc, * %gep1 +; CHECK-DAG: MayAlias: * %alloc, * %gep2 +; CHECK-DAG: MayAlias: * %gep1, * %gep2 +define void @gep_alloca_symbolic_offset(i64 %idx1, i64 %idx2) { + %alloc = alloca + %gep1 = getelementptr , * %alloc, i64 %idx1 + %gep2 = getelementptr , * %alloc, i64 %idx2 + ret void +} + +; CHECK-LABEL: gep_same_base_const_offset +; CHECK-DAG: MayAlias: * %p, i32* %gep1 +; CHECK-DAG: MayAlias: * %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(* %p) { + %gep1 = getelementptr , * %p, i64 1, i64 0 + %gep2 = getelementptr , * %p, i64 1, i64 1 + ret void +} + +; CHECK-LABEL: gep_same_base_symbolic_offset +; CHECK-DAG: MayAlias: * %gep1, * %p +; CHECK-DAG: MayAlias: * %gep2, * %p +; CHECK-DAG: MayAlias: * %gep1, * %gep2 +define void @gep_same_base_symbolic_offset(* %p, i64 %idx1, i64 %idx2) { + %gep1 = getelementptr , * %p, i64 %idx1 + %gep2 = getelementptr , * %p, i64 %idx2 + ret void +} + +; CHECK-LABEL: gep_different_base_const_offset +; CHECK-DAG: MayAlias: * %gep1, * %p1 +; CHECK-DAG: MayAlias: * %gep2, * %p2 +; CHECK-DAG: NoAlias: * %p1, * %p2 +; CHECK-DAG: NoAlias: * %gep1, * %p2 +; CHECK-DAG: NoAlias: * %gep2, * %p1 +; CHECK-DAG: NoAlias: * %gep1, * %gep2 +define void @gep_different_base_const_offset(* noalias %p1, * noalias %p2) { + %gep1 = getelementptr , * %p1, i64 1 + %gep2 = getelementptr , * %p2, i64 1 + ret void +} + +; getelementptr + bitcast + +; CHECK-LABEL: gep_bitcast_1 +; CHECK-DAG: MustAlias: * %p, i32* %p2 +; CHECK-DAG: MayAlias: * %p, i32* %gep1 +; CHECK-DAG: MayAlias: i32* %gep1, i32* %p2 +; CHECK-DAG: MayAlias: * %p, i32* %gep2 +; CHECK-DAG: MayAlias: i32* %gep1, i32* %gep2 +; CHECK-DAG: NoAlias: i32* %gep2, i32* %p2 +define void @gep_bitcast_1(* %p) { + %gep1 = getelementptr , * %p, i64 1, i64 0 + %p2 = bitcast * %p to i32* + %gep2 = getelementptr i32, i32* %p2, i64 4 + ret void +} + +; CHECK-LABEL: gep_bitcast_2 +; CHECK-DAG: MustAlias: * %p2, * %p +; CHECK-DAG: MayAlias: * %p, i32* %gep1 +; CHECK-DAG: MayAlias: * %p2, i32* %gep1 +; CHECK-DAG: MayAlias: * %p, float* %gep2 +; CHECK-DAG: MayAlias: float* %gep2, i32* %gep1 +; CHECK-DAG: MayAlias: * %p2, float* %gep2 +define void @gep_bitcast_2(* %p) { + %gep1 = getelementptr , * %p, i64 1, i64 0 + %p2 = bitcast * %p to * + %gep2 = getelementptr , * %p2, i64 1, i64 0 + ret void +} + +; getelementptr recursion + +; CHECK-LABEL: gep_recursion_level_1 +; CHECK-DAG: MayAlias: * %p, i32* %a +; CHECK-DAG: MayAlias: i32* %a, i32* %gep +; CHECK-DAG: MayAlias: i32* %a, i32* %gep_rec_1 +; CHECK-DAG: MayAlias: * %p, i32* %gep +; CHECK-DAG: MayAlias: * %p, i32* %gep_rec_1 +; CHECK-DAG: MayAlias: i32* %gep, i32* %gep_rec_1 +define void @gep_recursion_level_1(i32* %a, * %p) { + %gep = getelementptr , * %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: * %p, i32* %a +; CHECK-DAG: MayAlias: i32* %a, i32* %gep +; CHECK-DAG: MayAlias: i32* %a, i32* %gep_rec_1 +; CHECK-DAG: MayAlias: * %p, i32* %gep +; CHECK-DAG: MayAlias: * %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 * + %gep = getelementptr , * %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: * %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: * %p, i32* %gep +; CHECK-DAG: MayAlias: * %p, i32* %gep_rec_1 +; CHECK-DAG: MayAlias: * %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, * %p) { + %gep = getelementptr , * %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: * %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: * %p, i32* %gep +; CHECK-DAG: MayAlias: * %p, i32* %gep_rec_1 +; CHECK-DAG: MayAlias: * %p, i32* %gep_rec_2 +; CHECK-DAG: MayAlias: * %p, i32* %gep_rec_3 +; CHECK-DAG: MayAlias: * %p, i32* %gep_rec_4 +; CHECK-DAG: MayAlias: * %p, i32* %gep_rec_5 +; CHECK-DAG: MayAlias: * %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, * %p) { + %gep = getelementptr , * %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 +}