[llvm] [DA] batch delinearization for fixed-size arrays (PR #170519)

Sebastian Pop via llvm-commits llvm-commits at lists.llvm.org
Thu Jan 8 11:37:10 PST 2026


https://github.com/sebpop updated https://github.com/llvm/llvm-project/pull/170519

>From 38c61438bf787cd684b7664d3e865038176de7fb Mon Sep 17 00:00:00 2001
From: Sebastian Pop <spop at nvidia.com>
Date: Fri, 5 Dec 2025 16:56:39 -0600
Subject: [PATCH] [DA] Add BatchDelinearizationAnalysis for fixed-size arrays

Add a pass manager analysis that caches fixed-size array delinearization
results for DependenceAnalysis. Delinearization is performed lazily on
first query for each instruction. Parametric delinearization remains
pairwise. DependenceInfo is added to LoopStandardAnalysisResults for
loop passes (DDG, LoopInterchange, LoopUnrollAndJam).
---
 llvm/include/llvm/Analysis/Delinearization.h  |  53 +++++++
 .../llvm/Analysis/DependenceAnalysis.h        |   7 +-
 .../llvm/Analysis/LoopAnalysisManager.h       |   2 +
 llvm/lib/Analysis/DDG.cpp                     |   4 +-
 llvm/lib/Analysis/Delinearization.cpp         |  70 +++++++++
 llvm/lib/Analysis/DependenceAnalysis.cpp      |  22 ++-
 llvm/lib/Passes/PassRegistry.def              |   1 +
 .../lib/Transforms/Scalar/LoopInterchange.cpp |   3 +-
 .../lib/Transforms/Scalar/LoopPassManager.cpp |   2 +
 .../Scalar/LoopUnrollAndJamPass.cpp           |   5 +-
 .../Analysis/DependenceAnalysis/Banerjee.ll   |  22 +--
 .../BatchDelinearization.ll                   | 147 ++++++++++++++++++
 .../DependenceAnalysis/Constraints.ll         |  14 +-
 .../DependenceAnalysis/DifferentOffsets.ll    |   2 +-
 llvm/test/Analysis/DependenceAnalysis/GCD.ll  |  20 +--
 .../Analysis/DependenceAnalysis/Invariant.ll  |   7 +-
 .../NonCanonicalizedSubscript.ll              |   2 +-
 .../DependenceAnalysis/Preliminary.ll         |   6 +-
 .../PreliminaryNoValidityCheckFixedSize.ll    |   6 +-
 .../DependenceAnalysis/Propagating.ll         |  14 +-
 .../DependenceAnalysis/new-pm-invalidation.ll |  16 +-
 llvm/test/Transforms/LICM/lnicm.ll            |  34 ++--
 .../loop-interchange-optimization-remarks.ll  |  22 ++-
 .../LoopInterchange/outer-dependency-lte.ll   |   2 +-
 llvm/test/Transforms/LoopRotate/pr35210.ll    |   8 +
 .../nontrivial-unswitch-markloopasdeleted.ll  |   2 +
 26 files changed, 396 insertions(+), 97 deletions(-)
 create mode 100644 llvm/test/Analysis/DependenceAnalysis/BatchDelinearization.ll

diff --git a/llvm/include/llvm/Analysis/Delinearization.h b/llvm/include/llvm/Analysis/Delinearization.h
index d48b57cc4284f..ff07e841e3b6b 100644
--- a/llvm/include/llvm/Analysis/Delinearization.h
+++ b/llvm/include/llvm/Analysis/Delinearization.h
@@ -16,16 +16,23 @@
 #ifndef LLVM_ANALYSIS_DELINEARIZATION_H
 #define LLVM_ANALYSIS_DELINEARIZATION_H
 
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
 #include "llvm/IR/PassManager.h"
 #include "llvm/IR/Value.h"
+#include "llvm/Support/Compiler.h"
 
 namespace llvm {
+class Function;
 class raw_ostream;
 template <typename T> class SmallVectorImpl;
 class GetElementPtrInst;
 class Instruction;
+class LoopInfo;
 class ScalarEvolution;
 class SCEV;
+class SCEVUnknown;
 
 /// Compute the array dimensions Sizes from the set of Terms extracted from
 /// the memory access function of this SCEVAddRecExpr (second step of
@@ -162,6 +169,52 @@ bool getIndexExpressionsFromGEP(ScalarEvolution &SE,
                                 SmallVectorImpl<const SCEV *> &Subscripts,
                                 SmallVectorImpl<const SCEV *> &Sizes);
 
+/// BatchDelinearization - A wrapper for batch delinearization that caches
+/// results across multiple queries. Similar to BatchAAResults, this class
+/// should be used when analyzing multiple memory accesses that can be
+/// delinearized as fixed-size arrays.
+///
+/// This class lazily delinearizes memory accesses on demand and caches the
+/// results for efficient lookups during dependence analysis.
+class LLVM_ABI BatchDelinearization {
+public:
+  BatchDelinearization(ScalarEvolution &SE, LoopInfo &LI) : SE(SE), LI(LI) {}
+
+  /// Handle invalidation events in the new pass manager.
+  bool invalidate(Function &F, const PreservedAnalyses &PA,
+                  FunctionAnalysisManager::Invalidator &Inv);
+
+  /// Get the cached subscripts for an instruction.
+  /// Lazily computes and caches the result on first query for each instruction.
+  /// Returns nullptr if delinearization fails or is not applicable.
+  const SmallVector<const SCEV *, 4> *getSubscripts(Instruction *I);
+
+private:
+  ScalarEvolution &SE;
+  LoopInfo &LI;
+
+  /// Map from instruction to computed subscripts.
+  SmallDenseMap<Instruction *, SmallVector<const SCEV *, 4>, 16> Subscripts;
+
+  /// Track instructions we've already attempted to delinearize (to avoid
+  /// retrying failed ones).
+  SmallPtrSet<Instruction *, 16> Attempted;
+};
+
+/// Analysis pass that computes BatchDelinearization for a function.
+/// This enables the pass manager to cache and automatically invalidate
+/// the delinearization results.
+class BatchDelinearizationAnalysis
+    : public AnalysisInfoMixin<BatchDelinearizationAnalysis> {
+  friend AnalysisInfoMixin<BatchDelinearizationAnalysis>;
+  LLVM_ABI static AnalysisKey Key;
+
+public:
+  using Result = BatchDelinearization;
+
+  LLVM_ABI BatchDelinearization run(Function &F, FunctionAnalysisManager &AM);
+};
+
 struct DelinearizationPrinterPass
     : public PassInfoMixin<DelinearizationPrinterPass> {
   explicit DelinearizationPrinterPass(raw_ostream &OS);
diff --git a/llvm/include/llvm/Analysis/DependenceAnalysis.h b/llvm/include/llvm/Analysis/DependenceAnalysis.h
index 6dec24fc9f104..af74678bcb87e 100644
--- a/llvm/include/llvm/Analysis/DependenceAnalysis.h
+++ b/llvm/include/llvm/Analysis/DependenceAnalysis.h
@@ -49,6 +49,7 @@
 namespace llvm {
 class AAResults;
 template <typename T> class ArrayRef;
+class BatchDelinearization;
 class Loop;
 class LoopInfo;
 class SCEVConstant;
@@ -335,8 +336,9 @@ class LLVM_ABI FullDependence final : public Dependence {
 /// DependenceInfo - This class is the main dependence-analysis driver.
 class DependenceInfo {
 public:
-  DependenceInfo(Function *F, AAResults *AA, ScalarEvolution *SE, LoopInfo *LI)
-      : AA(AA), SE(SE), LI(LI), F(F) {}
+  DependenceInfo(Function *F, AAResults *AA, ScalarEvolution *SE, LoopInfo *LI,
+                 BatchDelinearization *BD = nullptr)
+      : AA(AA), SE(SE), LI(LI), F(F), BatchDelin(BD) {}
 
   /// Handle transitive invalidation when the cached analysis results go away.
   LLVM_ABI bool invalidate(Function &F, const PreservedAnalyses &PA,
@@ -360,6 +362,7 @@ class DependenceInfo {
   ScalarEvolution *SE;
   LoopInfo *LI;
   Function *F;
+  BatchDelinearization *BatchDelin;
 
   /// Subscript - This private struct represents a pair of subscripts from
   /// a pair of potentially multi-dimensional array references. We use a
diff --git a/llvm/include/llvm/Analysis/LoopAnalysisManager.h b/llvm/include/llvm/Analysis/LoopAnalysisManager.h
index 1c09889b80064..031e4da7a6cb0 100644
--- a/llvm/include/llvm/Analysis/LoopAnalysisManager.h
+++ b/llvm/include/llvm/Analysis/LoopAnalysisManager.h
@@ -36,6 +36,7 @@ namespace llvm {
 
 class AAResults;
 class AssumptionCache;
+class DependenceInfo;
 class DominatorTree;
 class Function;
 class Loop;
@@ -57,6 +58,7 @@ struct LoopStandardAnalysisResults {
   ScalarEvolution &SE;
   TargetLibraryInfo &TLI;
   TargetTransformInfo &TTI;
+  DependenceInfo *DI;
   MemorySSA *MSSA;
 };
 
diff --git a/llvm/lib/Analysis/DDG.cpp b/llvm/lib/Analysis/DDG.cpp
index 0907a7fb021fc..d3a1c8e25314a 100644
--- a/llvm/lib/Analysis/DDG.cpp
+++ b/llvm/lib/Analysis/DDG.cpp
@@ -307,9 +307,7 @@ bool DDGBuilder::shouldCreatePiBlocks() const { return CreatePiBlocks; }
 /// DDG as a loop pass.
 DDGAnalysis::Result DDGAnalysis::run(Loop &L, LoopAnalysisManager &AM,
                                      LoopStandardAnalysisResults &AR) {
-  Function *F = L.getHeader()->getParent();
-  DependenceInfo DI(F, &AR.AA, &AR.SE, &AR.LI);
-  return std::make_unique<DataDependenceGraph>(L, AR.LI, DI);
+  return std::make_unique<DataDependenceGraph>(L, AR.LI, *AR.DI);
 }
 AnalysisKey DDGAnalysis::Key;
 
diff --git a/llvm/lib/Analysis/Delinearization.cpp b/llvm/lib/Analysis/Delinearization.cpp
index 4263c6f49993e..d441742b7d592 100644
--- a/llvm/lib/Analysis/Delinearization.cpp
+++ b/llvm/lib/Analysis/Delinearization.cpp
@@ -880,3 +880,73 @@ PreservedAnalyses DelinearizationPrinterPass::run(Function &F,
                        &AM.getResult<ScalarEvolutionAnalysis>(F));
   return PreservedAnalyses::all();
 }
+
+/// Return true for a Load or Store instruction.
+static bool isLoadOrStore(const Instruction *I) {
+  return isa<LoadInst>(I) || isa<StoreInst>(I);
+}
+
+const SmallVector<const SCEV *, 4> *
+BatchDelinearization::getSubscripts(Instruction *I) {
+  // Check cache first.
+  auto It = Subscripts.find(I);
+  if (It != Subscripts.end())
+    return &It->second;
+
+  // Already tried and failed?
+  if (Attempted.contains(I))
+    return nullptr;
+
+  Attempted.insert(I);
+
+  // Only handle loads and stores.
+  if (!isLoadOrStore(I))
+    return nullptr;
+
+  Value *Ptr = getLoadStorePointerOperand(I);
+  Loop *L = LI.getLoopFor(I->getParent());
+  const SCEV *AccessFn = SE.getSCEVAtScope(Ptr, L);
+  const SCEVUnknown *Base = dyn_cast<SCEVUnknown>(SE.getPointerBase(AccessFn));
+
+  if (!Base)
+    return nullptr;
+
+  // Only consider accesses where the base is loop invariant.
+  if (L && !SE.isLoopInvariant(Base, L))
+    return nullptr;
+
+  const SCEV *ElemSize = SE.getElementSize(I);
+  SmallVector<const SCEV *, 4> Subs, Sizes;
+
+  if (delinearizeFixedSizeArray(SE, SE.removePointerBase(AccessFn), Subs, Sizes,
+                                ElemSize) &&
+      Subs.size() >= 2) {
+    Subscripts[I] = std::move(Subs);
+    return &Subscripts[I];
+  }
+
+  return nullptr;
+}
+
+bool BatchDelinearization::invalidate(
+    Function &F, const PreservedAnalyses &PA,
+    FunctionAnalysisManager::Invalidator &Inv) {
+  // Invalidate if ScalarEvolution or LoopInfo are invalidated.
+  // Check dependencies first - if SE or LI are invalidated, we must invalidate.
+  if (Inv.invalidate<ScalarEvolutionAnalysis>(F, PA) ||
+      Inv.invalidate<LoopAnalysis>(F, PA))
+    return true;
+
+  // If our dependencies are preserved, check if we're explicitly preserved.
+  auto PAC = PA.getChecker<BatchDelinearizationAnalysis>();
+  return !(PAC.preserved() || PAC.preservedSet<AllAnalysesOn<Function>>());
+}
+
+AnalysisKey BatchDelinearizationAnalysis::Key;
+
+BatchDelinearization
+BatchDelinearizationAnalysis::run(Function &F, FunctionAnalysisManager &AM) {
+  auto &SE = AM.getResult<ScalarEvolutionAnalysis>(F);
+  auto &LI = AM.getResult<LoopAnalysis>(F);
+  return BatchDelinearization(SE, LI);
+}
diff --git a/llvm/lib/Analysis/DependenceAnalysis.cpp b/llvm/lib/Analysis/DependenceAnalysis.cpp
index 23820853e6fee..49f52e4309831 100644
--- a/llvm/lib/Analysis/DependenceAnalysis.cpp
+++ b/llvm/lib/Analysis/DependenceAnalysis.cpp
@@ -175,7 +175,8 @@ DependenceAnalysis::run(Function &F, FunctionAnalysisManager &FAM) {
   auto &AA = FAM.getResult<AAManager>(F);
   auto &SE = FAM.getResult<ScalarEvolutionAnalysis>(F);
   auto &LI = FAM.getResult<LoopAnalysis>(F);
-  return DependenceInfo(&F, &AA, &SE, &LI);
+  auto &BD = FAM.getResult<BatchDelinearizationAnalysis>(F);
+  return DependenceInfo(&F, &AA, &SE, &LI, &BD);
 }
 
 AnalysisKey DependenceAnalysis::Key;
@@ -3360,6 +3361,19 @@ bool DependenceInfo::tryDelinearizeFixedSize(
            "expected src and dst scev unknowns to be equal");
   });
 
+  // Try to use cached subscripts from BatchDelinearization.
+  if (BatchDelin) {
+    const auto *SrcSubs = BatchDelin->getSubscripts(Src);
+    const auto *DstSubs = BatchDelin->getSubscripts(Dst);
+    if (SrcSubs && DstSubs && SrcSubs->size() >= 2 && DstSubs->size() >= 2 &&
+        SrcSubs->size() == DstSubs->size()) {
+      SrcSubscripts.assign(SrcSubs->begin(), SrcSubs->end());
+      DstSubscripts.assign(DstSubs->begin(), DstSubs->end());
+      LLVM_DEBUG(dbgs() << "Using cached fixed-size delinearization results\n");
+      return true;
+    }
+  }
+
   const SCEV *ElemSize = SE->getElementSize(Src);
   assert(ElemSize == SE->getElementSize(Dst) && "Different element sizes");
   SmallVector<const SCEV *, 4> SrcSizes, DstSizes;
@@ -3428,16 +3442,16 @@ bool DependenceInfo::tryDelinearizeParametricSize(
   if (!SrcAR || !DstAR || !SrcAR->isAffine() || !DstAR->isAffine())
     return false;
 
-  // First step: collect parametric terms in both array references.
+  // Pairwise delinearization: collect parametric terms from both array
+  // references and find subscript sizes.
   SmallVector<const SCEV *, 4> Terms;
   collectParametricTerms(*SE, SrcAR, Terms);
   collectParametricTerms(*SE, DstAR, Terms);
 
-  // Second step: find subscript sizes.
   SmallVector<const SCEV *, 4> Sizes;
   findArrayDimensions(*SE, Terms, Sizes, ElementSize);
 
-  // Third step: compute the access functions for each subscript.
+  // Compute the access functions for each subscript.
   computeAccessFunctions(*SE, SrcAR, SrcSubscripts, Sizes);
   computeAccessFunctions(*SE, DstAR, DstSubscripts, Sizes);
 
diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def
index 2cfb5b2592601..eca599eb7d6ae 100644
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -350,6 +350,7 @@ FUNCTION_ANALYSIS("assumptions", AssumptionAnalysis())
 FUNCTION_ANALYSIS("bb-sections-profile-reader",
                   BasicBlockSectionsProfileReaderAnalysis(*TM))
 FUNCTION_ANALYSIS("block-freq", BlockFrequencyAnalysis())
+FUNCTION_ANALYSIS("batch-delinearization", BatchDelinearizationAnalysis())
 FUNCTION_ANALYSIS("branch-prob", BranchProbabilityAnalysis())
 FUNCTION_ANALYSIS("cycles", CycleAnalysis())
 FUNCTION_ANALYSIS("da", DependenceAnalysis())
diff --git a/llvm/lib/Transforms/Scalar/LoopInterchange.cpp b/llvm/lib/Transforms/Scalar/LoopInterchange.cpp
index c59816e56431f..0e67ff49c7747 100644
--- a/llvm/lib/Transforms/Scalar/LoopInterchange.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopInterchange.cpp
@@ -2156,8 +2156,7 @@ PreservedAnalyses LoopInterchangePass::run(LoopNest &LN,
            << "Computed dependence info, invoking the transform.";
   });
 
-  DependenceInfo DI(&F, &AR.AA, &AR.SE, &AR.LI);
-  if (!LoopInterchange(&AR.SE, &AR.LI, &DI, &AR.DT, &AR, &ORE).run(LN))
+  if (!LoopInterchange(&AR.SE, &AR.LI, AR.DI, &AR.DT, &AR, &ORE).run(LN))
     return PreservedAnalyses::all();
   U.markLoopNestChanged(true);
   return getLoopPassPreservedAnalyses();
diff --git a/llvm/lib/Transforms/Scalar/LoopPassManager.cpp b/llvm/lib/Transforms/Scalar/LoopPassManager.cpp
index d827e649d0842..3a266b9b21ae1 100644
--- a/llvm/lib/Transforms/Scalar/LoopPassManager.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopPassManager.cpp
@@ -8,6 +8,7 @@
 
 #include "llvm/Transforms/Scalar/LoopPassManager.h"
 #include "llvm/Analysis/AssumptionCache.h"
+#include "llvm/Analysis/DependenceAnalysis.h"
 #include "llvm/Analysis/MemorySSA.h"
 #include "llvm/Analysis/ScalarEvolution.h"
 #include "llvm/Analysis/TargetLibraryInfo.h"
@@ -223,6 +224,7 @@ PreservedAnalyses FunctionToLoopPassAdaptor::run(Function &F,
                                      AM.getResult<ScalarEvolutionAnalysis>(F),
                                      AM.getResult<TargetLibraryAnalysis>(F),
                                      AM.getResult<TargetIRAnalysis>(F),
+                                     &AM.getResult<DependenceAnalysis>(F),
                                      MSSA};
 
   // Setup the loop analysis manager from its proxy. It is important that
diff --git a/llvm/lib/Transforms/Scalar/LoopUnrollAndJamPass.cpp b/llvm/lib/Transforms/Scalar/LoopUnrollAndJamPass.cpp
index 4fe74c7c3bbcd..bc80aa2080b6b 100644
--- a/llvm/lib/Transforms/Scalar/LoopUnrollAndJamPass.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopUnrollAndJamPass.cpp
@@ -457,12 +457,11 @@ PreservedAnalyses LoopUnrollAndJamPass::run(LoopNest &LN,
                                             LPMUpdater &U) {
   Function &F = *LN.getParent();
 
-  DependenceInfo DI(&F, &AR.AA, &AR.SE, &AR.LI);
   OptimizationRemarkEmitter ORE(&F);
 
   bool AnyLoopRemoved = false;
-  if (!tryToUnrollAndJamLoop(LN, AR.DT, AR.LI, AR.SE, AR.TTI, AR.AC, DI, ORE,
-                             OptLevel, U, AnyLoopRemoved))
+  if (!tryToUnrollAndJamLoop(LN, AR.DT, AR.LI, AR.SE, AR.TTI, AR.AC, *AR.DI,
+                             ORE, OptLevel, U, AnyLoopRemoved))
     return PreservedAnalyses::all();
 
   auto PA = getLoopPassPreservedAnalyses();
diff --git a/llvm/test/Analysis/DependenceAnalysis/Banerjee.ll b/llvm/test/Analysis/DependenceAnalysis/Banerjee.ll
index 6dde8844c6040..b447d74acebdf 100644
--- a/llvm/test/Analysis/DependenceAnalysis/Banerjee.ll
+++ b/llvm/test/Analysis/DependenceAnalysis/Banerjee.ll
@@ -48,7 +48,7 @@ define void @banerjee0(ptr %A, ptr %B, i64 %m, i64 %n) nounwind uwtable ssp {
 ; DELIN-NEXT:  Src: store i64 0, ptr %arrayidx, align 8 --> Dst: store i64 0, ptr %arrayidx, align 8
 ; DELIN-NEXT:    da analyze - none!
 ; DELIN-NEXT:  Src: store i64 0, ptr %arrayidx, align 8 --> Dst: %0 = load i64, ptr %arrayidx6, align 8
-; DELIN-NEXT:    da analyze - flow [<= <>]!
+; DELIN-NEXT:    da analyze - consistent flow [0 1]!
 ; DELIN-NEXT:  Src: store i64 0, ptr %arrayidx, align 8 --> Dst: store i64 %0, ptr %B.addr.11, align 8
 ; DELIN-NEXT:    da analyze - confused!
 ; DELIN-NEXT:  Src: %0 = load i64, ptr %arrayidx6, align 8 --> Dst: %0 = load i64, ptr %arrayidx6, align 8
@@ -131,13 +131,13 @@ define void @banerjee1(ptr %A, ptr %B, i64 %m, i64 %n) nounwind uwtable ssp {
 ;
 ; DELIN-LABEL: 'banerjee1'
 ; DELIN-NEXT:  Src: store i64 0, ptr %arrayidx, align 8 --> Dst: store i64 0, ptr %arrayidx, align 8
-; DELIN-NEXT:    da analyze - output [* *]!
+; DELIN-NEXT:    da analyze - none!
 ; DELIN-NEXT:  Src: store i64 0, ptr %arrayidx, align 8 --> Dst: %2 = load i64, ptr %arrayidx6, align 8
-; DELIN-NEXT:    da analyze - flow [* <>]!
+; DELIN-NEXT:    da analyze - consistent flow [0 1]!
 ; DELIN-NEXT:  Src: store i64 0, ptr %arrayidx, align 8 --> Dst: store i64 %2, ptr %B.addr.12, align 8
 ; DELIN-NEXT:    da analyze - confused!
 ; DELIN-NEXT:  Src: %2 = load i64, ptr %arrayidx6, align 8 --> Dst: %2 = load i64, ptr %arrayidx6, align 8
-; DELIN-NEXT:    da analyze - input [* *]!
+; DELIN-NEXT:    da analyze - none!
 ; DELIN-NEXT:  Src: %2 = load i64, ptr %arrayidx6, align 8 --> Dst: store i64 %2, ptr %B.addr.12, align 8
 ; DELIN-NEXT:    da analyze - confused!
 ; DELIN-NEXT:  Src: store i64 %2, ptr %B.addr.12, align 8 --> Dst: store i64 %2, ptr %B.addr.12, align 8
@@ -320,7 +320,7 @@ define void @banerjee3(ptr %A, ptr %B, i64 %m, i64 %n) nounwind uwtable ssp {
 ; DELIN-NEXT:  Src: store i64 0, ptr %arrayidx, align 8 --> Dst: store i64 0, ptr %arrayidx, align 8
 ; DELIN-NEXT:    da analyze - none!
 ; DELIN-NEXT:  Src: store i64 0, ptr %arrayidx, align 8 --> Dst: %0 = load i64, ptr %arrayidx7, align 8
-; DELIN-NEXT:    da analyze - flow [> >]!
+; DELIN-NEXT:    da analyze - consistent flow [-9 -9]!
 ; DELIN-NEXT:  Src: store i64 0, ptr %arrayidx, align 8 --> Dst: store i64 %0, ptr %B.addr.11, align 8
 ; DELIN-NEXT:    da analyze - confused!
 ; DELIN-NEXT:  Src: %0 = load i64, ptr %arrayidx7, align 8 --> Dst: %0 = load i64, ptr %arrayidx7, align 8
@@ -490,7 +490,7 @@ define void @banerjee5(ptr %A, ptr %B, i64 %m, i64 %n) nounwind uwtable ssp {
 ; DELIN-NEXT:  Src: store i64 0, ptr %arrayidx, align 8 --> Dst: store i64 0, ptr %arrayidx, align 8
 ; DELIN-NEXT:    da analyze - none!
 ; DELIN-NEXT:  Src: store i64 0, ptr %arrayidx, align 8 --> Dst: %0 = load i64, ptr %arrayidx6, align 8
-; DELIN-NEXT:    da analyze - flow [< <]!
+; DELIN-NEXT:    da analyze - consistent flow [9 9]!
 ; DELIN-NEXT:  Src: store i64 0, ptr %arrayidx, align 8 --> Dst: store i64 %0, ptr %B.addr.11, align 8
 ; DELIN-NEXT:    da analyze - confused!
 ; DELIN-NEXT:  Src: %0 = load i64, ptr %arrayidx6, align 8 --> Dst: %0 = load i64, ptr %arrayidx6, align 8
@@ -575,7 +575,7 @@ define void @banerjee6(ptr %A, ptr %B, i64 %m, i64 %n) nounwind uwtable ssp {
 ; DELIN-NEXT:  Src: store i64 0, ptr %arrayidx, align 8 --> Dst: store i64 0, ptr %arrayidx, align 8
 ; DELIN-NEXT:    da analyze - none!
 ; DELIN-NEXT:  Src: store i64 0, ptr %arrayidx, align 8 --> Dst: %0 = load i64, ptr %arrayidx7, align 8
-; DELIN-NEXT:    da analyze - flow [=> <>]!
+; DELIN-NEXT:    da analyze - consistent flow [0 -9]!
 ; DELIN-NEXT:  Src: store i64 0, ptr %arrayidx, align 8 --> Dst: store i64 %0, ptr %B.addr.11, align 8
 ; DELIN-NEXT:    da analyze - confused!
 ; DELIN-NEXT:  Src: %0 = load i64, ptr %arrayidx7, align 8 --> Dst: %0 = load i64, ptr %arrayidx7, align 8
@@ -745,7 +745,7 @@ define void @banerjee8(ptr %A, ptr %B, i64 %m, i64 %n) nounwind uwtable ssp {
 ; DELIN-NEXT:  Src: store i64 0, ptr %arrayidx, align 8 --> Dst: store i64 0, ptr %arrayidx, align 8
 ; DELIN-NEXT:    da analyze - none!
 ; DELIN-NEXT:  Src: store i64 0, ptr %arrayidx, align 8 --> Dst: %0 = load i64, ptr %arrayidx7, align 8
-; DELIN-NEXT:    da analyze - flow [> <>]!
+; DELIN-NEXT:    da analyze - consistent flow [-1 -1]!
 ; DELIN-NEXT:  Src: store i64 0, ptr %arrayidx, align 8 --> Dst: store i64 %0, ptr %B.addr.11, align 8
 ; DELIN-NEXT:    da analyze - confused!
 ; DELIN-NEXT:  Src: %0 = load i64, ptr %arrayidx7, align 8 --> Dst: %0 = load i64, ptr %arrayidx7, align 8
@@ -828,9 +828,9 @@ define void @banerjee9(ptr %A, ptr %B, i64 %m, i64 %n) nounwind uwtable ssp {
 ;
 ; DELIN-LABEL: 'banerjee9'
 ; DELIN-NEXT:  Src: store i64 0, ptr %arrayidx, align 8 --> Dst: store i64 0, ptr %arrayidx, align 8
-; DELIN-NEXT:    da analyze - output [* *]!
+; DELIN-NEXT:    da analyze - none!
 ; DELIN-NEXT:  Src: store i64 0, ptr %arrayidx, align 8 --> Dst: %1 = load i64, ptr %arrayidx7, align 8
-; DELIN-NEXT:    da analyze - flow [<= 0|<]!
+; DELIN-NEXT:    da analyze - flow [< 0]!
 ; DELIN-NEXT:  Src: store i64 0, ptr %arrayidx, align 8 --> Dst: store i64 %1, ptr %B.addr.11, align 8
 ; DELIN-NEXT:    da analyze - confused!
 ; DELIN-NEXT:  Src: %1 = load i64, ptr %arrayidx7, align 8 --> Dst: %1 = load i64, ptr %arrayidx7, align 8
@@ -1001,7 +1001,7 @@ define void @banerjee11(ptr %A, ptr %B, i64 %m, i64 %n) nounwind uwtable ssp {
 ; DELIN-NEXT:  Src: store i64 0, ptr %arrayidx, align 8 --> Dst: store i64 0, ptr %arrayidx, align 8
 ; DELIN-NEXT:    da analyze - none!
 ; DELIN-NEXT:  Src: store i64 0, ptr %arrayidx, align 8 --> Dst: %0 = load i64, ptr %arrayidx6, align 8
-; DELIN-NEXT:    da analyze - flow [<= <>]!
+; DELIN-NEXT:    da analyze - flow [0 <>]!
 ; DELIN-NEXT:  Src: store i64 0, ptr %arrayidx, align 8 --> Dst: store i64 %0, ptr %B.addr.11, align 8
 ; DELIN-NEXT:    da analyze - confused!
 ; DELIN-NEXT:  Src: %0 = load i64, ptr %arrayidx6, align 8 --> Dst: %0 = load i64, ptr %arrayidx6, align 8
diff --git a/llvm/test/Analysis/DependenceAnalysis/BatchDelinearization.ll b/llvm/test/Analysis/DependenceAnalysis/BatchDelinearization.ll
new file mode 100644
index 0000000000000..27ef4c6db3f27
--- /dev/null
+++ b/llvm/test/Analysis/DependenceAnalysis/BatchDelinearization.ll
@@ -0,0 +1,147 @@
+; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py UTC_ARGS: --version 5
+; RUN: opt < %s -disable-output "-passes=print<da>" -aa-pipeline=basic-aa 2>&1 \
+; RUN: | FileCheck %s
+
+; Test case for batch delinearization. When multiple accesses to the same
+; base pointer are analyzed together, terms from all accesses are collected
+; to determine array dimensions, leading to better precision.
+;
+; This test has three accesses to array A:
+;   A[i*m + j]  (in the write)
+;   A[i*m + j]  (in the read)
+;   A[k*m + l]  (third access that provides additional context)
+;
+; The third access helps provide more terms for delinearization,
+; which can improve precision when analyzing the first two accesses.
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Three accesses to the same 2D array A[n][m].
+; Batch delinearization collects terms from all accesses.
+define void @batch_delin_test(i64 %n, i64 %m, ptr nocapture %A) {
+; CHECK-LABEL: 'batch_delin_test'
+; CHECK-NEXT:  Src: %load1 = load double, ptr %arrayidx1, align 8 --> Dst: %load1 = load double, ptr %arrayidx1, align 8
+; CHECK-NEXT:    da analyze - input [* *]!
+; CHECK-NEXT:  Src: %load1 = load double, ptr %arrayidx1, align 8 --> Dst: store double %add, ptr %arrayidx1, align 8
+; CHECK-NEXT:    da analyze - anti [* *|<]!
+; CHECK-NEXT:  Src: %load1 = load double, ptr %arrayidx1, align 8 --> Dst: %load2 = load double, ptr %arrayidx2, align 8
+; CHECK-NEXT:    da analyze - input [<> *]!
+; CHECK-NEXT:  Src: store double %add, ptr %arrayidx1, align 8 --> Dst: store double %add, ptr %arrayidx1, align 8
+; CHECK-NEXT:    da analyze - output [* *]!
+; CHECK-NEXT:  Src: store double %add, ptr %arrayidx1, align 8 --> Dst: %load2 = load double, ptr %arrayidx2, align 8
+; CHECK-NEXT:    da analyze - flow [<> *]!
+; CHECK-NEXT:  Src: %load2 = load double, ptr %arrayidx2, align 8 --> Dst: %load2 = load double, ptr %arrayidx2, align 8
+; CHECK-NEXT:    da analyze - input [* *]!
+;
+entry:
+  %cmp1 = icmp sgt i64 %n, 0
+  %cmp2 = icmp sgt i64 %m, 0
+  %cond = and i1 %cmp1, %cmp2
+  br i1 %cond, label %loop.i.preheader, label %exit
+
+loop.i.preheader:
+  br label %loop.i
+
+loop.i:
+  %i = phi i64 [ 0, %loop.i.preheader ], [ %i.next, %loop.i.latch ]
+  br label %loop.j
+
+loop.j:
+  %j = phi i64 [ 0, %loop.i ], [ %j.next, %loop.j ]
+  ; Compute linear index: i*m + j
+  %mul1 = mul nsw i64 %i, %m
+  %idx1 = add nsw i64 %mul1, %j
+  %arrayidx1 = getelementptr inbounds double, ptr %A, i64 %idx1
+  ; First access: load A[i*m + j]
+  %load1 = load double, ptr %arrayidx1, align 8
+  %add = fadd double %load1, 1.0
+  ; Second access: store A[i*m + j]
+  store double %add, ptr %arrayidx1, align 8
+  ; Third access at a different index: load A[(i+1)*m + j]
+  ; This provides additional terms for delinearization.
+  %i_plus_1 = add nsw i64 %i, 1
+  %mul2 = mul nsw i64 %i_plus_1, %m
+  %idx2 = add nsw i64 %mul2, %j
+  %arrayidx2 = getelementptr inbounds double, ptr %A, i64 %idx2
+  %load2 = load double, ptr %arrayidx2, align 8
+  %j.next = add nuw nsw i64 %j, 1
+  %j.cond = icmp slt i64 %j.next, %m
+  br i1 %j.cond, label %loop.j, label %loop.i.latch
+
+loop.i.latch:
+  %i.next = add nuw nsw i64 %i, 1
+  %i.cond = icmp slt i64 %i.next, %n
+  br i1 %i.cond, label %loop.i, label %exit
+
+exit:
+  ret void
+}
+
+; Test with parametric sizes where batch delinearization helps.
+; Two separate loop nests accessing the same array.
+define void @batch_delin_two_nests(i64 %n, i64 %m, ptr nocapture %A) {
+; CHECK-LABEL: 'batch_delin_two_nests'
+; CHECK-NEXT:  Src: store double 1.000000e+00, ptr %arrayidx1, align 8 --> Dst: store double 1.000000e+00, ptr %arrayidx1, align 8
+; CHECK-NEXT:    da analyze - output [* *]!
+; CHECK-NEXT:  Src: store double 1.000000e+00, ptr %arrayidx1, align 8 --> Dst: %load = load double, ptr %arrayidx2, align 8
+; CHECK-NEXT:    da analyze - flow [|<]!
+; CHECK-NEXT:  Src: %load = load double, ptr %arrayidx2, align 8 --> Dst: %load = load double, ptr %arrayidx2, align 8
+; CHECK-NEXT:    da analyze - input [* *]!
+;
+entry:
+  %cmp1 = icmp sgt i64 %n, 0
+  %cmp2 = icmp sgt i64 %m, 0
+  %cond = and i1 %cmp1, %cmp2
+  br i1 %cond, label %nest1.i.preheader, label %exit
+
+; First loop nest: stores to A[i*m + j]
+nest1.i.preheader:
+  br label %nest1.i
+
+nest1.i:
+  %i1 = phi i64 [ 0, %nest1.i.preheader ], [ %i1.next, %nest1.i.latch ]
+  br label %nest1.j
+
+nest1.j:
+  %j1 = phi i64 [ 0, %nest1.i ], [ %j1.next, %nest1.j ]
+  %mul1 = mul nsw i64 %i1, %m
+  %idx1 = add nsw i64 %mul1, %j1
+  %arrayidx1 = getelementptr inbounds double, ptr %A, i64 %idx1
+  store double 1.0, ptr %arrayidx1, align 8
+  %j1.next = add nuw nsw i64 %j1, 1
+  %j1.cond = icmp slt i64 %j1.next, %m
+  br i1 %j1.cond, label %nest1.j, label %nest1.i.latch
+
+nest1.i.latch:
+  %i1.next = add nuw nsw i64 %i1, 1
+  %i1.cond = icmp slt i64 %i1.next, %n
+  br i1 %i1.cond, label %nest1.i, label %nest2.i.preheader
+
+; Second loop nest: reads from A[k*m + l]
+nest2.i.preheader:
+  br label %nest2.i
+
+nest2.i:
+  %i2 = phi i64 [ 0, %nest2.i.preheader ], [ %i2.next, %nest2.i.latch ]
+  br label %nest2.j
+
+nest2.j:
+  %j2 = phi i64 [ 0, %nest2.i ], [ %j2.next, %nest2.j ]
+  %mul2 = mul nsw i64 %i2, %m
+  %idx2 = add nsw i64 %mul2, %j2
+  %arrayidx2 = getelementptr inbounds double, ptr %A, i64 %idx2
+  %load = load double, ptr %arrayidx2, align 8
+  %j2.next = add nuw nsw i64 %j2, 1
+  %j2.cond = icmp slt i64 %j2.next, %m
+  br i1 %j2.cond, label %nest2.j, label %nest2.i.latch
+
+nest2.i.latch:
+  %i2.next = add nuw nsw i64 %i2, 1
+  %i2.cond = icmp slt i64 %i2.next, %n
+  br i1 %i2.cond, label %nest2.i, label %exit
+
+exit:
+  ret void
+}
+
diff --git a/llvm/test/Analysis/DependenceAnalysis/Constraints.ll b/llvm/test/Analysis/DependenceAnalysis/Constraints.ll
index 65dbcef153d19..a393048c90861 100644
--- a/llvm/test/Analysis/DependenceAnalysis/Constraints.ll
+++ b/llvm/test/Analysis/DependenceAnalysis/Constraints.ll
@@ -37,7 +37,7 @@ define void @dep_constraint_crash_test(i32 %M, i32 %N) {
 ; CHECK-NEXT:  Src: %out_l.promoted = load i32, ptr @out_l, align 4 --> Dst: store i32 %33, ptr @out_l, align 4
 ; CHECK-NEXT:    da analyze - consistent anti [|<]!
 ; CHECK-NEXT:  Src: store i32 0, ptr %13, align 4 --> Dst: store i32 0, ptr %13, align 4
-; CHECK-NEXT:    da analyze - output [S * *]!
+; CHECK-NEXT:    da analyze - consistent output [S 0 0]!
 ; CHECK-NEXT:  Src: store i32 0, ptr %13, align 4 --> Dst: %18 = load i32, ptr %17, align 4
 ; CHECK-NEXT:    da analyze - flow [S * *|<]!
 ; CHECK-NEXT:  Src: store i32 0, ptr %13, align 4 --> Dst: %20 = load i32, ptr %19, align 4
@@ -47,7 +47,7 @@ define void @dep_constraint_crash_test(i32 %M, i32 %N) {
 ; CHECK-NEXT:  Src: store i32 0, ptr %13, align 4 --> Dst: store i32 %24, ptr %25, align 4
 ; CHECK-NEXT:    da analyze - output [S * *|<]!
 ; CHECK-NEXT:  Src: store i32 0, ptr %13, align 4 --> Dst: %27 = load i32, ptr %26, align 4
-; CHECK-NEXT:    da analyze - flow [S * *|<]!
+; CHECK-NEXT:    da analyze - flow [S 0 *|<]!
 ; CHECK-NEXT:  Src: store i32 0, ptr %13, align 4 --> Dst: %29 = load i32, ptr %28, align 4
 ; CHECK-NEXT:    da analyze - none!
 ; CHECK-NEXT:  Src: store i32 0, ptr %13, align 4 --> Dst: store i32 %30, ptr %31, align 4
@@ -75,7 +75,7 @@ define void @dep_constraint_crash_test(i32 %M, i32 %N) {
 ; CHECK-NEXT:  Src: %18 = load i32, ptr %17, align 4 --> Dst: store i32 %33, ptr @out_l, align 4
 ; CHECK-NEXT:    da analyze - none!
 ; CHECK-NEXT:  Src: %20 = load i32, ptr %19, align 4 --> Dst: %20 = load i32, ptr %19, align 4
-; CHECK-NEXT:    da analyze - input [S * S *]!
+; CHECK-NEXT:    da analyze - consistent input [S 0 S 0]!
 ; CHECK-NEXT:  Src: %20 = load i32, ptr %19, align 4 --> Dst: %23 = load i32, ptr %22, align 4
 ; CHECK-NEXT:    da analyze - input [S * * *|<]!
 ; CHECK-NEXT:  Src: %20 = load i32, ptr %19, align 4 --> Dst: store i32 %24, ptr %25, align 4
@@ -85,7 +85,7 @@ define void @dep_constraint_crash_test(i32 %M, i32 %N) {
 ; CHECK-NEXT:  Src: %20 = load i32, ptr %19, align 4 --> Dst: %29 = load i32, ptr %28, align 4
 ; CHECK-NEXT:    da analyze - none!
 ; CHECK-NEXT:  Src: %20 = load i32, ptr %19, align 4 --> Dst: store i32 %30, ptr %31, align 4
-; CHECK-NEXT:    da analyze - anti [S * *|<]!
+; CHECK-NEXT:    da analyze - anti [S 0 *|<]!
 ; CHECK-NEXT:  Src: %20 = load i32, ptr %19, align 4 --> Dst: %32 = load i32, ptr %6, align 4
 ; CHECK-NEXT:    da analyze - input [S|<]!
 ; CHECK-NEXT:  Src: %20 = load i32, ptr %19, align 4 --> Dst: store i32 %33, ptr @out_l, align 4
@@ -117,7 +117,7 @@ define void @dep_constraint_crash_test(i32 %M, i32 %N) {
 ; CHECK-NEXT:  Src: store i32 %24, ptr %25, align 4 --> Dst: store i32 %33, ptr @out_l, align 4
 ; CHECK-NEXT:    da analyze - none!
 ; CHECK-NEXT:  Src: %27 = load i32, ptr %26, align 4 --> Dst: %27 = load i32, ptr %26, align 4
-; CHECK-NEXT:    da analyze - input [S * *]!
+; CHECK-NEXT:    da analyze - consistent input [S 0 0]!
 ; CHECK-NEXT:  Src: %27 = load i32, ptr %26, align 4 --> Dst: %29 = load i32, ptr %28, align 4
 ; CHECK-NEXT:    da analyze - none!
 ; CHECK-NEXT:  Src: %27 = load i32, ptr %26, align 4 --> Dst: store i32 %30, ptr %31, align 4
@@ -127,7 +127,7 @@ define void @dep_constraint_crash_test(i32 %M, i32 %N) {
 ; CHECK-NEXT:  Src: %27 = load i32, ptr %26, align 4 --> Dst: store i32 %33, ptr @out_l, align 4
 ; CHECK-NEXT:    da analyze - none!
 ; CHECK-NEXT:  Src: %29 = load i32, ptr %28, align 4 --> Dst: %29 = load i32, ptr %28, align 4
-; CHECK-NEXT:    da analyze - input [S * *]!
+; CHECK-NEXT:    da analyze - consistent input [S 0 0]!
 ; CHECK-NEXT:  Src: %29 = load i32, ptr %28, align 4 --> Dst: store i32 %30, ptr %31, align 4
 ; CHECK-NEXT:    da analyze - none!
 ; CHECK-NEXT:  Src: %29 = load i32, ptr %28, align 4 --> Dst: %32 = load i32, ptr %6, align 4
@@ -135,7 +135,7 @@ define void @dep_constraint_crash_test(i32 %M, i32 %N) {
 ; CHECK-NEXT:  Src: %29 = load i32, ptr %28, align 4 --> Dst: store i32 %33, ptr @out_l, align 4
 ; CHECK-NEXT:    da analyze - none!
 ; CHECK-NEXT:  Src: store i32 %30, ptr %31, align 4 --> Dst: store i32 %30, ptr %31, align 4
-; CHECK-NEXT:    da analyze - output [S * *]!
+; CHECK-NEXT:    da analyze - consistent output [S 0 0]!
 ; CHECK-NEXT:  Src: store i32 %30, ptr %31, align 4 --> Dst: %32 = load i32, ptr %6, align 4
 ; CHECK-NEXT:    da analyze - flow [S|<]!
 ; CHECK-NEXT:  Src: store i32 %30, ptr %31, align 4 --> Dst: store i32 %33, ptr @out_l, align 4
diff --git a/llvm/test/Analysis/DependenceAnalysis/DifferentOffsets.ll b/llvm/test/Analysis/DependenceAnalysis/DifferentOffsets.ll
index 3360e603eb406..a450b6f8b5101 100644
--- a/llvm/test/Analysis/DependenceAnalysis/DifferentOffsets.ll
+++ b/llvm/test/Analysis/DependenceAnalysis/DifferentOffsets.ll
@@ -150,7 +150,7 @@ define void @multidim_accesses(ptr %A) {
 ; CHECK-NEXT:  Src: store i32 1, ptr %idx0, align 4 --> Dst: store i32 1, ptr %idx0, align 4
 ; CHECK-NEXT:    da analyze - none!
 ; CHECK-NEXT:  Src: store i32 1, ptr %idx0, align 4 --> Dst: store i32 1, ptr %idx1, align 4
-; CHECK-NEXT:    da analyze - output [<= * *|<]!
+; CHECK-NEXT:    da analyze - output [0 0 <=|<]!
 ; CHECK-NEXT:  Src: store i32 1, ptr %idx1, align 4 --> Dst: store i32 1, ptr %idx1, align 4
 ; CHECK-NEXT:    da analyze - none!
 ;
diff --git a/llvm/test/Analysis/DependenceAnalysis/GCD.ll b/llvm/test/Analysis/DependenceAnalysis/GCD.ll
index cb14d189afe4c..d0fc3b648b47f 100644
--- a/llvm/test/Analysis/DependenceAnalysis/GCD.ll
+++ b/llvm/test/Analysis/DependenceAnalysis/GCD.ll
@@ -15,13 +15,13 @@ target triple = "x86_64-apple-macosx10.6.0"
 define void @gcd0(ptr %A, ptr %B) nounwind uwtable ssp {
 ; CHECK-LABEL: 'gcd0'
 ; CHECK-NEXT:  Src: store i32 %conv, ptr %arrayidx, align 4 --> Dst: store i32 %conv, ptr %arrayidx, align 4
-; CHECK-NEXT:    da analyze - output [* *]!
+; CHECK-NEXT:    da analyze - none!
 ; CHECK-NEXT:  Src: store i32 %conv, ptr %arrayidx, align 4 --> Dst: %0 = load i32, ptr %arrayidx7, align 4
-; CHECK-NEXT:    da analyze - flow [=> *|<]!
+; CHECK-NEXT:    da analyze - flow [=> 0|<]!
 ; CHECK-NEXT:  Src: store i32 %conv, ptr %arrayidx, align 4 --> Dst: store i32 %0, ptr %B.addr.11, align 4
 ; CHECK-NEXT:    da analyze - confused!
 ; CHECK-NEXT:  Src: %0 = load i32, ptr %arrayidx7, align 4 --> Dst: %0 = load i32, ptr %arrayidx7, align 4
-; CHECK-NEXT:    da analyze - input [* *]!
+; CHECK-NEXT:    da analyze - none!
 ; CHECK-NEXT:  Src: %0 = load i32, ptr %arrayidx7, align 4 --> Dst: store i32 %0, ptr %B.addr.11, align 4
 ; CHECK-NEXT:    da analyze - confused!
 ; CHECK-NEXT:  Src: store i32 %0, ptr %B.addr.11, align 4 --> Dst: store i32 %0, ptr %B.addr.11, align 4
@@ -74,13 +74,13 @@ for.end10:                                        ; preds = %for.inc8
 define void @gcd1(ptr %A, ptr %B) nounwind uwtable ssp {
 ; CHECK-LABEL: 'gcd1'
 ; CHECK-NEXT:  Src: store i32 %conv, ptr %arrayidx, align 4 --> Dst: store i32 %conv, ptr %arrayidx, align 4
-; CHECK-NEXT:    da analyze - output [* *]!
+; CHECK-NEXT:    da analyze - none!
 ; CHECK-NEXT:  Src: store i32 %conv, ptr %arrayidx, align 4 --> Dst: %0 = load i32, ptr %arrayidx8, align 4
 ; CHECK-NEXT:    da analyze - none!
 ; CHECK-NEXT:  Src: store i32 %conv, ptr %arrayidx, align 4 --> Dst: store i32 %0, ptr %B.addr.11, align 4
 ; CHECK-NEXT:    da analyze - confused!
 ; CHECK-NEXT:  Src: %0 = load i32, ptr %arrayidx8, align 4 --> Dst: %0 = load i32, ptr %arrayidx8, align 4
-; CHECK-NEXT:    da analyze - input [* *]!
+; CHECK-NEXT:    da analyze - none!
 ; CHECK-NEXT:  Src: %0 = load i32, ptr %arrayidx8, align 4 --> Dst: store i32 %0, ptr %B.addr.11, align 4
 ; CHECK-NEXT:    da analyze - confused!
 ; CHECK-NEXT:  Src: store i32 %0, ptr %B.addr.11, align 4 --> Dst: store i32 %0, ptr %B.addr.11, align 4
@@ -134,13 +134,13 @@ for.end11:                                        ; preds = %for.inc9
 define void @gcd2(ptr %A, ptr %B) nounwind uwtable ssp {
 ; CHECK-LABEL: 'gcd2'
 ; CHECK-NEXT:  Src: store i32 %conv, ptr %arrayidx, align 4 --> Dst: store i32 %conv, ptr %arrayidx, align 4
-; CHECK-NEXT:    da analyze - output [* *]!
+; CHECK-NEXT:    da analyze - none!
 ; CHECK-NEXT:  Src: store i32 %conv, ptr %arrayidx, align 4 --> Dst: %0 = load i32, ptr %arrayidx8, align 4
 ; CHECK-NEXT:    da analyze - none!
 ; CHECK-NEXT:  Src: store i32 %conv, ptr %arrayidx, align 4 --> Dst: store i32 %0, ptr %B.addr.11, align 4
 ; CHECK-NEXT:    da analyze - confused!
 ; CHECK-NEXT:  Src: %0 = load i32, ptr %arrayidx8, align 4 --> Dst: %0 = load i32, ptr %arrayidx8, align 4
-; CHECK-NEXT:    da analyze - input [* *]!
+; CHECK-NEXT:    da analyze - none!
 ; CHECK-NEXT:  Src: %0 = load i32, ptr %arrayidx8, align 4 --> Dst: store i32 %0, ptr %B.addr.11, align 4
 ; CHECK-NEXT:    da analyze - confused!
 ; CHECK-NEXT:  Src: store i32 %0, ptr %B.addr.11, align 4 --> Dst: store i32 %0, ptr %B.addr.11, align 4
@@ -194,13 +194,13 @@ for.end11:                                        ; preds = %for.inc9
 define void @gcd3(ptr %A, ptr %B) nounwind uwtable ssp {
 ; CHECK-LABEL: 'gcd3'
 ; CHECK-NEXT:  Src: store i32 %conv, ptr %arrayidx, align 4 --> Dst: store i32 %conv, ptr %arrayidx, align 4
-; CHECK-NEXT:    da analyze - output [* *]!
+; CHECK-NEXT:    da analyze - none!
 ; CHECK-NEXT:  Src: store i32 %conv, ptr %arrayidx, align 4 --> Dst: %0 = load i32, ptr %arrayidx6, align 4
-; CHECK-NEXT:    da analyze - flow [<> *]!
+; CHECK-NEXT:    da analyze - consistent flow [1 0]!
 ; CHECK-NEXT:  Src: store i32 %conv, ptr %arrayidx, align 4 --> Dst: store i32 %0, ptr %B.addr.11, align 4
 ; CHECK-NEXT:    da analyze - confused!
 ; CHECK-NEXT:  Src: %0 = load i32, ptr %arrayidx6, align 4 --> Dst: %0 = load i32, ptr %arrayidx6, align 4
-; CHECK-NEXT:    da analyze - input [* *]!
+; CHECK-NEXT:    da analyze - none!
 ; CHECK-NEXT:  Src: %0 = load i32, ptr %arrayidx6, align 4 --> Dst: store i32 %0, ptr %B.addr.11, align 4
 ; CHECK-NEXT:    da analyze - confused!
 ; CHECK-NEXT:  Src: store i32 %0, ptr %B.addr.11, align 4 --> Dst: store i32 %0, ptr %B.addr.11, align 4
diff --git a/llvm/test/Analysis/DependenceAnalysis/Invariant.ll b/llvm/test/Analysis/DependenceAnalysis/Invariant.ll
index 5fc9dc3e031ab..b90eaa8cf943c 100644
--- a/llvm/test/Analysis/DependenceAnalysis/Invariant.ll
+++ b/llvm/test/Analysis/DependenceAnalysis/Invariant.ll
@@ -2,11 +2,6 @@
 ; RUN: opt < %s -disable-output "-passes=print<da>" -aa-pipeline=basic-aa 2>&1 \
 ; RUN: | FileCheck %s
 
-; XFAIL: *
-; Currently fails since delinearization doesn't work as expected, due to the
-; inconsistency in the estimated array sizes between `rr[i][j]` and `rr[j][j]`.
-; The latter is now regarded as an access to a 1D array.
-
 ; Test for a bug, which caused an assert when an invalid
 ; SCEVAddRecExpr is created in addToCoefficient.
 
@@ -26,7 +21,7 @@ define float @foo(float %g, ptr %rr) nounwind {
 ; CHECK-NEXT:  Src: %0 = load float, ptr %arrayidx4, align 4 --> Dst: %0 = load float, ptr %arrayidx4, align 4
 ; CHECK-NEXT:    da analyze - consistent input [S 0]!
 ; CHECK-NEXT:  Src: %0 = load float, ptr %arrayidx4, align 4 --> Dst: %1 = load float, ptr %arrayidx6, align 4
-; CHECK-NEXT:    da analyze - input [* 0|<]!
+; CHECK-NEXT:    da analyze - input [* *|<]!
 ; CHECK-NEXT:  Src: %1 = load float, ptr %arrayidx6, align 4 --> Dst: %1 = load float, ptr %arrayidx6, align 4
 ; CHECK-NEXT:    da analyze - none!
 ;
diff --git a/llvm/test/Analysis/DependenceAnalysis/NonCanonicalizedSubscript.ll b/llvm/test/Analysis/DependenceAnalysis/NonCanonicalizedSubscript.ll
index 0cee9aa90236a..efa7d979c1959 100644
--- a/llvm/test/Analysis/DependenceAnalysis/NonCanonicalizedSubscript.ll
+++ b/llvm/test/Analysis/DependenceAnalysis/NonCanonicalizedSubscript.ll
@@ -59,7 +59,7 @@ define void @coupled_miv_type_mismatch(i32 %n) {
 ; CHECK-NEXT:  Src: %2 = load i32, ptr %arrayidx5, align 4 --> Dst: %2 = load i32, ptr %arrayidx5, align 4
 ; CHECK-NEXT:    da analyze - none!
 ; CHECK-NEXT:  Src: %2 = load i32, ptr %arrayidx5, align 4 --> Dst: store i32 %add6, ptr %arrayidx10, align 4
-; CHECK-NEXT:    da analyze - anti [< >]!
+; CHECK-NEXT:    da analyze - none!
 ; CHECK-NEXT:  Src: store i32 %add6, ptr %arrayidx10, align 4 --> Dst: store i32 %add6, ptr %arrayidx10, align 4
 ; CHECK-NEXT:    da analyze - none!
 ;
diff --git a/llvm/test/Analysis/DependenceAnalysis/Preliminary.ll b/llvm/test/Analysis/DependenceAnalysis/Preliminary.ll
index 8cb0e2ac770dc..58d359dc6c1fa 100644
--- a/llvm/test/Analysis/DependenceAnalysis/Preliminary.ll
+++ b/llvm/test/Analysis/DependenceAnalysis/Preliminary.ll
@@ -59,13 +59,13 @@ entry:
 define void @p2(i64 %n, ptr %A, ptr %B) nounwind uwtable ssp {
 ; CHECK-LABEL: 'p2'
 ; CHECK-NEXT:  Src: store i64 %i.011, ptr %arrayidx8, align 8 --> Dst: store i64 %i.011, ptr %arrayidx8, align 8
-; CHECK-NEXT:    da analyze - output [* * *]!
+; CHECK-NEXT:    da analyze - none!
 ; CHECK-NEXT:  Src: store i64 %i.011, ptr %arrayidx8, align 8 --> Dst: %0 = load i64, ptr %arrayidx17, align 8
-; CHECK-NEXT:    da analyze - flow [* *|<]!
+; CHECK-NEXT:    da analyze - flow [-3 -2] / assuming 1 loop level(s) fused: [-3 -2 -1]!
 ; CHECK-NEXT:  Src: store i64 %i.011, ptr %arrayidx8, align 8 --> Dst: store i64 %0, ptr %B.addr.24, align 8
 ; CHECK-NEXT:    da analyze - confused!
 ; CHECK-NEXT:  Src: %0 = load i64, ptr %arrayidx17, align 8 --> Dst: %0 = load i64, ptr %arrayidx17, align 8
-; CHECK-NEXT:    da analyze - input [* * *]!
+; CHECK-NEXT:    da analyze - none!
 ; CHECK-NEXT:  Src: %0 = load i64, ptr %arrayidx17, align 8 --> Dst: store i64 %0, ptr %B.addr.24, align 8
 ; CHECK-NEXT:    da analyze - confused!
 ; CHECK-NEXT:  Src: store i64 %0, ptr %B.addr.24, align 8 --> Dst: store i64 %0, ptr %B.addr.24, align 8
diff --git a/llvm/test/Analysis/DependenceAnalysis/PreliminaryNoValidityCheckFixedSize.ll b/llvm/test/Analysis/DependenceAnalysis/PreliminaryNoValidityCheckFixedSize.ll
index 8cd29e691a7ef..eebe2b1fa9437 100644
--- a/llvm/test/Analysis/DependenceAnalysis/PreliminaryNoValidityCheckFixedSize.ll
+++ b/llvm/test/Analysis/DependenceAnalysis/PreliminaryNoValidityCheckFixedSize.ll
@@ -32,13 +32,13 @@ define void @p2(i64 %n, ptr %A, ptr %B) nounwind uwtable ssp {
 ;
 ; LIN-LABEL: 'p2'
 ; LIN-NEXT:  Src: store i64 %i.011, ptr %arrayidx8, align 8 --> Dst: store i64 %i.011, ptr %arrayidx8, align 8
-; LIN-NEXT:    da analyze - output [* * *]!
+; LIN-NEXT:    da analyze - none!
 ; LIN-NEXT:  Src: store i64 %i.011, ptr %arrayidx8, align 8 --> Dst: %0 = load i64, ptr %arrayidx17, align 8
-; LIN-NEXT:    da analyze - flow [* *|<]!
+; LIN-NEXT:    da analyze - flow [-3 -2] / assuming 1 loop level(s) fused: [-3 -2 -1]!
 ; LIN-NEXT:  Src: store i64 %i.011, ptr %arrayidx8, align 8 --> Dst: store i64 %0, ptr %B.addr.24, align 8
 ; LIN-NEXT:    da analyze - confused!
 ; LIN-NEXT:  Src: %0 = load i64, ptr %arrayidx17, align 8 --> Dst: %0 = load i64, ptr %arrayidx17, align 8
-; LIN-NEXT:    da analyze - input [* * *]!
+; LIN-NEXT:    da analyze - none!
 ; LIN-NEXT:  Src: %0 = load i64, ptr %arrayidx17, align 8 --> Dst: store i64 %0, ptr %B.addr.24, align 8
 ; LIN-NEXT:    da analyze - confused!
 ; LIN-NEXT:  Src: store i64 %0, ptr %B.addr.24, align 8 --> Dst: store i64 %0, ptr %B.addr.24, align 8
diff --git a/llvm/test/Analysis/DependenceAnalysis/Propagating.ll b/llvm/test/Analysis/DependenceAnalysis/Propagating.ll
index 17f2de43cc611..aaf22be8456d3 100644
--- a/llvm/test/Analysis/DependenceAnalysis/Propagating.ll
+++ b/llvm/test/Analysis/DependenceAnalysis/Propagating.ll
@@ -16,7 +16,7 @@ define void @prop0(ptr %A, ptr %B, i32 %n) nounwind uwtable ssp {
 ; CHECK-NEXT:  Src: store i32 %conv, ptr %arrayidx5, align 4 --> Dst: store i32 %conv, ptr %arrayidx5, align 4
 ; CHECK-NEXT:    da analyze - none!
 ; CHECK-NEXT:  Src: store i32 %conv, ptr %arrayidx5, align 4 --> Dst: %0 = load i32, ptr %arrayidx8, align 4
-; CHECK-NEXT:    da analyze - flow [< >]!
+; CHECK-NEXT:    da analyze - none!
 ; CHECK-NEXT:  Src: store i32 %conv, ptr %arrayidx5, align 4 --> Dst: store i32 %0, ptr %B.addr.11, align 4
 ; CHECK-NEXT:    da analyze - confused!
 ; CHECK-NEXT:  Src: %0 = load i32, ptr %arrayidx8, align 4 --> Dst: %0 = load i32, ptr %arrayidx8, align 4
@@ -198,13 +198,13 @@ for.end10:                                        ; preds = %for.inc8
 define void @prop3(ptr %A, ptr %B, i32 %n) nounwind uwtable ssp {
 ; CHECK-LABEL: 'prop3'
 ; CHECK-NEXT:  Src: store i32 %conv, ptr %arrayidx4, align 4 --> Dst: store i32 %conv, ptr %arrayidx4, align 4
-; CHECK-NEXT:    da analyze - output [* *]!
+; CHECK-NEXT:    da analyze - none!
 ; CHECK-NEXT:  Src: store i32 %conv, ptr %arrayidx4, align 4 --> Dst: %0 = load i32, ptr %arrayidx8, align 4
-; CHECK-NEXT:    da analyze - flow [<> *]!
+; CHECK-NEXT:    da analyze - none!
 ; CHECK-NEXT:  Src: store i32 %conv, ptr %arrayidx4, align 4 --> Dst: store i32 %0, ptr %B.addr.11, align 4
 ; CHECK-NEXT:    da analyze - confused!
 ; CHECK-NEXT:  Src: %0 = load i32, ptr %arrayidx8, align 4 --> Dst: %0 = load i32, ptr %arrayidx8, align 4
-; CHECK-NEXT:    da analyze - input [* *]!
+; CHECK-NEXT:    da analyze - none!
 ; CHECK-NEXT:  Src: %0 = load i32, ptr %arrayidx8, align 4 --> Dst: store i32 %0, ptr %B.addr.11, align 4
 ; CHECK-NEXT:    da analyze - confused!
 ; CHECK-NEXT:  Src: store i32 %0, ptr %B.addr.11, align 4 --> Dst: store i32 %0, ptr %B.addr.11, align 4
@@ -258,7 +258,7 @@ define void @prop4(ptr %A, ptr %B, i32 %n) nounwind uwtable ssp {
 ; CHECK-NEXT:  Src: store i32 %conv, ptr %arrayidx6, align 4 --> Dst: store i32 %conv, ptr %arrayidx6, align 4
 ; CHECK-NEXT:    da analyze - none!
 ; CHECK-NEXT:  Src: store i32 %conv, ptr %arrayidx6, align 4 --> Dst: %0 = load i32, ptr %arrayidx10, align 4
-; CHECK-NEXT:    da analyze - flow [< <>]!
+; CHECK-NEXT:    da analyze - consistent flow [1 99]!
 ; CHECK-NEXT:  Src: store i32 %conv, ptr %arrayidx6, align 4 --> Dst: store i32 %0, ptr %B.addr.11, align 4
 ; CHECK-NEXT:    da analyze - confused!
 ; CHECK-NEXT:  Src: %0 = load i32, ptr %arrayidx10, align 4 --> Dst: %0 = load i32, ptr %arrayidx10, align 4
@@ -317,7 +317,7 @@ define void @prop5(ptr %A, ptr %B, i32 %n) nounwind uwtable ssp {
 ; CHECK-NEXT:  Src: store i32 %conv, ptr %arrayidx7, align 4 --> Dst: store i32 %conv, ptr %arrayidx7, align 4
 ; CHECK-NEXT:    da analyze - none!
 ; CHECK-NEXT:  Src: store i32 %conv, ptr %arrayidx7, align 4 --> Dst: %0 = load i32, ptr %arrayidx12, align 4
-; CHECK-NEXT:    da analyze - flow [* *|<]!
+; CHECK-NEXT:    da analyze - none!
 ; CHECK-NEXT:  Src: store i32 %conv, ptr %arrayidx7, align 4 --> Dst: store i32 %0, ptr %B.addr.11, align 4
 ; CHECK-NEXT:    da analyze - confused!
 ; CHECK-NEXT:  Src: %0 = load i32, ptr %arrayidx12, align 4 --> Dst: %0 = load i32, ptr %arrayidx12, align 4
@@ -377,7 +377,7 @@ define void @prop6(ptr %A, ptr %B, i32 %n) nounwind uwtable ssp {
 ; CHECK-NEXT:  Src: store i32 %conv, ptr %arrayidx6, align 4 --> Dst: store i32 %conv, ptr %arrayidx6, align 4
 ; CHECK-NEXT:    da analyze - none!
 ; CHECK-NEXT:  Src: store i32 %conv, ptr %arrayidx6, align 4 --> Dst: %0 = load i32, ptr %arrayidx11, align 4
-; CHECK-NEXT:    da analyze - flow [=> <>]!
+; CHECK-NEXT:    da analyze - none!
 ; CHECK-NEXT:  Src: store i32 %conv, ptr %arrayidx6, align 4 --> Dst: store i32 %0, ptr %B.addr.11, align 4
 ; CHECK-NEXT:    da analyze - confused!
 ; CHECK-NEXT:  Src: %0 = load i32, ptr %arrayidx11, align 4 --> Dst: %0 = load i32, ptr %arrayidx11, align 4
diff --git a/llvm/test/Analysis/DependenceAnalysis/new-pm-invalidation.ll b/llvm/test/Analysis/DependenceAnalysis/new-pm-invalidation.ll
index 1018ec5e8661c..9317f2c931d58 100644
--- a/llvm/test/Analysis/DependenceAnalysis/new-pm-invalidation.ll
+++ b/llvm/test/Analysis/DependenceAnalysis/new-pm-invalidation.ll
@@ -1,17 +1,27 @@
 ; RUN: opt < %s -passes='require<da>,invalidate<scalar-evolution>,print<da>'   \
 ; RUN:   -disable-output -debug-pass-manager 2>&1 | FileCheck %s
 
-; This test cannot be converted to use utils/update_analyze_test_checks.py
-; because the pass order printing is not deterministic.
+; This test verifies that BatchDelinearizationAnalysis is invalidated when
+; ScalarEvolution is invalidated.
 
+; First run of DependenceAnalysis triggers BatchDelinearizationAnalysis
 ; CHECK: Running analysis: DependenceAnalysis on test_no_noalias
 ; CHECK: Running analysis: ScalarEvolutionAnalysis on test_no_noalias
+; CHECK: Running analysis: BatchDelinearizationAnalysis on test_no_noalias
+
+; Invalidating SE invalidates BatchDelinearization and DA
 ; CHECK: Invalidating analysis: ScalarEvolutionAnalysis on test_no_noalias
+; CHECK: Invalidating analysis: BatchDelinearizationAnalysis on test_no_noalias
 ; CHECK: Invalidating analysis: DependenceAnalysis on test_no_noalias
-; CHECK: Running analysis: DependenceAnalysis on test_no_noalias
+
+; Second run re-runs BatchDelinearizationAnalysis
+; CHECK: DependenceAnalysis on test_no_noalias
+; CHECK: ScalarEvolutionAnalysis on test_no_noalias
+; CHECK: BatchDelinearizationAnalysis on test_no_noalias
 ; CHECK: da analyze - none!
 ; CHECK: da analyze - confused!
 ; CHECK: da analyze - none!
+
 define void @test_no_noalias(ptr %A, ptr %B) {
   store i32 1, ptr %A
   store i32 2, ptr %B
diff --git a/llvm/test/Transforms/LICM/lnicm.ll b/llvm/test/Transforms/LICM/lnicm.ll
index e331ab7d39e83..d03667d216ef4 100644
--- a/llvm/test/Transforms/LICM/lnicm.ll
+++ b/llvm/test/Transforms/LICM/lnicm.ll
@@ -3,9 +3,6 @@
 ; RUN: opt -aa-pipeline=basic-aa -passes='loop-mssa(lnicm),loop(loop-interchange)' -cache-line-size=64 -S %s | FileCheck %s --check-prefixes LNICM
 ; RUN: opt -aa-pipeline=basic-aa -passes='loop-mssa(licm),loop(loop-interchange)' -cache-line-size=64 -S %s | FileCheck %s --check-prefixes LICM
 
-; XFAIL: *
-; Loop interchange currently fails due to a failure in dependence analysis.
-
 ; This test represents the following function:
 ; void test(int n, int m, int x[m][n], int y[n], int *z) {
 ;   for (int k = 0; k < n; k++) {
@@ -64,7 +61,6 @@ define dso_local void @test(i64 %n, i64 %m, ptr noalias %x, ptr noalias readonly
 ; INTC:       for.end11:
 ; INTC-NEXT:    ret void
 ;
-; The loopnest is interchanged when we run lnicm and loop interchange.
 ; LNICM-LABEL: @test(
 ; LNICM-NEXT:  gurad:
 ; LNICM-NEXT:    [[CMP23:%.*]] = icmp sgt i64 [[M:%.*]], 0
@@ -75,17 +71,13 @@ define dso_local void @test(i64 %n, i64 %m, ptr noalias %x, ptr noalias readonly
 ; LNICM:       for.i.preheader:
 ; LNICM-NEXT:    br label [[FOR_BODY3_PREHEADER:%.*]]
 ; LNICM:       entry:
+; LNICM-NEXT:    [[TMP0:%.*]] = load i32, ptr [[Z:%.*]], align 4
 ; LNICM-NEXT:    br label [[FOR_BODY:%.*]]
 ; LNICM:       for.body:
-; LNICM-NEXT:    [[K_02:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC10:%.*]], [[FOR_END:%.*]] ]
-; LNICM-NEXT:    br label [[FOR_BODY3_SPLIT1:%.*]]
-; LNICM:       for.body3.preheader:
-; LNICM-NEXT:    [[TMP0:%.*]] = load i32, ptr [[Z:%.*]], align 4
-; LNICM-NEXT:    br label [[FOR_BODY3:%.*]]
+; LNICM-NEXT:    [[K_02:%.*]] = phi i32 [ 0, [[FOR_BODY3_PREHEADER]] ], [ [[INC10:%.*]], [[FOR_END:%.*]] ]
+; LNICM-NEXT:    br label [[FOR_BODY4:%.*]]
 ; LNICM:       for.body3:
-; LNICM-NEXT:    [[I_01:%.*]] = phi i32 [ [[TMP3:%.*]], [[FOR_BODY3_SPLIT:%.*]] ], [ 0, [[FOR_BODY3_PREHEADER]] ]
-; LNICM-NEXT:    br label [[ENTRY]]
-; LNICM:       for.body3.split1:
+; LNICM-NEXT:    [[I_01:%.*]] = phi i32 [ 0, [[FOR_BODY]] ], [ [[TMP6:%.*]], [[FOR_BODY4]] ]
 ; LNICM-NEXT:    [[IDXPROM:%.*]] = sext i32 [[K_02]] to i64
 ; LNICM-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[Y:%.*]], i64 [[IDXPROM]]
 ; LNICM-NEXT:    [[TMP1:%.*]] = load i32, ptr [[ARRAYIDX]], align 4
@@ -97,26 +89,20 @@ define dso_local void @test(i64 %n, i64 %m, ptr noalias %x, ptr noalias readonly
 ; LNICM-NEXT:    [[TMP2:%.*]] = load i32, ptr [[ARRAYIDX7]], align 4
 ; LNICM-NEXT:    [[ADD8:%.*]] = add nsw i32 [[TMP2]], [[ADD]]
 ; LNICM-NEXT:    store i32 [[ADD8]], ptr [[ARRAYIDX7]], align 4
-; LNICM-NEXT:    [[INC:%.*]] = add nsw i32 [[I_01]], 1
-; LNICM-NEXT:    [[INC_EXT:%.*]] = sext i32 [[INC]] to i64
-; LNICM-NEXT:    [[CMP2:%.*]] = icmp slt i64 [[INC_EXT]], [[M]]
-; LNICM-NEXT:    br label [[FOR_END]]
-; LNICM:       for.body3.split:
-; LNICM-NEXT:    [[TMP3]] = add nsw i32 [[I_01]], 1
-; LNICM-NEXT:    [[TMP4:%.*]] = sext i32 [[TMP3]] to i64
-; LNICM-NEXT:    [[TMP5:%.*]] = icmp slt i64 [[TMP4]], [[M]]
-; LNICM-NEXT:    br i1 [[TMP5]], label [[FOR_BODY3]], label [[FOR_END11_LOOPEXIT:%.*]], !llvm.loop [[LOOP0:![0-9]+]]
+; LNICM-NEXT:    [[TMP6]] = add nsw i32 [[I_01]], 1
+; LNICM-NEXT:    [[TMP7:%.*]] = sext i32 [[TMP6]] to i64
+; LNICM-NEXT:    [[TMP8:%.*]] = icmp slt i64 [[TMP7]], [[M]]
+; LNICM-NEXT:    br i1 [[TMP8]], label [[FOR_BODY4]], label [[FOR_END]], !llvm.loop [[LOOP0:![0-9]+]]
 ; LNICM:       for.end:
 ; LNICM-NEXT:    [[INC10]] = add nsw i32 [[K_02]], 1
 ; LNICM-NEXT:    [[INC10_EXT:%.*]] = sext i32 [[INC10]] to i64
 ; LNICM-NEXT:    [[CMP:%.*]] = icmp slt i64 [[INC10_EXT]], [[N]]
-; LNICM-NEXT:    br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_BODY3_SPLIT]], !llvm.loop [[LOOP2:![0-9]+]]
+; LNICM-NEXT:    br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END11_LOOPEXIT:%.*]], !llvm.loop [[LOOP2:![0-9]+]]
 ; LNICM:       for.end11.loopexit:
 ; LNICM-NEXT:    br label [[FOR_END11]]
 ; LNICM:       for.end11:
 ; LNICM-NEXT:    ret void
 ;
-; The loopnest is not interchanged when we run licm and loop interchange.
 ; LICM-LABEL: @test(
 ; LICM-NEXT:  gurad:
 ; LICM-NEXT:    [[CMP23:%.*]] = icmp sgt i64 [[M:%.*]], 0
@@ -159,6 +145,8 @@ define dso_local void @test(i64 %n, i64 %m, ptr noalias %x, ptr noalias readonly
 ; LICM:       for.end11:
 ; LICM-NEXT:    ret void
 ;
+; The loopnest is interchanged when we run lnicm and loop interchange.
+; The loopnest is not interchanged when we run licm and loop interchange.
 
 gurad:
   %cmp23 = icmp sgt i64 %m, 0
diff --git a/llvm/test/Transforms/LoopInterchange/loop-interchange-optimization-remarks.ll b/llvm/test/Transforms/LoopInterchange/loop-interchange-optimization-remarks.ll
index 14836ba73433d..b6a7a2f21c7e7 100644
--- a/llvm/test/Transforms/LoopInterchange/loop-interchange-optimization-remarks.ll
+++ b/llvm/test/Transforms/LoopInterchange/loop-interchange-optimization-remarks.ll
@@ -68,10 +68,10 @@ for.end19:
 
 ; CHECK: --- !Missed
 ; CHECK-NEXT: Pass:            loop-interchange
-; CHECK-NEXT: Name:            Dependence
+; CHECK-NEXT: Name:            InterchangeNotProfitable
 ; CHECK-NEXT: Function:        test01
 ; CHECK-NEXT: Args:
-; CHECK-NEXT:   - String:          All loops have dependencies in all directions.
+; CHECK-NEXT:   - String:          Interchanging loops is not considered to improve cache locality nor vectorization.
 ; CHECK-NEXT: ...
 
 ; DELIN: --- !Analysis
@@ -142,12 +142,12 @@ define void @test02(i32 %k, i32 %N) {
 ; CHECK-NEXT:   - String:          Computed dependence info, invoking the transform.
 ; CHECK-NEXT: ...
 
-; CHECK: --- !Missed
+; CHECK: --- !Passed
 ; CHECK-NEXT: Pass:            loop-interchange
-; CHECK-NEXT: Name:            Dependence
+; CHECK-NEXT: Name:            Interchanged
 ; CHECK-NEXT: Function:        test02
 ; CHECK-NEXT: Args:
-; CHECK-NEXT:   - String:          All loops have dependencies in all directions.
+; CHECK-NEXT:   - String:          Loop interchanged with enclosing loop.
 ; CHECK-NEXT: ...
 
 ; DELIN: --- !Analysis
@@ -285,12 +285,20 @@ for.end17:
   ret void
 }
 
-; CHECK: --- !Missed
+; CHECK: --- !Analysis
 ; CHECK-NEXT: Pass:            loop-interchange
 ; CHECK-NEXT: Name:            Dependence
 ; CHECK-NEXT: Function:        test04
 ; CHECK-NEXT: Args:
-; CHECK-NEXT:   - String:          All loops have dependencies in all directions.
+; CHECK-NEXT:   - String:          Computed dependence info, invoking the transform.
+; CHECK-NEXT: ...
+
+; CHECK: --- !Missed
+; CHECK-NEXT: Pass:            loop-interchange
+; CHECK-NEXT: Name:            NotTightlyNested
+; CHECK-NEXT: Function:        test04
+; CHECK-NEXT: Args:
+; CHECK-NEXT:   - String:          Cannot interchange loops because they are not tightly nested.
 ; CHECK-NEXT: ...
 
 ; DELIN: --- !Missed
diff --git a/llvm/test/Transforms/LoopInterchange/outer-dependency-lte.ll b/llvm/test/Transforms/LoopInterchange/outer-dependency-lte.ll
index 4aba99f35678e..c8e79dc169b1d 100644
--- a/llvm/test/Transforms/LoopInterchange/outer-dependency-lte.ll
+++ b/llvm/test/Transforms/LoopInterchange/outer-dependency-lte.ll
@@ -22,7 +22,7 @@
 ; CHECK-NEXT: Name:            Dependence
 ; CHECK-NEXT: Function:        f
 ; CHECK-NEXT: Args:
-; CHECK-NEXT:   - String:          All loops have dependencies in all directions.
+; CHECK-NEXT:   - String:          Cannot interchange loops due to dependences.
 ; CHECK-NEXT: ...
 
 
diff --git a/llvm/test/Transforms/LoopRotate/pr35210.ll b/llvm/test/Transforms/LoopRotate/pr35210.ll
index c24f5164e532c..a0f65448d4e5a 100644
--- a/llvm/test/Transforms/LoopRotate/pr35210.ll
+++ b/llvm/test/Transforms/LoopRotate/pr35210.ll
@@ -16,10 +16,14 @@
 ; CHECK-NEXT: Running analysis: AAManager on f
 ; CHECK-NEXT: Running analysis: TargetLibraryAnalysis on f
 ; CHECK-NEXT: Running analysis: ScalarEvolutionAnalysis on f
+; CHECK-NEXT: Running analysis: DependenceAnalysis on f
+; CHECK-NEXT: Running analysis: BatchDelinearizationAnalysis on f
 ; CHECK-NEXT: Running analysis: InnerAnalysisManagerProxy{{.*}} on f
 ; CHECK-NEXT: Running pass: LoopRotatePass on loop %bb in function f
 ; CHECK-NEXT: Folding loop latch bb4 into bb
 ; CHECK-NEXT: Invalidating analysis: PostDominatorTreeAnalysis on f
+; CHECK-NEXT: Invalidating analysis: BatchDelinearizationAnalysis on f
+; CHECK-NEXT: Invalidating analysis: DependenceAnalysis on f
 ; CHECK-NEXT: Running pass: ADCEPass on f
 ; CHECK-NEXT: Running analysis: PostDominatorTreeAnalysis on f
 
@@ -35,10 +39,14 @@
 ; MSSA-NEXT: Running analysis: AAManager on f
 ; MSSA-NEXT: Running analysis: TargetLibraryAnalysis on f
 ; MSSA-NEXT: Running analysis: ScalarEvolutionAnalysis on f
+; MSSA-NEXT: Running analysis: DependenceAnalysis on f
+; MSSA-NEXT: Running analysis: BatchDelinearizationAnalysis on f
 ; MSSA-NEXT: Running analysis: InnerAnalysisManagerProxy{{.*}} on f
 ; MSSA-NEXT: Running pass: LoopRotatePass on loop %bb in function f
 ; MSSA-NEXT: Folding loop latch bb4 into bb
 ; MSSA-NEXT: Invalidating analysis: PostDominatorTreeAnalysis on f
+; MSSA-NEXT: Invalidating analysis: BatchDelinearizationAnalysis on f
+; MSSA-NEXT: Invalidating analysis: DependenceAnalysis on f
 ; MSSA-NEXT: Running pass: ADCEPass on f
 ; MSSA-NEXT: Running analysis: PostDominatorTreeAnalysis on f
 
diff --git a/llvm/test/Transforms/SimpleLoopUnswitch/nontrivial-unswitch-markloopasdeleted.ll b/llvm/test/Transforms/SimpleLoopUnswitch/nontrivial-unswitch-markloopasdeleted.ll
index 383407b371da0..77318f3a89f5b 100644
--- a/llvm/test/Transforms/SimpleLoopUnswitch/nontrivial-unswitch-markloopasdeleted.ll
+++ b/llvm/test/Transforms/SimpleLoopUnswitch/nontrivial-unswitch-markloopasdeleted.ll
@@ -27,6 +27,8 @@
 ; loop_a_inner related analysis above.
 ;
 ; CHECK: Invalidating analysis: LoopAccessAnalysis on test6
+; CHECK-NEXT: Invalidating analysis: BatchDelinearizationAnalysis on test6
+; CHECK-NEXT: Invalidating analysis: DependenceAnalysis on test6
 ; CHECK-NEXT: Running pass: LoopDistributePass on test6
 ; CHECK-NEXT: Running analysis: LoopAccessAnalysis on test6
 



More information about the llvm-commits mailing list