[llvm] [BasicAA] Cancel common scalable GEP offsets (PR #218195)

via llvm-commits llvm-commits at lists.llvm.org
Sat Aug 22 22:16:10 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-analysis

Author: SomeFlyingThing

<details>
<summary>Changes</summary>

The patch teaches BasicAA to retain and cancel common constant vscale GEP offsets. This improves several results from MayAlias to MustAlias or NoAlias, providing better dependency information to vectorizers while remaining conservative for unequal scalable offsets.

This pr is LLM assisted

---
Full diff: https://github.com/llvm/llvm-project/pull/218195.diff


2 Files Affected:

- (modified) llvm/lib/Analysis/BasicAliasAnalysis.cpp (+18-4) 
- (modified) llvm/test/Analysis/BasicAA/vscale.ll (+7-9) 


``````````diff
diff --git a/llvm/lib/Analysis/BasicAliasAnalysis.cpp b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
index 7df62577e04db..6b874a1efd224 100644
--- a/llvm/lib/Analysis/BasicAliasAnalysis.cpp
+++ b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
@@ -560,8 +560,10 @@ struct VariableGEPIndex {
 struct BasicAAResult::DecomposedGEP {
   // Base pointer of the GEP
   const Value *Base;
-  // Total constant offset from base.
+  // Total fixed constant offset from base.
   APInt Offset;
+  // Coefficient of vscale in the constant offset from base.
+  APInt ScalableOffset;
   // Scaled variable (non-constant) indices.
   SmallVector<VariableGEPIndex, 4> VarIndices;
   // Nowrap flags common to all GEP operations involved in expression.
@@ -575,6 +577,7 @@ struct BasicAAResult::DecomposedGEP {
     OS << ", inbounds=" << (NWFlags.isInBounds() ? "1" : "0")
        << ", nuw=" << (NWFlags.hasNoUnsignedWrap() ? "1" : "0")
        << "(DecomposedGEP Base=" << Base->getName() << ", Offset=" << Offset
+       << ", ScalableOffset=" << ScalableOffset
        << ", VarIndices=[";
     for (size_t i = 0; i < VarIndices.size(); i++) {
       if (i != 0)
@@ -604,6 +607,7 @@ BasicAAResult::DecomposeGEPExpression(const Value *V, const DataLayout &DL,
   unsigned IndexSize = DL.getIndexTypeSizeInBits(V->getType());
   DecomposedGEP Decomposed;
   Decomposed.Offset = APInt(IndexSize, 0);
+  Decomposed.ScalableOffset = APInt(IndexSize, 0);
   do {
     // See if this is a bitcast or GEP.
     const Operator *Op = dyn_cast<Operator>(V);
@@ -692,11 +696,14 @@ BasicAAResult::DecomposeGEPExpression(const Value *V, const DataLayout &DL,
         if (CIdx->isZero())
           continue;
 
-        // Don't attempt to analyze GEPs if the scalable index is not zero.
         TypeSize AllocTypeSize = GTI.getSequentialElementStride(DL);
         if (AllocTypeSize.isScalable()) {
-          Decomposed.Base = V;
-          return Decomposed;
+          // Keep constant scalable offsets separate from fixed offsets. This
+          // lets equal scalable terms cancel when two GEPs are compared.
+          Decomposed.ScalableOffset +=
+              APInt(IndexSize, AllocTypeSize.getKnownMinValue()) *
+              CIdx->getValue().sextOrTrunc(IndexSize);
+          continue;
         }
 
         Decomposed.Offset += AllocTypeSize.getFixedValue() *
@@ -1163,6 +1170,12 @@ AliasResult BasicAAResult::aliasGEP(
   // symbolic difference.
   subtractDecomposedGEPs(DecompGEP1, DecompGEP2, AAQI);
 
+  // Scalable offsets can be compared only after common terms cancel. Keep
+  // the existing fixed-offset reasoning for that useful case, and otherwise
+  // fall back to comparing the base objects.
+  if (!DecompGEP1.ScalableOffset.isZero())
+    return BaseObjectsAlias();
+
   // If an inbounds GEP would have to start from an out of bounds address
   // for the two to alias, then we can assume noalias.
   // TODO: Remove !isScalable() once BasicAA fully support scalable location
@@ -1952,6 +1965,7 @@ void BasicAAResult::subtractDecomposedGEPs(DecomposedGEP &DestGEP,
     DestGEP.NWFlags = DestGEP.NWFlags.withoutNoUnsignedWrap();
 
   DestGEP.Offset -= SrcGEP.Offset;
+  DestGEP.ScalableOffset -= SrcGEP.ScalableOffset;
   for (const VariableGEPIndex &Src : SrcGEP.VarIndices) {
     // Find V in Dest.  This is N^2, but pointer indices almost never have more
     // than a few variable indexes.
diff --git a/llvm/test/Analysis/BasicAA/vscale.ll b/llvm/test/Analysis/BasicAA/vscale.ll
index 05b9b6b3c3a97..c08068df1a3a6 100644
--- a/llvm/test/Analysis/BasicAA/vscale.ll
+++ b/llvm/test/Analysis/BasicAA/vscale.ll
@@ -19,8 +19,7 @@ define void @gep_alloca_const_offset_1() {
 ; 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
+; CHECK-DAG:  MustAlias:    <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>, ptr %alloc, i64 1
@@ -76,8 +75,7 @@ define void @gep_alloca_symbolic_offset(i64 %idx1, i64 %idx2) {
 ; CHECK-LABEL: gep_same_base_const_offset
 ; CHECK-DAG:  MayAlias:     i32* %gep1, <vscale x 4 x i32>* %p
 ; CHECK-DAG:  MayAlias:     i32* %gep2, <vscale x 4 x i32>* %p
-; TODO: AliasResult for gep1,gep2 can be improved as NoAlias
-; CHECK-DAG:  MayAlias:     i32* %gep1, i32* %gep2
+; CHECK-DAG:  NoAlias:      i32* %gep1, i32* %gep2
 define void @gep_same_base_const_offset(ptr %p) {
   %gep1 = getelementptr <vscale x 4 x i32>, ptr %p, i64 1, i64 0
   %gep2 = getelementptr <vscale x 4 x i32>, ptr %p, i64 1, i64 1
@@ -171,7 +169,7 @@ define void @gep_bitcast_1(ptr %p) {
 ; CHECK-DAG:  MayAlias:     i32* %gep1, <vscale x 4 x i32>* %p
 ; CHECK-DAG:  MayAlias:     i32* %gep1, <vscale x 4 x float>* %p
 ; CHECK-DAG:  MayAlias:     float* %gep2, <vscale x 4 x i32>* %p
-; CHECK-DAG:  MayAlias:     i32* %gep1, float* %gep2
+; CHECK-DAG:  MustAlias:    i32* %gep1, float* %gep2
 ; CHECK-DAG:  MayAlias:     float* %gep2, <vscale x 4 x float>* %p
 define void @gep_bitcast_2(ptr %p) {
   %gep1 = getelementptr <vscale x 4 x i32>, ptr %p, i64 1, i64 0
@@ -216,7 +214,7 @@ define void @gep_neg_notscalable(ptr %p) vscale_range(1,16) {
 ; CHECK-DAG:   MayAlias:     <vscale x 4 x i32>* %p, <vscale x 4 x i32>* %vm16m16
 ; CHECK-DAG:   MayAlias:     <vscale x 4 x i32>* %vm16, <vscale x 4 x i32>* %vm16m16
 ; CHECK-DAG:   MayAlias:     <vscale x 4 x i32>* %m16, <vscale x 4 x i32>* %vm16m16
-; CHECK-DAG:   MayAlias:     <vscale x 4 x i32>* %m16pv16, <vscale x 4 x i32>* %p
+; CHECK-DAG:   MustAlias:    <vscale x 4 x i32>* %m16pv16, <vscale x 4 x i32>* %p
 ; CHECK-DAG:   MayAlias:     <vscale x 4 x i32>* %m16pv16, <vscale x 4 x i32>* %vm16
 ; CHECK-DAG:   MayAlias:     <vscale x 4 x i32>* %m16, <vscale x 4 x i32>* %m16pv16
 ; CHECK-DAG:   MayAlias:     <vscale x 4 x i32>* %m16pv16, <vscale x 4 x i32>* %vm16m16
@@ -240,9 +238,9 @@ define void @gep_neg_scalable(ptr %p) vscale_range(1,16) {
 ; CHECK-DAG:   MayAlias:     <4 x i32>* %p, <4 x i32>* %vm16m16
 ; CHECK-DAG:   NoAlias:      <4 x i32>* %vm16, <4 x i32>* %vm16m16
 ; CHECK-DAG:   MayAlias:     <4 x i32>* %m16, <4 x i32>* %vm16m16
-; CHECK-DAG:   MayAlias:     <4 x i32>* %m16pv16, <4 x i32>* %p
+; CHECK-DAG:   MustAlias:    <4 x i32>* %m16pv16, <4 x i32>* %p
 ; CHECK-DAG:   MayAlias:     <4 x i32>* %m16pv16, <4 x i32>* %vm16
-; CHECK-DAG:   MayAlias:     <4 x i32>* %m16, <4 x i32>* %m16pv16
+; CHECK-DAG:   NoAlias:      <4 x i32>* %m16, <4 x i32>* %m16pv16
 ; CHECK-DAG:   MayAlias:     <4 x i32>* %m16pv16, <4 x i32>* %vm16m16
 define void @gep_pos_notscalable(ptr %p) vscale_range(1,16) {
   %vm16 = getelementptr <vscale x 4 x i32>, ptr %p, i64 1
@@ -264,7 +262,7 @@ define void @gep_pos_notscalable(ptr %p) vscale_range(1,16) {
 ; CHECK-DAG:   MayAlias:     <vscale x 4 x i32>* %p, <vscale x 4 x i32>* %vm16m16
 ; CHECK-DAG:   MayAlias:     <vscale x 4 x i32>* %vm16, <vscale x 4 x i32>* %vm16m16
 ; CHECK-DAG:   MayAlias:     <vscale x 4 x i32>* %m16, <vscale x 4 x i32>* %vm16m16
-; CHECK-DAG:   MayAlias:     <vscale x 4 x i32>* %m16pv16, <vscale x 4 x i32>* %p
+; CHECK-DAG:   MustAlias:    <vscale x 4 x i32>* %m16pv16, <vscale x 4 x i32>* %p
 ; CHECK-DAG:   MayAlias:     <vscale x 4 x i32>* %m16pv16, <vscale x 4 x i32>* %vm16
 ; CHECK-DAG:   MayAlias:     <vscale x 4 x i32>* %m16, <vscale x 4 x i32>* %m16pv16
 ; CHECK-DAG:   MayAlias:     <vscale x 4 x i32>* %m16pv16, <vscale x 4 x i32>* %vm16m16

``````````

</details>


https://github.com/llvm/llvm-project/pull/218195


More information about the llvm-commits mailing list