Bug type: crash
Component: LoopVectorize
Bug location: llvm/lib/Transforms/Vectorize/LoopVectorize.cpp: LoopVectorizationCostModel::collectValuesToIgnore
Issue title: llvm/lib/Transforms/Vectorize/LoopVectorize.cpp:10353: bool llvm::LoopVectorizePass::processLoop(llvm::Loop*): Assertion `VF.Width == Width && "VPlan cost model and legacy cost model disagreed"' failed.
Labels: vectorizers
crash-on-valid
Reported by: dcb314

[calcc-0ebd65.c.gz](https://github.com/user-attachments/files/15926158/calcc-0ebd65.c.gz)
[calcc-0ebd65.sh.gz](https://github.com/user-attachments/files/15926159/calcc-0ebd65.sh.gz)

Stack backtrace is 

#11 0x0000000003adfddd llvm::LoopVectorizePass::processLoop(llvm::Loop*) /home/dcb40b/llvm/trunk/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp:10353:9
#12 0x0000000003ae347f llvm::LoopVectorizePass::runImpl(llvm::Function&, llvm::ScalarEvolution&, llvm::LoopInfo&, llvm::TargetTransformInfo&, llvm::DominatorTree&, llvm::BlockFrequencyInfo*, llvm::TargetLibraryInfo*, llvm::DemandedBits&, llvm::AssumptionCache&, llvm::LoopAccessInfoManager&, llvm::OptimizationRemarkEmitter&, llvm::ProfileSummaryInfo*) /home/dcb40b/llvm/trunk/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp:10446:27
#13 0x0000000003ae4382 llvm::LoopVectorizePass::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) /home/dcb40b/llvm/trunk/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp:10486:5
#14 0x00000000034fbd6d llvm::detail::PassModel<llvm::Function, llvm::LoopVectorizePass, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) /home/dcb40b/llvm/trunk/llvm/include/llvm/IR/PassManagerInternal.h:91:3
#15 0x0000000001ae5b21 llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) /home/dcb40b/llvm/trunk/llvm/include/llvm/IR/PassManagerImpl.h:53:18


Comments: author: dcb314
body: The crash first seems to occur sometime between git hash fd88089151e66a4cb1d90aaa224e4cb4e7a748f4 from yesterday 20240620
and 225d8fc8eb24fb797154c1ef6dcbe5ba033142da from today,
which is 134 commits.

author: fhahn
body: Thanks for the report, caused by https://github.com/llvm/llvm-project/pull/92555 which has been reverted for now. I'll add a reduced test based on the reproducer.
author: fhahn
body: https://github.com/llvm/llvm-project/pull/92555 has been recommitted with a fix. Please let me know if you see any other issues!
author: dcb314
body: It has come back:

clang: /home/dcb40b/llvm/trunk/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp:10377: bool llvm::LoopVectorizePass::processLoop(llvm::Loop*): Assertion `VF.Width == Width && "VPlan cost model and legacy cost model disagreed"' failed.

