[llvm] [Delinearization] Extract array dimensions from global declarations (PR #175158)

Sjoerd Meijer via llvm-commits llvm-commits at lists.llvm.org
Fri Jan 9 04:05:33 PST 2026


https://github.com/sjoerdmeijer created https://github.com/llvm/llvm-project/pull/175158

This is extracted from #156342 that implements multiple things at the same time. This patch is focusing on one thing only: to extract array bounds from global declarations to help loop interchange with our motivating example: test/Transforms/LoopInterchange/large-nested-4d.ll.

With this patch, loop bounds are extracted from a global variable declaration. The result is that Delinearization now succeeds and the different subscripts are recognised, leading to improved DA results.

A few remarks on this approach to extract bounds from global declarations:
- This is certainly not meant to be the silver bullet to make Delinearization as robust and precise as possible, but the idea is to use bounds information if it is available, and thus every little helps.
- Global declarations have type information, but this might change in the future due to LLVM IR simplifications. That's okay because the transition from this to emitting some additional type information is trivial, so we will support that when this becomes relevant.
- The bigger picture is to let the front-end emit subscript or bound information in the form of assumes, see #159046 that needs to be revived, but that is orthogonal to this work.

Next steps:
- Minor changes are required in DependenceAnalysis and `delinearizeFixedSizeArray()` to actually use this; currently this is only used in `printDelinearization()` in Delinearization.
- Add support for alloca's, that should be now be a small incremental change.

>From 39e21fc537977a0cb6b43ffa865006c4022b10a8 Mon Sep 17 00:00:00 2001
From: Sjoerd Meijer <smeijer at nvidia.com>
Date: Wed, 7 Jan 2026 02:52:13 -0800
Subject: [PATCH] [Delinearization] Extract array dimensions from global
 declarations

This is extracted from #156342 that implements multiple things at
the same time. This patch is focusing on one thing only: to extract
array bounds from global declarations to help loop interchang with our
motivating example: test/Transforms/LoopInterchange/large-nested-4d.ll.

With this patch, loop bounds are extracted from a global variable
declaration. The result is that Delinearization now succeeds and
the different subscripts are recognised, leading to improved DA results.

A few remarks on this approach to extract bounds from global
declarations:
- This is certainly not meant to be the silver bullet to make
  Delinearization as robust and precise as possible, but the idea is to
  use bounds information if it is available, and thus every little helps.
- Global declarations have type information, but this might change in
  the future due to LLVM IR simplifications. That's okay because the
  transition from this to emitting some additional type information is
  trivial, so we will support that when this becomes relevant.
- The bigger picture is to let the front-end emit subscript or bound
  information in the form of assumes, see #159046 that needs to be
  revived, but that is orthogonal to this work.

Next steps:
- Minor changes are required in DependenceAnalysis and
  `delinearizeFixedSizeArray()` to actually use this; currently this
  is only used in `printDelinearization()` in Delinearization.
- Add support for alloca's, that should be now be a small incremental
  change.
---
 llvm/include/llvm/Analysis/Delinearization.h  |  10 +-
 llvm/lib/Analysis/Delinearization.cpp         | 210 +++++++++++++++---
 llvm/lib/Analysis/DependenceAnalysis.cpp      |   4 +-
 llvm/test/Analysis/Delinearization/a.ll       |   3 +-
 .../Analysis/Delinearization/byte_offset.ll   |   2 +-
 .../constant_functions_multi_dim.ll           |   6 +-
 .../Analysis/Delinearization/divide_by_one.ll |   6 +-
 .../Delinearization/fixed_size_array.ll       |  62 ++----
 .../Delinearization/gcd_multiply_expr.ll      |  56 ++---
 .../Delinearization/global_array_bounds.ll    |  54 +++++
 .../test/Analysis/Delinearization/himeno_1.ll |   3 +-
 .../test/Analysis/Delinearization/himeno_2.ll |   3 +-
 .../iv_times_constant_in_subscript.ll         |   3 +-
 .../multidim_ivs_and_integer_offsets_3d.ll    |   3 +-
 ...multidim_ivs_and_integer_offsets_nts_3d.ll |   3 +-
 ...multidim_ivs_and_parameteric_offsets_3d.ll |   3 +-
 .../Delinearization/multidim_only_ivs_2d.ll   |   6 +-
 .../multidim_only_ivs_2d_nested.ll            |   2 +-
 .../Delinearization/multidim_only_ivs_3d.ll   |   3 +-
 .../multidim_only_ivs_3d_cast.ll              |   3 +-
 ..._two_accesses_different_delinearization.ll |   6 +-
 .../parameter_addrec_product.ll               |   8 +-
 .../terms_with_identity_factor.ll             |   6 +-
 .../Analysis/Delinearization/type_mismatch.ll |   2 +-
 .../Delinearization/validation_large_size.ll  |  17 +-
 25 files changed, 326 insertions(+), 158 deletions(-)
 create mode 100644 llvm/test/Analysis/Delinearization/global_array_bounds.ll

diff --git a/llvm/include/llvm/Analysis/Delinearization.h b/llvm/include/llvm/Analysis/Delinearization.h
index d48b57cc4284f..a616fbb03e6f4 100644
--- a/llvm/include/llvm/Analysis/Delinearization.h
+++ b/llvm/include/llvm/Analysis/Delinearization.h
@@ -44,7 +44,15 @@ void collectParametricTerms(ScalarEvolution &SE, const SCEV *Expr,
 /// (third step of delinearization).
 void computeAccessFunctions(ScalarEvolution &SE, const SCEV *Expr,
                             SmallVectorImpl<const SCEV *> &Subscripts,
-                            SmallVectorImpl<const SCEV *> &Sizes);
+                            SmallVectorImpl<const SCEV *> &Sizes,
+                            const SCEV *ElementSize = nullptr);
+
+
+bool delinearizeUsingArrayInfo(ScalarEvolution &SE, const SCEV *AccessFn,
+                               SmallVectorImpl<const SCEV *> &Subscripts,
+                               SmallVectorImpl<const SCEV *> &Sizes,
+                               const SCEV *ElementSize);
+
 /// Split this SCEVAddRecExpr into two vectors of SCEVs representing the
 /// subscripts and sizes of an array access.
 ///
diff --git a/llvm/lib/Analysis/Delinearization.cpp b/llvm/lib/Analysis/Delinearization.cpp
index 4263c6f49993e..cd0481c939a28 100644
--- a/llvm/lib/Analysis/Delinearization.cpp
+++ b/llvm/lib/Analysis/Delinearization.cpp
@@ -21,6 +21,7 @@
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/DerivedTypes.h"
 #include "llvm/IR/Function.h"
+#include "llvm/IR/GlobalVariable.h"
 #include "llvm/IR/InstIterator.h"
 #include "llvm/IR/Instructions.h"
 #include "llvm/IR/PassManager.h"
@@ -345,7 +346,8 @@ void llvm::findArrayDimensions(ScalarEvolution &SE,
 
 void llvm::computeAccessFunctions(ScalarEvolution &SE, const SCEV *Expr,
                                   SmallVectorImpl<const SCEV *> &Subscripts,
-                                  SmallVectorImpl<const SCEV *> &Sizes) {
+                                  SmallVectorImpl<const SCEV *> &Sizes,
+                                  const SCEV *ElementSize) {
   // Early exit in case this SCEV is not an affine multivariate function.
   if (Sizes.empty())
     return;
@@ -397,9 +399,13 @@ void llvm::computeAccessFunctions(ScalarEvolution &SE, const SCEV *Expr,
     Subscripts.push_back(R);
   }
 
-  // Also push in last position the remainder of the last division: it will be
-  // the access function of the innermost dimension.
-  Subscripts.push_back(Res);
+  if (!Res->isZero()) {
+    // This is only needed when the outermost array size is not known.  Res = 0
+    // when the outermost array dimension is known, as for example when reading
+    // array sizes from a local or global declaration.
+    Subscripts.push_back(Res);
+    LLVM_DEBUG(dbgs() << "Subscripts push_back Res: " << *Res << "\n");
+  }
 
   std::reverse(Subscripts.begin(), Subscripts.end());
 
@@ -411,6 +417,139 @@ void llvm::computeAccessFunctions(ScalarEvolution &SE, const SCEV *Expr,
   });
 }
 
+// Extract array dimensions from global variable declarations and return true
+// if array dimensions were successfully extracted.
+//
+// TODO:
+// - This can easily be extended to also extract dimensions from alloca
+//   instructions.
+// - Global variable declarations might be subject to LLVM IR simplifications,
+//   i.e. dimenions might be omitted. Adapting this function to that should
+//   be easy as we would need to emit and pick up meta-data (or something
+//   similar).
+//
+static bool
+extractArrayInfoFromGlobal(ScalarEvolution &SE, Value *BasePtr,
+                           SmallVectorImpl<const SCEV *> &Sizes,
+                           const SCEV *ElementSize) {
+  // Clear output vector.
+  Sizes.clear();
+
+  LLVM_DEBUG(
+      dbgs() << "extractArrayInfoFromGlobal called with BasePtr: "
+             << *BasePtr << "\n");
+
+  // Distinguish between simple array accesses and complex pointer arithmetic,
+  // i.e. check if this is a simple array access pattern:
+  //   GEP [N x T]* @array, 0, idx
+  // This represents direct indexing like array[i], which should use array
+  // dimensions.
+  if (auto *GEP = dyn_cast<GetElementPtrInst>(BasePtr)) {
+    if (GEP->getNumIndices() == 2) {
+      auto *FirstIdx = dyn_cast<ConstantInt>(GEP->getOperand(1));
+      if (FirstIdx && FirstIdx->isZero()) {
+        // Simple array access: extract dimensions from the underlying array
+        // type
+        Value *Source = GEP->getPointerOperand()->stripPointerCasts();
+        return extractArrayInfoFromGlobal(SE, Source, Sizes, ElementSize);
+      }
+    }
+    // Complex GEPs like (&array[offset])[index] represent pointer arithmetic,
+    // not simple array indexing. These should be handled by parametric
+    // delinearization to preserve the linearized byte-offset semantics rather
+    // than treating them as multidimensional array accesses.
+    return false;
+  }
+
+  // Check if BasePtr is a global variable (todo: check also alloca's).
+  Type *ElementType = nullptr;
+  if (auto *GV = dyn_cast<GlobalVariable>(BasePtr)) {
+    ElementType = GV->getValueType();
+    LLVM_DEBUG(dbgs() << "Found global variable with type: " << *ElementType
+                      << "\n");
+  } else {
+    LLVM_DEBUG(dbgs() << "No global found for base pointer\n");
+    return false;
+  }
+
+  // Extract dimensions from nested array types.
+  Type *I64Ty = Type::getInt64Ty(SE.getContext());
+
+  while (auto *ArrayTy = dyn_cast<ArrayType>(ElementType)) {
+    uint64_t Size = ArrayTy->getNumElements();
+    const SCEV *SizeSCEV = SE.getConstant(I64Ty, Size);
+    Sizes.push_back(SizeSCEV);
+    ElementType = ArrayTy->getElementType();
+    LLVM_DEBUG(dbgs() << "  Found array dimension: " << Size << "\n");
+  }
+
+  if (Sizes.empty()) {
+    LLVM_DEBUG(dbgs() << "No array dimensions found in type\n");
+    return false;
+  }
+
+  // Add element size as the last element for computeAccessFunctions algorithm.
+  Sizes.push_back(ElementSize);
+
+  LLVM_DEBUG({
+    dbgs() << "Extracted array info from global for base pointer "
+           << *BasePtr << "\n";
+    dbgs() << "Dimensions: ";
+    for (const SCEV *Size : Sizes)
+      dbgs() << *Size << " ";
+    dbgs() << "\n";
+  });
+
+  return true;
+}
+
+// Try to infer array information and dimensions. Currently, we only extract
+// bounds from static global variable declarations. Work in progress is to
+// make this more general by using type information emitted by the front-end.
+bool llvm::delinearizeUsingArrayInfo(ScalarEvolution &SE, const SCEV *AccessFn,
+                                     SmallVectorImpl<const SCEV *> &Subscripts,
+                                     SmallVectorImpl<const SCEV *> &Sizes,
+                                     const SCEV *ElementSize) {
+  // Clear output vectors.
+  Subscripts.clear();
+  Sizes.clear();
+
+  const SCEVUnknown *BasePointer =
+      dyn_cast<SCEVUnknown>(SE.getPointerBase(AccessFn));
+  if (!BasePointer) {
+    LLVM_DEBUG(dbgs() << "No base pointer for AccessFn: " << *AccessFn << "\n");
+    return false;
+  }
+
+  Value *BasePtr = BasePointer->getValue();
+
+  // Extract array dimensions from global declarations.
+  if (!extractArrayInfoFromGlobal(SE, BasePtr, Sizes, ElementSize))
+    return false;
+
+  // Get the full SCEV expression and subtract the base pointer to get
+  // offset-only expression.
+  const SCEV *Expr = SE.getMinusSCEV(AccessFn, BasePointer);
+
+  computeAccessFunctions(SE, Expr, Subscripts, Sizes, ElementSize);
+  if (Sizes.empty() || Subscripts.empty())
+    return false;
+
+  // Validate dimension consistency: subscripts should match array dimensions
+  // (Sizes includes element size as last element, so array dimensions =
+  // Sizes.size() - 1)
+  unsigned ArrayDims = Sizes.size() - 1;
+  if (Subscripts.size() != ArrayDims) {
+    LLVM_DEBUG(
+        dbgs() << "delinearizeUsingArrayInfo: Dimension mismatch - "
+               << Subscripts.size() << " subscripts for " << ArrayDims
+               << " array dimensions. Falling back to parametric method.\n");
+    return false;
+  }
+
+  return true;
+}
+
 /// Splits the SCEV into two vectors of SCEVs representing the subscripts and
 /// sizes of an array access. Returns the remainder of the delinearization that
 /// is the offset start of the array.  The SCEV->delinearize algorithm computes
@@ -468,6 +607,16 @@ void llvm::delinearize(ScalarEvolution &SE, const SCEV *Expr,
   Subscripts.clear();
   Sizes.clear();
 
+  if (delinearizeUsingArrayInfo(SE, Expr, Subscripts, Sizes, ElementSize))
+    return;
+
+  LLVM_DEBUG(dbgs() << "delinearize falling back to parametric method\n");
+
+  // Fall back to parametric delinearization.
+  if (const SCEVUnknown *BasePointer =
+          dyn_cast<SCEVUnknown>(SE.getPointerBase(Expr)))
+    Expr = SE.getMinusSCEV(Expr, BasePointer);
+
   // First step: collect parametric terms.
   SmallVector<const SCEV *, 4> Terms;
   collectParametricTerms(SE, Expr, Terms);
@@ -826,7 +975,6 @@ void printDelinearization(raw_ostream &O, Function *F, LoopInfo *LI,
     // Do not delinearize if we cannot find the base pointer.
     if (!BasePointer)
       break;
-    AccessFn = SE->getMinusSCEV(AccessFn, BasePointer);
 
     O << "\n";
     O << "Inst:" << Inst << "\n";
@@ -835,8 +983,7 @@ void printDelinearization(raw_ostream &O, Function *F, LoopInfo *LI,
     SmallVector<const SCEV *, 3> Subscripts, Sizes;
 
     auto IsDelinearizationFailed = [&]() {
-      return Subscripts.size() == 0 || Sizes.size() == 0 ||
-             Subscripts.size() != Sizes.size();
+     return Subscripts.empty() || Sizes.empty();
     };
 
     delinearize(*SE, AccessFn, Subscripts, Sizes, SE->getElementSize(&Inst));
@@ -847,26 +994,37 @@ void printDelinearization(raw_ostream &O, Function *F, LoopInfo *LI,
                                 SE->getElementSize(&Inst));
     }
 
-      if (IsDelinearizationFailed()) {
-        O << "failed to delinearize\n";
-        continue;
-      }
+    if (IsDelinearizationFailed()) {
+      O << "failed to delinearize\n";
+      continue;
+    }
+
+    O << "Base offset: " << *BasePointer << "\n";
+    O << "ArrayDecl";
+    // Print [Unknown] when the outermost dimension of the array is not known.
+    // Sizes[NumSizes - 1] is the array element size.
+    int NumSubscripts = Subscripts.size();
+    int NumSizes = Sizes.size();
+    if (NumSizes == NumSubscripts)
+      O << "[UnknownSize]";
+
+    // Handle different size relationships between Subscripts and Sizes.
+    if (NumSizes > 0) {
+      // Print array dimensions (all but the last, which is element size).
+      for (const SCEV *Size : ArrayRef(Sizes).drop_back())
+        O << "[" << *Size << "]";
+
+      // Print element size (last element in Sizes array).
+      O << " with elements of " << *Sizes[NumSizes - 1] << " bytes.\n";
+    } else {
+      O << " unknown sizes.\n";
+    }
+
+    O << "ArrayRef";
+    for (int i = 0; i < NumSubscripts; i++)
+      O << "[" << *Subscripts[i] << "]";
+    O << "\n"; 
 
-      O << "Base offset: " << *BasePointer << "\n";
-      O << "ArrayDecl[UnknownSize]";
-      int Size = Subscripts.size();
-      for (int i = 0; i < Size - 1; i++)
-        O << "[" << *Sizes[i] << "]";
-      O << " with elements of " << *Sizes[Size - 1] << " bytes.\n";
-
-      O << "ArrayRef";
-      for (int i = 0; i < Size; i++)
-        O << "[" << *Subscripts[i] << "]";
-      O << "\n";
-
-      bool IsValid = validateDelinearizationResult(*SE, Sizes, Subscripts);
-      O << "Delinearization validation: " << (IsValid ? "Succeeded" : "Failed")
-        << "\n";
   }
 }
 
diff --git a/llvm/lib/Analysis/DependenceAnalysis.cpp b/llvm/lib/Analysis/DependenceAnalysis.cpp
index 23820853e6fee..b6ee848ebd605 100644
--- a/llvm/lib/Analysis/DependenceAnalysis.cpp
+++ b/llvm/lib/Analysis/DependenceAnalysis.cpp
@@ -3363,9 +3363,9 @@ bool DependenceInfo::tryDelinearizeFixedSize(
   const SCEV *ElemSize = SE->getElementSize(Src);
   assert(ElemSize == SE->getElementSize(Dst) && "Different element sizes");
   SmallVector<const SCEV *, 4> SrcSizes, DstSizes;
-  if (!delinearizeFixedSizeArray(*SE, SE->removePointerBase(SrcAccessFn),
+  if (!delinearizeFixedSizeArray(*SE, SrcAccessFn /*SE->removePointerBase(SrcAccessFn)*/,
                                  SrcSubscripts, SrcSizes, ElemSize) ||
-      !delinearizeFixedSizeArray(*SE, SE->removePointerBase(DstAccessFn),
+      !delinearizeFixedSizeArray(*SE, DstAccessFn /*SE->removePointerBase(DstAccessFn)*/,
                                  DstSubscripts, DstSizes, ElemSize))
     return false;
 
diff --git a/llvm/test/Analysis/Delinearization/a.ll b/llvm/test/Analysis/Delinearization/a.ll
index 5d2d4dc29206e..55ca1c70d0a86 100644
--- a/llvm/test/Analysis/Delinearization/a.ll
+++ b/llvm/test/Analysis/Delinearization/a.ll
@@ -11,11 +11,10 @@
 define void @foo(i64 %n, i64 %m, i64 %o, ptr nocapture %A) #0 {
 ; CHECK-LABEL: 'foo'
 ; CHECK-NEXT:  Inst: store i32 1, ptr %arrayidx11.us.us, align 4
-; CHECK-NEXT:  AccessFunction: {{\{\{\{}}(28 + (4 * (-4 + (3 * %m)) * %o)),+,(8 * %m * %o)}<%for.i>,+,(12 * %o)}<%for.j>,+,20}<%for.k>
+; CHECK-NEXT:  AccessFunction: {{\{\{\{}}(28 + (4 * (-4 + (3 * %m)) * %o) + %A),+,(8 * %m * %o)}<%for.i>,+,(12 * %o)}<%for.j>,+,20}<%for.k>
 ; CHECK-NEXT:  Base offset: %A
 ; CHECK-NEXT:  ArrayDecl[UnknownSize][%m][%o] with elements of 4 bytes.
 ; CHECK-NEXT:  ArrayRef[{3,+,2}<nuw><%for.i>][{-4,+,3}<nw><%for.j>][{7,+,5}<nw><%for.k>]
-; CHECK-NEXT:  Delinearization validation: Failed
 ;
 entry:
   %cmp32 = icmp sgt i64 %n, 0
diff --git a/llvm/test/Analysis/Delinearization/byte_offset.ll b/llvm/test/Analysis/Delinearization/byte_offset.ll
index 743dcfcca6400..b17082dd3e31a 100644
--- a/llvm/test/Analysis/Delinearization/byte_offset.ll
+++ b/llvm/test/Analysis/Delinearization/byte_offset.ll
@@ -13,7 +13,7 @@
 define void @foo(ptr %A, i64 %i2, i64 %arg, i1 %c) {
 ; CHECK-LABEL: 'foo'
 ; CHECK-NEXT:  Inst: store float 0.000000e+00, ptr %arrayidx, align 4
-; CHECK-NEXT:  AccessFunction: ({0,+,%i2}<%outer.loop> + %unknown)
+; CHECK-NEXT:  AccessFunction: ({%A,+,%i2}<%outer.loop> + %unknown)
 ; CHECK-NEXT:  failed to delinearize
 ;
 entry:
diff --git a/llvm/test/Analysis/Delinearization/constant_functions_multi_dim.ll b/llvm/test/Analysis/Delinearization/constant_functions_multi_dim.ll
index 7e5c5142dccbc..911f109272c16 100644
--- a/llvm/test/Analysis/Delinearization/constant_functions_multi_dim.ll
+++ b/llvm/test/Analysis/Delinearization/constant_functions_multi_dim.ll
@@ -7,18 +7,16 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
 define void @mat_mul(ptr %C, ptr %A, ptr %B, i64 %N) !kernel_arg_addr_space !2 !kernel_arg_access_qual !3 !kernel_arg_type !4 !kernel_arg_base_type !4 !kernel_arg_type_qual !5 {
 ; CHECK-LABEL: 'mat_mul'
 ; CHECK-NEXT:  Inst: %tmp = load float, ptr %arrayidx, align 4
-; CHECK-NEXT:  AccessFunction: {(4 * %N * %call),+,4}<%for.inc>
+; CHECK-NEXT:  AccessFunction: {((4 * %N * %call) + %A),+,4}<%for.inc>
 ; CHECK-NEXT:  Base offset: %A
 ; CHECK-NEXT:  ArrayDecl[UnknownSize][%N] with elements of 4 bytes.
 ; CHECK-NEXT:  ArrayRef[%call][{0,+,1}<nuw><nsw><%for.inc>]
-; CHECK-NEXT:  Delinearization validation: Failed
 ; CHECK-EMPTY:
 ; CHECK-NEXT:  Inst: %tmp5 = load float, ptr %arrayidx4, align 4
-; CHECK-NEXT:  AccessFunction: {(4 * %call1),+,(4 * %N)}<%for.inc>
+; CHECK-NEXT:  AccessFunction: {((4 * %call1) + %B),+,(4 * %N)}<%for.inc>
 ; CHECK-NEXT:  Base offset: %B
 ; CHECK-NEXT:  ArrayDecl[UnknownSize][%N] with elements of 4 bytes.
 ; CHECK-NEXT:  ArrayRef[{0,+,1}<nuw><nsw><%for.inc>][%call1]
-; CHECK-NEXT:  Delinearization validation: Failed
 ;
 entry:
   br label %entry.split
diff --git a/llvm/test/Analysis/Delinearization/divide_by_one.ll b/llvm/test/Analysis/Delinearization/divide_by_one.ll
index 3d8e55984291e..747b2c5489785 100644
--- a/llvm/test/Analysis/Delinearization/divide_by_one.ll
+++ b/llvm/test/Analysis/Delinearization/divide_by_one.ll
@@ -14,18 +14,16 @@ target datalayout = "e-m:e-p:32:32-i1:32-i64:64-a:0-n32"
 define void @test(ptr nocapture %dst, i32 %stride, i32 %bs) {
 ; CHECK-LABEL: 'test'
 ; CHECK-NEXT:  Inst: %0 = load i8, ptr %arrayidx, align 1
-; CHECK-NEXT:  AccessFunction: {{\{\{}}(-1 + ((1 + %bs) * %stride)),+,(-1 * %stride)}<%for.cond1.preheader>,+,1}<nw><%for.body3>
+; CHECK-NEXT:  AccessFunction: {{\{\{}}(-1 + ((1 + %bs) * %stride) + %dst),+,(-1 * %stride)}<%for.cond1.preheader>,+,1}<nw><%for.body3>
 ; CHECK-NEXT:  Base offset: %dst
 ; CHECK-NEXT:  ArrayDecl[UnknownSize][%stride] with elements of 1 bytes.
 ; CHECK-NEXT:  ArrayRef[{(1 + %bs),+,-1}<nw><%for.cond1.preheader>][{-1,+,1}<nw><%for.body3>]
-; CHECK-NEXT:  Delinearization validation: Failed
 ; CHECK-EMPTY:
 ; CHECK-NEXT:  Inst: store i8 %0, ptr %arrayidx7, align 1
-; CHECK-NEXT:  AccessFunction: {{\{\{}}(%stride * %bs),+,(-1 * %stride)}<%for.cond1.preheader>,+,1}<nsw><%for.body3>
+; CHECK-NEXT:  AccessFunction: {{\{\{}}((%stride * %bs) + %dst),+,(-1 * %stride)}<%for.cond1.preheader>,+,1}<nw><%for.body3>
 ; CHECK-NEXT:  Base offset: %dst
 ; CHECK-NEXT:  ArrayDecl[UnknownSize][%stride] with elements of 1 bytes.
 ; CHECK-NEXT:  ArrayRef[{%bs,+,-1}<nsw><%for.cond1.preheader>][{0,+,1}<nuw><nsw><%for.body3>]
-; CHECK-NEXT:  Delinearization validation: Failed
 ;
 entry:
   %cmp20 = icmp sgt i32 %bs, -1
diff --git a/llvm/test/Analysis/Delinearization/fixed_size_array.ll b/llvm/test/Analysis/Delinearization/fixed_size_array.ll
index 250d46c81a25b..284e4e95b8a28 100644
--- a/llvm/test/Analysis/Delinearization/fixed_size_array.ll
+++ b/llvm/test/Analysis/Delinearization/fixed_size_array.ll
@@ -11,11 +11,8 @@
 define void @a_i_j_k(ptr %a) {
 ; CHECK-LABEL: 'a_i_j_k'
 ; CHECK-NEXT:  Inst: store i32 1, ptr %idx, align 4
-; CHECK-NEXT:  AccessFunction: {{\{\{\{}}0,+,1024}<nuw><nsw><%for.i.header>,+,128}<nw><%for.j.header>,+,4}<nw><%for.k>
-; CHECK-NEXT:  Base offset: %a
-; CHECK-NEXT:  ArrayDecl[UnknownSize][8][32] with elements of 4 bytes.
-; CHECK-NEXT:  ArrayRef[{0,+,1}<nuw><nsw><%for.i.header>][{0,+,1}<nuw><nsw><%for.j.header>][{0,+,1}<nuw><nsw><%for.k>]
-; CHECK-NEXT:  Delinearization validation: Succeeded
+; CHECK-NEXT:  AccessFunction: {{\{\{\{}}%a,+,1024}<nw><%for.i.header>,+,128}<nw><%for.j.header>,+,4}<nw><%for.k>
+; CHECK-NEXT:  failed to delinearize
 ;
 entry:
   br label %for.i.header
@@ -60,11 +57,8 @@ exit:
 define void @a_i_nj_k(ptr %a) {
 ; CHECK-LABEL: 'a_i_nj_k'
 ; CHECK-NEXT:  Inst: store i32 1, ptr %idx, align 4
-; CHECK-NEXT:  AccessFunction: {{\{\{\{}}896,+,1024}<nuw><nsw><%for.i.header>,+,-128}<nw><%for.j.header>,+,4}<nw><%for.k>
-; CHECK-NEXT:  Base offset: %a
-; CHECK-NEXT:  ArrayDecl[UnknownSize][8][32] with elements of 4 bytes.
-; CHECK-NEXT:  ArrayRef[{0,+,1}<nuw><nsw><%for.i.header>][{7,+,-1}<nsw><%for.j.header>][{0,+,1}<nuw><nsw><%for.k>]
-; CHECK-NEXT:  Delinearization validation: Succeeded
+; CHECK-NEXT:  AccessFunction: {{\{\{\{}}(896 + %a),+,1024}<nw><%for.i.header>,+,-128}<nw><%for.j.header>,+,4}<nw><%for.k>
+; CHECK-NEXT:  failed to delinearize
 ;
 entry:
   br label %for.i.header
@@ -116,18 +110,12 @@ exit:
 define void @a_ijk_b_i2jk(ptr %a, ptr %b) {
 ; CHECK-LABEL: 'a_ijk_b_i2jk'
 ; CHECK-NEXT:  Inst: store i32 1, ptr %a.idx, align 4
-; CHECK-NEXT:  AccessFunction: {{\{\{\{}}0,+,1024}<nuw><nsw><%for.i.header>,+,256}<nw><%for.j.header>,+,4}<nw><%for.k>
-; CHECK-NEXT:  Base offset: %a
-; CHECK-NEXT:  ArrayDecl[UnknownSize][4][64] with elements of 4 bytes.
-; CHECK-NEXT:  ArrayRef[{0,+,1}<nuw><nsw><%for.i.header>][{0,+,1}<nuw><nsw><%for.j.header>][{0,+,1}<nuw><nsw><%for.k>]
-; CHECK-NEXT:  Delinearization validation: Succeeded
+; CHECK-NEXT:  AccessFunction: {{\{\{\{}}%a,+,1024}<nw><%for.i.header>,+,256}<nw><%for.j.header>,+,4}<nw><%for.k>
+; CHECK-NEXT:  failed to delinearize
 ; CHECK-EMPTY:
 ; CHECK-NEXT:  Inst: store i32 1, ptr %b.idx, align 4
-; CHECK-NEXT:  AccessFunction: {{\{\{\{}}0,+,1024}<nuw><nsw><%for.i.header>,+,256}<nw><%for.j.header>,+,4}<nw><%for.k>
-; CHECK-NEXT:  Base offset: %b
-; CHECK-NEXT:  ArrayDecl[UnknownSize][4][64] with elements of 4 bytes.
-; CHECK-NEXT:  ArrayRef[{0,+,1}<nuw><nsw><%for.i.header>][{0,+,1}<nuw><nsw><%for.j.header>][{0,+,1}<nuw><nsw><%for.k>]
-; CHECK-NEXT:  Delinearization validation: Succeeded
+; CHECK-NEXT:  AccessFunction: {{\{\{\{}}%b,+,1024}<nw><%for.i.header>,+,256}<nw><%for.j.header>,+,4}<nw><%for.k>
+; CHECK-NEXT:  failed to delinearize
 ;
 entry:
   br label %for.i.header
@@ -180,11 +168,8 @@ exit:
 define void @a_i_2j1_k(ptr %a) {
 ; CHECK-LABEL: 'a_i_2j1_k'
 ; CHECK-NEXT:  Inst: store i32 1, ptr %idx, align 4
-; CHECK-NEXT:  AccessFunction: {{\{\{\{}}128,+,1024}<nuw><nsw><%for.i.header>,+,256}<nw><%for.j.header>,+,4}<nw><%for.k>
-; CHECK-NEXT:  Base offset: %a
-; CHECK-NEXT:  ArrayDecl[UnknownSize][4][64] with elements of 4 bytes.
-; CHECK-NEXT:  ArrayRef[{0,+,1}<nuw><nsw><%for.i.header>][{0,+,1}<nuw><%for.j.header>][{32,+,1}<nw><%for.k>]
-; CHECK-NEXT:  Delinearization validation: Succeeded
+; CHECK-NEXT:  AccessFunction: {{\{\{\{}}(128 + %a),+,1024}<nw><%for.i.header>,+,256}<nw><%for.j.header>,+,4}<nw><%for.k>
+; CHECK-NEXT:  failed to delinearize
 ;
 entry:
   br label %for.i.header
@@ -234,7 +219,7 @@ exit:
 define void @a_i_3j_k(ptr %a) {
 ; CHECK-LABEL: 'a_i_3j_k'
 ; CHECK-NEXT:  Inst: store i32 1, ptr %idx, align 4
-; CHECK-NEXT:  AccessFunction: {{\{\{\{}}0,+,1024}<nuw><nsw><%for.i.header>,+,384}<nw><%for.j.header>,+,4}<nw><%for.k>
+; CHECK-NEXT:  AccessFunction: {{\{\{\{}}%a,+,1024}<nw><%for.i.header>,+,384}<nw><%for.j.header>,+,4}<nw><%for.k>
 ; CHECK-NEXT:  failed to delinearize
 ;
 entry:
@@ -285,11 +270,8 @@ exit:
 define void @a_i_j_3k(ptr %a) {
 ; CHECK-LABEL: 'a_i_j_3k'
 ; CHECK-NEXT:  Inst: store i32 1, ptr %idx, align 4
-; CHECK-NEXT:  AccessFunction: {{\{\{\{}}0,+,1024}<nuw><nsw><%for.i.header>,+,128}<nw><%for.j.header>,+,12}<nw><%for.k>
-; CHECK-NEXT:  Base offset: %a
-; CHECK-NEXT:  ArrayDecl[UnknownSize][8][32] with elements of 4 bytes.
-; CHECK-NEXT:  ArrayRef[{0,+,1}<nuw><nsw><%for.i.header>][{0,+,1}<nuw><nsw><%for.j.header>][{0,+,3}<nuw><nsw><%for.k>]
-; CHECK-NEXT:  Delinearization validation: Succeeded
+; CHECK-NEXT:  AccessFunction: {{\{\{\{}}%a,+,1024}<nw><%for.i.header>,+,128}<nw><%for.j.header>,+,12}<nw><%for.k>
+; CHECK-NEXT:  failed to delinearize
 ;
 entry:
   br label %for.i.header
@@ -337,7 +319,7 @@ exit:
 define void @a_i_j2k_i(ptr %a) {
 ; CHECK-LABEL: 'a_i_j2k_i'
 ; CHECK-NEXT:  Inst: store i32 1, ptr %idx, align 4
-; CHECK-NEXT:  AccessFunction: {{\{\{\{}}0,+,1028}<%for.i.header>,+,256}<nw><%for.j.header>,+,128}<nw><%for.k>
+; CHECK-NEXT:  AccessFunction: {{\{\{\{}}%a,+,1028}<%for.i.header>,+,256}<nw><%for.j.header>,+,128}<nw><%for.k>
 ; CHECK-NEXT:  failed to delinearize
 ;
 entry:
@@ -388,11 +370,8 @@ exit:
 define void @a_i_i_jk(ptr %a) {
 ; CHECK-LABEL: 'a_i_i_jk'
 ; CHECK-NEXT:  Inst: store i32 1, ptr %idx, align 4
-; CHECK-NEXT:  AccessFunction: {{\{\{\{}}0,+,1152}<%for.i.header>,+,4}<nw><%for.j.header>,+,4}<nw><%for.k>
-; CHECK-NEXT:  Base offset: %a
-; CHECK-NEXT:  ArrayDecl[UnknownSize][288] with elements of 4 bytes.
-; CHECK-NEXT:  ArrayRef[{0,+,1}<nuw><nsw><%for.i.header>][{{\{\{}}0,+,1}<nuw><nsw><%for.j.header>,+,1}<nuw><nsw><%for.k>]
-; CHECK-NEXT:  Delinearization validation: Succeeded
+; CHECK-NEXT:  AccessFunction: {{\{\{\{}}%a,+,1152}<%for.i.header>,+,4}<nw><%for.j.header>,+,4}<nw><%for.k>
+; CHECK-NEXT:  failed to delinearize
 ;
 entry:
   br label %for.i.header
@@ -439,11 +418,8 @@ exit:
 define void @a_i_jk_l(ptr %a) {
 ; CHECK-LABEL: 'a_i_jk_l'
 ; CHECK-NEXT:  Inst: store i32 1, ptr %idx, align 4
-; CHECK-NEXT:  AccessFunction: {{\{\{\{\{}}0,+,1024}<nuw><nsw><%for.i.header>,+,128}<nw><%for.j.header>,+,128}<nw><%for.k.header>,+,4}<nw><%for.l>
-; CHECK-NEXT:  Base offset: %a
-; CHECK-NEXT:  ArrayDecl[UnknownSize][8][32] with elements of 4 bytes.
-; CHECK-NEXT:  ArrayRef[{0,+,1}<nuw><nsw><%for.i.header>][{{\{\{}}0,+,1}<nuw><nsw><%for.j.header>,+,1}<nuw><nsw><%for.k.header>][{0,+,1}<nuw><nsw><%for.l>]
-; CHECK-NEXT:  Delinearization validation: Succeeded
+; CHECK-NEXT:  AccessFunction: {{\{\{\{\{}}%a,+,1024}<nw><%for.i.header>,+,128}<nw><%for.j.header>,+,128}<nw><%for.k.header>,+,4}<nw><%for.l>
+; CHECK-NEXT:  failed to delinearize
 ;
 entry:
   br label %for.i.header
@@ -500,7 +476,7 @@ exit:
 define void @non_divisible_by_element_size(ptr %a) {
 ; CHECK-LABEL: 'non_divisible_by_element_size'
 ; CHECK-NEXT:  Inst: store i32 1, ptr %idx, align 4
-; CHECK-NEXT:  AccessFunction: {{\{\{\{}}0,+,256}<nuw><nsw><%for.i.header>,+,32}<nw><%for.j.header>,+,1}<nw><%for.k>
+; CHECK-NEXT:  AccessFunction: {{\{\{\{}}%a,+,256}<nw><%for.i.header>,+,32}<nw><%for.j.header>,+,1}<nw><%for.k>
 ; CHECK-NEXT:  failed to delinearize
 ;
 entry:
diff --git a/llvm/test/Analysis/Delinearization/gcd_multiply_expr.ll b/llvm/test/Analysis/Delinearization/gcd_multiply_expr.ll
index a5af30011f487..74f4d29a2383b 100644
--- a/llvm/test/Analysis/Delinearization/gcd_multiply_expr.ll
+++ b/llvm/test/Analysis/Delinearization/gcd_multiply_expr.ll
@@ -29,115 +29,115 @@
 define i32 @fn2() {
 ; CHECK-LABEL: 'fn2'
 ; CHECK-NEXT:  Inst: store i32 %storemerge.i, ptr @a, align 4
-; CHECK-NEXT:  AccessFunction: 0
+; CHECK-NEXT:  AccessFunction: @a
 ; CHECK-NEXT:  failed to delinearize
 ; CHECK-EMPTY:
 ; CHECK-NEXT:  Inst: %9 = load i8, ptr %arrayidx.i, align 1
-; CHECK-NEXT:  AccessFunction: (sext i32 {({(%1 * %2),+,1}<nw><%for.cond2thread-pre-split.i> + %.pr.i),+,8}<nw><%for.body4.i> to i64)
+; CHECK-NEXT:  AccessFunction: ((sext i32 {({(%1 * %2),+,1}<nw><%for.cond2thread-pre-split.i> + %.pr.i),+,8}<nw><%for.body4.i> to i64) + %3)
 ; CHECK-NEXT:  failed to delinearize
 ; CHECK-EMPTY:
 ; CHECK-NEXT:  Inst: store i32 %conv.i, ptr @c, align 4
-; CHECK-NEXT:  AccessFunction: 0
+; CHECK-NEXT:  AccessFunction: @c
 ; CHECK-NEXT:  failed to delinearize
 ; CHECK-EMPTY:
 ; CHECK-NEXT:  Inst: store i32 %inc.i, ptr @b, align 4
-; CHECK-NEXT:  AccessFunction: 0
+; CHECK-NEXT:  AccessFunction: @b
 ; CHECK-NEXT:  failed to delinearize
 ; CHECK-EMPTY:
 ; CHECK-NEXT:  Inst: %10 = load i8, ptr %arrayidx.1.i, align 1
-; CHECK-NEXT:  AccessFunction: (sext i32 {({(1 + (%1 * %2)),+,1}<nw><%for.cond2thread-pre-split.i> + %.pr.i),+,8}<nw><%for.body4.i> to i64)
+; CHECK-NEXT:  AccessFunction: ((sext i32 {({(1 + (%1 * %2)),+,1}<nw><%for.cond2thread-pre-split.i> + %.pr.i),+,8}<nw><%for.body4.i> to i64) + %3)
 ; CHECK-NEXT:  failed to delinearize
 ; CHECK-EMPTY:
 ; CHECK-NEXT:  Inst: store i32 %conv.1.i, ptr @c, align 4
-; CHECK-NEXT:  AccessFunction: 0
+; CHECK-NEXT:  AccessFunction: @c
 ; CHECK-NEXT:  failed to delinearize
 ; CHECK-EMPTY:
 ; CHECK-NEXT:  Inst: store i32 %inc.1.i, ptr @b, align 4
-; CHECK-NEXT:  AccessFunction: 0
+; CHECK-NEXT:  AccessFunction: @b
 ; CHECK-NEXT:  failed to delinearize
 ; CHECK-EMPTY:
 ; CHECK-NEXT:  Inst: %11 = load i8, ptr %arrayidx.2.i, align 1
-; CHECK-NEXT:  AccessFunction: (sext i32 {({(2 + (%1 * %2)),+,1}<nw><%for.cond2thread-pre-split.i> + %.pr.i),+,8}<nw><%for.body4.i> to i64)
+; CHECK-NEXT:  AccessFunction: ((sext i32 {({(2 + (%1 * %2)),+,1}<nw><%for.cond2thread-pre-split.i> + %.pr.i),+,8}<nw><%for.body4.i> to i64) + %3)
 ; CHECK-NEXT:  failed to delinearize
 ; CHECK-EMPTY:
 ; CHECK-NEXT:  Inst: store i32 %conv.2.i, ptr @c, align 4
-; CHECK-NEXT:  AccessFunction: 0
+; CHECK-NEXT:  AccessFunction: @c
 ; CHECK-NEXT:  failed to delinearize
 ; CHECK-EMPTY:
 ; CHECK-NEXT:  Inst: store i32 %inc.2.i, ptr @b, align 4
-; CHECK-NEXT:  AccessFunction: 0
+; CHECK-NEXT:  AccessFunction: @b
 ; CHECK-NEXT:  failed to delinearize
 ; CHECK-EMPTY:
 ; CHECK-NEXT:  Inst: %12 = load i8, ptr %arrayidx.3.i, align 1
-; CHECK-NEXT:  AccessFunction: (sext i32 {({(3 + (%1 * %2)),+,1}<nw><%for.cond2thread-pre-split.i> + %.pr.i),+,8}<nw><%for.body4.i> to i64)
+; CHECK-NEXT:  AccessFunction: ((sext i32 {({(3 + (%1 * %2)),+,1}<nw><%for.cond2thread-pre-split.i> + %.pr.i),+,8}<nw><%for.body4.i> to i64) + %3)
 ; CHECK-NEXT:  failed to delinearize
 ; CHECK-EMPTY:
 ; CHECK-NEXT:  Inst: store i32 %conv.3.i, ptr @c, align 4
-; CHECK-NEXT:  AccessFunction: 0
+; CHECK-NEXT:  AccessFunction: @c
 ; CHECK-NEXT:  failed to delinearize
 ; CHECK-EMPTY:
 ; CHECK-NEXT:  Inst: store i32 %inc.3.i, ptr @b, align 4
-; CHECK-NEXT:  AccessFunction: 0
+; CHECK-NEXT:  AccessFunction: @b
 ; CHECK-NEXT:  failed to delinearize
 ; CHECK-EMPTY:
 ; CHECK-NEXT:  Inst: %13 = load i8, ptr %arrayidx.4.i, align 1
-; CHECK-NEXT:  AccessFunction: (sext i32 {({(4 + (%1 * %2)),+,1}<nw><%for.cond2thread-pre-split.i> + %.pr.i),+,8}<nw><%for.body4.i> to i64)
+; CHECK-NEXT:  AccessFunction: ((sext i32 {({(4 + (%1 * %2)),+,1}<nw><%for.cond2thread-pre-split.i> + %.pr.i),+,8}<nw><%for.body4.i> to i64) + %3)
 ; CHECK-NEXT:  failed to delinearize
 ; CHECK-EMPTY:
 ; CHECK-NEXT:  Inst: store i32 %conv.4.i, ptr @c, align 4
-; CHECK-NEXT:  AccessFunction: 0
+; CHECK-NEXT:  AccessFunction: @c
 ; CHECK-NEXT:  failed to delinearize
 ; CHECK-EMPTY:
 ; CHECK-NEXT:  Inst: store i32 %inc.4.i, ptr @b, align 4
-; CHECK-NEXT:  AccessFunction: 0
+; CHECK-NEXT:  AccessFunction: @b
 ; CHECK-NEXT:  failed to delinearize
 ; CHECK-EMPTY:
 ; CHECK-NEXT:  Inst: %14 = load i8, ptr %arrayidx.5.i, align 1
-; CHECK-NEXT:  AccessFunction: (sext i32 {({(5 + (%1 * %2)),+,1}<nw><%for.cond2thread-pre-split.i> + %.pr.i),+,8}<nw><%for.body4.i> to i64)
+; CHECK-NEXT:  AccessFunction: ((sext i32 {({(5 + (%1 * %2)),+,1}<nw><%for.cond2thread-pre-split.i> + %.pr.i),+,8}<nw><%for.body4.i> to i64) + %3)
 ; CHECK-NEXT:  failed to delinearize
 ; CHECK-EMPTY:
 ; CHECK-NEXT:  Inst: store i32 %conv.5.i, ptr @c, align 4
-; CHECK-NEXT:  AccessFunction: 0
+; CHECK-NEXT:  AccessFunction: @c
 ; CHECK-NEXT:  failed to delinearize
 ; CHECK-EMPTY:
 ; CHECK-NEXT:  Inst: store i32 %inc.5.i, ptr @b, align 4
-; CHECK-NEXT:  AccessFunction: 0
+; CHECK-NEXT:  AccessFunction: @b
 ; CHECK-NEXT:  failed to delinearize
 ; CHECK-EMPTY:
 ; CHECK-NEXT:  Inst: %15 = load i8, ptr %arrayidx.6.i, align 1
-; CHECK-NEXT:  AccessFunction: (sext i32 {({(6 + (%1 * %2)),+,1}<nw><%for.cond2thread-pre-split.i> + %.pr.i),+,8}<nw><%for.body4.i> to i64)
+; CHECK-NEXT:  AccessFunction: ((sext i32 {({(6 + (%1 * %2)),+,1}<nw><%for.cond2thread-pre-split.i> + %.pr.i),+,8}<nw><%for.body4.i> to i64) + %3)
 ; CHECK-NEXT:  failed to delinearize
 ; CHECK-EMPTY:
 ; CHECK-NEXT:  Inst: store i32 %conv.6.i, ptr @c, align 4
-; CHECK-NEXT:  AccessFunction: 0
+; CHECK-NEXT:  AccessFunction: @c
 ; CHECK-NEXT:  failed to delinearize
 ; CHECK-EMPTY:
 ; CHECK-NEXT:  Inst: store i32 %inc.6.i, ptr @b, align 4
-; CHECK-NEXT:  AccessFunction: 0
+; CHECK-NEXT:  AccessFunction: @b
 ; CHECK-NEXT:  failed to delinearize
 ; CHECK-EMPTY:
 ; CHECK-NEXT:  Inst: %16 = load i8, ptr %arrayidx.7.i, align 1
-; CHECK-NEXT:  AccessFunction: (sext i32 {({(7 + (%1 * %2)),+,1}<nw><%for.cond2thread-pre-split.i> + %.pr.i),+,8}<nw><%for.body4.i> to i64)
+; CHECK-NEXT:  AccessFunction: ((sext i32 {({(7 + (%1 * %2)),+,1}<nw><%for.cond2thread-pre-split.i> + %.pr.i),+,8}<nw><%for.body4.i> to i64) + %3)
 ; CHECK-NEXT:  failed to delinearize
 ; CHECK-EMPTY:
 ; CHECK-NEXT:  Inst: store i32 %conv.7.i, ptr @c, align 4
-; CHECK-NEXT:  AccessFunction: 0
+; CHECK-NEXT:  AccessFunction: @c
 ; CHECK-NEXT:  failed to delinearize
 ; CHECK-EMPTY:
 ; CHECK-NEXT:  Inst: store i32 %inc.7.i, ptr @b, align 4
-; CHECK-NEXT:  AccessFunction: 0
+; CHECK-NEXT:  AccessFunction: @b
 ; CHECK-NEXT:  failed to delinearize
 ; CHECK-EMPTY:
 ; CHECK-NEXT:  Inst: %21 = load i8, ptr %arrayidx.ur.i, align 1
-; CHECK-NEXT:  AccessFunction: (sext i32 {({(%1 * %2),+,1}<nw><%for.cond2thread-pre-split.i> + %.ph),+,1}<nw><%for.body4.ur.i> to i64)
+; CHECK-NEXT:  AccessFunction: ((sext i32 {({(%1 * %2),+,1}<nw><%for.cond2thread-pre-split.i> + %.ph),+,1}<nw><%for.body4.ur.i> to i64) + %3)
 ; CHECK-NEXT:  failed to delinearize
 ; CHECK-EMPTY:
 ; CHECK-NEXT:  Inst: store i32 %conv.ur.i, ptr @c, align 4
-; CHECK-NEXT:  AccessFunction: 0
+; CHECK-NEXT:  AccessFunction: @c
 ; CHECK-NEXT:  failed to delinearize
 ; CHECK-EMPTY:
 ; CHECK-NEXT:  Inst: store i32 %inc.ur.i, ptr @b, align 4
-; CHECK-NEXT:  AccessFunction: 0
+; CHECK-NEXT:  AccessFunction: @b
 ; CHECK-NEXT:  failed to delinearize
 ;
 entry:
diff --git a/llvm/test/Analysis/Delinearization/global_array_bounds.ll b/llvm/test/Analysis/Delinearization/global_array_bounds.ll
new file mode 100644
index 0000000000000..129d9e5ae81de
--- /dev/null
+++ b/llvm/test/Analysis/Delinearization/global_array_bounds.ll
@@ -0,0 +1,54 @@
+; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py UTC_ARGS: --version 5
+; RUN: opt < %s -passes='print<delinearization>' -disable-output 2>&1 | FileCheck %s
+
+; Pseudo-code:
+;
+;   arr[10][20];
+;
+;   for i=0 to 10
+;     for j=0 to 20
+;       a[i][j];  // arr + i*20 + j
+;
+
+ at test_array_10x20 = global [10 x [20 x i32]] zeroinitializer
+
+; Function that accesses a 2D array with dimensions [10][20].
+define void @test_2d_array(i64 %i, i64 %j) {
+; CHECK-LABEL: 'test_2d_array'
+; CHECK-NEXT:  Inst: %val = load i32, ptr %ptr, align 4
+; CHECK-NEXT:  AccessFunction: {{\{\{}}@test_array_10x20,+,80}<nw><%for.i>,+,4}<%for.j>
+; CHECK-NEXT:  Base offset: @test_array_10x20
+; CHECK-NEXT:  ArrayDecl[10][20] with elements of 4 bytes.
+; CHECK-NEXT:  ArrayRef[{0,+,1}<nuw><nsw><%for.i>][{0,+,1}<nuw><nsw><%for.j>]
+;
+entry:
+  %arr = getelementptr inbounds [10 x [20 x i32]], ptr @test_array_10x20, i32 0, i32 0
+  br label %for.i
+
+for.i:                                            ; preds = %for.j.end, %entry
+  %i.cur = phi i64 [ 0, %entry ], [ %i.next, %for.j.end ]
+  %i.cmp = icmp slt i64 %i.cur, 10
+  br i1 %i.cmp, label %for.j, label %exit
+
+for.j:                                            ; preds = %for.j, %for.i
+  %j.cur = phi i64 [ 0, %for.i ], [ %j.next, %for.j ]
+
+  ; Compute linear access: arr[i][j] = arr + i*20 + j
+  %i.mul = mul i64 %i.cur, 20
+  %idx = add i64 %i.mul, %j.cur
+  %ptr = getelementptr inbounds i32, ptr %arr, i64 %idx
+
+  ; Load from the computed address
+  %val = load i32, ptr %ptr, align 4
+
+  %j.next = add i64 %j.cur, 1
+  %j.cmp = icmp slt i64 %j.next, 20
+  br i1 %j.cmp, label %for.j, label %for.j.end
+
+for.j.end:                                        ; preds = %for.j
+  %i.next = add i64 %i.cur, 1
+  br label %for.i
+
+exit:                                             ; preds = %for.i
+  ret void
+}
diff --git a/llvm/test/Analysis/Delinearization/himeno_1.ll b/llvm/test/Analysis/Delinearization/himeno_1.ll
index 8655a257d8b74..2419b0931f752 100644
--- a/llvm/test/Analysis/Delinearization/himeno_1.ll
+++ b/llvm/test/Analysis/Delinearization/himeno_1.ll
@@ -32,11 +32,10 @@
 define void @jacobi(i32 %nn, ptr nocapture %a, ptr nocapture %p) nounwind uwtable {
 ; CHECK-LABEL: 'jacobi'
 ; CHECK-NEXT:  Inst: store float 1.000000e+00, ptr %arrayidx, align 4
-; CHECK-NEXT:  AccessFunction: {{\{\{\{}}(4 + (4 * (sext i32 %a.deps to i64) * (1 + (sext i32 %a.cols to i64))<nsw>)),+,(4 * (sext i32 %a.deps to i64) * (sext i32 %a.cols to i64))}<%for.i>,+,(4 * (sext i32 %a.deps to i64))<nsw>}<%for.j>,+,4}<%for.k>
+; CHECK-NEXT:  AccessFunction: {{\{\{\{}}(4 + (4 * (sext i32 %a.deps to i64) * (1 + (sext i32 %a.cols to i64))<nsw>) + %a.base),+,(4 * (sext i32 %a.deps to i64) * (sext i32 %a.cols to i64))}<%for.i>,+,(4 * (sext i32 %a.deps to i64))<nsw>}<%for.j>,+,4}<%for.k>
 ; CHECK-NEXT:  Base offset: %a.base
 ; CHECK-NEXT:  ArrayDecl[UnknownSize][(sext i32 %a.cols to i64)][(sext i32 %a.deps to i64)] with elements of 4 bytes.
 ; CHECK-NEXT:  ArrayRef[{1,+,1}<nuw><nsw><%for.i>][{1,+,1}<nuw><nsw><%for.j>][{1,+,1}<nuw><nsw><%for.k>]
-; CHECK-NEXT:  Delinearization validation: Failed
 ;
 entry:
   %p.rows.ptr = getelementptr inbounds %struct.Mat, ptr %p, i64 0, i32 2
diff --git a/llvm/test/Analysis/Delinearization/himeno_2.ll b/llvm/test/Analysis/Delinearization/himeno_2.ll
index 21a445eeaf841..a33d8b5fa3068 100644
--- a/llvm/test/Analysis/Delinearization/himeno_2.ll
+++ b/llvm/test/Analysis/Delinearization/himeno_2.ll
@@ -32,11 +32,10 @@
 define void @jacobi(i32 %nn, ptr nocapture %a, ptr nocapture %p) nounwind uwtable {
 ; CHECK-LABEL: 'jacobi'
 ; CHECK-NEXT:  Inst: store float 1.000000e+00, ptr %arrayidx, align 4
-; CHECK-NEXT:  AccessFunction: {{\{\{\{}}(4 + (4 * (sext i32 %a.deps to i64) * (1 + (sext i32 %a.cols to i64))<nsw>)),+,(4 * (sext i32 %a.deps to i64) * (sext i32 %a.cols to i64))}<%for.i>,+,(4 * (sext i32 %a.deps to i64))<nsw>}<%for.j>,+,4}<%for.k>
+; CHECK-NEXT:  AccessFunction: {{\{\{\{}}(4 + (4 * (sext i32 %a.deps to i64) * (1 + (sext i32 %a.cols to i64))<nsw>) + %a.base),+,(4 * (sext i32 %a.deps to i64) * (sext i32 %a.cols to i64))}<%for.i>,+,(4 * (sext i32 %a.deps to i64))<nsw>}<%for.j>,+,4}<%for.k>
 ; CHECK-NEXT:  Base offset: %a.base
 ; CHECK-NEXT:  ArrayDecl[UnknownSize][(sext i32 %a.cols to i64)][(sext i32 %a.deps to i64)] with elements of 4 bytes.
 ; CHECK-NEXT:  ArrayRef[{1,+,1}<nuw><nsw><%for.i>][{1,+,1}<nuw><nsw><%for.j>][{1,+,1}<nuw><nsw><%for.k>]
-; CHECK-NEXT:  Delinearization validation: Failed
 ;
 entry:
   %p.rows.ptr = getelementptr inbounds %struct.Mat, ptr %p, i64 0, i32 2
diff --git a/llvm/test/Analysis/Delinearization/iv_times_constant_in_subscript.ll b/llvm/test/Analysis/Delinearization/iv_times_constant_in_subscript.ll
index da993fc35ce7c..c4bad4a1776bd 100644
--- a/llvm/test/Analysis/Delinearization/iv_times_constant_in_subscript.ll
+++ b/llvm/test/Analysis/Delinearization/iv_times_constant_in_subscript.ll
@@ -12,11 +12,10 @@
 define void @foo(i64 %n, i64 %m, i64 %b, ptr %A) {
 ; CHECK-LABEL: 'foo'
 ; CHECK-NEXT:  Inst: store double 1.000000e+00, ptr %arrayidx, align 8
-; CHECK-NEXT:  AccessFunction: {{\{\{}}(8 * %m * %b),+,(16 * %m)}<%for.i>,+,16}<%for.j>
+; CHECK-NEXT:  AccessFunction: {{\{\{}}((8 * %m * %b) + %A),+,(16 * %m)}<%for.i>,+,16}<%for.j>
 ; CHECK-NEXT:  Base offset: %A
 ; CHECK-NEXT:  ArrayDecl[UnknownSize][%m] with elements of 8 bytes.
 ; CHECK-NEXT:  ArrayRef[{%b,+,2}<nsw><%for.i>][{0,+,2}<nuw><%for.j>]
-; CHECK-NEXT:  Delinearization validation: Failed
 ;
 entry:
   br label %for.i
diff --git a/llvm/test/Analysis/Delinearization/multidim_ivs_and_integer_offsets_3d.ll b/llvm/test/Analysis/Delinearization/multidim_ivs_and_integer_offsets_3d.ll
index c3d21de28fa65..18d4cc0a94bba 100644
--- a/llvm/test/Analysis/Delinearization/multidim_ivs_and_integer_offsets_3d.ll
+++ b/llvm/test/Analysis/Delinearization/multidim_ivs_and_integer_offsets_3d.ll
@@ -12,11 +12,10 @@
 define void @foo(i64 %n, i64 %m, i64 %o, ptr %A) {
 ; CHECK-LABEL: 'foo'
 ; CHECK-NEXT:  Inst: store double 1.000000e+00, ptr %idx, align 8
-; CHECK-NEXT:  AccessFunction: {{\{\{\{}}(56 + (8 * (-4 + (3 * %m)) * %o)),+,(8 * %m * %o)}<%for.i>,+,(8 * %o)}<%for.j>,+,8}<%for.k>
+; CHECK-NEXT:  AccessFunction: {{\{\{\{}}(56 + (8 * (-4 + (3 * %m)) * %o) + %A),+,(8 * %m * %o)}<%for.i>,+,(8 * %o)}<%for.j>,+,8}<%for.k>
 ; CHECK-NEXT:  Base offset: %A
 ; CHECK-NEXT:  ArrayDecl[UnknownSize][%m][%o] with elements of 8 bytes.
 ; CHECK-NEXT:  ArrayRef[{3,+,1}<nuw><%for.i>][{-4,+,1}<nsw><%for.j>][{7,+,1}<nuw><nsw><%for.k>]
-; CHECK-NEXT:  Delinearization validation: Failed
 ;
 entry:
   br label %for.i
diff --git a/llvm/test/Analysis/Delinearization/multidim_ivs_and_integer_offsets_nts_3d.ll b/llvm/test/Analysis/Delinearization/multidim_ivs_and_integer_offsets_nts_3d.ll
index 96ea88df56a9f..c810852803b92 100644
--- a/llvm/test/Analysis/Delinearization/multidim_ivs_and_integer_offsets_nts_3d.ll
+++ b/llvm/test/Analysis/Delinearization/multidim_ivs_and_integer_offsets_nts_3d.ll
@@ -12,11 +12,10 @@
 define void @foo(i64 %n, i64 %m, i64 %o, i64 %p, ptr nocapture %A) nounwind uwtable {
 ; CHECK-LABEL: 'foo'
 ; CHECK-NEXT:  Inst: store double 1.000000e+00, ptr %arrayidx10.us.us, align 8
-; CHECK-NEXT:  AccessFunction: {{\{\{\{}}(56 + (8 * (-4 + (3 * %m)) * (%o + %p))),+,(8 * (%o + %p) * %m)}<%for.cond4.preheader.lr.ph.us>,+,(8 * (%o + %p))}<%for.body6.lr.ph.us.us>,+,8}<%for.body6.us.us>
+; CHECK-NEXT:  AccessFunction: {{\{\{\{}}(56 + (8 * (-4 + (3 * %m)) * (%o + %p)) + %A),+,(8 * (%o + %p) * %m)}<%for.cond4.preheader.lr.ph.us>,+,(8 * (%o + %p))}<%for.body6.lr.ph.us.us>,+,8}<%for.body6.us.us>
 ; CHECK-NEXT:  Base offset: %A
 ; CHECK-NEXT:  ArrayDecl[UnknownSize][%m][(%o + %p)] with elements of 8 bytes.
 ; CHECK-NEXT:  ArrayRef[{3,+,1}<nuw><%for.cond4.preheader.lr.ph.us>][{-4,+,1}<nw><%for.body6.lr.ph.us.us>][{7,+,1}<nw><%for.body6.us.us>]
-; CHECK-NEXT:  Delinearization validation: Failed
 ;
 entry:
   %add = add nsw i64 %p, %o
diff --git a/llvm/test/Analysis/Delinearization/multidim_ivs_and_parameteric_offsets_3d.ll b/llvm/test/Analysis/Delinearization/multidim_ivs_and_parameteric_offsets_3d.ll
index 4d95e2f117e6a..2f7df5da7cdd4 100644
--- a/llvm/test/Analysis/Delinearization/multidim_ivs_and_parameteric_offsets_3d.ll
+++ b/llvm/test/Analysis/Delinearization/multidim_ivs_and_parameteric_offsets_3d.ll
@@ -12,11 +12,10 @@
 define void @foo(i64 %n, i64 %m, i64 %o, ptr %A, i64 %p, i64 %q, i64 %r) {
 ; CHECK-LABEL: 'foo'
 ; CHECK-NEXT:  Inst: store double 1.000000e+00, ptr %idx, align 8
-; CHECK-NEXT:  AccessFunction: {{\{\{\{}}(8 * ((((%m * %p) + %q) * %o) + %r)),+,(8 * %m * %o)}<%for.i>,+,(8 * %o)}<%for.j>,+,8}<%for.k>
+; CHECK-NEXT:  AccessFunction: {{\{\{\{}}((8 * ((((%m * %p) + %q) * %o) + %r)) + %A),+,(8 * %m * %o)}<%for.i>,+,(8 * %o)}<%for.j>,+,8}<%for.k>
 ; CHECK-NEXT:  Base offset: %A
 ; CHECK-NEXT:  ArrayDecl[UnknownSize][%m][%o] with elements of 8 bytes.
 ; CHECK-NEXT:  ArrayRef[{%p,+,1}<nw><%for.i>][{%q,+,1}<nsw><%for.j>][{%r,+,1}<nsw><%for.k>]
-; CHECK-NEXT:  Delinearization validation: Failed
 ;
 entry:
   br label %for.i
diff --git a/llvm/test/Analysis/Delinearization/multidim_only_ivs_2d.ll b/llvm/test/Analysis/Delinearization/multidim_only_ivs_2d.ll
index e5d2806101926..5fe0eac04c9b9 100644
--- a/llvm/test/Analysis/Delinearization/multidim_only_ivs_2d.ll
+++ b/llvm/test/Analysis/Delinearization/multidim_only_ivs_2d.ll
@@ -12,18 +12,16 @@
 define void @foo(i64 %n, i64 %m, ptr %A) {
 ; CHECK-LABEL: 'foo'
 ; CHECK-NEXT:  Inst: %val = load double, ptr %arrayidx, align 8
-; CHECK-NEXT:  AccessFunction: {{\{\{}}0,+,(8 * %m)}<%for.i>,+,8}<%for.j>
+; CHECK-NEXT:  AccessFunction: {{\{\{}}%A,+,(8 * %m)}<%for.i>,+,8}<%for.j>
 ; CHECK-NEXT:  Base offset: %A
 ; CHECK-NEXT:  ArrayDecl[UnknownSize][%m] with elements of 8 bytes.
 ; CHECK-NEXT:  ArrayRef[{0,+,1}<nuw><nsw><%for.i>][{0,+,1}<nuw><nsw><%for.j>]
-; CHECK-NEXT:  Delinearization validation: Failed
 ; CHECK-EMPTY:
 ; CHECK-NEXT:  Inst: store double %val, ptr %arrayidx, align 8
-; CHECK-NEXT:  AccessFunction: {{\{\{}}0,+,(8 * %m)}<%for.i>,+,8}<%for.j>
+; CHECK-NEXT:  AccessFunction: {{\{\{}}%A,+,(8 * %m)}<%for.i>,+,8}<%for.j>
 ; CHECK-NEXT:  Base offset: %A
 ; CHECK-NEXT:  ArrayDecl[UnknownSize][%m] with elements of 8 bytes.
 ; CHECK-NEXT:  ArrayRef[{0,+,1}<nuw><nsw><%for.i>][{0,+,1}<nuw><nsw><%for.j>]
-; CHECK-NEXT:  Delinearization validation: Failed
 ;
 entry:
   br label %for.i
diff --git a/llvm/test/Analysis/Delinearization/multidim_only_ivs_2d_nested.ll b/llvm/test/Analysis/Delinearization/multidim_only_ivs_2d_nested.ll
index c7a2a89e3183d..7392ed8086816 100644
--- a/llvm/test/Analysis/Delinearization/multidim_only_ivs_2d_nested.ll
+++ b/llvm/test/Analysis/Delinearization/multidim_only_ivs_2d_nested.ll
@@ -18,7 +18,7 @@
 define void @foo(i64 %a, i64 %b) nounwind uwtable {
 ; CHECK-LABEL: 'foo'
 ; CHECK-NEXT:  Inst: store double 1.000000e+00, ptr %arrayidx10.us.us, align 8
-; CHECK-NEXT:  AccessFunction: {{\{\{}}0,+,{8,+,8}<%for.cond7.preheader.lr.ph.split.us.us>}<%for.body9.lr.ph.us.us>,+,8}<%for.body9.us.us>
+; CHECK-NEXT:  AccessFunction: {{\{\{}}%vla.us,+,{8,+,8}<%for.cond7.preheader.lr.ph.split.us.us>}<%for.body9.lr.ph.us.us>,+,8}<%for.body9.us.us>
 ; CHECK-NEXT:  failed to delinearize
 ;
 entry:
diff --git a/llvm/test/Analysis/Delinearization/multidim_only_ivs_3d.ll b/llvm/test/Analysis/Delinearization/multidim_only_ivs_3d.ll
index f5f0628ede937..67a8977e2e7d4 100644
--- a/llvm/test/Analysis/Delinearization/multidim_only_ivs_3d.ll
+++ b/llvm/test/Analysis/Delinearization/multidim_only_ivs_3d.ll
@@ -12,11 +12,10 @@
 define void @foo(i64 %n, i64 %m, i64 %o, ptr %A) {
 ; CHECK-LABEL: 'foo'
 ; CHECK-NEXT:  Inst: store double 1.000000e+00, ptr %idx, align 8
-; CHECK-NEXT:  AccessFunction: {{\{\{\{}}0,+,(8 * %m * %o)}<%for.i>,+,(8 * %o)}<%for.j>,+,8}<%for.k>
+; CHECK-NEXT:  AccessFunction: {{\{\{\{}}%A,+,(8 * %m * %o)}<%for.i>,+,(8 * %o)}<%for.j>,+,8}<%for.k>
 ; CHECK-NEXT:  Base offset: %A
 ; CHECK-NEXT:  ArrayDecl[UnknownSize][%m][%o] with elements of 8 bytes.
 ; CHECK-NEXT:  ArrayRef[{0,+,1}<nuw><nsw><%for.i>][{0,+,1}<nuw><nsw><%for.j>][{0,+,1}<nuw><nsw><%for.k>]
-; CHECK-NEXT:  Delinearization validation: Failed
 ;
 entry:
   br label %for.i
diff --git a/llvm/test/Analysis/Delinearization/multidim_only_ivs_3d_cast.ll b/llvm/test/Analysis/Delinearization/multidim_only_ivs_3d_cast.ll
index 1dae34f785be4..5eb8d6146634a 100644
--- a/llvm/test/Analysis/Delinearization/multidim_only_ivs_3d_cast.ll
+++ b/llvm/test/Analysis/Delinearization/multidim_only_ivs_3d_cast.ll
@@ -14,11 +14,10 @@ target triple = "x86_64-unknown-linux-gnu"
 define void @foo(i32 %n, i32 %m, i32 %o, ptr %A) {
 ; CHECK-LABEL: 'foo'
 ; CHECK-NEXT:  Inst: store double 1.000000e+00, ptr %idx, align 8
-; CHECK-NEXT:  AccessFunction: {{\{\{\{}}0,+,(8 * (zext i32 %m to i64) * (zext i32 %o to i64))}<%for.i>,+,(8 * (zext i32 %o to i64))<nuw><nsw>}<%for.j>,+,8}<%for.k>
+; CHECK-NEXT:  AccessFunction: {{\{\{\{}}%A,+,(8 * (zext i32 %m to i64) * (zext i32 %o to i64))}<%for.i>,+,(8 * (zext i32 %o to i64))<nuw><nsw>}<%for.j>,+,8}<%for.k>
 ; CHECK-NEXT:  Base offset: %A
 ; CHECK-NEXT:  ArrayDecl[UnknownSize][(zext i32 %m to i64)][(zext i32 %o to i64)] with elements of 8 bytes.
 ; CHECK-NEXT:  ArrayRef[{0,+,1}<nuw><nsw><%for.i>][{0,+,1}<nuw><nsw><%for.j>][{0,+,1}<nuw><nsw><%for.k>]
-; CHECK-NEXT:  Delinearization validation: Failed
 ;
 entry:
   %m_zext = zext i32 %m to i64
diff --git a/llvm/test/Analysis/Delinearization/multidim_two_accesses_different_delinearization.ll b/llvm/test/Analysis/Delinearization/multidim_two_accesses_different_delinearization.ll
index f768002dd9e41..bb483c3f8352e 100644
--- a/llvm/test/Analysis/Delinearization/multidim_two_accesses_different_delinearization.ll
+++ b/llvm/test/Analysis/Delinearization/multidim_two_accesses_different_delinearization.ll
@@ -15,18 +15,16 @@ target triple = "x86_64-unknown-linux-gnu"
 define void @foo(i64 %n, i64 %m, ptr %A) {
 ; CHECK-LABEL: 'foo'
 ; CHECK-NEXT:  Inst: store double 1.000000e+00, ptr %arrayidx, align 8
-; CHECK-NEXT:  AccessFunction: {{\{\{}}0,+,(8 * %m)}<%for.i>,+,8}<%for.j>
+; CHECK-NEXT:  AccessFunction: {{\{\{}}%A,+,(8 * %m)}<%for.i>,+,8}<%for.j>
 ; CHECK-NEXT:  Base offset: %A
 ; CHECK-NEXT:  ArrayDecl[UnknownSize][%m] with elements of 8 bytes.
 ; CHECK-NEXT:  ArrayRef[{0,+,1}<nuw><nsw><%for.i>][{0,+,1}<nuw><nsw><%for.j>]
-; CHECK-NEXT:  Delinearization validation: Failed
 ; CHECK-EMPTY:
 ; CHECK-NEXT:  Inst: store double 1.000000e+00, ptr %arrayidx1, align 8
-; CHECK-NEXT:  AccessFunction: {{\{\{}}0,+,8}<%for.i>,+,(8 * %n)}<%for.j>
+; CHECK-NEXT:  AccessFunction: {{\{\{}}%A,+,8}<%for.i>,+,(8 * %n)}<%for.j>
 ; CHECK-NEXT:  Base offset: %A
 ; CHECK-NEXT:  ArrayDecl[UnknownSize][%n] with elements of 8 bytes.
 ; CHECK-NEXT:  ArrayRef[{0,+,1}<nuw><nsw><%for.j>][{0,+,1}<nuw><nsw><%for.i>]
-; CHECK-NEXT:  Delinearization validation: Failed
 ;
 entry:
   br label %for.i
diff --git a/llvm/test/Analysis/Delinearization/parameter_addrec_product.ll b/llvm/test/Analysis/Delinearization/parameter_addrec_product.ll
index 4ef29701bdf49..491f0a859af71 100644
--- a/llvm/test/Analysis/Delinearization/parameter_addrec_product.ll
+++ b/llvm/test/Analysis/Delinearization/parameter_addrec_product.ll
@@ -11,22 +11,20 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
 define void @foo(ptr %A, ptr %p) {
 ; CHECK-LABEL: 'foo'
 ; CHECK-NEXT:  Inst: %pval = load i64, ptr %p, align 8
-; CHECK-NEXT:  AccessFunction: 0
+; CHECK-NEXT:  AccessFunction: %p
 ; CHECK-NEXT:  failed to delinearize
 ; CHECK-EMPTY:
 ; CHECK-NEXT:  Inst: %tmp11 = load float, ptr %tmp10, align 4
-; CHECK-NEXT:  AccessFunction: (4 * (({0,+,1}<nuw><nsw><%bb2> * %pval)<nsw> + {0,+,1}<nuw><nsw><%bb4>)<nsw>)<nsw>
+; CHECK-NEXT:  AccessFunction: ((4 * (({0,+,1}<nuw><nsw><%bb2> * %pval)<nsw> + {0,+,1}<nuw><nsw><%bb4>)<nsw>)<nsw> + %A)
 ; CHECK-NEXT:  Base offset: %A
 ; CHECK-NEXT:  ArrayDecl[UnknownSize][%pval] with elements of 4 bytes.
 ; CHECK-NEXT:  ArrayRef[{0,+,1}<nuw><nsw><%bb2>][{0,+,1}<nuw><nsw><%bb4>]
-; CHECK-NEXT:  Delinearization validation: Failed
 ; CHECK-EMPTY:
 ; CHECK-NEXT:  Inst: store float %tmp12, ptr %tmp10, align 4
-; CHECK-NEXT:  AccessFunction: (4 * (({0,+,1}<nuw><nsw><%bb2> * %pval)<nsw> + {0,+,1}<nuw><nsw><%bb4>)<nsw>)<nsw>
+; CHECK-NEXT:  AccessFunction: ((4 * (({0,+,1}<nuw><nsw><%bb2> * %pval)<nsw> + {0,+,1}<nuw><nsw><%bb4>)<nsw>)<nsw> + %A)
 ; CHECK-NEXT:  Base offset: %A
 ; CHECK-NEXT:  ArrayDecl[UnknownSize][%pval] with elements of 4 bytes.
 ; CHECK-NEXT:  ArrayRef[{0,+,1}<nuw><nsw><%bb2>][{0,+,1}<nuw><nsw><%bb4>]
-; CHECK-NEXT:  Delinearization validation: Failed
 ;
 bb:
   br label %bb2
diff --git a/llvm/test/Analysis/Delinearization/terms_with_identity_factor.ll b/llvm/test/Analysis/Delinearization/terms_with_identity_factor.ll
index 323cce3dff05b..3d60f2e82c19f 100644
--- a/llvm/test/Analysis/Delinearization/terms_with_identity_factor.ll
+++ b/llvm/test/Analysis/Delinearization/terms_with_identity_factor.ll
@@ -9,18 +9,16 @@
 define void @foo(i32 %m, i32 %n, ptr nocapture %A) #0 {
 ; CHECK-LABEL: 'foo'
 ; CHECK-NEXT:  Inst: %4 = load i8, ptr %arrayidx.us, align 1
-; CHECK-NEXT:  AccessFunction: {{\{\{}}0,+,(sext i32 %n to i64)}<nsw><%for.body3.lr.ph.us>,+,1}<nsw><%for.body3.us>
+; CHECK-NEXT:  AccessFunction: {{\{\{}}%A,+,(sext i32 %n to i64)}<nw><%for.body3.lr.ph.us>,+,1}<nw><%for.body3.us>
 ; CHECK-NEXT:  Base offset: %A
 ; CHECK-NEXT:  ArrayDecl[UnknownSize][(sext i32 %n to i64)] with elements of 1 bytes.
 ; CHECK-NEXT:  ArrayRef[{0,+,1}<nuw><nsw><%for.body3.lr.ph.us>][{0,+,1}<nuw><nsw><%for.body3.us>]
-; CHECK-NEXT:  Delinearization validation: Failed
 ; CHECK-EMPTY:
 ; CHECK-NEXT:  Inst: store i8 %add4.us, ptr %arrayidx.us, align 1
-; CHECK-NEXT:  AccessFunction: {{\{\{}}0,+,(sext i32 %n to i64)}<nsw><%for.body3.lr.ph.us>,+,1}<nsw><%for.body3.us>
+; CHECK-NEXT:  AccessFunction: {{\{\{}}%A,+,(sext i32 %n to i64)}<nw><%for.body3.lr.ph.us>,+,1}<nw><%for.body3.us>
 ; CHECK-NEXT:  Base offset: %A
 ; CHECK-NEXT:  ArrayDecl[UnknownSize][(sext i32 %n to i64)] with elements of 1 bytes.
 ; CHECK-NEXT:  ArrayRef[{0,+,1}<nuw><nsw><%for.body3.lr.ph.us>][{0,+,1}<nuw><nsw><%for.body3.us>]
-; CHECK-NEXT:  Delinearization validation: Failed
 ;
 entry:
   br label %entry.split
diff --git a/llvm/test/Analysis/Delinearization/type_mismatch.ll b/llvm/test/Analysis/Delinearization/type_mismatch.ll
index 6d344975daf92..db55263dd6c1e 100644
--- a/llvm/test/Analysis/Delinearization/type_mismatch.ll
+++ b/llvm/test/Analysis/Delinearization/type_mismatch.ll
@@ -12,7 +12,7 @@ target datalayout = "e-m:e-p:32:32-i64:64-a:0-v32:32-n16:32"
 define fastcc void @test(i1 %arg, ptr %x) {
 ; CHECK-LABEL: 'test'
 ; CHECK-NEXT:  Inst: store i8 42, ptr %arrayidx.phi, align 1
-; CHECK-NEXT:  AccessFunction: 0
+; CHECK-NEXT:  AccessFunction: %arrayidx.phi
 ; CHECK-NEXT:  failed to delinearize
 ;
 entry:
diff --git a/llvm/test/Analysis/Delinearization/validation_large_size.ll b/llvm/test/Analysis/Delinearization/validation_large_size.ll
index ad36d84b8d914..86ab71b29e82c 100644
--- a/llvm/test/Analysis/Delinearization/validation_large_size.ll
+++ b/llvm/test/Analysis/Delinearization/validation_large_size.ll
@@ -22,11 +22,8 @@
 define void @large_size_fixed(ptr %A) {
 ; CHECK-LABEL: 'large_size_fixed'
 ; CHECK-NEXT:  Inst: store i8 0, ptr %gep, align 1
-; CHECK-NEXT:  AccessFunction: {{\{\{}}0,+,256}<%for.i.header>,+,1}<nsw><%for.j>
-; CHECK-NEXT:  Base offset: %A
-; CHECK-NEXT:  ArrayDecl[UnknownSize][256] with elements of 1 bytes.
-; CHECK-NEXT:  ArrayRef[{0,+,1}<nuw><nsw><%for.i.header>][{0,+,1}<nuw><nsw><%for.j>]
-; CHECK-NEXT:  Delinearization validation: Failed
+; CHECK-NEXT:  AccessFunction: {{\{\{}}%A,+,256}<%for.i.header>,+,1}<nw><%for.j>
+; CHECK-NEXT:  failed to delinearize
 ;
 entry:
   br label %for.i.header
@@ -74,11 +71,10 @@ exit:
 define void @large_size_parametric(i64 %n, i64 %m, i64 %o, ptr %A) {
 ; CHECK-LABEL: 'large_size_parametric'
 ; CHECK-NEXT:  Inst: store i8 0, ptr %gep, align 1
-; CHECK-NEXT:  AccessFunction: {{\{\{\{}}0,+,(%m * %o)}<%for.i.header>,+,%o}<%for.j.header>,+,1}<nw><%for.k.header>
+; CHECK-NEXT:  AccessFunction: {{\{\{\{}}%A,+,(%m * %o)}<%for.i.header>,+,%o}<%for.j.header>,+,1}<nw><%for.k.header>
 ; CHECK-NEXT:  Base offset: %A
 ; CHECK-NEXT:  ArrayDecl[UnknownSize][%m][%o] with elements of 1 bytes.
 ; CHECK-NEXT:  ArrayRef[{0,+,1}<nuw><nsw><%for.i.header>][{0,+,1}<nuw><nsw><%for.j.header>][{0,+,1}<nuw><nsw><%for.k.header>]
-; CHECK-NEXT:  Delinearization validation: Failed
 ;
 entry:
   %guard.i = icmp sgt i64 %n, 0
@@ -147,11 +143,8 @@ exit:
 define void @elementsize_cause_ovfl(ptr %A) {
 ; CHECK-LABEL: 'elementsize_cause_ovfl'
 ; CHECK-NEXT:  Inst: store i64 0, ptr %gep, align 4
-; CHECK-NEXT:  AccessFunction: {{\{\{}}0,+,2048}<%for.i.header>,+,8}<%for.j>
-; CHECK-NEXT:  Base offset: %A
-; CHECK-NEXT:  ArrayDecl[UnknownSize][256] with elements of 8 bytes.
-; CHECK-NEXT:  ArrayRef[{0,+,1}<nuw><nsw><%for.i.header>][{0,+,1}<nuw><nsw><%for.j>]
-; CHECK-NEXT:  Delinearization validation: Failed
+; CHECK-NEXT:  AccessFunction: {{\{\{}}%A,+,2048}<%for.i.header>,+,8}<%for.j>
+; CHECK-NEXT:  failed to delinearize
 ;
 entry:
   br label %for.i.header



More information about the llvm-commits mailing list