[llvm] f007053 - [LoopVectorize] Clear stale CycleAnalysis after vectorizing a loop (#215237)

via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 14 00:15:28 PDT 2026


Author: Karthika Devi C
Date: 2026-08-14T12:45:23+05:30
New Revision: f0070530bfa4eb2158c567216d801d819ece35f6

URL: https://github.com/llvm/llvm-project/commit/f0070530bfa4eb2158c567216d801d819ece35f6
DIFF: https://github.com/llvm/llvm-project/commit/f0070530bfa4eb2158c567216d801d819ece35f6.diff

LOG: [LoopVectorize] Clear stale CycleAnalysis after vectorizing a loop (#215237)

After a6af12620778, LoopVectorizePass crashes when processing functions
with multiple loops. After vectorizing a loop, locks may be deleted, but
the cached CycleAnalysis still holds pointers to those blocks. If BFI is
later requested for a subsequent loop, it uses the stale CycleInfo and
crashes. Clear the cached CycleAnalysis after each loop vectorization so
that BlockFrequencyAnalysis recomputes it fresh if needed.

Fixes #215236

---------

Co-authored-by: Florian Hahn <flo at fhahn.com>

Added: 
    llvm/test/Transforms/LoopVectorize/bfi-stale-crash.ll

Modified: 
    llvm/include/llvm/Transforms/Vectorize/LoopVectorize.h
    llvm/lib/Transforms/Vectorize/LoopVectorize.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/Transforms/Vectorize/LoopVectorize.h b/llvm/include/llvm/Transforms/Vectorize/LoopVectorize.h
index 4512e5664cfc4..31bba6d8d3b79 100644
--- a/llvm/include/llvm/Transforms/Vectorize/LoopVectorize.h
+++ b/llvm/include/llvm/Transforms/Vectorize/LoopVectorize.h
@@ -153,6 +153,7 @@ struct LoopVectorizePass : public OptionalPassInfoMixin<LoopVectorizePass> {
   OptimizationRemarkEmitter *ORE;
   ProfileSummaryInfo *PSI;
   AAResults *AA;
+  FunctionAnalysisManager *FAM = nullptr;
 
   LLVM_ABI PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
   LLVM_ABI void

diff  --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index 137f3e4a023b3..c12a4f562f600 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -83,6 +83,7 @@
 #include "llvm/Analysis/BlockFrequencyInfo.h"
 #include "llvm/Analysis/CFG.h"
 #include "llvm/Analysis/CodeMetrics.h"
+#include "llvm/Analysis/CycleAnalysis.h"
 #include "llvm/Analysis/DemandedBits.h"
 #include "llvm/Analysis/GlobalsModRef.h"
 #include "llvm/Analysis/LoopAccessAnalysis.h"
@@ -8432,6 +8433,13 @@ LoopVectorizeResult LoopVectorizePass::runImpl(Function &F) {
     if (Changed) {
       LAIs->clear();
 
+      // If CycleAnalysis was cached by a prior pass (e.g. DSE), it now holds
+      // stale pointers to blocks that may have been deleted during
+      // vectorization. Clear it so that BlockFrequencyAnalysis (if requested
+      // for a later loop) recomputes it fresh.
+      if (FAM->getCachedResult<CycleAnalysis>(F))
+        FAM->clearAnalysis<CycleAnalysis>(F);
+
 #ifndef NDEBUG
       if (VerifySCEV)
         SE->verify();
@@ -8462,6 +8470,7 @@ PreservedAnalyses LoopVectorizePass::run(Function &F,
 
   auto &MAMProxy = AM.getResult<ModuleAnalysisManagerFunctionProxy>(F);
   PSI = MAMProxy.getCachedResult<ProfileSummaryAnalysis>(*F.getParent());
+  FAM = &AM;
   GetBFI = [&AM, &F]() -> BlockFrequencyInfo & {
     return AM.getResult<BlockFrequencyAnalysis>(F);
   };

diff  --git a/llvm/test/Transforms/LoopVectorize/bfi-stale-crash.ll b/llvm/test/Transforms/LoopVectorize/bfi-stale-crash.ll
new file mode 100644
index 0000000000000..f370badf773f9
--- /dev/null
+++ b/llvm/test/Transforms/LoopVectorize/bfi-stale-crash.ll
@@ -0,0 +1,121 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -passes='dse,loop-vectorize' -force-vector-width=4 -S | FileCheck %s
+;
+; Verify that LoopVectorize does not crash when BlockFrequencyInfo is computed
+; after an earlier loop has been vectorized and a prior pass (DSE) has cached
+; CycleAnalysis.
+
+ at clear_mask = external global [65 x i64]
+
+define void @InitializeMasks(ptr %mask_1) {
+; CHECK-LABEL: @InitializeMasks(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[VECTOR_PH:%.*]]
+; CHECK:       vector.ph:
+; CHECK-NEXT:    br label [[VECTOR_BODY:%.*]]
+; CHECK:       vector.body:
+; CHECK-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, [[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], [[VECTOR_BODY]] ]
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr [8 x i8], ptr @clear_mask, i64 [[INDEX]]
+; CHECK-NEXT:    store <4 x i64> splat (i64 1), ptr [[TMP0]], align 8
+; CHECK-NEXT:    [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 4
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i64 [[INDEX_NEXT]], 64
+; CHECK-NEXT:    br i1 [[TMP1]], label [[MIDDLE_BLOCK:%.*]], label [[VECTOR_BODY]], !llvm.loop [[LOOP0:![0-9]+]]
+; CHECK:       middle.block:
+; CHECK-NEXT:    br label [[FOR_END:%.*]]
+; CHECK:       for.end:
+; CHECK-NEXT:    store i64 0, ptr [[MASK_1:%.*]], align 8
+; CHECK-NEXT:    br label [[VECTOR_PH1:%.*]]
+; CHECK:       vector.ph1:
+; CHECK-NEXT:    br label [[VECTOR_BODY2:%.*]]
+; CHECK:       vector.body2:
+; CHECK-NEXT:    [[INDEX3:%.*]] = phi i64 [ 0, [[VECTOR_PH1]] ], [ [[INDEX_NEXT10:%.*]], [[PRED_STORE_CONTINUE9:%.*]] ]
+; CHECK-NEXT:    [[VEC_IND:%.*]] = phi <4 x i64> [ <i64 0, i64 1, i64 2, i64 3>, [[VECTOR_PH1]] ], [ [[VEC_IND_NEXT:%.*]], [[PRED_STORE_CONTINUE9]] ]
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ule <4 x i64> [[VEC_IND]], splat (i64 15)
+; CHECK-NEXT:    [[TMP3:%.*]] = extractelement <4 x i1> [[TMP2]], i64 0
+; CHECK-NEXT:    br i1 [[TMP3]], label [[PRED_STORE_IF:%.*]], label [[PRED_STORE_CONTINUE:%.*]]
+; CHECK:       pred.store.if:
+; CHECK-NEXT:    store i64 0, ptr [[MASK_1]], align 8
+; CHECK-NEXT:    br label [[PRED_STORE_CONTINUE]]
+; CHECK:       pred.store.continue:
+; CHECK-NEXT:    [[TMP4:%.*]] = extractelement <4 x i1> [[TMP2]], i64 1
+; CHECK-NEXT:    br i1 [[TMP4]], label [[PRED_STORE_IF4:%.*]], label [[PRED_STORE_CONTINUE5:%.*]]
+; CHECK:       pred.store.if4:
+; CHECK-NEXT:    store i64 0, ptr [[MASK_1]], align 8
+; CHECK-NEXT:    br label [[PRED_STORE_CONTINUE5]]
+; CHECK:       pred.store.continue5:
+; CHECK-NEXT:    [[TMP5:%.*]] = extractelement <4 x i1> [[TMP2]], i64 2
+; CHECK-NEXT:    br i1 [[TMP5]], label [[PRED_STORE_IF6:%.*]], label [[PRED_STORE_CONTINUE7:%.*]]
+; CHECK:       pred.store.if6:
+; CHECK-NEXT:    store i64 0, ptr [[MASK_1]], align 8
+; CHECK-NEXT:    br label [[PRED_STORE_CONTINUE7]]
+; CHECK:       pred.store.continue7:
+; CHECK-NEXT:    [[TMP6:%.*]] = extractelement <4 x i1> [[TMP2]], i64 3
+; CHECK-NEXT:    br i1 [[TMP6]], label [[PRED_STORE_IF8:%.*]], label [[PRED_STORE_CONTINUE9]]
+; CHECK:       pred.store.if8:
+; CHECK-NEXT:    store i64 0, ptr [[MASK_1]], align 8
+; CHECK-NEXT:    br label [[PRED_STORE_CONTINUE9]]
+; CHECK:       pred.store.continue9:
+; CHECK-NEXT:    [[INDEX_NEXT10]] = add nuw i64 [[INDEX3]], 4
+; CHECK-NEXT:    [[VEC_IND_NEXT]] = add <4 x i64> [[VEC_IND]], splat (i64 4)
+; CHECK-NEXT:    [[TMP7:%.*]] = icmp eq i64 [[INDEX_NEXT10]], 56
+; CHECK-NEXT:    br i1 [[TMP7]], label [[MIDDLE_BLOCK11:%.*]], label [[VECTOR_BODY2]], !llvm.loop [[LOOP3:![0-9]+]]
+; CHECK:       middle.block11:
+; CHECK-NEXT:    br label [[SCALAR_PH:%.*]]
+; CHECK:       scalar.ph:
+; CHECK-NEXT:    br label [[FOR_BODY98:%.*]]
+; CHECK:       for.body98:
+; CHECK-NEXT:    [[INDVARS_IV3551:%.*]] = phi i64 [ 56, [[SCALAR_PH]] ], [ [[INDVARS_IV_NEXT356:%.*]], [[FOR_INC140:%.*]] ]
+; CHECK-NEXT:    [[INDVARS_IV_NEXT356]] = add i64 [[INDVARS_IV3551]], 1
+; CHECK-NEXT:    [[CMP107:%.*]] = icmp ugt i64 [[INDVARS_IV3551]], 15
+; CHECK-NEXT:    br i1 [[CMP107]], label [[IF_END:%.*]], label [[IF_END_THREAD:%.*]]
+; CHECK:       if.end.thread:
+; CHECK-NEXT:    store i64 0, ptr [[MASK_1]], align 8
+; CHECK-NEXT:    br label [[FOR_INC140]]
+; CHECK:       if.end:
+; CHECK-NEXT:    br i1 false, label [[IF_END_IF_THEN128_CRIT_EDGE:%.*]], label [[FOR_INC140]]
+; CHECK:       if.end.if.then128_crit_edge:
+; CHECK-NEXT:    ret void
+; CHECK:       for.inc140:
+; CHECK-NEXT:    [[EXITCOND358_NOT:%.*]] = icmp eq i64 [[INDVARS_IV3551]], 56
+; CHECK-NEXT:    br i1 [[EXITCOND358_NOT]], label [[FOR_COND180_LOOPEXIT_7:%.*]], label [[FOR_BODY98]], !llvm.loop [[LOOP4:![0-9]+]]
+; CHECK:       for.cond180.loopexit.7:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br label %for.body
+
+for.body:
+  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
+  %arrayidx = getelementptr [8 x i8], ptr @clear_mask, i64 %indvars.iv
+  store i64 1, ptr %arrayidx, align 8
+  %indvars.iv.next = add i64 %indvars.iv, 1
+  %exitcond.not = icmp eq i64 %indvars.iv.next, 64
+  br i1 %exitcond.not, label %for.end, label %for.body
+
+for.end:
+  store i64 0, ptr %mask_1, align 8
+  br label %for.body98
+
+for.body98:
+  %indvars.iv3551 = phi i64 [ 0, %for.end ], [ %indvars.iv.next356, %for.inc140 ]
+  %indvars.iv.next356 = add i64 %indvars.iv3551, 1
+  %cmp107 = icmp ugt i64 %indvars.iv3551, 15
+  br i1 %cmp107, label %if.end, label %if.end.thread
+
+if.end.thread:
+  store i64 0, ptr %mask_1, align 8
+  br label %for.inc140
+
+if.end:
+  br i1 false, label %if.end.if.then128_crit_edge, label %for.inc140
+
+if.end.if.then128_crit_edge:
+  ret void
+
+for.inc140:
+  %exitcond358.not = icmp eq i64 %indvars.iv3551, 56
+  br i1 %exitcond358.not, label %for.cond180.loopexit.7, label %for.body98
+
+for.cond180.loopexit.7:
+  ret void
+}


        


More information about the llvm-commits mailing list