[in-4e39b8.sh.gz](https://github.com/user-attachments/files/16445872/in-4e39b8.sh.gz)
[Uploading in-4e39b8.c.gz…]()

author: dcb314
body: Seems to have come back sometime between d99efd53f5103df4db517f499fcdd26cd3b080a3
(dated 20240710) and 4710e0f498cb661ca17c99cb174616102fcad923, dated 20240711.


author: fhahn
body: @dcb314 it looks like there has been an issue with uploading the `.c` file. Could you re-upload it again?
author: dcb314
body: My apologies for the failed upload.
Here is another try:

[in-4e39b8.c.gz](https://github.com/user-attachments/files/16455342/in-4e39b8.c.gz)


Fix patch:
commit fdb9f96fa2a926425bdf8315048db7623d63547d
Author: Florian Hahn <flo@fhahn.com>
Date:   Sun Aug 4 20:54:25 2024 +0100

    [LV] Consider earlier stores to invariant reduction address as dead.
    
    For invariant stores to an address of a reduction, only the latest store
    will be generated outside the loop. Consider earlier stores as dead.
    
    This fixes a difference between the legacy and VPlan-based cost model.
    
    Fixes https://github.com/llvm/llvm-project/issues/96294.

diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index 40d10395de17..1eca9b10fad5 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -6723,14 +6723,18 @@ void LoopVectorizationCostModel::collectValuesToIgnore() {
     return RequiresScalarEpilogue &&
            !TheLoop->contains(cast<Instruction>(U)->getParent());
   };
+  MapVector<Value *, SmallVector<Value *>> DeadInvariantStoreOps;
   for (BasicBlock *BB : TheLoop->blocks())
     for (Instruction &I : *BB) {
       // Find all stores to invariant variables. Since they are going to sink
       // outside the loop we do not need calculate cost for them.
       StoreInst *SI;
       if ((SI = dyn_cast<StoreInst>(&I)) &&
-          Legal->isInvariantAddressOfReduction(SI->getPointerOperand()))
+          Legal->isInvariantAddressOfReduction(SI->getPointerOperand())) {
         ValuesToIgnore.insert(&I);
+        auto I = DeadInvariantStoreOps.insert({SI->getPointerOperand(), {}});
+        I.first->second.push_back(SI->getValueOperand());
+      }
 
       if (VecValuesToIgnore.contains(&I) || ValuesToIgnore.contains(&I))
         continue;
@@ -6771,6 +6775,10 @@ void LoopVectorizationCostModel::collectValuesToIgnore() {
     DeadInterleavePointerOps.append(Op->op_begin(), Op->op_end());
   }
 
+  for (const auto &[_, Ops] : DeadInvariantStoreOps) {
+    for (Value *Op : ArrayRef(Ops).drop_back())
+      DeadOps.push_back(Op);
+  }
   // Mark ops that would be trivially dead and are only used by ignored
   // instructions as free.
   BasicBlock *Header = TheLoop->getHeader();
@@ -6781,8 +6789,8 @@ void LoopVectorizationCostModel::collectValuesToIgnore() {
         (isa<PHINode>(Op) && Op->getParent() == Header) ||
         !wouldInstructionBeTriviallyDead(Op, TLI) ||
         any_of(Op->users(), [this, IsLiveOutDead](User *U) {
-          return !VecValuesToIgnore.contains(U) && ValuesToIgnore.contains(U) &&
-                 !IsLiveOutDead(U);
+          return !VecValuesToIgnore.contains(U) &&
+                 !ValuesToIgnore.contains(U) && !IsLiveOutDead(U);
         }))
       continue;
 


Regression tests:
file: llvm/test/Transforms/LoopVectorize/X86/cost-model.ll
commands: opt < %s -passes=loop-vectorize -mtriple=x86_64-apple-macosx10.8.0 -mcpu=corei7-avx -S
tests: test_name: reduction_store
test_body: target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.8.0"

define void @reduction_store(ptr noalias %src, ptr %dst, i1 %x) #0 {
entry:
  br label %loop

loop:                                             ; preds = %loop, %entry
  %red = phi i32 [ 0, %entry ], [ %red.next, %loop ]
  %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
  %gep.src = getelementptr inbounds i32, ptr %src, i32 %iv
  %l = load i32, ptr %gep.src, align 4
  %l.and = and i32 %l, 3
  store i32 %l.and, ptr %dst, align 4
  %x.ext = zext i1 %x to i64
  %lshr = lshr i64 %x.ext, 12
  %t = trunc i64 %lshr to i32
  %red.next = and i32 %red, %t
  store i32 %red.next, ptr %dst, align 4
  %iv.next = add i32 %iv, 1
  %ec = icmp eq i32 %iv, 29
  br i1 %ec, label %exit, label %loop

exit:                                             ; preds = %loop
  ret void
}

attributes #0 = { "target-cpu"="znver3" }