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;

opt < %s -passes=loop-vectorize -mtriple=x86_64-apple-macosx10.8.0 -mcpu=corei7-avx -S

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" }

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.

[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

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

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.

https://github.com/llvm/llvm-project/pull/92555 has been recommitted with a fix. Please let me know if you see any other issues!

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…]()

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

@dcb314 it looks like there has been an issue with uploading the `.c` file. Could you re-upload it again?

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)


commit 320038579d3c23b78f99618b71640f51423fe321
Author: Florian Hahn <flo@fhahn.com>
Date:   Thu Nov 21 21:11:20 2024 +0000

    [VPlan] Return cost of PHI for scalar VFs in computeCost for FORs.

    This fixes a crash when the VF is scalar.

    Fixes https://github.com/llvm/llvm-project/issues/116375.

diff --git a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
index 71aca3be9e5d..24cf4666c62c 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
@@ -3317,6 +3317,10 @@ void VPFirstOrderRecurrencePHIRecipe::execute(VPTransformState &State) {
 InstructionCost
 VPFirstOrderRecurrencePHIRecipe::computeCost(ElementCount VF,
                                              VPCostContext &Ctx) const {
+  TTI::TargetCostKind CostKind = TTI::TCK_RecipThroughput;
+  if (VF.isScalar())
+  return Ctx.TTI.getCFInstrCost(Instruction::PHI, CostKind);
+
   if (VF.isScalable() && VF.getKnownMinValue() == 1)
     return InstructionCost::getInvalid();

@@ -3325,7 +3329,6 @@ VPFirstOrderRecurrencePHIRecipe::computeCost(ElementCount VF,
   Type *VectorTy =
       ToVectorTy(Ctx.Types.inferScalarType(this->getVPSingleValue()), VF);

-  TTI::TargetCostKind CostKind = TTI::TCK_RecipThroughput;
   return Ctx.TTI.getShuffleCost(TargetTransformInfo::SK_Splice,
                                 cast<VectorType>(VectorTy), Mask, CostKind,
                                 VF.getKnownMinValue() - 1);

opt -passes="loop-vectorize" -pass-remarks-output=/dev/stderr -S %s

; REMARKS: the cost-model indicates that vectorization is not beneficial

; Test for https://github.com/llvm/llvm-project/issues/116375.
define void @test_i24_load_for(ptr noalias %src, ptr %dst) {
;
entry:
  br label %loop

loop:
  %iv = phi i16 [ 0, %entry ], [ %iv.next, %loop ]
  %for = phi i24 [ 0, %entry ], [ %for.next, %loop ]
  %iv.next = add i16 %iv, 1
  %gep.src = getelementptr inbounds i24, ptr %src, i16 %iv
  %for.next = load i24, ptr %gep.src, align 1
  %gep.dst = getelementptr inbounds i24, ptr %dst, i16 %iv
  store i24 %for, ptr %gep.dst
  %ec = icmp eq i16 %iv.next, 1000
  br i1 %ec, label %exit, label %loop

exit:
  ret void
}

opt -passes="loop-vectorize" -pass-remarks-output=tmp.opts crashes with 'Assertion `isa<To>(Val) && "cast<Ty>() argument of incompatible type!"' failed.'

llvm commit: 10b048c8922d
Reproduce with: ```opt -passes="loop-vectorize" bbi-101140.ll -o /dev/null -pass-remarks-output=tmp.opts```
Result:
```
opt: ../include/llvm/Support/Casting.h:578: decltype(auto) llvm::cast(From *) [To = llvm::VectorType, From = llvm::Type]: Assertion `isa<To>(Val) && "cast<Ty>() argument of incompatible type!"' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:
0.	Program arguments: build-all/bin/opt -passes=loop-vectorize bbi-101140.ll -o /dev/null -pass-remarks-output=tmp.opts
1.	Running pass "function(loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>)" on module "bbi-101140.ll"
2.	Running pass "loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>" on function "main"
 #0 0x000055b814f24938 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (build-all/bin/opt+0x4435938)
 #1 0x000055b814f223fe llvm::sys::RunSignalHandlers() (build-all/bin/opt+0x44333fe)
 #2 0x000055b814f2516d SignalHandler(int) Signals.cpp:0:0
 #3 0x00007f5d1b5dbcf0 __restore_rt (/lib64/libpthread.so.0+0x12cf0)
 #4 0x00007f5d19194acf raise (/lib64/libc.so.6+0x4eacf)
 #5 0x00007f5d19167ea5 abort (/lib64/libc.so.6+0x21ea5)
 #6 0x00007f5d19167d79 _nl_load_domain.cold.0 (/lib64/libc.so.6+0x21d79)
 #7 0x00007f5d1918d426 (/lib64/libc.so.6+0x47426)
 #8 0x000055b816474525 llvm::VPFirstOrderRecurrencePHIRecipe::computeCost(llvm::ElementCount, llvm::VPCostContext&) const (build-all/bin/opt+0x5985525)
 #9 0x000055b816461f4c llvm::VPRecipeBase::cost(llvm::ElementCount, llvm::VPCostContext&) (build-all/bin/opt+0x5972f4c)
#10 0x000055b8163faa3a llvm::LoopVectorizationPlanner::emitInvalidCostRemarks(llvm::OptimizationRemarkEmitter*) (build-all/bin/opt+0x590ba3a)
#11 0x000055b816427189 llvm::LoopVectorizePass::processLoop(llvm::Loop*) (build-all/bin/opt+0x5938189)
#12 0x000055b81642cd0b llvm::LoopVectorizePass::runImpl(llvm::Function&) (build-all/bin/opt+0x593dd0b)
#13 0x000055b81642d568 llvm::LoopVectorizePass::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (build-all/bin/opt+0x593e568)
#14 0x000055b8162e33dd llvm::detail::PassModel<llvm::Function, llvm::LoopVectorizePass, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) PassBuilderPipelines.cpp:0:0
#15 0x000055b81512d317 llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (build-all/bin/opt+0x463e317)
#16 0x000055b8162dcf6d llvm::detail::PassModel<llvm::Function, llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) PassBuilderPipelines.cpp:0:0
#17 0x000055b815131ea6 llvm::ModuleToFunctionPassAdaptor::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (build-all/bin/opt+0x4642ea6)
#18 0x000055b8162d6a0d llvm::detail::PassModel<llvm::Module, llvm::ModuleToFunctionPassAdaptor, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) PassBuilderPipelines.cpp:0:0
#19 0x000055b81512c047 llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (build-all/bin/opt+0x463d047)
#20 0x000055b81627ab63 llvm::runPassPipeline(llvm::StringRef, llvm::Module&, llvm::TargetMachine*, llvm::TargetLibraryInfoImpl*, llvm::ToolOutputFile*, llvm::ToolOutputFile*, llvm::ToolOutputFile*, llvm::StringRef, llvm::ArrayRef<llvm::PassPlugin>, llvm::ArrayRef<std::function<void (llvm::PassBuilder&)>>, llvm::opt_tool::OutputKind, llvm::opt_tool::VerifierKind, bool, bool, bool, bool, bool, bool, bool) (build-all/bin/opt+0x578bb63)
#21 0x000055b814eebd0a optMain (build-all/bin/opt+0x43fcd0a)
#22 0x00007f5d19180d85 __libc_start_main (/lib64/libc.so.6+0x3ad85)
#23 0x000055b814ee5b2e _start (build-all/bin/opt+0x43f6b2e)
Abort (core dumped)
```
[bbi-101140.ll.gz](https://github.com/user-attachments/files/17774956/bbi-101140.ll.gz)

This starts happening with https://github.com/llvm/llvm-project/commit/680901ed8010319843cd81275b845d682f77e27f
```
[VPlan] Implement VPHeaderPHIRecipe::computeCost.

Fill out computeCost implementations for various header PHI recipes,
matching the legacy cost model for now.
```

Thanks!


commit 87a988e881ac92e3d87aae01dc632f33c1fb36aa
Author: Alexey Bataev <a.bataev@outlook.com>
Date:   Fri Aug 30 05:16:57 2024 -0700

    [SLP]Fix PR106655: Use FinalShuffle for alternate cast nodes.

    Need to use FinalShuffle function for all vectorized results to
    correctly produce vectorized value.

    Fixes https://github.com/llvm/llvm-project/issues/106655

diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index edb2567fa057..345b01b82c6a 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -13137,7 +13137,7 @@ Value *BoUpSLP::vectorizeTree(TreeEntry *E, bool PostponedPHIs) {
   }

   bool IsReverseOrder = isReverseOrder(E->ReorderIndices);
-  auto FinalShuffle = [&](Value *V, const TreeEntry *E, VectorType *VecTy) {
+  auto FinalShuffle = [&](Value *V, const TreeEntry *E) {
     ShuffleInstructionBuilder ShuffleBuilder(ScalarTy, Builder, *this);
     if (E->getOpcode() == Instruction::Store &&
         E->State == TreeEntry::Vectorize) {
@@ -13197,7 +13197,7 @@ Value *BoUpSLP::vectorizeTree(TreeEntry *E, bool PostponedPHIs) {
                                PH->getParent()->getFirstInsertionPt());
         Builder.SetCurrentDebugLocation(PH->getDebugLoc());

-        V = FinalShuffle(V, E, VecTy);
+        V = FinalShuffle(V, E);

         E->VectorizedValue = V;
         if (PostponedPHIs)
@@ -13249,7 +13249,7 @@ Value *BoUpSLP::vectorizeTree(TreeEntry *E, bool PostponedPHIs) {
       if (const TreeEntry *TE = getTreeEntry(V))
         V = TE->VectorizedValue;
       setInsertPointAfterBundle(E);
-      V = FinalShuffle(V, E, VecTy);
+      V = FinalShuffle(V, E);
       E->VectorizedValue = V;
       return V;
     }
@@ -13259,7 +13259,7 @@ Value *BoUpSLP::vectorizeTree(TreeEntry *E, bool PostponedPHIs) {
       Value *Ptr = LI->getPointerOperand();
       LoadInst *V = Builder.CreateAlignedLoad(VecTy, Ptr, LI->getAlign());
       Value *NewV = propagateMetadata(V, E->Scalars);
-      NewV = FinalShuffle(NewV, E, VecTy);
+      NewV = FinalShuffle(NewV, E);
       E->VectorizedValue = NewV;
       return NewV;
     }
@@ -13474,7 +13474,7 @@ Value *BoUpSLP::vectorizeTree(TreeEntry *E, bool PostponedPHIs) {
       Value *V = (VecOpcode != ShuffleOrOp && VecOpcode == Instruction::BitCast)
                      ? InVec
                      : Builder.CreateCast(VecOpcode, InVec, VecTy);
-      V = FinalShuffle(V, E, VecTy);
+      V = FinalShuffle(V, E);

       E->VectorizedValue = V;
       ++NumVectorInstructions;
@@ -13518,7 +13518,7 @@ Value *BoUpSLP::vectorizeTree(TreeEntry *E, bool PostponedPHIs) {
       propagateIRFlags(V, E->Scalars, VL0);
       // Do not cast for cmps.
       VecTy = cast<FixedVectorType>(V->getType());
-      V = FinalShuffle(V, E, VecTy);
+      V = FinalShuffle(V, E);

       E->VectorizedValue = V;
       ++NumVectorInstructions;
@@ -13571,7 +13571,7 @@ Value *BoUpSLP::vectorizeTree(TreeEntry *E, bool PostponedPHIs) {
       assert(getNumElements(Cond->getType()) == TrueNumElements &&
              "Cannot vectorize Instruction::Select");
       Value *V = Builder.CreateSelect(Cond, True, False);
-      V = FinalShuffle(V, E, VecTy);
+      V = FinalShuffle(V, E);

       E->VectorizedValue = V;
       ++NumVectorInstructions;
@@ -13593,7 +13593,7 @@ Value *BoUpSLP::vectorizeTree(TreeEntry *E, bool PostponedPHIs) {
       if (auto *I = dyn_cast<Instruction>(V))
         V = propagateMetadata(I, E->Scalars);

-      V = FinalShuffle(V, E, VecTy);
+      V = FinalShuffle(V, E);

       E->VectorizedValue = V;
       ++NumVectorInstructions;
@@ -13611,7 +13611,7 @@ Value *BoUpSLP::vectorizeTree(TreeEntry *E, bool PostponedPHIs) {
       }

       Value *V = Builder.CreateFreeze(Op);
-      V = FinalShuffle(V, E, VecTy);
+      V = FinalShuffle(V, E);

       E->VectorizedValue = V;
       ++NumVectorInstructions;
@@ -13655,7 +13655,7 @@ Value *BoUpSLP::vectorizeTree(TreeEntry *E, bool PostponedPHIs) {
                 auto *CI = dyn_cast<ConstantInt>(Op);
                 return CI && CI->getValue().countr_one() >= It->second.first;
               })) {
-            V = FinalShuffle(I == 0 ? RHS : LHS, E, VecTy);
+            V = FinalShuffle(I == 0 ? RHS : LHS, E);
             E->VectorizedValue = V;
             ++NumVectorInstructions;
             return V;
@@ -13688,7 +13688,7 @@ Value *BoUpSLP::vectorizeTree(TreeEntry *E, bool PostponedPHIs) {
           I->setHasNoUnsignedWrap(/*b=*/false);
       }

-      V = FinalShuffle(V, E, VecTy);
+      V = FinalShuffle(V, E);

       E->VectorizedValue = V;
       ++NumVectorInstructions;
@@ -13780,7 +13780,7 @@ Value *BoUpSLP::vectorizeTree(TreeEntry *E, bool PostponedPHIs) {
       }
       Value *V = propagateMetadata(NewLI, E->Scalars);

-      V = FinalShuffle(V, E, VecTy);
+      V = FinalShuffle(V, E);
       E->VectorizedValue = V;
       ++NumVectorInstructions;
       return V;
@@ -13794,7 +13794,7 @@ Value *BoUpSLP::vectorizeTree(TreeEntry *E, bool PostponedPHIs) {
       if (VecValue->getType() != VecTy)
         VecValue =
             Builder.CreateIntCast(VecValue, VecTy, GetOperandSignedness(0));
-      VecValue = FinalShuffle(VecValue, E, VecTy);
+      VecValue = FinalShuffle(VecValue, E);

       Value *Ptr = SI->getPointerOperand();
       Instruction *ST;
@@ -13859,7 +13859,7 @@ Value *BoUpSLP::vectorizeTree(TreeEntry *E, bool PostponedPHIs) {
         V = propagateMetadata(I, GEPs);
       }

-      V = FinalShuffle(V, E, VecTy);
+      V = FinalShuffle(V, E);

       E->VectorizedValue = V;
       ++NumVectorInstructions;
@@ -13941,7 +13941,7 @@ Value *BoUpSLP::vectorizeTree(TreeEntry *E, bool PostponedPHIs) {
       Value *V = Builder.CreateCall(CF, OpVecs, OpBundles);

       propagateIRFlags(V, E->Scalars, VL0);
-      V = FinalShuffle(V, E, VecTy);
+      V = FinalShuffle(V, E);

       E->VectorizedValue = V;
       ++NumVectorInstructions;
@@ -14039,6 +14039,7 @@ Value *BoUpSLP::vectorizeTree(TreeEntry *E, bool PostponedPHIs) {
                      "Expected same type as operand.");
               if (auto *I = dyn_cast<Instruction>(LHS))
                 LHS = propagateMetadata(I, E->Scalars);
+              LHS = FinalShuffle(LHS, E);
               E->VectorizedValue = LHS;
               ++NumVectorInstructions;
               return LHS;

opt -S --passes=slp-vectorizer -slp-vectorize-hor=false < %s

[SLP] Assertion `I >= 0 && I < (NumOpElts * 2) && "Out-of-bounds shuffle mask element"' failed.

Live link: https://godbolt.org/z/nePMscjGr

Test case:

```ll
define void @func(i32 %0) {
  %2 = shl i32 %0, 0
  %3 = sext i32 %2 to i64
  %4 = shl i32 0, 0
  %5 = sext i32 %4 to i64
  %6 = or i32 0, 0
  %7 = or i32 0, 0
  %8 = zext i32 %6 to i64
  %9 = zext i32 %7 to i64
  %10 = zext i32 0 to i64
  %11 = zext i32 0 to i64
  %12 = zext i32 0 to i64
  %13 = zext i32 0 to i64
  %14 = zext i32 0 to i64
  %15 = zext i32 0 to i64
  %16 = zext i32 0 to i64
  %17 = zext i32 0 to i64
  %18 = zext i32 0 to i64
  %19 = zext i32 0 to i64
  %20 = zext i32 0 to i64
  %21 = zext i32 0 to i64
  %22 = zext i32 0 to i64
  %23 = zext i32 0 to i64
  %24 = zext i32 0 to i64
  %25 = zext i32 0 to i64
  %26 = zext i32 0 to i64
  %27 = or i64 %3, 0
  %28 = or i64 %3, %8
  %29 = or i64 %3, %9
  %30 = or i64 %3, %10
  %31 = or i64 %3, %11
  %32 = or i64 %3, %12
  %33 = or i64 %3, %13
  %34 = or i64 %3, %14
  %35 = or i64 %3, %15
  %36 = or i64 %3, %16
  %37 = or i64 %3, %17
  %38 = or i64 %3, %18
  %39 = or i64 %3, %19
  %40 = or i64 %3, %20
  %41 = or i64 %3, %21
  %42 = or i64 %3, %22
  %43 = or i64 %3, %23
  %44 = or i64 %3, %24
  %45 = or i64 %3, %25
  %46 = or i64 %3, 0
  %47 = or i64 %3, 0
  %48 = or i64 %3, 0
  %49 = or i64 %3, 0
  %50 = or i64 %3, 0
  %51 = or i64 %3, 0
  %52 = or i64 %3, 0
  %53 = or i64 %3, 0
  %54 = or i64 %3, 0
  %55 = or i64 %3, 0
  %56 = or i64 %3, 0
  %57 = or i64 %3, 0
  %58 = or i64 %3, 0
  %59 = icmp slt i64 %28, 0
  %60 = icmp slt i64 %29, 0
  %61 = icmp slt i64 %30, 0
  %62 = icmp slt i64 %31, 0
  %63 = icmp slt i64 %32, 0
  %64 = icmp slt i64 %33, 0
  %65 = icmp slt i64 %34, 0
  %66 = icmp slt i64 %35, 0
  %67 = icmp slt i64 %36, 0
  %68 = icmp slt i64 %37, 0
  %69 = icmp slt i64 %38, 0
  %70 = icmp slt i64 %39, 0
  %71 = icmp slt i64 %40, 0
  %72 = icmp slt i64 %41, 0
  %73 = icmp slt i64 %42, 0
  %74 = icmp slt i64 %43, 0
  %75 = icmp slt i64 %44, 0
  %76 = icmp slt i64 %45, 0
  %77 = icmp slt i64 %46, 0
  %78 = icmp slt i64 %47, 0
  %79 = icmp slt i64 %48, 0
  %80 = icmp slt i64 %49, 0
  %81 = icmp slt i64 %50, 0
  %82 = icmp slt i64 %51, 0
  %83 = icmp slt i64 %52, 0
  %84 = icmp slt i64 %53, 0
  %85 = icmp slt i64 %54, 0
  %86 = icmp slt i64 %55, 0
  %87 = icmp slt i64 %56, 0
  %88 = icmp slt i64 %57, 0
  %89 = icmp slt i64 %58, 0
  %90 = and i1 false, %59
  %91 = and i1 false, %60
  %92 = and i1 false, %61
  %93 = and i1 false, %62
  %94 = and i1 false, %63
  %95 = and i1 false, %64
  %96 = and i1 false, %65
  %97 = and i1 false, %66
  %98 = and i1 false, %67
  %99 = and i1 false, %68
  %100 = and i1 false, %69
  %101 = and i1 false, %70
  %102 = and i1 false, %71
  %103 = and i1 false, %72
  %104 = and i1 false, %73
  %105 = and i1 false, %74
  %106 = and i1 false, %75
  %107 = and i1 false, %76
  %108 = icmp eq i32 %2, 0
  %109 = and i1 false, %77
  %110 = and i1 false, %78
  %111 = and i1 false, %79
  %112 = and i1 false, %80
  %113 = and i1 false, %81
  %114 = and i1 false, %82
  %115 = and i1 false, %83
  %116 = and i1 false, %84
  %117 = and i1 false, %85
  %118 = and i1 false, %86
  %119 = or i64 %5, %26
  %120 = getelementptr float, ptr addrspace(1) null, i64 %119
  %121 = icmp slt i64 %119, 0
  ret void
}
```

Running via `opt --passes=slp-vectorizer -slp-vectorize-hor=false`:

```sh
opt: /root/llvm-project/llvm/lib/IR/Instructions.cpp:1853: bool isSingleSourceMaskImpl(llvm::ArrayRef<int>, int): Assertion `I >= 0 && I < (NumOpElts * 2) && "Out-of-bounds shuffle mask element"' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:
0.	Program arguments: /opt/compiler-explorer/clang-assertions-trunk/bin/opt -o /app/output.s -S --passes=slp-vectorizer -slp-vectorize-hor=false <source>
1.	Running pass "function(slp-vectorizer)" on module "<source>"
2.	Running pass "slp-vectorizer" on function "func"
 #0 0x0000000004fa4138 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4fa4138)
 #1 0x0000000004fa18ac SignalHandler(int) Signals.cpp:0:0
 #2 0x000073f701e42520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #3 0x000073f701e969fc pthread_kill (/lib/x86_64-linux-gnu/libc.so.6+0x969fc)
 #4 0x000073f701e42476 gsignal (/lib/x86_64-linux-gnu/libc.so.6+0x42476)
 #5 0x000073f701e287f3 abort (/lib/x86_64-linux-gnu/libc.so.6+0x287f3)
 #6 0x000073f701e2871b (/lib/x86_64-linux-gnu/libc.so.6+0x2871b)
 #7 0x000073f701e39e96 (/lib/x86_64-linux-gnu/libc.so.6+0x39e96)
 #8 0x0000000004d097f6 isSingleSourceMaskImpl(llvm::ArrayRef<int>, int) Instructions.cpp:0:0
 #9 0x0000000004d1097a llvm::ShuffleVectorInst::isExtractSubvectorMask(llvm::ArrayRef<int>, int, int&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4d1097a)
#10 0x000000000400fc53 (anonymous namespace)::BaseShuffleAnalysis::isIdentityMask(llvm::ArrayRef<int>, llvm::FixedVectorType const*, bool) SLPVectorizer.cpp:0:0
#11 0x0000000004043781 (anonymous namespace)::BaseShuffleAnalysis::peekThroughShuffles(llvm::Value*&, llvm::SmallVectorImpl<int>&, bool) SLPVectorizer.cpp:0:0
#12 0x000000000405bd21 llvm::Value* (anonymous namespace)::BaseShuffleAnalysis::createShuffle<llvm::Value*, llvm::slpvectorizer::BoUpSLP::ShuffleInstructionBuilder::ShuffleIRBuilder>(llvm::Value*, llvm::Value*, llvm::ArrayRef<int>, llvm::slpvectorizer::BoUpSLP::ShuffleInstructionBuilder::ShuffleIRBuilder&) SLPVectorizer.cpp:0:0
#13 0x000000000405c50a llvm::slpvectorizer::BoUpSLP::ShuffleInstructionBuilder::createShuffle(llvm::Value*, llvm::Value*, llvm::ArrayRef<int>) (.isra.0) SLPVectorizer.cpp:0:0
#14 0x000000000405ce73 llvm::slpvectorizer::BoUpSLP::ShuffleInstructionBuilder::finalize(llvm::ArrayRef<int>, llvm::ArrayRef<std::pair<llvm::slpvectorizer::BoUpSLP::TreeEntry const*, unsigned int>>, unsigned int, llvm::function_ref<void (llvm::Value*&, llvm::SmallVectorImpl<int>&)>) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x405ce73)
#15 0x000000000405d3d9 llvm::slpvectorizer::BoUpSLP::vectorizeOperand(llvm::slpvectorizer::BoUpSLP::TreeEntry*, unsigned int, bool)::'lambda1'(llvm::Value*, llvm::ArrayRef<int>)::operator()(llvm::Value*, llvm::ArrayRef<int>) const SLPVectorizer.cpp:0:0
#16 0x0000000004095c0a llvm::slpvectorizer::BoUpSLP::vectorizeOperand(llvm::slpvectorizer::BoUpSLP::TreeEntry*, unsigned int, bool) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4095c0a)
#17 0x0000000004097032 llvm::slpvectorizer::BoUpSLP::vectorizeTree(llvm::slpvectorizer::BoUpSLP::TreeEntry*, bool) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4097032)
#18 0x0000000004095aa8 llvm::slpvectorizer::BoUpSLP::vectorizeOperand(llvm::slpvectorizer::BoUpSLP::TreeEntry*, unsigned int, bool) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4095aa8)
#19 0x0000000004097294 llvm::slpvectorizer::BoUpSLP::vectorizeTree(llvm::slpvectorizer::BoUpSLP::TreeEntry*, bool) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4097294)
#20 0x00000000040b31cc llvm::slpvectorizer::BoUpSLP::vectorizeTree(llvm::MapVector<llvm::Value*, llvm::SmallVector<llvm::Instruction*, 2u>, llvm::DenseMap<llvm::Value*, unsigned int, llvm::DenseMapInfo<llvm::Value*, void>, llvm::detail::DenseMapPair<llvm::Value*, unsigned int>>, llvm::SmallVector<std::pair<llvm::Value*, llvm::SmallVector<llvm::Instruction*, 2u>>, 0u>> const&, llvm::SmallVectorImpl<std::pair<llvm::Value*, llvm::Value*>>&, llvm::Instruction*) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x40b31cc)
#21 0x00000000040b6d45 llvm::slpvectorizer::BoUpSLP::vectorizeTree() (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x40b6d45)
#22 0x00000000040c3b2a llvm::SLPVectorizerPass::tryToVectorizeList(llvm::ArrayRef<llvm::Value*>, llvm::slpvectorizer::BoUpSLP&, bool) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x40c3b2a)
#23 0x00000000040c78a7 bool llvm::SLPVectorizerPass::vectorizeCmpInsts<std::reverse_iterator<llvm::CmpInst* const*>>(llvm::iterator_range<std::reverse_iterator<llvm::CmpInst* const*>>, llvm::BasicBlock*, llvm::slpvectorizer::BoUpSLP&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x40c78a7)
#24 0x00000000040cb5d0 llvm::SLPVectorizerPass::vectorizeChainsInBlock(llvm::BasicBlock*, llvm::slpvectorizer::BoUpSLP&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x40cb5d0)
#25 0x00000000040d1d49 llvm::SLPVectorizerPass::runImpl(llvm::Function&, llvm::ScalarEvolution*, llvm::TargetTransformInfo*, llvm::TargetLibraryInfo*, llvm::AAResults*, llvm::LoopInfo*, llvm::DominatorTree*, llvm::AssumptionCache*, llvm::DemandedBits*, llvm::OptimizationRemarkEmitter*) (.part.0) SLPVectorizer.cpp:0:0
#26 0x00000000040d29fb llvm::SLPVectorizerPass::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x40d29fb)
...
```

Bisected to f3d2609af3031ddb54030548e86335f295cf49ca / https://github.com/llvm/llvm-project/pull/104144

Confirmed this resolved the issue. Thanks!


commit 7d01a8f2b9ac28ffe73bef4b513d383d3edf34b5
Author: Alexey Bataev <a.bataev@outlook.com>
Date:   Mon Jan 20 14:22:20 2025 -0800

    [SLP]Fix vector factor for repeated node for bv

    When adding a node vector, when it is used already in the shuffle for
    buildvector, need to calculate vector factor from all vector, not only
    this single vector, to avoid incorrect result. Also, need to increase
    stability of the reused entries detection to avoid mismatch in cost
    estimation/codegen.

    Fixes #123639

diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index fc3afed391a0..ad4855d90874 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -13205,9 +13205,12 @@ BoUpSLP::isGatherShuffledSingleRegisterEntry(
           VTE = *MIt;
         }
       }
-      Instruction &LastBundleInst = getLastInstructionInBundle(VTE);
-      if (&LastBundleInst == TEInsertPt || !CheckOrdering(&LastBundleInst))
-        continue;
+      if (none_of(TE->CombinedEntriesWithIndices,
+                  [&](const auto &P) { return P.first == VTE->Idx; })) {
+        Instruction &LastBundleInst = getLastInstructionInBundle(VTE);
+        if (&LastBundleInst == TEInsertPt || !CheckOrdering(&LastBundleInst))
+          continue;
+      }
       VToTEs.insert(VTE);
     }
     if (VToTEs.empty())
@@ -14497,7 +14500,9 @@ public:
           break;
         }
     }
-    int VF = getVF(V1);
+    unsigned VF = 0;
+    for (Value *V : InVectors)
+      VF = std::max(VF, getVF(V));
     for (unsigned Idx = 0, Sz = CommonMask.size(); Idx < Sz; ++Idx)
       if (Mask[Idx] != PoisonMaskElem && CommonMask[Idx] == PoisonMaskElem)
         CommonMask[Idx] = Mask[Idx] + (It == InVectors.begin() ? 0 : VF);

opt -S --passes=slp-vectorizer -mtriple=x86_64-unknown-linux-gnu -mattr=+avx2 < %s

SLP Vectorizer miscompilation

During our local testing, we identified a miscompilation where the SLP Vectorizer appears to be the cause. Here is the reproducer we managed to prepare:
https://godbolt.org/z/9nePcq7Go

The issue can be demonstrated using the `lli` tool. Unfortunately, I cannot use alive2 due to unknown libcall errors, such as @llvm.vector.insert.v32i32.v16i32 not being recognized by alive2

```
$ bin/opt -passes=slp-vectorizer -mattr=+avx2 src.ll -S > tgt.ll
$ bin/lli src.ll
Result: -256
$ bin/lli tgt.ll
Result: -272
```

The pseudocode represented by the IR is
```
t = 0
for (i = 0; i < 16; i++) {
    s -= (t + i)
    t = i
}
```
```
s -= (1 + 0) + (2 + 1) + (3 + 2) + (4 + 3) + ... + (14 + 15) + (15 + 16)
s = -256
```
This indicates that the SLP Vectorizer pass produces incorrect IR.

The issue became reproducible after patch `[SLP] Match poison as instruction with the same opcode` made by @alexey-bataev
https://github.com/llvm/llvm-project/commit/b8703369daf777706196ff914c0376c27adde3cf

I'll provide more details on how the patch affects the issue as soon as I receive them.

No related directly to this patch, reveals the bug that can be triggered even without patch. I reduced the reproducer, will commit fix soon


commit 57b9c15227ec15a5e2abf4587d7d0ad536cff9e6
Author: Ramkumar Ramachandra <r@artagnon.com>
Date:   Wed May 8 09:47:55 2024 +0100

    VectorCombine: fix logical error after m_Trunc match (#91201)

    The matcher m_Trunc() matches an Operator with a given Opcode, which
    could either be an Instruction or ConstExpr.
    VectorCombine::foldTruncFromReductions() incorrectly assumes that the
    pattern matched is always an Instruction, and attempts a cast. Fix this.

    Fixes #88796.

diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
index bbb70134870a..8573a8adf53b 100644
--- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
+++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
@@ -1961,17 +1961,17 @@ bool VectorCombine::foldTruncFromReductions(Instruction &I) {
   if (!match(ReductionSrc, m_OneUse(m_Trunc(m_Value(TruncSrc)))))
     return false;

-  auto *Trunc = cast<CastInst>(ReductionSrc);
   auto *TruncSrcTy = cast<VectorType>(TruncSrc->getType());
   auto *ReductionSrcTy = cast<VectorType>(ReductionSrc->getType());
   Type *ResultTy = I.getType();

   TTI::TargetCostKind CostKind = TTI::TCK_RecipThroughput;
-  InstructionCost OldCost =
-      TTI.getCastInstrCost(Instruction::Trunc, ReductionSrcTy, TruncSrcTy,
-                           TTI::CastContextHint::None, CostKind, Trunc) +
-      TTI.getArithmeticReductionCost(ReductionOpc, ReductionSrcTy, std::nullopt,
-                                     CostKind);
+  InstructionCost OldCost = TTI.getArithmeticReductionCost(
+      ReductionOpc, ReductionSrcTy, std::nullopt, CostKind);
+  if (auto *Trunc = dyn_cast<CastInst>(ReductionSrc))
+    OldCost +=
+        TTI.getCastInstrCost(Instruction::Trunc, ReductionSrcTy, TruncSrcTy,
+                             TTI::CastContextHint::None, CostKind, Trunc);
   InstructionCost NewCost =
       TTI.getArithmeticReductionCost(ReductionOpc, TruncSrcTy, std::nullopt,
                                      CostKind) +

define i32 @test() {
entry:
  %0 = tail call i16 @llvm.vector.reduce.and.nxv8i16(<vscale x 8 x i16> trunc (<vscale x 8 x i32> splat (i32 268435456) to <vscale x 8 x i16>))
  ret i32 0
}

; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i16 @llvm.vector.reduce.and.nxv8i16(<vscale x 8 x i16>) #0

attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }

[VectorCombine] Assertion 'isa<To>(Val) && "cast<Ty>() argument of incompatible type!"' failed.

Reduced LLVM IR:
```llvm ir
target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"
target triple = "riscv64-unknown-linux-gnu"

define i32 @main() #0 {
entry:
  %0 = tail call i16 @llvm.vector.reduce.and.nxv8i16(<vscale x 8 x i16> trunc (<vscale x 8 x i32> shufflevector (<vscale x 8 x i32> insertelement (<vscale x 8 x i32> poison, i32 268435456, i64 0), <vscale x 8 x i32> poison, <vscale x 8 x i32> zeroinitializer) to <vscale x 8 x i16>))
  ret i32 0
}

; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i16 @llvm.vector.reduce.and.nxv8i16(<vscale x 8 x i16>) #1

attributes #0 = { "target-features"="+64bit,+a,+c,+d,+f,+m,+relax,+v,+zicsr,+zifencei,+zve32f,+zve32x,+zve64d,+zve64f,+zve64x,+zvl128b,+zvl256b,+zvl32b,+zvl64b,-e,-experimental-smmpm,-experimental-smnpm,-experimental-ssnpm,-experimental-sspm,-experimental-ssqosid,-experimental-supm,-experimental-zaamo,-experimental-zabha,-experimental-zalasr,-experimental-zalrsc,-experimental-zfbfmin,-experimental-zicfilp,-experimental-zicfiss,-experimental-ztso,-experimental-zvfbfmin,-experimental-zvfbfwma,-h,-shcounterenw,-shgatpa,-shtvala,-shvsatpa,-shvstvala,-shvstvecd,-smaia,-smepmp,-ssaia,-ssccptr,-sscofpmf,-sscounterenw,-ssstateen,-ssstrict,-sstc,-sstvala,-sstvecd,-ssu64xl,-svade,-svadu,-svbare,-svinval,-svnapot,-svpbmt,-xcvalu,-xcvbi,-xcvbitmanip,-xcvelw,-xcvmac,-xcvmem,-xcvsimd,-xsfcease,-xsfvcp,-xsfvfnrclipxfqf,-xsfvfwmaccqqq,-xsfvqmaccdod,-xsfvqmaccqoq,-xsifivecdiscarddlone,-xsifivecflushdlone,-xtheadba,-xtheadbb,-xtheadbs,-xtheadcmo,-xtheadcondmov,-xtheadfmemidx,-xtheadmac,-xtheadmemidx,-xtheadmempair,-xtheadsync,-xtheadvdot,-xventanacondops,-za128rs,-za64rs,-zacas,-zawrs,-zba,-zbb,-zbc,-zbkb,-zbkc,-zbkx,-zbs,-zca,-zcb,-zcd,-zce,-zcf,-zcmop,-zcmp,-zcmt,-zdinx,-zfa,-zfh,-zfhmin,-zfinx,-zhinx,-zhinxmin,-zic64b,-zicbom,-zicbop,-zicboz,-ziccamoa,-ziccif,-zicclsm,-ziccrse,-zicntr,-zicond,-zihintntl,-zihintpause,-zihpm,-zimop,-zk,-zkn,-zknd,-zkne,-zknh,-zkr,-zks,-zksed,-zksh,-zkt,-zmmul,-zvbb,-zvbc,-zvfh,-zvfhmin,-zvkb,-zvkg,-zvkn,-zvknc,-zvkned,-zvkng,-zvknha,-zvknhb,-zvks,-zvksc,-zvksed,-zvksg,-zvksh,-zvkt,-zvl1024b,-zvl16384b,-zvl2048b,-zvl32768b,-zvl4096b,-zvl512b,-zvl65536b,-zvl8192b" }
attributes #1 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
```
Godbolt: https://godbolt.org/z/jrEv178Ev

Backtrace:
```
opt: /scratch/tc-testing/tc-apr-15/llvm/llvm/include/llvm/Support/Casting.h:578: decltype(auto) llvm::cast(From*) [with To = llvm::CastInst; From = llvm::Value]: Assertion `isa<To>(Val) && "cast<Ty>() argument of incompatible type!"' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:
0.      Program arguments: /scratch/tc-testing/tc-apr-15/build-rv64gcv/build-llvm-linux/bin/opt --passes=vector-combine reduced.ll
 #0 0x00005eb857c5a1b0 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/scratch/tc-testing/tc-apr-15/build-rv64gcv/build-llvm-linux/bin/opt+0x2da91b0)
 #1 0x00005eb857c575bf llvm::sys::RunSignalHandlers() (/scratch/tc-testing/tc-apr-15/build-rv64gcv/build-llvm-linux/bin/opt+0x2da65bf)
 #2 0x00005eb857c57715 SignalHandler(int) Signals.cpp:0:0
 #3 0x000071f7d0e42520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #4 0x000071f7d0e969fc __pthread_kill_implementation ./nptl/pthread_kill.c:44:76
 #5 0x000071f7d0e969fc __pthread_kill_internal ./nptl/pthread_kill.c:78:10
 #6 0x000071f7d0e969fc pthread_kill ./nptl/pthread_kill.c:89:10
 #7 0x000071f7d0e42476 gsignal ./signal/../sysdeps/posix/raise.c:27:6
 #8 0x000071f7d0e287f3 abort ./stdlib/abort.c:81:7
 #9 0x000071f7d0e2871b _nl_load_domain ./intl/loadmsgcat.c:1177:9
#10 0x000071f7d0e39e96 (/lib/x86_64-linux-gnu/libc.so.6+0x39e96)
#11 0x00005eb856da36eb (anonymous namespace)::VectorCombine::run()::'lambda'(llvm::Instruction&)::operator()(llvm::Instruction&) const VectorCombine.cpp:0:0
#12 0x00005eb856da4290 llvm::VectorCombinePass::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/scratch/tc-testing/tc-apr-15/build-rv64gcv/build-llvm-linux/bin/opt+0x1ef3290)
#13 0x00005eb855bc7936 llvm::detail::PassModel<llvm::Function, llvm::VectorCombinePass, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/scratch/tc-testing/tc-apr-15/build-rv64gcv/build-llvm-linux/bin/opt+0xd16936)
#14 0x00005eb857a7f451 llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/scratch/tc-testing/tc-apr-15/build-rv64gcv/build-llvm-linux/bin/opt+0x2bce451)
#15 0x00005eb855bbec26 llvm::detail::PassModel<llvm::Function, llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/scratch/tc-testing/tc-apr-15/build-rv64gcv/build-llvm-linux/bin/opt+0xd0dc26)
#16 0x00005eb857a7e12b llvm::ModuleToFunctionPassAdaptor::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/scratch/tc-testing/tc-apr-15/build-rv64gcv/build-llvm-linux/bin/opt+0x2bcd12b)
#17 0x00005eb855bc6ee6 llvm::detail::PassModel<llvm::Module, llvm::ModuleToFunctionPassAdaptor, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/scratch/tc-testing/tc-apr-15/build-rv64gcv/build-llvm-linux/bin/opt+0xd15ee6)
#18 0x00005eb857a7bf61 llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/scratch/tc-testing/tc-apr-15/build-rv64gcv/build-llvm-linux/bin/opt+0x2bcaf61)
#19 0x00005eb855440205 llvm::runPassPipeline(llvm::StringRef, llvm::Module&, llvm::TargetMachine*, llvm::TargetLibraryInfoImpl*, llvm::ToolOutputFile*, llvm::ToolOutputFile*, llvm::ToolOutputFile*, llvm::StringRef, llvm::ArrayRef<llvm::PassPlugin>, llvm::ArrayRef<std::function<void (llvm::PassBuilder&)>>, llvm::opt_tool::OutputKind, llvm::opt_tool::VerifierKind, bool, bool, bool, bool, bool, bool, bool) (/scratch/tc-testing/tc-apr-15/build-rv64gcv/build-llvm-linux/bin/opt+0x58f205)
#20 0x00005eb855432836 optMain (/scratch/tc-testing/tc-apr-15/build-rv64gcv/build-llvm-linux/bin/opt+0x581836)
#21 0x000071f7d0e29d90 __libc_start_call_main ./csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#22 0x000071f7d0e29e40 call_init ./csu/../csu/libc-start.c:128:20
#23 0x000071f7d0e29e40 __libc_start_main ./csu/../csu/libc-start.c:379:5
#24 0x00005eb8554284b5 _start (/scratch/tc-testing/tc-apr-15/build-rv64gcv/build-llvm-linux/bin/opt+0x5774b5)
zsh: IOT instruction  /scratch/tc-testing/tc-apr-15/build-rv64gcv/build-llvm-linux/bin/op
```

Found via fuzzer.


commit f035351af785b7349ab7bcd55149c781ceca24cb
Author: Julian Nagele <j.nagele@apple.com>
Date:   Tue Dec 31 10:24:48 2024 +0100

    [SCEV] Make sure starting block is marked as visited when recursively collecting loop guards. (#120749)

    When `collectFromBlock` is called without a predecessor (in particular
    for loops that don't have a unique predecessor outside the loop) we
    never start climbing the predecessor chain, and thus don't mark the
    starting block as visited.

    Fixes https://github.com/llvm/llvm-project/issues/120615.

diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index 8ab56025546e..b5668a14a4a2 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -15765,6 +15765,7 @@ void ScalarEvolution::LoopGuards::collectFromBlock(
   // original header.
   // TODO: share this logic with isLoopEntryGuardedByCond.
   unsigned NumCollectedConditions = 0;
+  VisitedBlocks.insert(Block);
   std::pair<const BasicBlock *, const BasicBlock *> Pair(Pred, Block);
   for (; Pair.first;
        Pair = SE.getPredecessorWithUniqueSuccessorForBB(Pair.first)) {

opt < %s -disable-output -passes=nary-reassociate --scalar-evolution-use-expensive-range-sharpening 2>&1

define void @pr120615() {
entry:
  br label %header

bb:                                               ; No predecessors!
  br label %header

header:                                           ; preds = %header, %bb, %entry
  %0 = phi i32 [ %1, %header ], [ 0, %bb ], [ 0, %entry ]
  %1 = add i32 %0, 1
  %icmp = icmp slt i32 %0, 0
  br i1 %icmp, label %header, label %exit

exit:                                             ; preds = %header
  ret void
}

[SCEV] Segfault in SCEV LoopGuards

For the following IR:
```llvm
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128-ni:1-p2:32:8:8:32-ni:2"
target triple = "x86_64-unknown-linux-gnu"

define void @foo() {
.split.us120:
  br label %.split.us120.split.split.us.split.split.us.split.split.us.split

.split.us120.split.split.us.split.split.us.split.split.us.split: ; preds = %.noexc7.us.us.us.us.us, %.split.us120
  br label %.noexc7.us.us.us.us.us

.lr.ph.us.us.us.us407:                            ; No predecessors!
  switch i32 0, label %.split142.us.split.us.split.us [
    i32 0, label %.split160.us.split.us.split.us
    i32 1, label %.noexc7.us.us.us.us.us
  ]

.noexc7.us.us.us.us.us:                           ; preds = %.noexc7.us.us.us.us.us, %.lr.ph.us.us.us.us407, %.split.us120.split.split.us.split.split.us.split.split.us.split
  %0 = phi i32 [ %1, %.noexc7.us.us.us.us.us ], [ 0, %.lr.ph.us.us.us.us407 ], [ 0, %.split.us120.split.split.us.split.split.us.split.split.us.split ]
  %1 = add i32 %0, 1
  %.not.i3.us.us.us.us384.us = icmp slt i32 %0, 0
  br i1 %.not.i3.us.us.us.us384.us, label %.noexc7.us.us.us.us.us, label %.split.us120.split.split.us.split.split.us.split.split.us.split

.split142.us.split.us.split.us:                   ; preds = %.lr.ph.us.us.us.us407
  ret void

.split160.us.split.us.split.us:                   ; preds = %.lr.ph.us.us.us.us407
  ret void
}
```
`opt` crashes when run using `-passes=nary-reassociate --scalar-evolution-use-expensive-range-sharpening`

godbolt: https://godbolt.org/z/xPv4TMMo8

Backtrace (truncated due to length limits):
```
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:
0.	Program arguments: /opt/compiler-explorer/clang-assertions-trunk/bin/opt -o /app/output.s -S -passes=nary-reassociate --scalar-evolution-use-expensive-range-sharpening <source>
1.	Running pass "function(nary-reassociate)" on module "<source>"
2.	Running pass "nary-reassociate" on function "foo"
  #0 0x0000000005257198 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x5257198)
  #1 0x0000000005254b9c SignalHandler(int) Signals.cpp:0:0
  #2 0x00007f9ab9c42520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
  #3 0x00000000051640cb llvm::hash_value(llvm::APInt const&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x51640cb)
  #4 0x00000000051641a9 llvm::DenseMapInfo<llvm::APInt, void>::getHashValue(llvm::APInt const&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x51641a9)
  #5 0x0000000004ed726b bool llvm::DenseMapBase<llvm::DenseMap<llvm::APInt, std::unique_ptr<llvm::ConstantInt, std::default_delete<llvm::ConstantInt>>, llvm::DenseMapInfo<llvm::APInt, void>, llvm::detail::DenseMapPair<llvm::APInt, std::unique_ptr<llvm::ConstantInt, std::default_delete<llvm::ConstantInt>>>>, llvm::APInt, std::unique_ptr<llvm::ConstantInt, std::default_delete<llvm::ConstantInt>>, llvm::DenseMapInfo<llvm::APInt, void>, llvm::detail::DenseMapPair<llvm::APInt, std::unique_ptr<llvm::ConstantInt, std::default_delete<llvm::ConstantInt>>>>::LookupBucketFor<llvm::APInt>(llvm::APInt const&, llvm::detail::DenseMapPair<llvm::APInt, std::unique_ptr<llvm::ConstantInt, std::default_delete<llvm::ConstantInt>>>*&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4ed726b)
  #6 0x0000000004edb996 llvm::ConstantInt::get(llvm::LLVMContext&, llvm::APInt const&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4edb996)
  #7 0x0000000004eeba30 llvm::ConstantInt::get(llvm::Type*, llvm::APInt const&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4eeba30)
  #8 0x0000000004eb6172 llvm::ConstantFoldBinaryInstruction(unsigned int, llvm::Constant*, llvm::Constant*) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4eb6172)
  #9 0x0000000004ee9f2e llvm::ConstantExpr::get(unsigned int, llvm::Constant*, llvm::Constant*, unsigned int, llvm::Type*) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4ee9f2e)
 #10 0x00000000049427fb llvm::ScalarEvolution::getNegativeSCEV(llvm::SCEV const*, llvm::SCEV::NoWrapFlags) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x49427fb)
 #11 0x00000000049429c4 llvm::ScalarEvolution::getMinusSCEV(llvm::SCEV const*, llvm::SCEV const*, llvm::SCEV::NoWrapFlags, unsigned int) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x49429c4)
 #12 0x0000000004950e7a llvm::ScalarEvolution::LoopGuards::collectFromBlock(llvm::ScalarEvolution&, llvm::ScalarEvolution::LoopGuards&, llvm::BasicBlock const*, llvm::BasicBlock const*, llvm::SmallPtrSetImpl<llvm::BasicBlock const*>&, unsigned int) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4950e7a)
 #13 0x00000000049524c2 llvm::ScalarEvolution::LoopGuards::collectFromPHI(llvm::ScalarEvolution&, llvm::ScalarEvolution::LoopGuards&, llvm::PHINode const&, llvm::SmallPtrSetImpl<llvm::BasicBlock const*>&, llvm::SmallDenseMap<llvm::BasicBlock const*, llvm::ScalarEvolution::LoopGuards, 4u, llvm::DenseMapInfo<llvm::BasicBlock const*, void>, llvm::detail::DenseMapPair<llvm::BasicBlock const*, llvm::ScalarEvolution::LoopGuards>>&, unsigned int)::'lambda'(unsigned int)::operator()(unsigned int) const ScalarEvolution.cpp:0:0
 #14 0x0000000004952702 llvm::ScalarEvolution::LoopGuards::collectFromPHI(llvm::ScalarEvolution&, llvm::ScalarEvolution::LoopGuards&, llvm::PHINode const&, llvm::SmallPtrSetImpl<llvm::BasicBlock const*>&, llvm::SmallDenseMap<llvm::BasicBlock const*, llvm::ScalarEvolution::LoopGuards, 4u, llvm::DenseMapInfo<llvm::BasicBlock const*, void>, llvm::detail::DenseMapPair<llvm::BasicBlock const*, llvm::ScalarEvolution::LoopGuards>>&, unsigned int) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4952702)
 #15 0x0000000004951839 llvm::ScalarEvolution::LoopGuards::collectFromBlock(llvm::ScalarEvolution&, llvm::ScalarEvolution::LoopGuards&, llvm::BasicBlock const*, llvm::BasicBlock const*, llvm::SmallPtrSetImpl<llvm::BasicBlock const*>&, unsigned int) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4951839)
 #16 0x0000000004952c7d llvm::ScalarEvolution::applyLoopGuards(llvm::SCEV const*, llvm::Loop const*) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4952c7d)
 #17 0x0000000004952fb0 llvm::ScalarEvolution::getRangeForAffineNoSelfWrappingAR(llvm::SCEVAddRecExpr const*, llvm::SCEV const*, unsigned int, llvm::ScalarEvolution::RangeSignHint) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4952fb0)
 #18 0x000000000492888d llvm::ScalarEvolution::getRangeRef(llvm::SCEV const*, llvm::ScalarEvolution::RangeSignHint, unsigned int) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x492888d)
 #19 0x0000000004942b52 llvm::ScalarEvolution::isKnownPredicateViaConstantRanges(llvm::CmpInst::Predicate, llvm::SCEV const*, llvm::SCEV const*) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4942b52)
 #20 0x0000000004942e18 llvm::ScalarEvolution::isKnownViaNonRecursiveReasoning(llvm::CmpInst::Predicate, llvm::SCEV const*, llvm::SCEV const*) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4942e18)
 #21 0x0000000004943799 llvm::ScalarEvolution::getMinMaxExpr(llvm::SCEVTypes, llvm::SmallVectorImpl<llvm::SCEV const*>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4943799)
 #22 0x0000000004943f1a llvm::ScalarEvolution::getSMinExpr(llvm::SCEV const*, llvm::SCEV const*) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4943f1a)
 #23 0x0000000004951128 llvm::ScalarEvolution::LoopGuards::collectFromBlock(llvm::ScalarEvolution&, llvm::ScalarEvolution::LoopGuards&, llvm::BasicBlock const*, llvm::BasicBlock const*, llvm::SmallPtrSetImpl<llvm::BasicBlock const*>&, unsigned int) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4951128)
...
#255 0x00000000049524c2 llvm::ScalarEvolution::LoopGuards::collectFromPHI(llvm::ScalarEvolution&, llvm::ScalarEvolution::LoopGuards&, llvm::PHINode const&, llvm::SmallPtrSetImpl<llvm::BasicBlock const*>&, llvm::SmallDenseMap<llvm::BasicBlock const*, llvm::ScalarEvolution::LoopGuards, 4u, llvm::DenseMapInfo<llvm::BasicBlock const*, void>, llvm::detail::DenseMapPair<llvm::BasicBlock const*, llvm::ScalarEvolution::LoopGuards>>&, unsigned int)::'lambda'(unsigned int)::operator()(unsigned int) const ScalarEvolution.cpp:0:0
Program terminated with signal: SIGSEGV
Compiler returned: 139
```

Stack exhaustion via some recursion error maybe?

@juliannagele possibly due to https://github.com/llvm/llvm-project/pull/113915 (from backtrace)

Likely the same as https://github.com/llvm/llvm-project/issues/120237

Related, but slightly different, should be fixed here https://github.com/llvm/llvm-project/pull/120749.


commit 9f45c5e1a65a1abf4920b617d36ed05e73c04bea
Author: Nikita Popov <npopov@redhat.com>
Date:   Wed Mar 6 09:33:51 2024 +0100

    [InstCombine] Fix infinite loop in select equivalence fold (#84036)

    When replacing with a non-constant, it's possible that the result of the
    simplification is actually more complicated than the original, and may
    result in an infinite combine loop.

    Mitigate the issue by requiring that either the replacement or
    simplification result is constant, which should ensure that it's
    simpler. While this check is crude, it does not appear to cause
    optimization regressions in real-world code in practice.

    Fixes https://github.com/llvm/llvm-project/issues/83127.

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index c47bc33df070..aee18d770f72 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -1285,7 +1285,11 @@ Instruction *InstCombinerImpl::foldSelectValueEquivalence(SelectInst &Sel,
       isGuaranteedNotToBeUndefOrPoison(CmpRHS, SQ.AC, &Sel, &DT)) {
     if (Value *V = simplifyWithOpReplaced(TrueVal, CmpLHS, CmpRHS, SQ,
                                           /* AllowRefinement */ true))
-      return replaceOperand(Sel, Swapped ? 2 : 1, V);
+      // Require either the replacement or the simplification result to be a
+      // constant to avoid infinite loops.
+      // FIXME: Make this check more precise.
+      if (isa<Constant>(CmpRHS) || isa<Constant>(V))
+        return replaceOperand(Sel, Swapped ? 2 : 1, V);

     // Even if TrueVal does not simplify, we can directly replace a use of
     // CmpLHS with CmpRHS, as long as the instruction is not used anywhere
@@ -1303,7 +1307,8 @@ Instruction *InstCombinerImpl::foldSelectValueEquivalence(SelectInst &Sel,
       isGuaranteedNotToBeUndefOrPoison(CmpLHS, SQ.AC, &Sel, &DT))
     if (Value *V = simplifyWithOpReplaced(TrueVal, CmpRHS, CmpLHS, SQ,
                                           /* AllowRefinement */ true))
-      return replaceOperand(Sel, Swapped ? 2 : 1, V);
+      if (isa<Constant>(CmpLHS) || isa<Constant>(V))
+        return replaceOperand(Sel, Swapped ? 2 : 1, V);

   auto *FalseInst = dyn_cast<Instruction>(FalseVal);
   if (!FalseInst)

target datalayout = "e-p:64:64-p1:16:16-p2:32:32:32-p3:64:64:64"

define i8 @select_replacement_shift_noundef(i8 %x, i8 %y, i8 %z) {
  %shr = lshr exact i8 %x, 1
  call void @use_i8(i8 noundef %shr)
  %cmp = icmp eq i8 %shr, %y
  %shl = shl i8 %y, 1
  %sel = select i1 %cmp, i8 %shl, i8 %z
  ret i8 %sel
}

declare void @use_i8(i8)

target datalayout = "e-p:64:64-p1:16:16-p2:32:32:32-p3:64:64:64"

define i16 @select_replacement_loop4(i16 noundef %p_12) {
  %cmp1 = icmp ult i16 %p_12, 2
  %and1 = and i16 %p_12, 1
  %and2 = select i1 %cmp1, i16 %and1, i16 0
  %cmp2 = icmp eq i16 %and2, %p_12
  %and3 = select i1 %cmp2, i16 %and1, i16 0
  ret i16 %and3
}

target datalayout = "e-p:64:64-p1:16:16-p2:32:32:32-p3:64:64:64"

define i8 @select_replacement_loop3(i32 noundef %x) {
  %trunc = trunc i32 %x to i8
  %rev = call i8 @llvm.bitreverse.i8(i8 %trunc)
  %ext = zext i8 %rev to i32
  %cmp = icmp eq i32 %ext, %x
  %sel = select i1 %cmp, i8 %trunc, i8 0
  ret i8 %sel
}

; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i8 @llvm.bitreverse.i8(i8) #0

attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }

target datalayout = "e-p:64:64-p1:16:16-p2:32:32:32-p3:64:64:64"

define i8 @select_replacement_sub(i8 %x, i8 %y, i8 %z) {
  %cmp = icmp eq i8 %x, %y
  %sub = sub i8 %x, %y
  %sel = select i1 %cmp, i8 %sub, i8 %z
  ret i8 %sel
}

target datalayout = "e-p:64:64-p1:16:16-p2:32:32:32-p3:64:64:64"

define ptr @select_replacement_gep_inbounds(ptr %base, i64 %offset) {
  %cmp = icmp eq i64 %offset, 0
  %gep = getelementptr inbounds i8, ptr %base, i64 %offset
  %sel = select i1 %cmp, ptr %base, ptr %gep
  ret ptr %sel
}

target datalayout = "e-p:64:64-p1:16:16-p2:32:32:32-p3:64:64:64"

define i32 @select_replacement_loop2(i32 %arg, i32 %arg2) {
  %div = udiv i32 %arg, %arg2
  %mul = mul nsw i32 %div, %arg2
  %cmp = icmp eq i32 %mul, %arg
  %sel = select i1 %cmp, i32 %div, i32 undef
  ret i32 %sel
}

[InstCombine] InstCombine gets stuck when simplifying selects

Reduced test case: https://godbolt.org/z/ds9eq96db
```
define i16 @func(i16 noundef %p_12) {
entry:
  %cmp1 = icmp ult i16 %p_12, 2
  %and1 = and i16 %p_12, 1
  %and2 = select i1 %cmp1, i16 %and1, i16 0
  %cmp2 = icmp eq i16 %and2, %p_12
  %and3 = select i1 %cmp2, i16 %and1, i16 0
  ret i16 %and3
}
```
```
ADD:   %and3 = select i1 %cmp2, i16 %and2, i16 0
ADD:   %and2 = select i1 %cmp1, i16 %and1, i16 0
ADD:   %and1 = and i16 %p_12, 1
IC: Visiting:   %and1 = and i16 %p_12, 1
IC: Visiting:   %and2 = select i1 %cmp1, i16 %and1, i16 0
IC: Visiting:   %and3 = select i1 %cmp2, i16 %and2, i16 0
ADD DEFERRED:   %and2 = select i1 %cmp1, i16 %and1, i16 0
ADD DEFERRED:   %cmp2 = icmp eq i16 %and2, %p_12
IC: Mod =   %and3 = select i1 %cmp2, i16 %and2, i16 0
    New =   %and3 = select i1 %cmp2, i16 %and1, i16 0
ADD:   %and3 = select i1 %cmp2, i16 %and1, i16 0
ADD:   %cmp2 = icmp eq i16 %and2, %p_12
ADD:   %and2 = select i1 %cmp1, i16 %and1, i16 0
IC: Visiting:   %and2 = select i1 %cmp1, i16 %and1, i16 0
IC: Visiting:   %cmp2 = icmp eq i16 %and2, %p_12
IC: Visiting:   %and3 = select i1 %cmp2, i16 %and1, i16 0
ADD DEFERRED:   %and1 = and i16 %p_12, 1
ADD DEFERRED:   %and2 = select i1 %cmp1, i16 %and1, i16 0
IC: Mod =   %and3 = select i1 %cmp2, i16 %and1, i16 0
    New =   %and3 = select i1 %cmp2, i16 %and2, i16 0

ADD:   %and3 = select i1 %cmp2, i16 %and2, i16 0
ADD:   %and2 = select i1 %cmp1, i16 %and1, i16 0
ADD:   %and1 = and i16 %p_12, 1
IC: Visiting:   %and1 = and i16 %p_12, 1
IC: Visiting:   %and2 = select i1 %cmp1, i16 %and1, i16 0
IC: Visiting:   %and3 = select i1 %cmp2, i16 %and2, i16 0
ADD DEFERRED:   %and2 = select i1 %cmp1, i16 %and1, i16 0
ADD DEFERRED:   %cmp2 = icmp eq i16 %and2, %p_12
IC: Mod =   %and3 = select i1 %cmp2, i16 %and2, i16 0
    New =   %and3 = select i1 %cmp2, i16 %and1, i16 0
ADD:   %and3 = select i1 %cmp2, i16 %and1, i16 0
ADD:   %cmp2 = icmp eq i16 %and2, %p_12
ADD:   %and2 = select i1 %cmp1, i16 %and1, i16 0
IC: Visiting:   %and2 = select i1 %cmp1, i16 %and1, i16 0
IC: Visiting:   %cmp2 = icmp eq i16 %and2, %p_12
IC: Visiting:   %and3 = select i1 %cmp2, i16 %and1, i16 0
ADD DEFERRED:   %and1 = and i16 %p_12, 1
ADD DEFERRED:   %and2 = select i1 %cmp1, i16 %and1, i16 0
IC: Mod =   %and3 = select i1 %cmp2, i16 %and1, i16 0
    New =   %and3 = select i1 %cmp2, i16 %and2, i16 0

...
```

Another reproducer:  https://godbolt.org/z/7MEYTe9cq
```
declare void @use(i32,i32)

define void @func(ptr %p) {
  %1 = load i32, ptr %p, align 4
  %2 = sext i32 %1 to i64
  %3 = icmp slt i64 %2, 2
  %4 = zext i1 %3 to i32
  %5 = and i32 %4, %1
  %6 = icmp eq i32 %5, %1
  %7 = zext i1 %6 to i32
  %8 = and i32 %7, %1
  call void @use(i32 %8, i32 noundef %1)
  ret void
}
```

Third reproducer: https://godbolt.org/z/8f8b4xved
```
define i8 @func(i32 noundef %p_38) {
entry:
  %conv393 = trunc i32 %p_38 to i8
  %0 = call i8 @llvm.bitreverse.i8(i8 %conv393)
  %conv394 = zext i8 %0 to i32
  %cmp395 = icmp eq i32 %conv394, %p_38
  %conv397 = zext i1 %cmp395 to i8
  %mul.i = mul i8 %conv393, %conv397
  ret i8 %mul.i
}
```

> Third reproducer: https://godbolt.org/z/8f8b4xved
>
> ```
> define i8 @func(i32 noundef %p_38) {
> entry:
>   %conv393 = trunc i32 %p_38 to i8
>   %0 = call i8 @llvm.bitreverse.i8(i8 %conv393)
>   %conv394 = zext i8 %0 to i32
>   %cmp395 = icmp eq i32 %conv394, %p_38
>   %conv397 = zext i1 %cmp395 to i8
>   %mul.i = mul i8 %conv393, %conv397
>   ret i8 %mul.i
> }
> ```

A simpler testcase:
```
define i8 @func(i32 noundef %x) {
entry:
  %trunc = trunc i32 %x to i8
  %rev = call i8 @llvm.bitreverse.i8(i8 %trunc)
  %ext = zext i8 %rev to i32
  %cmp = icmp eq i32 %ext, %x
  %sel = select i1 %cmp, i8 %trunc, i8 0
  ret i8 %sel
}
```

@nikic I have no idea how to fix it in `foldSelectValueEquivalence`/`simplifyWithOpReplaced`. `simplifyWithOpReplaced` may replace the input `x` with a more complicated value `f(x)`.

@nikic Ping.


commit 1c10821022f1799452065fb57474e894e2562b7f
Author: David Sherwood <57997763+david-arm@users.noreply.github.com>
Date:   Wed Feb 14 16:07:51 2024 +0000

    [LoopVectorize] Fix divide-by-zero bug (#80836) (#81721)

    When attempting to use the estimated trip count to refine the costs of
    the runtime memory checks we should also check for sane trip counts to
    prevent divide-by-zero faults on some platforms.

    Fixes #80836

diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index b39bf21cacdb..98b177cf5d2d 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -2010,16 +2010,18 @@ public:
               BestTripCount = *EstimatedTC;
           }

+          BestTripCount = std::max(BestTripCount, 1U);
           InstructionCost NewMemCheckCost = MemCheckCost / BestTripCount;

           // Let's ensure the cost is always at least 1.
           NewMemCheckCost = std::max(*NewMemCheckCost.getValue(),
                                      (InstructionCost::CostType)1);

-          LLVM_DEBUG(dbgs()
-                     << "We expect runtime memory checks to be hoisted "
-                     << "out of the outer loop. Cost reduced from "
-                     << MemCheckCost << " to " << NewMemCheckCost << '\n');
+          if (BestTripCount > 1)
+            LLVM_DEBUG(dbgs()
+                       << "We expect runtime memory checks to be hoisted "
+                       << "out of the outer loop. Cost reduced from "
+                       << MemCheckCost << " to " << NewMemCheckCost << '\n');

           MemCheckCost = NewMemCheckCost;
         }

opt -p loop-vectorize -debug-only=loop-vectorize -S -disable-output < %s 2>&1

target triple = "aarch64-unknown-linux-gnu"

define void @outer_known_tc3_full_range_checks(ptr nocapture noundef %dst, ptr nocapture noundef readonly %src, i64 noundef %n) {
entry:
  br label %outer.loop

outer.loop:                                       ; preds = %inner.exit, %entry
  %outer.iv = phi i64 [ 0, %entry ], [ %outer.iv.next, %inner.exit ]
  %0 = mul nsw i64 %outer.iv, %n
  br label %inner.loop

inner.loop:                                       ; preds = %inner.loop, %outer.loop
  %iv.inner = phi i64 [ 0, %outer.loop ], [ %iv.inner.next, %inner.loop ]
  %1 = add nuw nsw i64 %iv.inner, %0
  %arrayidx.us = getelementptr inbounds i32, ptr %src, i64 %1
  %2 = load i32, ptr %arrayidx.us, align 4
  %arrayidx8.us = getelementptr inbounds i32, ptr %dst, i64 %1
  %3 = load i32, ptr %arrayidx8.us, align 4
  %add9.us = add nsw i32 %3, %2
  store i32 %add9.us, ptr %arrayidx8.us, align 4
  %iv.inner.next = add nuw nsw i64 %iv.inner, 1
  %inner.exit.cond = icmp eq i64 %iv.inner.next, %n
  br i1 %inner.exit.cond, label %inner.exit, label %inner.loop

inner.exit:                                       ; preds = %inner.loop
  %outer.iv.next = add nuw nsw i64 %outer.iv, 1
  %outer.exit.cond = icmp eq i64 %outer.iv.next, 3
  br i1 %outer.exit.cond, label %outer.exit, label %outer.loop

outer.exit:                                       ; preds = %inner.exit
  ret void
}

target triple = "aarch64-unknown-linux-gnu"

define void @outer_pgo_minus1(ptr nocapture noundef %a, ptr nocapture noundef readonly %b, i64 noundef %m, i64 noundef %n) {
entry:
  br label %outer.loop

outer.loop:                                       ; preds = %inner.exit, %entry
  %outer.iv = phi i64 [ %outer.iv.next, %inner.exit ], [ 0, %entry ]
  %mul.us = mul nsw i64 %outer.iv, %n
  br label %inner.loop

inner.loop:                                       ; preds = %inner.loop, %outer.loop
  %inner.iv = phi i64 [ 0, %outer.loop ], [ %inner.iv.next, %inner.loop ]
  %add.us = add nuw nsw i64 %inner.iv, %mul.us
  %arrayidx.us = getelementptr inbounds i8, ptr %b, i64 %add.us
  %0 = load i8, ptr %arrayidx.us, align 1
  %arrayidx7.us = getelementptr inbounds i8, ptr %a, i64 %add.us
  %1 = load i8, ptr %arrayidx7.us, align 1
  %add9.us = add i8 %1, %0
  store i8 %add9.us, ptr %arrayidx7.us, align 1
  %inner.iv.next = add nuw nsw i64 %inner.iv, 1
  %exitcond.not = icmp eq i64 %inner.iv.next, %n
  br i1 %exitcond.not, label %inner.exit, label %inner.loop

inner.exit:                                       ; preds = %inner.loop
  %outer.iv.next = add nuw nsw i64 %outer.iv, 1
  %exitcond26.not = icmp eq i64 %outer.iv.next, %m
  br i1 %exitcond26.not, label %outer.exit, label %outer.loop, !prof !0

outer.exit:                                       ; preds = %inner.exit
  ret void
}

!0 = !{!"branch_weights", i32 1, i32 -1}

Unhandled  Floating point exception with loop-vectorize

Run opt with -passes=loop-vectorize

https://godbolt.org/z/s3PWY3vhE

Test.ll
```
; ModuleID = './reduced.ll'
source_filename = "./reduced.ll"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128-ni:1-p2:32:8:8:32-ni:2"
target triple = "x86_64-unknown-linux-gnu"

define ptr addrspace(1) @wombat(i64 %arg, ptr addrspace(1) %arg1) gc "statepoint-example" {
bb:
  br label %bb2

bb2:                                              ; preds = %bb4, %bb
  br label %bb3

bb3:                                              ; preds = %bb3, %bb2
  %phi = phi i64 [ 0, %bb2 ], [ %add, %bb3 ]
  %add = add i64 %phi, 1
  %load = load i8, ptr addrspace(1) %arg1, align 1
  %shl = shl i64 0, 0
  store i16 0, ptr addrspace(1) null, align 2
  %icmp = icmp ult i64 %phi, %arg
  br i1 %icmp, label %bb3, label %bb4

bb4:                                              ; preds = %bb3
  br i1 false, label %bb5, label %bb2, !prof !0

bb5:                                              ; preds = %bb4
  ret ptr addrspace(1) null
}

!0 = !{!"branch_weights", i32 1, i32 -1}
```

It started failing after 962fbafecf4730ba84a3b9fd7a662a5c30bb2c7c
```
Author: David Sherwood <57997763+david-arm@users.noreply.github.com>
Date:   Fri Jan 26 14:43:48 2024 +0000

    [LoopVectorize] Refine runtime memory check costs when there is an outer loop (#76034)

    When we generate runtime memory checks for an inner loop it's
    possible that these checks are invariant in the outer loop and
    so will get hoisted out. In such cases, the effective cost of
    the checks should reduce to reflect the outer loop trip count.

    This fixes a 25% performance regression introduced by commit

    49b0e6dcc296792b577ae8f0f674e61a0929b99d

    when building the SPEC2017 x264 benchmark with PGO, where we
    decided the inner loop trip count wasn't high enough to warrant
    the (incorrect) high cost of the runtime checks. Also, when
    runtime memory checks consist entirely of diff checks these are
    likely to be outer loop invariant.
```
We have a division by 0 here https://github.com/llvm/llvm-project/commit/962fbafecf4730ba84a3b9fd7a662a5c30bb2c7c#diff-da321d454a7246f8ae276bf1db2782bf26b5210b8133cb59e4d7fd45d0905decR2114 because `getLoopEstimatedTripCount(OuterLoop)` just above that line returns 0.

OK thanks for raising this issue - I'll take a look this morning!

I have a fix in review - https://github.com/llvm/llvm-project/pull/81721


commit 722151664ecfd53295392ad875ff9bfdcd1deaaf
Author: Yingwei Zheng <dtcxzyw2333@gmail.com>
Date:   Tue Jul 9 22:04:55 2024 +0800

    [InstCombine] Fix typo in `adjustKnownBitsForSelectArm` (#98155)

    Fixes https://github.com/llvm/llvm-project/issues/98139.

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
index 98f085a2c756..081e783c964f 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
@@ -411,7 +411,7 @@ Value *InstCombinerImpl::SimplifyDemandedUseBits(Instruction *I,
     // Only known if known in both the LHS and RHS.
     adjustKnownBitsForSelectArm(LHSKnown, I->getOperand(0), I->getOperand(1),
                                 /*Invert=*/false, Depth, Q);
-    adjustKnownBitsForSelectArm(LHSKnown, I->getOperand(0), I->getOperand(2),
+    adjustKnownBitsForSelectArm(RHSKnown, I->getOperand(0), I->getOperand(2),
                                 /*Invert=*/true, Depth, Q);
     Known = LHSKnown.intersectWith(RHSKnown);
     break;

define i8 @pr98139(i16 %a, i16 %b, i1 %cond) {
  %sel = select i1 %cond, i16 1, i16 254
  %cond1 = icmp ne i16 %b, 0
  %mask = and i16 %a, 255
  %cond2 = icmp ne i16 %mask, 255
  %cond3 = or i1 %cond1, %cond2
  %sel2 = select i1 %cond3, i16 %sel, i16 255
  %sub = sub i16 %sel2, %a
  %trunc = trunc i16 %sub to i8
  ret i8 %trunc
}

wrong code at -O{s,2,3} on x86_64-linux-gnu

It appears to be a recent regression as it doesn't reproduce with 18.1.0 and earlier.

Compiler Explorer: https://godbolt.org/z/o595xsMdb

```
[512] % clangtk -v
clang version 19.0.0git (https://github.com/llvm/llvm-project.git 765e2f9a8de27cc8fd8c75540844e9630d8229ad)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /local/suz-local/software/local/clang-trunk/bin
Build config: +assertions
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/10
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/11
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/9
Selected GCC installation: /usr/lib/gcc/x86_64-linux-gnu/11
Candidate multilib: .;@m64
Selected multilib: .;@m64
[513] %
[513] % clangtk -O1 small.c; ./a.out
1
[514] % clangtk -O3 small.c; ./a.out
-2
1
[515] % cat small.c
int printf(const char *, ...);
int a, b, c, e;
char d;
int main() {
  int f = 1;
  unsigned g = 1;
  for (; c < 2; c++) {
    if (g)
      b = 1;
    char h = f;
    f = ~h;
    d = ~b - ~g * (a || f);
    g = ~g;
    if (g < 1)
      break;
    if (d)
      printf("%d\n", g);
    f = e;
  }
  return 0;
}
```

There is a bug in `SimplifyDemandedInstructionBits` :)
I am working to provide a minimal reproducer.

@nikic https://github.com/llvm/llvm-project/blob/a9183b8899f2c02ba3710b27c0cbdde6831a627b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp#L411-L416

I will post a fix later.

Reproducer: https://alive2.llvm.org/ce/z/GAUsBC
```
define i8 @src(i16 %a, i16 %b, i1 %cond) {
  %sel = select i1 %cond, i16 1, i16 254
  %cond1 = icmp ne i16 %b, 0
  %mask = and i16 %a, 255
  %cond2 = icmp ne i16 %mask, 255
  %cond3 = or i1 %cond1, %cond2
  %sel2 = select i1 %cond3, i16 %sel, i16 255
  %sub = sub i16 %sel2, %a
  %trunc = trunc i16 %sub to i8
  ret i8 %trunc
}

define i8 @tgt(i16 %a1, i16 %a2, i1 %cond) {
  %1 = trunc i16 %a1 to i8
  %conv6 = xor i8 %1, -1
  ret i8 %conv6
}
```


commit 3969d2c3b5f42e4a180f5205efa780b0f950d733
Author: Nikita Popov <npopov@redhat.com>
Date:   Wed Jul 3 09:47:01 2024 +0200

    [InstCombine] Disable select known bits fold for vectors

    This is not safe if the simplification ends up looking through
    lane-crossing operations. For now, we don't have a good way to
    limit this in computeKnownBits(), so just disable vector handling
    entirely.

    Fixes https://github.com/llvm/llvm-project/issues/97475.

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 736013395e8c..394dfca262e1 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -4049,7 +4049,9 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
   if (CondVal->getType() == SI.getType() && isKnownInversion(FalseVal, TrueVal))
     return BinaryOperator::CreateXor(CondVal, FalseVal);

-  if (SelType->isIntOrIntVectorTy() &&
+  // For vectors, this transform is only safe if the simplification does not
+  // look through any lane-crossing operations. For now, limit to scalars only.
+  if (SelType->isIntegerTy() &&
       (!isa<Constant>(TrueVal) || !isa<Constant>(FalseVal))) {
     // Try to simplify select arms based on KnownBits implied by the condition.
     CondContext CC(CondVal);

define <2 x i8> @select_xor_icmp_vec_bad(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) {
  %A = icmp eq <2 x i8> %x, <i8 5, i8 3>
  %B = xor <2 x i8> %x, %z
  %C = select <2 x i1> %A, <2 x i8> %B, <2 x i8> %y
  ret <2 x i8> %C
}

define <2 x i32> @vec_select_no_equivalence(<2 x i32> %x) {
  %x10 = shufflevector <2 x i32> %x, <2 x i32> undef, <2 x i32> <i32 1, i32 0>
  %cond = icmp eq <2 x i32> %x, zeroinitializer
  %s = select <2 x i1> %cond, <2 x i32> %x10, <2 x i32> %x
  ret <2 x i32> %s
}

integer vector miscompile from instcombine

I believe this is being mis-optimized:
```lllvm
define <4 x i32> @f(<4 x i32> %0) {
  %2 = icmp eq <4 x i32> %0, zeroinitializer
  %3 = shufflevector <4 x i32> %0, <4 x i32> zeroinitializer, <4 x i32> <i32 1, i32 1, i32 0, i32 3>
  %4 = select <4 x i1> %2, <4 x i32> %3, <4 x i32> zeroinitializer
  ret <4 x i32> %4
}
```
I'll just give Alive's reasoning, which is pretty easy to follow and seems correct:
```
regehr@ohm:~$ ~/alive2-regehr/build/alive-tv -passes=instcombine foo.ll

----------------------------------------
define <4 x i32> @f(<4 x i32> %#0) {
#1:
  %#2 = icmp eq <4 x i32> %#0, { 0, 0, 0, 0 }
  %#3 = shufflevector <4 x i32> %#0, <4 x i32> { 0, 0, 0, 0 }, 1, 1, 0, 3
  %#4 = select <4 x i1> %#2, <4 x i32> %#3, <4 x i32> { 0, 0, 0, 0 }
  ret <4 x i32> %#4
}
=>
define <4 x i32> @f(<4 x i32> %#0) {
#1:
  ret <4 x i32> { 0, 0, 0, 0 }
}
Transformation doesn't verify!

ERROR: Value mismatch

Example:
<4 x i32> %#0 = < #x00000000 (0), #x00000001 (1), #x00000000 (0), poison >

Source:
<4 x i1> %#2 = < #x1 (1), #x0 (0), #x1 (1), poison >
<4 x i32> %#3 = < #x00000001 (1), #x00000001 (1), #x00000000 (0), poison >
<4 x i32> %#4 = < #x00000001 (1), #x00000000 (0), #x00000000 (0), poison >

Target:
Source value: < #x00000001 (1), #x00000000 (0), #x00000000 (0), poison >
Target value: < #x00000000 (0), #x00000000 (0), #x00000000 (0), #x00000000 (0) >

Summary:
  0 correct transformations
  1 incorrect transformations
  0 failed-to-prove transformations
  0 Alive2 errors
regehr@ohm:~$
```
cc @nunoplopes

Probably caused by https://github.com/llvm/llvm-project/commit/77eb05683082dd3751ccfab963f5160f1852058d. Fell into the vector select trap again.


commit eb2b453eb73dfe0b8cf516dfb4d568c0b858d1fa
Author: Simon Pilgrim <llvm-dev@redking.me.uk>
Date:   Thu Feb 6 16:40:48 2025 +0000

    [VectorCombine] foldInsExtVectorToShuffle - ensure we call getShuffleCost with the input operand type, not the result

    Typo in #121216

    Fixes #126085

diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
index 4f46b621c8a7..746742e14d08 100644
--- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
+++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
@@ -3210,7 +3210,7 @@ bool VectorCombine::foldInsExtVectorToShuffle(Instruction &I) {
       ExtToVecMask[0] = ExtIdx;
     // Add cost for expanding or narrowing
     NewCost = TTI.getShuffleCost(TargetTransformInfo::SK_PermuteSingleSrc,
-                                 DstVecTy, ExtToVecMask, CostKind);
+                                 SrcVecTy, ExtToVecMask, CostKind);
     NewCost += TTI.getShuffleCost(SK, DstVecTy, Mask, CostKind);
   }

opt < %s -passes=vector-combine -S -mtriple=x86_64--

define i32 @test(ptr %a0) {
;
  %load = load <16 x i8>, ptr %a0, align 1
  %shuf = shufflevector <16 x i8> %load, <16 x i8> poison, <4 x i32> <i32 0, i32 poison, i32 poison, i32 poison>
  %elt = extractelement <16 x i8> %load, i64 11
  %ins = insertelement <4 x i8> %shuf, i8 %elt, i64 1
  %res = bitcast <4 x i8> %ins to i32
  ret i32 %res
}

[VectorCombine] Assertion `I >= 0 && I < (NumOpElts * 2) && "Out-of-bounds shuffle mask element"' failed.

Reproducer:
```
; bin/opt -passes=vector-combine reduced.ll -S
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

define i32 @test(ptr readonly captures(none) dereferenceable(16) %0) {
  %2 = load <16 x i8>, ptr %0, align 1
  %.sroa.01.2.vec.insert = shufflevector <16 x i8> %2, <16 x i8> poison, <4 x i32> <i32 0, i32 poison, i32 poison, i32 poison>
  %3 = extractelement <16 x i8> %2, i64 11
  %.sroa.01.3.vec.insert = insertelement <4 x i8> %.sroa.01.2.vec.insert, i8 %3, i64 1
  %4 = bitcast <4 x i8> %.sroa.01.3.vec.insert to i32
  ret i32 %4
}
```
```
opt: /home/dtcxzyw/WorkSpace/Projects/compilers/llvm-project/llvm/lib/IR/Instructions.cpp:1890: bool isSingleSourceMaskImpl(llvm::ArrayRef<int>, int): Assertion `I >= 0 && I < (NumOpElts * 2) && "Out-of-bounds shuffle mask element"' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:
0.      Program arguments: bin/opt -passes=vector-combine reduced.ll -S
1.      Running pass "function(vector-combine)" on module "reduced.ll"
2.      Running pass "vector-combine" on function "test"
 #0 0x00007f4379a17152 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/libLLVMSupport.so.21.0git+0x217152)
 #1 0x00007f4379a1403f llvm::sys::RunSignalHandlers() (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/libLLVMSupport.so.21.0git+0x21403f)
 #2 0x00007f4379a1417c SignalHandler(int) Signals.cpp:0:0
 #3 0x00007f4379442520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #4 0x00007f43794969fc __pthread_kill_implementation ./nptl/pthread_kill.c:44:76
 #5 0x00007f43794969fc __pthread_kill_internal ./nptl/pthread_kill.c:78:10
 #6 0x00007f43794969fc pthread_kill ./nptl/pthread_kill.c:89:10
 #7 0x00007f4379442476 gsignal ./signal/../sysdeps/posix/raise.c:27:6
 #8 0x00007f43794287f3 abort ./stdlib/abort.c:81:7
 #9 0x00007f437942871b _nl_load_domain ./intl/loadmsgcat.c:1177:9
#10 0x00007f4379439e96 (/lib/x86_64-linux-gnu/libc.so.6+0x39e96)
#11 0x00007f4370e71a16 isSingleSourceMaskImpl(llvm::ArrayRef<int>, int) Instructions.cpp:0:0
#12 0x00007f4370e7c3dc llvm::ShuffleVectorInst::isReverseMask(llvm::ArrayRef<int>, int) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMCore.so.21.0git+0x27c3dc)
#13 0x00007f43788933f2 llvm::X86TTIImpl::getShuffleCost(llvm::TargetTransformInfo::ShuffleKind, llvm::VectorType*, llvm::ArrayRef<int>, llvm::TargetTransformInfo::TargetCostKind, int, llvm::VectorType*, llvm::ArrayRef<llvm::Value const*>, llvm::Instruction const*) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMX86CodeGen.so.21.0git+0x4933f2)
#14 0x00007f43716ddf0c llvm::TargetTransformInfo::getShuffleCost(llvm::TargetTransformInfo::ShuffleKind, llvm::VectorType*, llvm::ArrayRef<int>, llvm::TargetTransformInfo::TargetCostKind, int, llvm::VectorType*, llvm::ArrayRef<llvm::Value const*>, llvm::Instruction const*) const (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMAnalysis.so.21.0git+0x4ddf0c)
#15 0x00007f437224f6e7 (anonymous namespace)::VectorCombine::foldInsExtVectorToShuffle(llvm::Instruction&) VectorCombine.cpp:0:0
#16 0x00007f4372256116 (anonymous namespace)::VectorCombine::run()::'lambda'(llvm::Instruction&)::operator()(llvm::Instruction&) const VectorCombine.cpp:0:0
#17 0x00007f437225787f llvm::VectorCombinePass::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMVectorize.so.21.0git+0x25787f)
#18 0x00007f4373f225c5 llvm::detail::PassModel<llvm::Function, llvm::VectorCombinePass, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMPasses.so.21.0git+0x1225c5)
#19 0x00007f4370f10cad llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMCore.so.21.0git+0x310cad)
#20 0x00007f43784dc235 llvm::detail::PassModel<llvm::Function, llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMX86CodeGen.so.21.0git+0xdc235)
#21 0x00007f4370f0ee75 llvm::ModuleToFunctionPassAdaptor::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMCore.so.21.0git+0x30ee75)
#22 0x00007f43784dcbf5 llvm::detail::PassModel<llvm::Module, llvm::ModuleToFunctionPassAdaptor, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMX86CodeGen.so.21.0git+0xdcbf5)
#23 0x00007f4370f0fb2a llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMCore.so.21.0git+0x30fb2a)
#24 0x00007f4379ba3dc6 llvm::runPassPipeline(llvm::StringRef, llvm::Module&, llvm::TargetMachine*, llvm::TargetLibraryInfoImpl*, llvm::ToolOutputFile*, llvm::ToolOutputFile*, llvm::ToolOutputFile*, llvm::StringRef, llvm::ArrayRef<llvm::PassPlugin>, llvm::ArrayRef<std::function<void (llvm::PassBuilder&)>>, llvm::opt_tool::OutputKind, llvm::opt_tool::VerifierKind, bool, bool, bool, bool, bool, bool, bool) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/libLLVMOptDriver.so.21.0git+0x2fdc6)
#25 0x00007f4379baf5c2 optMain (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/libLLVMOptDriver.so.21.0git+0x3b5c2)
#26 0x00007f4379429d90 __libc_start_call_main ./csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#27 0x00007f4379429e40 call_init ./csu/../csu/libc-start.c:128:20
#28 0x00007f4379429e40 __libc_start_main ./csu/../csu/libc-start.c:379:5
#29 0x00006293bc5a5095 _start (bin/opt+0x1095)
Aborted (core dumped)
```

Triggered by https://github.com/llvm/llvm-project/pull/121216. cc @ParkHanbum @RKSimon
Reported by https://github.com/dtcxzyw/llvm-opt-benchmark/issues/2093

Found the problem - fix incoming


commit 3fe6a064f15cd854fd497594cc20e8b680cd2133
Author: Florian Hahn <flo@fhahn.com>
Date:   Wed Sep 4 20:50:05 2024 +0100

    [LV] Check if compare is truncated directly in getInstructionCost.

    The current check for truncated compares in getInstructionCost misses
    cases where either the first or both operands are constants.
    Check directly if the compare is marked for truncation. In that case,
    the minimum bitwidth is that of the operands.

    The patch also adds asserts to ensure that.

    This fixes a divergence between legacy and VPlan-based cost model, where
    the legacy cost model incorrectly estimated the cost of compares with
    truncated operands.

    Fixes https://github.com/llvm/llvm-project/issues/107171.

diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index 0200525a718d..0ccf442dac99 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -6606,9 +6606,20 @@ LoopVectorizationCostModel::getInstructionCost(Instruction *I,
   case Instruction::ICmp:
   case Instruction::FCmp: {
     Type *ValTy = I->getOperand(0)->getType();
+
     Instruction *Op0AsInstruction = dyn_cast<Instruction>(I->getOperand(0));
-    if (canTruncateToMinimalBitwidth(Op0AsInstruction, VF))
-      ValTy = IntegerType::get(ValTy->getContext(), MinBWs[Op0AsInstruction]);
+    (void)Op0AsInstruction;
+    assert((!canTruncateToMinimalBitwidth(Op0AsInstruction, VF) ||
+            canTruncateToMinimalBitwidth(I, VF)) &&
+           "truncating Op0 must imply truncating the compare");
+    if (canTruncateToMinimalBitwidth(I, VF)) {
+      assert(!canTruncateToMinimalBitwidth(Op0AsInstruction, VF) ||
+             MinBWs[I] == MinBWs[Op0AsInstruction] &&
+                 "if both the operand and the compare are marked for "
+                 "truncation, they must have the same bitwidth");
+      ValTy = IntegerType::get(ValTy->getContext(), MinBWs[I]);
+    }
+
     VectorTy = ToVectorTy(ValTy, VF);
     return TTI.getCmpSelInstrCost(I->getOpcode(), VectorTy, nullptr,
                                   cast<CmpInst>(I)->getPredicate(), CostKind,

target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"
target triple = "riscv64-unknown-linux-gnu"

define void @test_pr98413_zext_removed(ptr %src, ptr noalias %dst, i64 %x) {
entry:
  br label %loop

loop:                                             ; preds = %loop, %entry
  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
  %gep.src = getelementptr inbounds i16, ptr %src, i64 %iv
  %l = load i16, ptr %gep.src, align 8
  %ext.l = zext i16 %l to i64
  %and = and i64 %x, %ext.l
  %trunc.and = trunc i64 %and to i8
  %gep.dst = getelementptr inbounds i8, ptr %dst, i64 %iv
  store i8 %trunc.and, ptr %gep.dst, align 1
  %iv.next = add i64 %iv, 1
  %exitcond.not = icmp eq i64 %iv, 96
  br i1 %exitcond.not, label %exit, label %loop

exit:                                             ; preds = %loop
  ret void
}

target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"
target triple = "riscv64-unknown-linux-gnu"

define void @truncate_to_i1_used_by_branch(i8 %x, ptr %dst) #0 {
entry:
  br label %loop.header

loop.header:                                      ; preds = %loop.latch, %entry
  %f.039 = phi i8 [ 0, %entry ], [ %add, %loop.latch ]
  %0 = or i8 23, %x
  %extract.t = trunc i8 %0 to i1
  br i1 %extract.t, label %then, label %loop.latch

then:                                             ; preds = %loop.header
  store i8 0, ptr %dst, align 1
  br label %loop.latch

loop.latch:                                       ; preds = %then, %loop.header
  %add = add i8 %f.039, 1
  %conv = sext i8 %f.039 to i32
  %cmp = icmp slt i32 %conv, 1
  br i1 %cmp, label %loop.header, label %exit

exit:                                             ; preds = %loop.latch
  ret void
}

attributes #0 = { "target-features"="+64bit,+v,+zvl256b" }

target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"
target triple = "riscv64-unknown-linux-gnu"

define i8 @icmp_ops_narrowed_to_i1() #0 {
entry:
  br label %loop

loop:                                             ; preds = %loop, %entry
  %iv = phi i16 [ 0, %entry ], [ %iv.next, %loop ]
  %c = icmp eq i8 0, 0
  %ext = zext i1 %c to i64
  %shr = lshr i64 %ext, 1
  %trunc = trunc i64 %shr to i8
  %iv.next = add i16 %iv, 1
  %ec = icmp eq i16 %iv.next, 100
  br i1 %ec, label %exit, label %loop

exit:                                             ; preds = %loop
  ret i8 %trunc
}

attributes #0 = { "target-features"="+64bit,+v" }

target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"
target triple = "riscv64-unknown-linux-gnu"

define void @test_pr98413_sext_removed(ptr %src, ptr noalias %dst, i64 %x) {
entry:
  br label %loop

loop:                                             ; preds = %loop, %entry
  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
  %gep.src = getelementptr inbounds i16, ptr %src, i64 %iv
  %l = load i16, ptr %gep.src, align 8
  %ext.l = sext i16 %l to i64
  %and = and i64 %x, %ext.l
  %trunc.and = trunc i64 %and to i8
  %gep.dst = getelementptr inbounds i8, ptr %dst, i64 %iv
  store i8 %trunc.and, ptr %gep.dst, align 1
  %iv.next = add i64 %iv, 1
  %exitcond.not = icmp eq i64 %iv, 96
  br i1 %exitcond.not, label %exit, label %loop

exit:                                             ; preds = %loop
  ret void
}

[VPlan] Assertion " VPlan cost model and legacy cost model disagreed"' failed.

Testing using 3bd161e98d89d31696002994771b7761f1c74859

C testcase:
```c
char a;
unsigned b = 221;
short c = 35;
char d[6];
int main() {
  d[0] = 4079751220931503459;
  for (short e = 3; e; e += 3)
    for (short f = 0; f < 1; f += -1832)
      for (long g = ({
             __typeof__(0) h = !d[f * 1];
             h;
           });
           g < c - 3; g += b - 219)
        a -= 8;
}
```
`/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/clang -I/scratch/tc-testing/compiler-fuzz-ci/csmith-build/include -fsigned-char -fno-strict-aliasing -fwrapv -march=rv64gcv -flto -O3 -fuse-ld=lld red.c -o rv64gcv.out -w`

LLVM IR:
```llvm ir
; ModuleID = 'reduced.bc'
target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"
target triple = "riscv64-unknown-linux-gnu"

define i32 @main() #0 {
entry:
  br label %for.body14.preheader48

for.cond.cleanup:                                 ; preds = %for.body14.preheader48
  store i8 %1, ptr null, align 1
  ret i32 0

for.body14.preheader48:                           ; preds = %for.body14.preheader48, %entry
  %e.047 = phi i16 [ 0, %entry ], [ %add27, %for.body14.preheader48 ]
  %tobool6.not = icmp eq i8 0, 0
  %conv7 = zext i1 %tobool6.not to i64
  %0 = lshr i64 %conv7, 1
  %1 = trunc i64 %0 to i8
  %add27 = add i16 %e.047, 1
  %tobool.not = icmp eq i16 %add27, 0
  br i1 %tobool.not, label %for.cond.cleanup, label %for.body14.preheader48
}

attributes #0 = { "target-features"="+64bit,+a,+c,+d,+f,+m,+relax,+v,+zicsr,+zifencei,+zmmul,+zve32f,+zve32x,+zve64d,+zve64f,+zve64x,+zvl128b,+zvl32b,+zvl64b,-b,-e,-experimental-smctr,-experimental-smmpm,-experimental-smnpm,-experimental-ssctr,-experimental-ssnpm,-experimental-sspm,-experimental-supm,-experimental-zacas,-experimental-zalasr,-experimental-zicfilp,-experimental-zicfiss,-experimental-zvbc32e,-experimental-zvkgs,-h,-shcounterenw,-shgatpa,-shtvala,-shvsatpa,-shvstvala,-shvstvecd,-smaia,-smcdeleg,-smcsrind,-smepmp,-smstateen,-ssaia,-ssccfg,-ssccptr,-sscofpmf,-sscounterenw,-sscsrind,-ssqosid,-ssstateen,-ssstrict,-sstc,-sstvala,-sstvecd,-ssu64xl,-svade,-svadu,-svbare,-svinval,-svnapot,-svpbmt,-xcvalu,-xcvbi,-xcvbitmanip,-xcvelw,-xcvmac,-xcvmem,-xcvsimd,-xsfcease,-xsfvcp,-xsfvfnrclipxfqf,-xsfvfwmaccqqq,-xsfvqmaccdod,-xsfvqmaccqoq,-xsifivecdiscarddlone,-xsifivecflushdlone,-xtheadba,-xtheadbb,-xtheadbs,-xtheadcmo,-xtheadcondmov,-xtheadfmemidx,-xtheadmac,-xtheadmemidx,-xtheadmempair,-xtheadsync,-xtheadvdot,-xventanacondops,-xwchc,-za128rs,-za64rs,-zaamo,-zabha,-zalrsc,-zama16b,-zawrs,-zba,-zbb,-zbc,-zbkb,-zbkc,-zbkx,-zbs,-zca,-zcb,-zcd,-zce,-zcf,-zcmop,-zcmp,-zcmt,-zdinx,-zfa,-zfbfmin,-zfh,-zfhmin,-zfinx,-zhinx,-zhinxmin,-zic64b,-zicbom,-zicbop,-zicboz,-ziccamoa,-ziccif,-zicclsm,-ziccrse,-zicntr,-zicond,-zihintntl,-zihintpause,-zihpm,-zimop,-zk,-zkn,-zknd,-zkne,-zknh,-zkr,-zks,-zksed,-zksh,-zkt,-ztso,-zvbb,-zvbc,-zvfbfmin,-zvfbfwma,-zvfh,-zvfhmin,-zvkb,-zvkg,-zvkn,-zvknc,-zvkned,-zvkng,-zvknha,-zvknhb,-zvks,-zvksc,-zvksed,-zvksg,-zvksh,-zvkt,-zvl1024b,-zvl16384b,-zvl2048b,-zvl256b,-zvl32768b,-zvl4096b,-zvl512b,-zvl65536b,-zvl8192b" }
```

Command/backtrace:
```
 /scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt -passes=loop-vectorize reduced.ll -S
opt: /scratch/tc-testing/tc-compiler-fuzz-trunk/llvm/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp:7389: llvm::VectorizationFactor llvm::LoopVectorizationPlanner::computeBestVF(): Assertion `(BestFactor.Width == LegacyVF.Width || planContainsAdditionalSimplifications(getPlanFor(BestFactor.Width), CostCtx, OrigLoop)) && " VPlan cost model and legacy cost model disagreed"' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:
0.      Program arguments: /scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt -passes=loop-vectorize reduced.ll -S
1.      Running pass "function(loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>)" on module "reduced.ll"
2.      Running pass "loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>" on function "main"
 #0 0x000061eac73d9f50 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x3010f50)
 #1 0x000061eac73d735f llvm::sys::RunSignalHandlers() (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x300e35f)
 #2 0x000061eac73d74b5 SignalHandler(int) Signals.cpp:0:0
 #3 0x00007496e1242520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #4 0x00007496e12969fc __pthread_kill_implementation ./nptl/pthread_kill.c:44:76
 #5 0x00007496e12969fc __pthread_kill_internal ./nptl/pthread_kill.c:78:10
 #6 0x00007496e12969fc pthread_kill ./nptl/pthread_kill.c:89:10
 #7 0x00007496e1242476 gsignal ./signal/../sysdeps/posix/raise.c:27:6
 #8 0x00007496e12287f3 abort ./stdlib/abort.c:81:7
 #9 0x00007496e122871b _nl_load_domain ./intl/loadmsgcat.c:1177:9
#10 0x00007496e1239e96 (/lib/x86_64-linux-gnu/libc.so.6+0x39e96)
#11 0x000061eac63ad810 llvm::LoopVectorizationPlanner::computeBestVF() (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x1fe4810)
#12 0x000061eac63c45bb llvm::LoopVectorizePass::processLoop(llvm::Loop*) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x1ffb5bb)
#13 0x000061eac63c75d1 llvm::LoopVectorizePass::runImpl(llvm::Function&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x1ffe5d1)
#14 0x000061eac63c7c47 llvm::LoopVectorizePass::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x1ffec47)
#15 0x000061eac5222626 llvm::detail::PassModel<llvm::Function, llvm::LoopVectorizePass, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0xe59626)
#16 0x000061eac71e5cef llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x2e1ccef)
#17 0x000061eac52257b6 llvm::detail::PassModel<llvm::Function, llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0xe5c7b6)
#18 0x000061eac71e4a6b llvm::ModuleToFunctionPassAdaptor::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x2e1ba6b)
#19 0x000061eac5221a56 llvm::detail::PassModel<llvm::Module, llvm::ModuleToFunctionPassAdaptor, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0xe58a56)
#20 0x000061eac71e2aad llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x2e19aad)
#21 0x000061eac4a4fde6 llvm::runPassPipeline(llvm::StringRef, llvm::Module&, llvm::TargetMachine*, llvm::TargetLibraryInfoImpl*, llvm::ToolOutputFile*, llvm::ToolOutputFile*, llvm::ToolOutputFile*, llvm::StringRef, llvm::ArrayRef<llvm::PassPlugin>, llvm::ArrayRef<std::function<void (llvm::PassBuilder&)>>, llvm::opt_tool::OutputKind, llvm::opt_tool::VerifierKind, bool, bool, bool, bool, bool, bool, bool) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x686de6)
#22 0x000061eac4a41b71 optMain (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x678b71)
#23 0x00007496e1229d90 __libc_start_call_main ./csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#24 0x00007496e1229e40 call_init ./csu/../csu/libc-start.c:128:20
#25 0x00007496e1229e40 __libc_start_main ./csu/../csu/libc-start.c:379:5
#26 0x000061eac4a37f25 _start (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x66ef25)
zsh: IOT instruction (core dumped)  /scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt
```
https://godbolt.org/z/x316voG8q

Found via fuzzer

Related/prior issue: https://github.com/llvm/llvm-project/issues/106780

cc @fhahn