commit b65b2b4ab60763515694c740935989f908a03312
Author: Alexey Bataev <a.bataev@outlook.com>
Date:   Wed Oct 23 12:03:38 2024 -0700

    [SLP]Expand vector to the whole register size in extracts adjustment

    Need to expand the number of elements to the whole register to correctly
    process estimation and avoid compiler crash.

    Fixes #113462

diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index d824c40c401d..889c4d94ba5e 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -9840,13 +9840,14 @@ class BoUpSLP::ShuffleCostEstimator : public BaseShuffleAnalysis {
             ::getShuffleCost(TTI, *RegShuffleKind,
                              getWidenedType(ScalarTy, EltsPerVector), SubMask);
       }
+      const unsigned BaseVF = getFullVectorNumberOfElements(
+          *R.TTI, VL.front()->getType(), alignTo(NumElts, EltsPerVector));
       for (unsigned Idx : Indices) {
-        assert((Idx + EltsPerVector) <= alignTo(NumElts, EltsPerVector) &&
+        assert((Idx + EltsPerVector) <= BaseVF &&
                "SK_ExtractSubvector index out of range");
-        Cost += ::getShuffleCost(
-            TTI, TTI::SK_ExtractSubvector,
-            getWidenedType(ScalarTy, alignTo(NumElts, EltsPerVector)), {},
-            CostKind, Idx, getWidenedType(ScalarTy, EltsPerVector));
+        Cost += ::getShuffleCost(TTI, TTI::SK_ExtractSubvector,
+                                 getWidenedType(ScalarTy, BaseVF), {}, CostKind,
+                                 Idx, getWidenedType(ScalarTy, EltsPerVector));
       }
       // Second attempt to check, if just a permute is better estimated than
       // subvector extract.

[SLPVectorizer] Assertion `(Idx + EltsPerVector) <= alignTo(NumElts, EltsPerVector) && "SK_ExtractSubvector index out of range"' failed.

Reproducer: https://godbolt.org/z/fxYWYnWKs
```
; bin/opt -passes=slp-vectorizer 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"

declare void @callee(i32, i64)

define i32 @main(i32 %g_274.promoted2477.i.i.i, ptr %p) {
entry:
  %g_274.promoted2477.i.i.i1 = load i32, ptr %p, align 4
  br i1 false, label %for.inc347.i.i.i, label %for.cond159.preheader.i.i.i

for.cond159.preheader.i.i.i:                      ; preds = %entry
  %tobool239.not.us.i.i.i.not = icmp eq i32 %g_274.promoted2477.i.i.i1, 0
  %tobool239.not.us.i.1.i.i = icmp eq i32 %g_274.promoted2477.i.i.i1, 0
  %tobool239.not.us.i.3.i.i = icmp eq i32 %g_274.promoted2477.i.i.i1, 0
  %0 = or i1 %tobool239.not.us.i.3.i.i, %tobool239.not.us.i.1.i.i
  %tobool239.not.us.i.4.i.i = icmp eq i32 %g_274.promoted2477.i.i.i1, 0
  %inc34.i21362404.us.v.i.4.i.i = select i1 %tobool239.not.us.i.4.i.i, i64 0, i64 0
  %tobool239.not.us.i.5.i.i = icmp eq i32 0, 0
  %inc34.i21362404.us.v.i.5.i.i = select i1 %tobool239.not.us.i.5.i.i, i64 0, i64 0
  %inc34.i21362404.us.i.5.i.i = or i64 %inc34.i21362404.us.v.i.4.i.i, %inc34.i21362404.us.v.i.5.i.i
  %1 = or i1 %tobool239.not.us.i.5.i.i, %tobool239.not.us.i.4.i.i
  %inc34.i21362404.us.v.i.6.i.i = select i1 false, i64 0, i64 0
  %inc34.i21362404.us.i.6.i.i = or i64 %inc34.i21362404.us.i.5.i.i, %inc34.i21362404.us.v.i.6.i.i
  %tobool239.not.us.i.7.i.i = icmp eq i32 0, 0
  %inc34.i21362404.us.v.i.7.i.i = select i1 false, i64 0, i64 0
  %inc34.i21362404.us.i.7.i.i = or i64 %inc34.i21362404.us.i.6.i.i, %inc34.i21362404.us.v.i.7.i.i
  %inc34.i21362404.us.v.i.8.i.i = select i1 false, i64 0, i64 0
  %inc34.i21362404.us.i.8.i.i = or i64 %inc34.i21362404.us.i.7.i.i, %inc34.i21362404.us.v.i.8.i.i
  %inc34.i21362404.us.v.i.9.i.i = select i1 false, i64 0, i64 0
  %inc34.i21362404.us.i.9.i.i = or i64 %inc34.i21362404.us.i.8.i.i, %inc34.i21362404.us.v.i.9.i.i
  %tobool239.not.us.i.10.i.i = icmp eq i32 0, 0
  %tobool239.not.us.i.11.i.i = icmp eq i32 0, 0
  %2 = or i1 %tobool239.not.us.i.11.i.i, %tobool239.not.us.i.10.i.i
  %tobool239.not.us.i.12.i.i = icmp eq i32 %g_274.promoted2477.i.i.i, 0
  %3 = or i1 %tobool239.not.us.i.12.i.i, %2
  %tobool239.not.us.i.13.i.i = icmp eq i32 0, 0
  %tobool239.not.us.i.14.i.i = icmp eq i32 0, 0
  %4 = or i1 %tobool239.not.us.i.14.i.i, %tobool239.not.us.i.13.i.i
  %tobool239.not.us.i.16.i.i = icmp eq i32 0, 0
  %tobool239.not.us.i.17.i.i = icmp eq i32 0, 0
  %5 = or i1 %tobool239.not.us.i.17.i.i, %tobool239.not.us.i.16.i.i
  %tobool239.not.us.i.18.i.i = icmp eq i32 0, 0
  %6 = or i1 %tobool239.not.us.i.18.i.i, %5
  %tobool239.not.us.i.19.i.i = icmp eq i32 0, 0
  %tobool239.not.us.i.20.i.i = icmp eq i32 0, 0
  %7 = or i1 %tobool239.not.us.i.20.i.i, %tobool239.not.us.i.19.i.i
  %tobool239.not.us.i.21.i.i = icmp eq i32 0, 0
  %8 = or i1 %tobool239.not.us.i.21.i.i, %7
  %tobool239.not.us.i.22.i.i = icmp eq i32 0, 0
  %tobool239.not.us.i.23.i.i = icmp eq i32 0, 0
  %9 = or i1 %tobool239.not.us.i.23.i.i, %tobool239.not.us.i.22.i.i
  %tobool239.not.us.i.24.i.i = icmp eq i32 0, 0
  %10 = or i1 %tobool239.not.us.i.24.i.i, %9
  %11 = select i1 %10, i1 true, i1 %8
  %12 = select i1 %11, i1 true, i1 %6
  %13 = select i1 %12, i1 true, i1 %4
  %14 = select i1 %13, i1 true, i1 %3
  %15 = select i1 %14, i1 true, i1 %tobool239.not.us.i.7.i.i
  %16 = select i1 %15, i1 true, i1 %1
  %17 = or i1 %0, %tobool239.not.us.i.i.i.not
  %18 = select i1 %16, i1 true, i1 %17
  %and252.us.i.24.i.i = select i1 %18, i32 0, i32 0
  br label %for.inc347.i.i.i

for.inc347.i.i.i:                                 ; preds = %for.cond159.preheader.i.i.i, %entry
  %g_202.promoted.i.i.i = phi i32 [ %and252.us.i.24.i.i, %for.cond159.preheader.i.i.i ], [ 0, %entry ]
  %.us-phi24612468.i.i.i = phi i64 [ %inc34.i21362404.us.i.9.i.i, %for.cond159.preheader.i.i.i ], [ 0, %entry ]
  call void @callee(i32 %g_202.promoted.i.i.i, i64 %.us-phi24612468.i.i.i)
  ret i32 0
}
```
```
opt: /root/llvm-project/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp:9844: llvm::InstructionCost llvm::slpvectorizer::BoUpSLP::ShuffleCostEstimator::computeExtractCost(llvm::ArrayRef<llvm::Value*>, llvm::ArrayRef<int>, llvm::ArrayRef<std::optional<llvm::TargetTransformInfo::ShuffleKind> >, unsigned int): Assertion `(Idx + EltsPerVector) <= alignTo(NumElts, EltsPerVector) && "SK_ExtractSubvector index out of range"' 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 <source>
1.	Running pass "function(slp-vectorizer)" on module "<source>"
2.	Running pass "slp-vectorizer" on function "main"
 #0 0x00000000050d8608 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x50d8608)
 #1 0x00000000050d5fbc SignalHandler(int) Signals.cpp:0:0
 #2 0x00007ed1b9642520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #3 0x00007ed1b96969fc pthread_kill (/lib/x86_64-linux-gnu/libc.so.6+0x969fc)
 #4 0x00007ed1b9642476 gsignal (/lib/x86_64-linux-gnu/libc.so.6+0x42476)
 #5 0x00007ed1b96287f3 abort (/lib/x86_64-linux-gnu/libc.so.6+0x287f3)
 #6 0x00007ed1b962871b (/lib/x86_64-linux-gnu/libc.so.6+0x2871b)
 #7 0x00007ed1b9639e96 (/lib/x86_64-linux-gnu/libc.so.6+0x39e96)
 #8 0x000000000413c75f llvm::slpvectorizer::BoUpSLP::ShuffleCostEstimator::computeExtractCost(llvm::ArrayRef<llvm::Value*>, llvm::ArrayRef<int>, llvm::ArrayRef<std::optional<llvm::TargetTransformInfo::ShuffleKind>>, unsigned int) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x413c75f)
 #9 0x0000000004140d8b llvm::slpvectorizer::BoUpSLP::ShuffleCostEstimator::adjustExtracts(llvm::slpvectorizer::BoUpSLP::TreeEntry const*, llvm::MutableArrayRef<int>, llvm::ArrayRef<std::optional<llvm::TargetTransformInfo::ShuffleKind>>, unsigned int, bool&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4140d8b)
#10 0x000000000417b42a llvm::InstructionCost llvm::slpvectorizer::BoUpSLP::processBuildVector<llvm::slpvectorizer::BoUpSLP::ShuffleCostEstimator, llvm::InstructionCost, llvm::TargetTransformInfo, llvm::ArrayRef<llvm::Value*>, llvm::slpvectorizer::BoUpSLP, llvm::SmallPtrSetImpl<llvm::Value*>>(llvm::slpvectorizer::BoUpSLP::TreeEntry const*, llvm::Type*, llvm::TargetTransformInfo&, llvm::ArrayRef<llvm::Value*>&, llvm::slpvectorizer::BoUpSLP&, llvm::SmallPtrSetImpl<llvm::Value*>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x417b42a)
#11 0x000000000417cae7 llvm::slpvectorizer::BoUpSLP::getEntryCost(llvm::slpvectorizer::BoUpSLP::TreeEntry const*, llvm::ArrayRef<llvm::Value*>, llvm::SmallPtrSetImpl<llvm::Value*>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x417cae7)
#12 0x00000000041b6e11 llvm::slpvectorizer::BoUpSLP::getTreeCost(llvm::ArrayRef<llvm::Value*>) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x41b6e11)
#13 0x00000000041bc5df (anonymous namespace)::HorizontalReduction::tryToReduce(llvm::slpvectorizer::BoUpSLP&, llvm::DataLayout const&, llvm::TargetTransformInfo*, llvm::TargetLibraryInfo const&) SLPVectorizer.cpp:0:0
#14 0x00000000041bfb71 llvm::SLPVectorizerPass::vectorizeHorReduction(llvm::PHINode*, llvm::Instruction*, llvm::BasicBlock*, llvm::slpvectorizer::BoUpSLP&, llvm::SmallVectorImpl<llvm::WeakTrackingVH>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x41bfb71)
#15 0x00000000041c431b llvm::SLPVectorizerPass::vectorizeRootInstruction(llvm::PHINode*, llvm::Instruction*, llvm::BasicBlock*, llvm::slpvectorizer::BoUpSLP&) (.constprop.0) SLPVectorizer.cpp:0:0
#16 0x00000000041c856e llvm::SLPVectorizerPass::vectorizeChainsInBlock(llvm::BasicBlock*, llvm::slpvectorizer::BoUpSLP&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x41c856e)
#17 0x00000000041cf231 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
#18 0x00000000041cfedb llvm::SLPVectorizerPass::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x41cfedb)
#19 0x0000000002f64f0e llvm::detail::PassModel<llvm::Function, llvm::SLPVectorizerPass, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x2f64f0e)
#20 0x0000000004ed9788 llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4ed9788)
#21 0x0000000000e2773e llvm::detail::PassModel<llvm::Function, llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0xe2773e)
#22 0x0000000004ed81ae llvm::ModuleToFunctionPassAdaptor::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4ed81ae)
#23 0x0000000000e26e8e llvm::detail::PassModel<llvm::Module, llvm::ModuleToFunctionPassAdaptor, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0xe26e8e)
#24 0x0000000004ed7be0 llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4ed7be0)
#25 0x000000000090a07a 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) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x90a07a)
#26 0x00000000008fce7c optMain (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x8fce7c)
#27 0x00007ed1b9629d90 (/lib/x86_64-linux-gnu/libc.so.6+0x29d90)
#28 0x00007ed1b9629e40 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e40)
#29 0x00000000008f493e _start (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x8f493e)
Program terminated with signal: SIGSEGV
Compiler returned: 139
```

llvm version: 8a9921f5692ab33451d11454b40a023ca0965a69


commit 46957a138dea339799059ea5bf032e40042ff185
Author: Nikita Popov <npopov@redhat.com>
Date:   Fri Apr 19 14:00:49 2024 +0900

    [InstCombine] Fix incorrect fshr to fshl transform

    This transform is only valid if the (modular) shift amount is not
    zero.

    Proof: https://alive2.llvm.org/ce/z/WBxn-x

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

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index aa547565bd08..e7a2f54f8680 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -1988,7 +1988,10 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
       // is not entirely arbitrary. For historical reasons, the backend may
       // recognize rotate left patterns but miss rotate right patterns.
       if (IID == Intrinsic::fshr) {
-        // fshr X, Y, C --> fshl X, Y, (BitWidth - C)
+        // fshr X, Y, C --> fshl X, Y, (BitWidth - C) if C is not zero.
+        if (!isKnownNonZero(ShAmtC, SQ.getWithInstruction(II)))
+          return nullptr;
+
         Constant *LeftShiftC = ConstantExpr::getSub(WidthC, ShAmtC);
         Module *Mod = II->getModule();
         Function *Fshl = Intrinsic::getDeclaration(Mod, Intrinsic::fshl, Ty);

; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare <2 x i32> @llvm.fshr.v2i32(<2 x i32>, <2 x i32>, <2 x i32>) #0

define <2 x i32> @fsh_unary_shuffle_ops_partial_widening(<3 x i32> %x, <2 x i32> %y, <2 x i32> %z) {
  %a = shufflevector <3 x i32> %x, <3 x i32> poison, <2 x i32> <i32 1, i32 0>
  %b = shufflevector <2 x i32> %y, <2 x i32> poison, <2 x i32> <i32 1, i32 0>
  %c = shufflevector <2 x i32> %z, <2 x i32> poison, <2 x i32> <i32 1, i32 0>
  %r = call <2 x i32> @llvm.fshr.v2i32(<2 x i32> %a, <2 x i32> %b, <2 x i32> %c)
  ret <2 x i32> %r
}

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

; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare <2 x i32> @llvm.fshr.v2i32(<2 x i32>, <2 x i32>, <2 x i32>) #0

define <2 x i32> @fshr_vec_zero_elem(<2 x i32> %x, <2 x i32> %y) {
  %fsh = call <2 x i32> @llvm.fshr.v2i32(<2 x i32> %x, <2 x i32> %y, <2 x i32> <i32 2, i32 0>)
  ret <2 x i32> %fsh
}

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

instcombine is wrong about a vector fshr->shl transformation

Instcombine seems to be mis-optimizing this function:
```llvm
define i32 @f(<4 x i8> %0) {
  %2 = call <4 x i8> @llvm.fshr.v4i8(<4 x i8> %0, <4 x i8> zeroinitializer, <4 x i8> <i8 -12, i8 -80, i8 35, i8 1>)
  %3 = bitcast <4 x i8> %2 to i32
  ret i32 %3
}

; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare <4 x i8> @llvm.fshr.v4i8(<4 x i8>, <4 x i8>, <4 x i8>) #0

attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
```
the result is:
```llvm
define i32 @f(<4 x i8> %0) {
  %2 = shl <4 x i8> %0, <i8 4, i8 0, i8 5, i8 7>
  %3 = bitcast <4 x i8> %2 to i32
  ret i32 %3
}

; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare <4 x i8> @llvm.fshr.v4i8(<4 x i8>, <4 x i8>, <4 x i8>) #0

; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare <4 x i8> @llvm.fshl.v4i8(<4 x i8>, <4 x i8>, <4 x i8>) #0

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

Alive says:
```
ERROR: Value mismatch

Example:
<4 x i8> %#0 = < #x00 (0), #x01 (1), #x00 (0), #x00 (0) >

Source:
<4 x i8> %#2 = < #x00 (0), #x00 (0), #x00 (0), #x00 (0) >
i32 %#3 = #x00000000 (0)

Target:
<4 x i8> %#2 = < #x00 (0), #x01 (1), #x00 (0), #x00 (0) >
i32 %#3 = #x00000100 (256)
Source value: #x00000000 (0)
Target value: #x00000100 (256)
```

https://alive2.llvm.org/ce/z/s4UpPe

cc @hatsunespica

Smaller test case: https://alive2.llvm.org/ce/z/hScyGk

I believe the root cause is the fshr to fshl canonicalization: https://alive2.llvm.org/ce/z/NQM3tR

We're performing this transform: https://alive2.llvm.org/ce/z/6UUEsS But we don't verify the pre-condition that the (modular) shift amount is not zero!

For non-vectors this is a non-issue because we'd fold a zero shift earlier, but for vectors it is an issue.


commit 4dede756f25b153a81ea883ef84064f5a1eaaec2
Author: Alexey Bataev <a.bataev@outlook.com>
Date:   Wed Oct 2 05:50:20 2024 -0700

    [SLP]Transform nodes before building externally used values

    transformNodes function may create new vector nodes, so the reduced
    values might be vectorized later. Need to build the list of the
    externally used values after the transformNodes() function call to avoid
    compiler crash.

    Fixe #110787

diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index 15e798bd6c98..ce1e5753c0c8 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -18848,6 +18848,7 @@ public:
             ++SameValuesCounter.try_emplace(OrigV).first->second;
           }
         }
+        V.transformNodes();
         SmallPtrSet<Value *, 4> VLScalars(VL.begin(), VL.end());
         // Gather externally used values.
         SmallPtrSet<Value *, 4> Visited;
@@ -18877,7 +18878,6 @@ public:
         for (Value *RdxVal : VL)
           if (RequiredExtract.contains(RdxVal))
             LocalExternallyUsedValues[RdxVal];
-        V.transformNodes();
         V.buildExternalUses(LocalExternallyUsedValues);

         V.computeMinimumValueSizes();

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

[SLPVectorizer] Assertion `(I->use_empty() || all_of(I->uses(), [&](Use &U) { return isDeleted( cast<Instruction>(U.getUser())); })) && "trying to erase instruction with users."' failed.

Reproducer: https://godbolt.org/z/b8cz56M9z
```
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(i1 %cond) {
entry:
  br label %for.end14.i.i.i.us.i

for.end14.i.i.i.us.i:
  %.promoted10921110.i.i.i.us.i = phi i32 [ %inc229.1.2.i.i.i.us.us.12.i, %for.end14.i.i.i.us.i ], [ 0, %entry ]
  %.promoted1106.i.i.i.us.i = phi i32 [ %0, %for.end14.i.i.i.us.i ], [ 0, %entry ]
  %g_276.promoted956960.i.i.i.us.i = phi i32 [ %4, %for.end14.i.i.i.us.i ], [ 0, %entry ]
  %0 = or i32 1, 0
  %inc229.1974.i.i.i.us.us.8.i = or i32 0, 0
  %inc229.1974.i.i.i.us.us.9.i = or i32 0, 0
  %inc229.1.2.i.i.i.us.us.9.i = or i32 %.promoted10921110.i.i.i.us.i, 0
  %inc229.1974.i.i.i.us.us.12.i = or i32 %.promoted1106.i.i.i.us.i, 0
  %inc229.1.2.i.i.i.us.us.12.i = or i32 1, 0
  %1 = xor i32 %inc229.1.2.i.i.i.us.us.9.i, %inc229.1974.i.i.i.us.us.12.i
  %2 = xor i32 %1, %inc229.1974.i.i.i.us.us.9.i
  %3 = xor i32 %2, %inc229.1974.i.i.i.us.us.8.i
  %4 = xor i32 %3, %inc229.1.2.i.i.i.us.us.12.i
  br i1 %cond, label %exit, label %for.end14.i.i.i.us.i

exit:
  ret i32 %4
}
```
```
opt: /root/llvm-project/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp:2720: void llvm::slpvectorizer::BoUpSLP::removeInstructionsAndOperands(llvm::ArrayRef<U*>) [with T = llvm::Instruction]: Assertion `(I->use_empty() || all_of(I->uses(), [&](Use &U) { return isDeleted( cast<Instruction>(U.getUser())); })) && "trying to erase instruction with users."' 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 <source>
1.	Running pass "function(slp-vectorizer)" on module "<source>"
2.	Running pass "slp-vectorizer" on function "test"
 #0 0x000000000507e338 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x507e338)
 #1 0x000000000507bcec SignalHandler(int) Signals.cpp:0:0
 #2 0x00007f54a0842520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #3 0x00007f54a08969fc pthread_kill (/lib/x86_64-linux-gnu/libc.so.6+0x969fc)
 #4 0x00007f54a0842476 gsignal (/lib/x86_64-linux-gnu/libc.so.6+0x42476)
 #5 0x00007f54a08287f3 abort (/lib/x86_64-linux-gnu/libc.so.6+0x287f3)
 #6 0x00007f54a082871b (/lib/x86_64-linux-gnu/libc.so.6+0x2871b)
 #7 0x00007f54a0839e96 (/lib/x86_64-linux-gnu/libc.so.6+0x39e96)
 #8 0x0000000004102d6f void llvm::slpvectorizer::BoUpSLP::removeInstructionsAndOperands<llvm::Instruction>(llvm::ArrayRef<llvm::Instruction*>) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4102d6f)
 #9 0x000000000415dea2 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::Instruction*) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x415dea2)
#10 0x0000000004167819 (anonymous namespace)::HorizontalReduction::tryToReduce(llvm::slpvectorizer::BoUpSLP&, llvm::DataLayout const&, llvm::TargetTransformInfo*, llvm::TargetLibraryInfo const&) SLPVectorizer.cpp:0:0
#11 0x000000000416a302 llvm::SLPVectorizerPass::vectorizeHorReduction(llvm::PHINode*, llvm::Instruction*, llvm::BasicBlock*, llvm::slpvectorizer::BoUpSLP&, llvm::TargetTransformInfo*, llvm::SmallVectorImpl<llvm::WeakTrackingVH>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x416a302)
#12 0x000000000416ebb8 llvm::SLPVectorizerPass::vectorizeRootInstruction(llvm::PHINode*, llvm::Instruction*, llvm::BasicBlock*, llvm::slpvectorizer::BoUpSLP&, llvm::TargetTransformInfo*) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x416ebb8)
#13 0x0000000004172da1 llvm::SLPVectorizerPass::vectorizeChainsInBlock(llvm::BasicBlock*, llvm::slpvectorizer::BoUpSLP&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4172da1)
#14 0x00000000041796b1 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
#15 0x000000000417a33b llvm::SLPVectorizerPass::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x417a33b)
#16 0x0000000002f33c8e llvm::detail::PassModel<llvm::Function, llvm::SLPVectorizerPass, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x2f33c8e)
#17 0x0000000004e81158 llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4e81158)
#18 0x0000000000e15bde llvm::detail::PassModel<llvm::Function, llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0xe15bde)
#19 0x0000000004e7fb7e llvm::ModuleToFunctionPassAdaptor::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4e7fb7e)
#20 0x0000000000e1538e llvm::detail::PassModel<llvm::Module, llvm::ModuleToFunctionPassAdaptor, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0xe1538e)
#21 0x0000000004e7f5b0 llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4e7f5b0)
#22 0x0000000000904102 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) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x904102)
#23 0x00000000008f6f8c optMain (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x8f6f8c)
#24 0x00007f54a0829d90 (/lib/x86_64-linux-gnu/libc.so.6+0x29d90)
#25 0x00007f54a0829e40 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e40)
#26 0x00000000008eea5e _start (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x8eea5e)
Program terminated with signal: SIGSEGV
Compiler returned: 139
```
llvm version: e379094328e49731a606304f7e3559d4f1fa96f9

Fixed in 4dede756f25b153a81ea883ef84064f5a1eaaec2


commit cf1963afad335cf74a9411f106d1f2fe80dbed2f
Author: Yingwei Zheng <dtcxzyw2333@gmail.com>
Date:   Thu Oct 31 23:26:45 2024 +0800

    [InstCombine] Fix FMF propagation in `foldSelectIntoOp` (#114356)

    Closes https://github.com/llvm/llvm-project/issues/113423.

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index c5f39a4c381e..9e193e7faa8a 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -529,9 +529,6 @@ Instruction *InstCombinerImpl::foldSelectIntoOp(SelectInst &SI, Value *TrueVal,
     if (!OpToFold)
       return nullptr;

-    // TODO: We probably ought to revisit cases where the select and FP
-    // instructions have different flags and add tests to ensure the
-    // behaviour is correct.
     FastMathFlags FMF;
     if (isa<FPMathOperator>(&SI))
       FMF = SI.getFastMathFlags();
@@ -564,6 +561,8 @@ Instruction *InstCombinerImpl::foldSelectIntoOp(SelectInst &SI, Value *TrueVal,
     BinaryOperator *BO =
         BinaryOperator::Create(TVI->getOpcode(), FalseVal, NewSel);
     BO->copyIRFlags(TVI);
+    if (isa<FPMathOperator>(&SI))
+      BO->andIRFlags(NewSel);
     return BO;
   };

define float @fmul_by_self_if_0_oeq_zero_f32_fmul_nnan_ninf_nsz(float %x) {
  %x.is.zero = fcmp oeq float %x, 0.000000e+00
  %scaled.x = fmul nnan ninf nsz float %x, %x
  %scaled.if.denormal = select nnan i1 %x.is.zero, float %scaled.x, float %x
  ret float %scaled.if.denormal
}

Wrong folding of `select` into floating number ops

https://github.com/llvm/llvm-project/blob/ae618d360456c5ccf6c8cf2294e708ac6625950e/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp#L559-L568

The compiler explorer's alive2 times out for this case.
But I post a proof that the optimization actually happens: https://alive2.llvm.org/ce/z/7MRSu5

This is the Alive2 report on my machine:
```llvm
----------------------------------------
define float @fmul_by_self_if_0_oeq_zero_f32_fmul_nnan_ninf_nsz.2(float %x) {
#0:
  %#1 = fcmp ule float %x, 0.000000
  %scaled.x = fmul nnan ninf nsz float %x, %x
  %scaled.if.denormal = select nnan i1 %#1, float %x, float %scaled.x
  ret float %scaled.if.denormal
}
=>
define float @fmul_by_self_if_0_oeq_zero_f32_fmul_nnan_ninf_nsz.2(float %x) {
#0:
  %#1 = fcmp ule float %x, 0.000000
  %scaled.x = select nnan i1 %#1, float 1.000000, float %x
  %scaled.if.denormal = fmul nnan ninf nsz float %scaled.x, %x
  ret float %scaled.if.denormal
}
Transformation doesn't verify!

ERROR: Target is more poisonous than source

Example:
float %x = #xff800000 (-oo)

Source:
i1 %#1 = #x1 (1)
float %scaled.x = poison
float %scaled.if.denormal = #xff800000 (-oo)

Target:
i1 %#1 = #x1 (1)
float %scaled.x = #x3f800000 (1)
float %scaled.if.denormal = poison
Source value: #xff800000 (-oo)
Target value: poison

Summary:
  0 correct transformations
  1 incorrect transformations
  0 failed-to-prove transformations
  0 Alive2 errors
```


commit f2f02b21cd581057e3c9b4a7a27e0014eeb9ba15
Author: Simon Pilgrim <llvm-dev@redking.me.uk>
Date:   Sat Dec 28 09:21:22 2024 +0000

    [VectorCombine] foldShuffleOfBinops - only accept exact matching cmp predicates

    m_SpecificCmp allowed equivalent predicate+flags which don't necessarily work after being folded from "shuffle (cmpop), (cmpop)" into "cmpop (shuffle), (shuffle)"

    Fixes #121110

diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
index ecbc13d489eb..2460ccc61d84 100644
--- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
+++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
@@ -1669,7 +1669,8 @@ bool VectorCombine::foldShuffleOfBinops(Instruction &I) {

   Value *X, *Y, *Z, *W;
   bool IsCommutative = false;
-  CmpPredicate Pred = CmpInst::BAD_ICMP_PREDICATE;
+  CmpPredicate PredLHS = CmpInst::BAD_ICMP_PREDICATE;
+  CmpPredicate PredRHS = CmpInst::BAD_ICMP_PREDICATE;
   if (match(LHS, m_BinOp(m_Value(X), m_Value(Y))) &&
       match(RHS, m_BinOp(m_Value(Z), m_Value(W)))) {
     auto *BO = cast<BinaryOperator>(LHS);
@@ -1677,8 +1678,9 @@ bool VectorCombine::foldShuffleOfBinops(Instruction &I) {
     if (llvm::is_contained(OldMask, PoisonMaskElem) && BO->isIntDivRem())
       return false;
     IsCommutative = BinaryOperator::isCommutative(BO->getOpcode());
-  } else if (match(LHS, m_Cmp(Pred, m_Value(X), m_Value(Y))) &&
-             match(RHS, m_SpecificCmp(Pred, m_Value(Z), m_Value(W)))) {
+  } else if (match(LHS, m_Cmp(PredLHS, m_Value(X), m_Value(Y))) &&
+             match(RHS, m_Cmp(PredRHS, m_Value(Z), m_Value(W))) &&
+             (CmpInst::Predicate)PredLHS == (CmpInst::Predicate)PredRHS) {
     IsCommutative = cast<CmpInst>(LHS)->isCommutative();
   } else
     return false;
@@ -1727,14 +1729,14 @@ bool VectorCombine::foldShuffleOfBinops(Instruction &I) {
       TTI.getShuffleCost(SK0, BinOpTy, NewMask0, CostKind, 0, nullptr, {X, Z}) +
       TTI.getShuffleCost(SK1, BinOpTy, NewMask1, CostKind, 0, nullptr, {Y, W});

-  if (Pred == CmpInst::BAD_ICMP_PREDICATE) {
+  if (PredLHS == CmpInst::BAD_ICMP_PREDICATE) {
     NewCost +=
         TTI.getArithmeticInstrCost(LHS->getOpcode(), ShuffleDstTy, CostKind);
   } else {
     auto *ShuffleCmpTy =
         FixedVectorType::get(BinOpTy->getElementType(), ShuffleDstTy);
     NewCost += TTI.getCmpSelInstrCost(LHS->getOpcode(), ShuffleCmpTy,
-                                      ShuffleDstTy, Pred, CostKind);
+                                      ShuffleDstTy, PredLHS, CostKind);
   }

   LLVM_DEBUG(dbgs() << "Found a shuffle feeding two binops: " << I
@@ -1750,10 +1752,10 @@ bool VectorCombine::foldShuffleOfBinops(Instruction &I) {

   Value *Shuf0 = Builder.CreateShuffleVector(X, Z, NewMask0);
   Value *Shuf1 = Builder.CreateShuffleVector(Y, W, NewMask1);
-  Value *NewBO = Pred == CmpInst::BAD_ICMP_PREDICATE
+  Value *NewBO = PredLHS == CmpInst::BAD_ICMP_PREDICATE
                      ? Builder.CreateBinOp(
                            cast<BinaryOperator>(LHS)->getOpcode(), Shuf0, Shuf1)
-                     : Builder.CreateCmp(Pred, Shuf0, Shuf1);
+                     : Builder.CreateCmp(PredLHS, Shuf0, Shuf1);

   // Intersect flags from the old binops.
   if (auto *NewInst = dyn_cast<Instruction>(NewBO)) {

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

opt < %s -passes=vector-combine -S -mtriple=x86_64-- -mattr=sse4.2

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

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

define <2 x i1> @PR121110() {
  %ugt = icmp samesign ugt <2 x i32> zeroinitializer, zeroinitializer
  %sgt = icmp sgt <2 x i32> zeroinitializer, <i32 6, i32 -4>
  %res = shufflevector <2 x i1> %ugt, <2 x i1> %sgt, <2 x i32> <i32 0, i32 3>
  ret <2 x i1> %res
}

[clang] Miscompilation at -Os

This code prints 9 at `-Os` and 0 at `-O0/1/2/3`:

```c
int printf(const char *, ...);
char a = 9, c, d;
int b, e;
unsigned short f;
char *g = &a;
void h(int i) {
  for (; b; b++)
    c &= 0 <= i;
}
static short j(unsigned long i) {
  int k;
  for (; e + d + 4 > 0;) {
    k = i + 49;
    h(k + i - 52 + i);
    *g = 0;
    return 0;
  }
  return 0;
}
int main() {
  j(6 < (unsigned short)(f - 7) + f);
  printf("%d\n", a);
}
```

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

Bisected to https://github.com/llvm/llvm-project/commit/5287299f8809ae927a0acafb179c4b37ce9ff21d, which was committed by @RKSimon

I'm not convinced the patch is responsible, it's more likely exposed something else.  I'll take a look after the Christmas break.

Reproducer: https://alive2.llvm.org/ce/z/jdkwFh
```
; bin/opt -passes=vector-combine test.ll -S
target triple = "x86_64-unknown-linux-gnu"

define <2 x i1> @src() {
entry:
  %0 = icmp samesign ugt <2 x i32> zeroinitializer, zeroinitializer
  %1 = icmp sgt <2 x i32> zeroinitializer, <i32 6, i32 -4>
  %2 = shufflevector <2 x i1> %0, <2 x i1> %1, <2 x i32> <i32 0, i32 3>
  ret <2 x i1> %2
}
```
```
define <2 x i1> @tgt() {
entry:
  ret <2 x i1> zeroinitializer
}
```
```

----------------------------------------
define <2 x i1> @src() {
entry:
  %#0 = icmp samesign ugt <2 x i32> { 0, 0 }, { 0, 0 }
  %#1 = icmp sgt <2 x i32> { 0, 0 }, { 6, 4294967292 }
  %#2 = shufflevector <2 x i1> %#0, <2 x i1> %#1, 0, 3
  ret <2 x i1> %#2
}
=>
define <2 x i1> @tgt() {
entry:
  ret <2 x i1> { 0, 0 }
}
Transformation doesn't verify!

ERROR: Value mismatch

Example:

Source:
<2 x i1> %#0 = < #x0 (0), #x0 (0) >
<2 x i1> %#1 = < #x0 (0), #x1 (1) >
<2 x i1> %#2 = < #x0 (0), #x1 (1) >

Target:
Source value: < #x0 (0), #x1 (1) >
Target value: < #x0 (0), #x0 (0) >
```


commit 5528388e3664c6d7d292f20a739f1bf1c8ef768d
Author: Ramkumar Ramachandra <ramkumar.ramachandra@codasip.com>
Date:   Fri Dec 13 22:06:39 2024 +0000

    EarlyCSE: fix CmpPredicate duplicate-hashing (#119902)

    Strip hash_value() for CmpPredicate, as different callers have different
    hashing use-cases. In this case, there is just one caller, namely
    EarlyCSE, which calls hash_combine() on a CmpPredicate, which used to
    call hash_combine() on a CmpInst::Predicate prior to 4a0d53a
    (PatternMatch: migrate to CmpPredicate). This has uncovered a bug where
    two icmp instructions differing in just the fact that one of them has
    the samesign flag on it are hashed differently, leading to divergent
    hashing, and a crash. Fix this crash by dropping samesign information on
    icmp instructions before hashing them, preserving the former behavior.

    Fixes #119893.

diff --git a/llvm/include/llvm/IR/CmpPredicate.h b/llvm/include/llvm/IR/CmpPredicate.h
index ce78e4311f9f..9aa1449465f5 100644
--- a/llvm/include/llvm/IR/CmpPredicate.h
+++ b/llvm/include/llvm/IR/CmpPredicate.h
@@ -71,13 +71,7 @@ public:

   /// Get the swapped predicate of a CmpInst.
   static CmpPredicate getSwapped(const CmpInst *Cmp);
-
-  /// Provided to facilitate storing a CmpPredicate in data structures that
-  /// require hashing.
-  friend hash_code hash_value(const CmpPredicate &Arg); // NOLINT
 };
-
-[[nodiscard]] hash_code hash_value(const CmpPredicate &Arg);
 } // namespace llvm

 #endif
diff --git a/llvm/lib/IR/Instructions.cpp b/llvm/lib/IR/Instructions.cpp
index d1da02c744f1..2d6fe40f4c1d 100644
--- a/llvm/lib/IR/Instructions.cpp
+++ b/llvm/lib/IR/Instructions.cpp
@@ -3946,10 +3946,6 @@ CmpPredicate CmpPredicate::getSwapped(const CmpInst *Cmp) {
   return getSwapped(get(Cmp));
 }

-hash_code llvm::hash_value(const CmpPredicate &Arg) { // NOLINT
-  return hash_combine(Arg.Pred, Arg.HasSameSign);
-}
-
 //===----------------------------------------------------------------------===//
 //                        SwitchInst Implementation
 //===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Transforms/Scalar/EarlyCSE.cpp b/llvm/lib/Transforms/Scalar/EarlyCSE.cpp
index 682c5c3d8c63..3a0ae6b01a11 100644
--- a/llvm/lib/Transforms/Scalar/EarlyCSE.cpp
+++ b/llvm/lib/Transforms/Scalar/EarlyCSE.cpp
@@ -290,7 +290,8 @@ static unsigned getHashValueImpl(SimpleValue Val) {
       Pred = CmpInst::getInversePredicate(Pred);
       std::swap(A, B);
     }
-    return hash_combine(Inst->getOpcode(), Pred, X, Y, A, B);
+    return hash_combine(Inst->getOpcode(),
+                        static_cast<CmpInst::Predicate>(Pred), X, Y, A, B);
   }

   if (CastInst *CI = dyn_cast<CastInst>(Inst))

define i32 @samesign_hash_bug(i16 %v) {
  %zext = zext i16 %v to i32
  %icmp.samesign = icmp samesign ugt i32 %zext, 31
  %select.icmp.samesign = select i1 %icmp.samesign, i32 0, i32 1
  %ashr = ashr i32 0, %select.icmp.samesign
  %icmp = icmp ugt i32 %zext, 31
  %select.icmp = select i1 %icmp, i32 1, i32 0
  %ret = add i32 %ashr, %select.icmp
  ret i32 %ret
}

[EarlyCSE] Assertion `!FoundVal && "Key already in new map?"' failed.

Reproducer:
```
; bin/opt -passes=early-cse reduced.ll -S

define i32 @func_207(i16 %p_208.coerce, i32 %conv, i32 %0, i64 %1, ptr %p) {
entry:
  %conv1 = zext i16 %p_208.coerce to i32
  %conv31 = sext i32 %conv to i64
  %cmp.i = icmp eq i64 %conv31, 0
  %xor = xor i32 %conv, 1
  store i32 %xor, ptr %p, align 4
  %cmp2.i = icmp samesign ugt i32 %conv1, 31
  %shr.i601 = select i1 %cmp2.i, i32 0, i32 %conv1
  %cond.i602 = ashr i32 1, %shr.i601
  %conv6.i603 = trunc i32 %cond.i602 to i16
  %conv245 = trunc i16 %p_208.coerce to i8
  %mul.i628 = mul i8 -107, %conv245
  %conv247 = sext i8 %mul.i628 to i64
  %cond.i629 = call i64 @llvm.smin.i64(i64 0, i64 %conv247)
  %cmp249 = icmp slt i64 %cond.i629, 0
  %conv251 = zext i1 %cmp249 to i64
  %cmp1.i630 = icmp ugt i32 %conv1, 31
  %narrow.i631 = select i1 %cmp1.i630, i32 0, i32 %conv1
  %shr.i632 = zext i32 %narrow.i631 to i64
  %cond.i633 = lshr i64 %conv251, %shr.i632
  %cmp258 = icmp slt i16 %p_208.coerce, 0
  %2 = zext i1 %cmp258 to i16
  %cmp261 = icmp ugt i16 1, %2
  %conv263 = zext i1 %cmp261 to i64
  %cmp344 = icmp eq i16 %p_208.coerce, 0
  %conv345 = zext i1 %cmp344 to i32
  store i32 %conv345, ptr %p, align 4
  %conv351 = sext i32 %0 to i64
  %sub.i641 = call i64 @llvm.ucmp.i64.i64(i64 0, i64 %conv351)
  %conv353 = trunc i64 %sub.i641 to i16
  %3 = mul i16 %conv353, -1
  %conv355 = zext i16 %3 to i64
  %cmp356 = icmp sle i64 1, %conv355
  %conv357 = zext i1 %cmp356 to i32
  %conv359 = trunc i32 %conv357 to i8
  %conv.i650 = sext i8 %conv359 to i32
  %4 = icmp ugt i32 %conv, 0
  %shr.i652 = lshr i32 1, %conv
  %cmp9.i = icmp slt i32 %shr.i652, 1
  %or.cond.i = select i1 %4, i1 false, i1 %cmp9.i
  %shl.i653 = shl i32 %conv.i650, 1
  %5 = trunc i32 %shl.i653 to i8
  %cond.i654 = select i1 %or.cond.i, i8 0, i8 %5
  %conv3612 = sext i8 %cond.i654 to i32
  %conv3623 = trunc i64 %1 to i32
  %6 = or i32 1, %conv3612
  %or.cond.i655 = icmp slt i32 %6, 0
  %cmp3.i = icmp sgt i32 %conv3623, 0
  %or.cond4.i = or i1 %cmp3.i, %or.cond.i655
  %shr.i656 = select i1 %or.cond4.i, i32 0, i32 1
  %cond.i657 = ashr i32 %conv, %shr.i656
  %cmp.i658 = icmp slt i32 %cond.i657, 0
  %shr.i660 = select i1 %cmp.i658, i32 0, i32 1
  %cond.i661 = ashr i32 1, %shr.i660
  %conv365 = trunc i32 %cond.i661 to i16
  %add.i662 = or i16 1, %conv365
  %conv368 = sext i16 %add.i662 to i32
  ret i32 %conv368
}
```
```
opt: /data/zyw/llvm-project/llvm/include/llvm/ADT/DenseMap.h:419: void llvm::DenseMapBase<DerivedT, KeyT, ValueT, KeyInfoT, BucketT>::moveFromOldBuckets(BucketT*, BucketT*) [with DerivedT = llvm::DenseMap<{anonymous}::SimpleValue, llvm::ScopedHashTableVal<{anonymous}::SimpleValue, llvm::Value*>*, llvm::DenseMapInfo<{anonymous}::SimpleValue>, llvm::detail::DenseMapPair<{anonymous}::SimpleValue, llvm::ScopedHashTableVal<{anonymous}::SimpleValue, llvm::Value*>*> >; KeyT = {anonymous}::SimpleValue; ValueT = llvm::ScopedHashTableVal<{anonymous}::SimpleValue, llvm::Value*>*; KeyInfoT = llvm::DenseMapInfo<{anonymous}::SimpleValue>; BucketT = llvm::detail::DenseMapPair<{anonymous}::SimpleValue, llvm::ScopedHashTableVal<{anonymous}::SimpleValue, llvm::Value*>*>]: Assertion `!FoundVal && "Key already in new map?"' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:
0.      Program arguments: /data/zyw/llvm-build/bin/opt -passes=early-cse reduced.ll
1.      Running pass "function(early-cse<>)" on module "reduced.ll"
2.      Running pass "early-cse<>" on function "func_207"
 #0 0x00007ffff7def832 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/data/zyw/llvm-build/bin/../lib/libLLVMSupport.so.20.0git+0x1ef832)
 #1 0x00007ffff7dec9ef llvm::sys::RunSignalHandlers() (/data/zyw/llvm-build/bin/../lib/libLLVMSupport.so.20.0git+0x1ec9ef)
 #2 0x00007ffff7decb35 SignalHandler(int) Signals.cpp:0:0
 #3 0x00007ffff7842520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #4 0x00007ffff78969fc pthread_kill (/lib/x86_64-linux-gnu/libc.so.6+0x969fc)
 #5 0x00007ffff7842476 gsignal (/lib/x86_64-linux-gnu/libc.so.6+0x42476)
 #6 0x00007ffff78287f3 abort (/lib/x86_64-linux-gnu/libc.so.6+0x287f3)
 #7 0x00007ffff782871b (/lib/x86_64-linux-gnu/libc.so.6+0x2871b)
 #8 0x00007ffff7839e96 (/lib/x86_64-linux-gnu/libc.so.6+0x39e96)
 #9 0x00007ffff4efa75e llvm::DenseMap<(anonymous namespace)::SimpleValue, llvm::ScopedHashTableVal<(anonymous namespace)::SimpleValue, llvm::Value*>*, llvm::DenseMapInfo<(anonymous namespace)::SimpleValue, void>, llvm::detail::DenseMapPair<(anonymous namespace)::SimpleValue, llvm::ScopedHashTableVal<(anonymous namespace)::SimpleValue, llvm::Value*>*>>::grow(unsigned int) EarlyCSE.cpp:0:0
#10 0x00007ffff4efbd5a llvm::ScopedHashTable<(anonymous namespace)::SimpleValue, llvm::Value*, llvm::DenseMapInfo<(anonymous namespace)::SimpleValue, void>, llvm::RecyclingAllocator<llvm::BumpPtrAllocatorImpl<llvm::MallocAllocator, 4096ul, 4096ul, 128ul>, llvm::ScopedHashTableVal<(anonymous namespace)::SimpleValue, llvm::Value*>, 32ul, 8ul>>::insertIntoScope(llvm::ScopedHashTableScope<(anonymous namespace)::SimpleValue, llvm::Value*, llvm::DenseMapInfo<(anonymous namespace)::SimpleValue, void>, llvm::RecyclingAllocator<llvm::BumpPtrAllocatorImpl<llvm::MallocAllocator, 4096ul, 4096ul, 128ul>, llvm::ScopedHashTableVal<(anonymous namespace)::SimpleValue, llvm::Value*>, 32ul, 8ul>>*, (anonymous namespace)::SimpleValue const&, llvm::Value* const&) EarlyCSE.cpp:0:0
#11 0x00007ffff4efdf19 (anonymous namespace)::EarlyCSE::processNode(llvm::DomTreeNodeBase<llvm::BasicBlock>*) (.isra.0) EarlyCSE.cpp:0:0
#12 0x00007ffff4efeef5 (anonymous namespace)::EarlyCSE::run() EarlyCSE.cpp:0:0
#13 0x00007ffff4f00796 llvm::EarlyCSEPass::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/data/zyw/llvm-build/bin/../lib/../lib/libLLVMScalarOpts.so.20.0git+0x100796)
#14 0x00007ffff6684345 llvm::detail::PassModel<llvm::Function, llvm::EarlyCSEPass, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/data/zyw/llvm-build/bin/../lib/../lib/libLLVMPasses.so.20.0git+0x84345)
#15 0x00007ffff38ee63d llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/data/zyw/llvm-build/bin/../lib/../lib/libLLVMCore.so.20.0git+0x2ee63d)
#16 0x00007ffff70a9445 llvm::detail::PassModel<llvm::Function, llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/data/zyw/llvm-build/bin/../lib/../lib/libLLVMX86CodeGen.so.20.0git+0xa9445)
#17 0x00007ffff38ec628 llvm::ModuleToFunctionPassAdaptor::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/data/zyw/llvm-build/bin/../lib/../lib/libLLVMCore.so.20.0git+0x2ec628)
#18 0x00007ffff70a9e05 llvm::detail::PassModel<llvm::Module, llvm::ModuleToFunctionPassAdaptor, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/data/zyw/llvm-build/bin/../lib/../lib/libLLVMX86CodeGen.so.20.0git+0xa9e05)
#19 0x00007ffff38ed28d llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/data/zyw/llvm-build/bin/../lib/../lib/libLLVMCore.so.20.0git+0x2ed28d)
#20 0x00007ffff7f9b1eb 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) (/data/zyw/llvm-build/bin/../lib/libLLVMOptDriver.so.20.0git+0x241eb)
#21 0x00007ffff7fa5619 optMain (/data/zyw/llvm-build/bin/../lib/libLLVMOptDriver.so.20.0git+0x2e619)
#22 0x00007ffff7829d90 (/lib/x86_64-linux-gnu/libc.so.6+0x29d90)
#23 0x00007ffff7829e40 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e40)
#24 0x0000555555555095 _start (/data/zyw/llvm-build/bin/opt+0x1095)
Aborted (core dumped)
```

Reverting 4a0d53a0b0a58a3c6980a7c551357ac71ba3db10 fixes this issue.
cc @artagnon @nikic Can you double check the implementation of `hash_value(const CmpPredicate&)`?

Yeah, the implementation is incorrect for EarlyCSE (which should not take into account poison generating flags). I think we should remove the hash_value implementation and make the caller handler it appropriately.

Not sure I understand. The backtrace points to EarlyCSE.cpp:1558, and the Instruction it crashes on is an `or`. With surrounding context it is:

https://github.com/llvm/llvm-project/blob/main/llvm/lib/Transforms/Scalar/EarlyCSE.cpp#L1392-L1560

So I think this would fix the issue, although I'm not sure I understand the underlying issue:

```diff
diff --git a/llvm/lib/Transforms/Scalar/EarlyCSE.cpp b/llvm/lib/Transforms/Scalar/EarlyCSE.cpp
index 682c5c3d8c63..8e87f8b9a457 100644
--- a/llvm/lib/Transforms/Scalar/EarlyCSE.cpp
+++ b/llvm/lib/Transforms/Scalar/EarlyCSE.cpp
@@ -290,7 +290,7 @@ static unsigned getHashValueImpl(SimpleValue Val) {
       Pred = CmpInst::getInversePredicate(Pred);
       std::swap(A, B);
     }
-    return hash_combine(Inst->getOpcode(), Pred, X, Y, A, B);
+    return hash_combine(Inst->getOpcode(), static_cast<CmpInst::Predicate>(Pred), X, Y, A, B);
   }

   if (CastInst *CI = dyn_cast<CastInst>(Inst))
```

We hash two equal predicates, one with with samesign information (leading to a divergent hash), leading to a divergent hash_combine call, and hence a duplicate insertion into DenseMap:

```cpp
  SelectPatternFlavor SPF;
  Value *Cond, *A, *B;
  if (matchSelectWithOptionalNotCond(Inst, Cond, A, B, SPF)) {
    // Hash min/max (cmp + select) to allow for commuted operands.
    // Min/max may also have non-canonical compare predicate (eg, the compare for
    // smin may use 'sgt' rather than 'slt'), and non-canonical operands in the
    // compare.
    // TODO: We should also detect FP min/max.
    if (SPF == SPF_SMIN || SPF == SPF_SMAX ||
        SPF == SPF_UMIN || SPF == SPF_UMAX) {
      if (A > B)
        std::swap(A, B);
      return hash_combine(Inst->getOpcode(), SPF, A, B);
    }

    // Hash general selects to allow matching commuted true/false operands.

    // If we do not have a compare as the condition, just hash in the condition.
    CmpPredicate Pred;
    Value *X, *Y;
    if (!match(Cond, m_Cmp(Pred, m_Value(X), m_Value(Y))))
      return hash_combine(Inst->getOpcode(), Cond, A, B);

    // Similar to cmp normalization (above) - canonicalize the predicate value:
    // select (icmp Pred, X, Y), A, B --> select (icmp InvPred, X, Y), B, A
    if (CmpInst::getInversePredicate(Pred) < Pred) {
      Pred = CmpInst::getInversePredicate(Pred);
      std::swap(A, B);
    }
    return hash_combine(Inst->getOpcode(), static_cast<CmpInst::Predicate>(Pred), X, Y, A, B); /// fixed
  }
```

These are the duplicates:

```llvm
  %cmp2.i = icmp samesign ugt i32 %conv1, 31
  %cmp1.i630 = icmp ugt i32 %conv1, 31
```


commit 4cc9c6d98dfef90d1ffa69977d13ffa2894a10f7
Author: Simon Pilgrim <llvm-dev@redking.me.uk>
Date:   Mon Apr 22 09:00:20 2024 +0100

    [VectorCombine] foldShuffleOfBinops - don't fold shuffle(divrem(x,y),divrem(z,w)) if mask contains poison

    Fixes #89390

diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
index 4918cee1fa82..f23b10540338 100644
--- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
+++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
@@ -1405,6 +1405,11 @@ bool VectorCombine::foldShuffleOfBinops(Instruction &I) {
       B0->getOpcode() != B1->getOpcode() || B0->getType() != VecTy)
     return false;

+  // Don't introduce poison into div/rem.
+  if (any_of(Mask, [](int M) { return M == PoisonMaskElem; }) &&
+      B0->isIntDivRem())
+    return false;
+
   // Try to replace a binop with a shuffle if the shuffle is not costly.
   // The new shuffle will choose from a single, common operand, so it may be
   // cheaper than the existing two-operand shuffle.

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

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

VectorCombine transform leading to srem by poison

https://alive2.llvm.org/ce/z/HRAkAK

this:
```llvm
define <4 x i32> @f(<4 x i32> %0, <4 x i32> %1) {
  %3 = srem <4 x i32> %1, %0
  %4 = srem <4 x i32> <i32 1, i32 1, i32 1, i32 1>, %0
  %5 = shufflevector <4 x i32> %3, <4 x i32> %4, <4 x i32> <i32 0, i32 poison, i32 6, i32 3>
  ret <4 x i32> %5
}
```
is getting vector-combined to this:
```llvm
define <4 x i32> @f(<4 x i32> %0, <4 x i32> %1) {
  %3 = shufflevector <4 x i32> %1, <4 x i32> <i32 1, i32 1, i32 1, i32 1>, <4 x i32> <i32 0, i32 poison, i32 6, i32 3>
  %4 = shufflevector <4 x i32> %0, <4 x i32> poison, <4 x i32> <i32 0, i32 poison, i32 2, i32 3>
  %5 = srem <4 x i32> %3, %4
  ret <4 x i32> %5
}
```

but that poison in lane 1 is now problematic, this gives us full UB when it hits the srem

cc @nunoplopes @hatsunespica

I'll take a look at this


commit 27392a35ef052aa515f38359de89aced11a4363d
Author: Nikita Popov <npopov@redhat.com>
Date:   Thu May 23 15:14:34 2024 +0200

    [SCCP] Don't allow undef ranges when performing operations (#93163)

    When performing some range operation (e.g. and) on a constant range that
    includes undef, we currently just ignore the undef value, which is
    obviously incorrect. Instead, we can do one of two things:
     * Say that the result range also includes undef.
     * Treat undef as a full range.

    This patch goes with the second approach -- I'd expect it to be a bit
    better overall, e.g. it allows preserving the fact that a zext of a
    range with undef isn't a full range.

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

diff --git a/llvm/lib/Transforms/Utils/SCCPSolver.cpp b/llvm/lib/Transforms/Utils/SCCPSolver.cpp
index ce40e8b31b76..4f36bac11e34 100644
--- a/llvm/lib/Transforms/Utils/SCCPSolver.cpp
+++ b/llvm/lib/Transforms/Utils/SCCPSolver.cpp
@@ -43,7 +43,7 @@ static ValueLatticeElement::MergeOptions getMaxWidenStepsOpts() {
 }

 static ConstantRange getConstantRange(const ValueLatticeElement &LV, Type *Ty,
-                                      bool UndefAllowed = true) {
+                                      bool UndefAllowed) {
   assert(Ty->isIntOrIntVectorTy() && "Should be int or int vector");
   if (LV.isConstantRange(UndefAllowed))
     return LV.getConstantRange();
@@ -1297,7 +1297,8 @@ void SCCPInstVisitor::visitCastInst(CastInst &I) {

   if (I.getDestTy()->isIntegerTy() && I.getSrcTy()->isIntOrIntVectorTy()) {
     auto &LV = getValueState(&I);
-    ConstantRange OpRange = getConstantRange(OpSt, I.getSrcTy());
+    ConstantRange OpRange =
+        getConstantRange(OpSt, I.getSrcTy(), /*UndefAllowed=*/false);

     Type *DestTy = I.getDestTy();
     // Vectors where all elements have the same known constant range are treated
@@ -1329,8 +1330,8 @@ void SCCPInstVisitor::handleExtractOfWithOverflow(ExtractValueInst &EVI,
     return; // Wait to resolve.

   Type *Ty = LHS->getType();
-  ConstantRange LR = getConstantRange(L, Ty);
-  ConstantRange RR = getConstantRange(R, Ty);
+  ConstantRange LR = getConstantRange(L, Ty, /*UndefAllowed=*/false);
+  ConstantRange RR = getConstantRange(R, Ty, /*UndefAllowed=*/false);
   if (Idx == 0) {
     ConstantRange Res = LR.binaryOp(WO->getBinaryOp(), RR);
     mergeInValue(&EVI, ValueLatticeElement::getRange(Res));
@@ -1534,8 +1535,10 @@ void SCCPInstVisitor::visitBinaryOperator(Instruction &I) {
     return markOverdefined(&I);

   // Try to simplify to a constant range.
-  ConstantRange A = getConstantRange(V1State, I.getType());
-  ConstantRange B = getConstantRange(V2State, I.getType());
+  ConstantRange A =
+      getConstantRange(V1State, I.getType(), /*UndefAllowed=*/false);
+  ConstantRange B =
+      getConstantRange(V2State, I.getType(), /*UndefAllowed=*/false);

   auto *BO = cast<BinaryOperator>(&I);
   ConstantRange R = ConstantRange::getEmpty(I.getType()->getScalarSizeInBits());
@@ -1818,7 +1821,8 @@ void SCCPInstVisitor::handleCallResult(CallBase &CB) {

         // Combine range info for the original value with the new range from the
         // condition.
-        auto CopyOfCR = getConstantRange(CopyOfVal, CopyOf->getType());
+        auto CopyOfCR = getConstantRange(CopyOfVal, CopyOf->getType(),
+                                         /*UndefAllowed=*/true);
         auto NewCR = ImposedCR.intersectWith(CopyOfCR);
         // If the existing information is != x, do not use the information from
         // a chained predicate, as the != x information is more likely to be
@@ -1863,7 +1867,8 @@ void SCCPInstVisitor::handleCallResult(CallBase &CB) {
         const ValueLatticeElement &State = getValueState(Op);
         if (State.isUnknownOrUndef())
           return;
-        OpRanges.push_back(getConstantRange(State, Op->getType()));
+        OpRanges.push_back(
+            getConstantRange(State, Op->getType(), /*UndefAllowed=*/false));
       }

       ConstantRange Result =

declare hidden i32 @callee5(i32, i32)

define i32 @caller5() {
  %c1 = call i32 @callee5(i32 10, i32 100)
  %c2 = call i32 @callee5(i32 20, i32 200)
  %a = add i32 %c1, %c2
  ret i32 %a
}

define i9 @test_with_overflow(i1 %cond, i8 %a) {
entry:
  br i1 %cond, label %if, label %join

if:                                               ; preds = %entry
  %a.ext = zext i8 %a to i16
  br label %join

join:                                             ; preds = %if, %entry
  %phi = phi i16 [ undef, %entry ], [ %a.ext, %if ]
  %wo = call { i16, i1 } @llvm.uadd.with.overflow.i16(i16 %phi, i16 1)
  %add = extractvalue { i16, i1 } %wo, 0
  %trunc = trunc i16 %add to i9
  ret i9 %trunc
}

; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare { i16, i1 } @llvm.uadd.with.overflow.i16(i16, i16) #0

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

define i8 @test_binop(i1 %cond, i8 %a) {
entry:
  br i1 %cond, label %if, label %join

if:                                               ; preds = %entry
  %a.ext = zext i8 %a to i16
  br label %join

join:                                             ; preds = %if, %entry
  %phi = phi i16 [ undef, %entry ], [ %a.ext, %if ]
  %and = and i16 %phi, -1
  %trunc = trunc i16 %and to i8
  ret i8 %trunc
}

define i8 @test_cast(i1 %cond, i8 %a) {
entry:
  br i1 %cond, label %if, label %join

if:                                               ; preds = %entry
  %a.ext = zext i8 %a to i16
  br label %join

join:                                             ; preds = %if, %entry
  %phi = phi i16 [ undef, %entry ], [ %a.ext, %if ]
  %zext = zext i16 %phi to i32
  %trunc = trunc i32 %zext to i8
  ret i8 %trunc
}

define i8 @test_intrin(i1 %cond, i8 %a) {
entry:
  br i1 %cond, label %if, label %join

if:                                               ; preds = %entry
  %a.ext = zext i8 %a to i16
  br label %join

join:                                             ; preds = %if, %entry
  %phi = phi i16 [ undef, %entry ], [ %a.ext, %if ]
  %umax = call i16 @llvm.umax.i16(i16 %phi, i16 42)
  %trunc = trunc i16 %umax to i8
  ret i8 %trunc
}

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

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

nuw/nsw should not be added to trunc instruction when there are undef bits in the source value

Run ipsccp on the code
```
; opt -passes=ipsccp -S test.ll

define void @foo(i1 %cond1, i32 %p1) {
entry:
  br label %loop

loop:
  %phi1 = phi i64 [undef, %entry], [%phi2, %latch]
  br i1 %cond1, label %then2, label %else2

then2:
  %and = and i64 %phi1, -1095216660481     ; 0xFFFFFF00FFFFFFFF
  br label %latch

else2:
  %ext = zext i32 %p1 to i64
  %or  = or i64 %ext, 4294967296           ; 0x100000000
  br label %latch

latch:
  %phi2 = phi i64 [%and, %then2], [%or, %else2]
  %shr = lshr i64 %phi2, 32
  %res = trunc i64 %shr to i8
  %cond2 = call i1 @bar(i8 %res)
  br i1 %cond2, label %loop, label %exit

exit:
  ret void
}

declare i1 @bar(i8)
```
LLVM adds nuw/nsw flags to the trunc instruction
```
%res = trunc nuw nsw i64 %shr to i8
```
It means all high bits of %shr are 0.
But %phi1 may be undef, bits [32..39] of %and are cleared, bits[40..63] can still be undef, and later it is moved to bits[8..31] of %shr, so not all high bits of %shr are 0.

We do exclude ranges with undef here: https://github.com/llvm/llvm-project/blob/3061fed2f05cde574c84a26c702b1e7932fa4d7e/llvm/lib/Transforms/Utils/SCCPSolver.cpp#L118-L119 Maybe the undef flag doesn't get propagated properly somewhere...

Simplified test case:
```llvm
define i8 @src(i1 %cond, i8 %a) {
entry:
  br i1 %cond, label %if, label %join

if:
  %a.ext = zext i8 %a to i16
  br label %join

join:
  %phi = phi i16 [ undef, %entry ], [ %a.ext, %if ]
  %and = and i16 %phi, u0x0000ffff
  %trunc = trunc i16 %and to i8
  ret i8 %trunc
}
```
This is indeed an issue with the propagation of the undef flag.


commit cc01112660499a4db74bc3ee24b6f60b03d88dbd
Author: Han-Kuan Chen <hankuan.chen@sifive.com>
Date:   Tue Oct 1 19:15:58 2024 +0800

    [SLP][REVEC] getTypeSizeInBits should apply to scalar type instead of FixedVectorType. (#110610)

    reference: https://github.com/llvm/llvm-project/issues/109835

diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index 68bf5c52814f..54a1b99606bc 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -11786,7 +11786,7 @@ InstructionCost BoUpSLP::getTreeCost(ArrayRef<Value *> VectorizedVals) {
     auto BWIt = MinBWs.find(&Root);
     if (BWIt != MinBWs.end()) {
       Type *DstTy = Root.Scalars.front()->getType();
-      unsigned OriginalSz = DL->getTypeSizeInBits(DstTy);
+      unsigned OriginalSz = DL->getTypeSizeInBits(DstTy->getScalarType());
       unsigned SrcSz =
           ReductionBitWidth == 0 ? BWIt->second.first : ReductionBitWidth;
       if (OriginalSz != SrcSz) {
@@ -11794,6 +11794,10 @@ InstructionCost BoUpSLP::getTreeCost(ArrayRef<Value *> VectorizedVals) {
         if (OriginalSz > SrcSz)
           Opcode = BWIt->second.second ? Instruction::SExt : Instruction::ZExt;
         Type *SrcTy = IntegerType::get(DstTy->getContext(), SrcSz);
+        if (auto *VecTy = dyn_cast<FixedVectorType>(DstTy)) {
+          assert(SLPReVec && "Only supported by REVEC.");
+          SrcTy = getWidenedType(SrcTy, VecTy->getNumElements());
+        }
         Cost += TTI->getCastInstrCost(Opcode, DstTy, SrcTy,
                                       TTI::CastContextHint::None,
                                       TTI::TCK_RecipThroughput);

opt -mtriple=s390x-unknown-linux -mcpu=z16 -passes=slp-vectorizer -S -slp-revec %s

@g_3_1_0 = external dso_local global i32, align 4
@g_7 = external dso_local global [5 x i32], align 4

define void @func_1() {
  %.pre = load i32, ptr @g_7, align 4
  %1 = load <4 x i32>, ptr getelementptr inbounds nuw (i8, ptr @g_7, i64 4), align 4
  br label %.loopexit

.loopexit:                                        ; preds = %.loopexit, %0
  %2 = phi i32 [ %op.rdx15, %.loopexit ], [ %.pre, %0 ]
  %3 = phi <4 x i32> [ %71, %.loopexit ], [ %1, %0 ]
  %4 = load volatile i32, ptr @g_3_1_0, align 4
  %5 = load volatile i32, ptr @g_3_1_0, align 4
  %6 = load volatile i32, ptr @g_3_1_0, align 4
  %7 = load volatile i32, ptr @g_3_1_0, align 4
  %8 = load volatile i32, ptr @g_3_1_0, align 4
  %9 = load volatile i32, ptr @g_3_1_0, align 4
  %10 = load volatile i32, ptr @g_3_1_0, align 4
  %11 = load volatile i32, ptr @g_3_1_0, align 4
  %12 = load volatile i32, ptr @g_3_1_0, align 4
  %13 = load volatile i32, ptr @g_3_1_0, align 4
  %14 = load volatile i32, ptr @g_3_1_0, align 4
  %15 = load volatile i32, ptr @g_3_1_0, align 4
  %16 = load volatile i32, ptr @g_3_1_0, align 4
  %17 = load volatile i32, ptr @g_3_1_0, align 4
  %18 = load volatile i32, ptr @g_3_1_0, align 4
  %19 = load volatile i32, ptr @g_3_1_0, align 4
  %20 = insertelement <4 x i32> poison, i32 %4, i32 0
  %21 = insertelement <4 x i32> %20, i32 %9, i32 1
  %22 = insertelement <4 x i32> %21, i32 %14, i32 2
  %23 = insertelement <4 x i32> %22, i32 %19, i32 3
  %24 = icmp eq <4 x i32> %23, zeroinitializer
  %25 = load volatile i32, ptr @g_3_1_0, align 4
  %26 = load volatile i32, ptr @g_3_1_0, align 4
  %27 = load volatile i32, ptr @g_3_1_0, align 4
  %28 = load volatile i32, ptr @g_3_1_0, align 4
  %29 = load volatile i32, ptr @g_3_1_0, align 4
  %.not2.410 = icmp eq i32 %29, 0
  %30 = zext i1 %.not2.410 to i32
  %31 = zext <4 x i1> %24 to <4 x i32>
  %32 = call i32 @llvm.vector.reduce.xor.v4i32(<4 x i32> %31)
  %op.rdx = xor i32 %32, %30
  %op.rdx15 = xor i32 %op.rdx, %2
  %33 = load volatile i32, ptr @g_3_1_0, align 4
  %34 = load volatile i32, ptr @g_3_1_0, align 4
  %35 = load volatile i32, ptr @g_3_1_0, align 4
  %36 = load volatile i32, ptr @g_3_1_0, align 4
  %37 = insertelement <4 x i32> poison, i32 %5, i32 0
  %38 = insertelement <4 x i32> %37, i32 %6, i32 1
  %39 = insertelement <4 x i32> %38, i32 %7, i32 2
  %40 = insertelement <4 x i32> %39, i32 %8, i32 3
  %41 = icmp eq <4 x i32> %40, zeroinitializer
  %42 = zext <4 x i1> %41 to <4 x i32>
  %43 = xor <4 x i32> %3, %42
  %44 = insertelement <4 x i32> poison, i32 %10, i32 0
  %45 = insertelement <4 x i32> %44, i32 %11, i32 1
  %46 = insertelement <4 x i32> %45, i32 %12, i32 2
  %47 = insertelement <4 x i32> %46, i32 %13, i32 3
  %48 = icmp eq <4 x i32> %47, zeroinitializer
  %49 = zext <4 x i1> %48 to <4 x i32>
  %50 = xor <4 x i32> %43, %49
  %51 = insertelement <4 x i32> poison, i32 %15, i32 0
  %52 = insertelement <4 x i32> %51, i32 %16, i32 1
  %53 = insertelement <4 x i32> %52, i32 %17, i32 2
  %54 = insertelement <4 x i32> %53, i32 %18, i32 3
  %55 = icmp eq <4 x i32> %54, zeroinitializer
  %56 = zext <4 x i1> %55 to <4 x i32>
  %57 = xor <4 x i32> %50, %56
  %58 = insertelement <4 x i32> poison, i32 %25, i32 0
  %59 = insertelement <4 x i32> %58, i32 %26, i32 1
  %60 = insertelement <4 x i32> %59, i32 %27, i32 2
  %61 = insertelement <4 x i32> %60, i32 %28, i32 3
  %62 = icmp eq <4 x i32> %61, zeroinitializer
  %63 = zext <4 x i1> %62 to <4 x i32>
  %64 = xor <4 x i32> %57, %63
  %65 = insertelement <4 x i32> poison, i32 %33, i32 0
  %66 = insertelement <4 x i32> %65, i32 %34, i32 1
  %67 = insertelement <4 x i32> %66, i32 %35, i32 2
  %68 = insertelement <4 x i32> %67, i32 %36, i32 3
  %69 = icmp eq <4 x i32> %68, zeroinitializer
  %70 = zext <4 x i1> %69 to <4 x i32>
  %71 = xor <4 x i32> %64, %70
  br label %.loopexit
}

; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i32 @llvm.vector.reduce.xor.v4i32(<4 x i32>) #0

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

[SLP vectorizer] Assertion fails with slp-revec

[tc_slp_revec.tar.gz](https://github.com/user-attachments/files/17118250/tc_slp_revec.tar.gz)

opt -mtriple=systemz-unknown -mcpu=z16 -O3 -o out.ll tc_crash22_aftercreduce.ll -slp-revec

Type.cpp:691: static llvm::FixedVectorType* llvm::FixedVectorType::get(llvm::Type*, unsigned int): Assertion `isValidElementType(
ElementType) && "Element type of a VectorType must " "be an integer, floating point, or " "pointer type."' failed.

#9 0x000002aa076e014e llvm::slpvectorizer::BoUpSLP::ShuffleCostEstimator::finalize

The fix is landing.

Still failing, but this time I see another assertion:

[tc_slp_revec.tar.gz](https://github.com/user-attachments/files/17192435/tc_slp_revec.tar.gz)

opt -mtriple=s390x-unknown-linux -mcpu=z16 -O3 tc_crash38_aftercreduce.ll -o /dev/null -slp-revec

Assertion `!Dst->isVectorTy()' failed.
14 0x00000000030504c2 llvm::SLPVectorizerPass::vectorizeHorReduction

The fix is landing.


commit 7339f7ba3053db7595ece1ca5f49bd2e4c3c8305
Author: Nikita Popov <npopov@redhat.com>
Date:   Wed Apr 24 10:57:17 2024 +0900

    [InstCombine] Fix poison propagation in select of bitwise fold (#89701)

    We're replacing the select with the false value here, but it may be more
    poisonous if m_Not contains poison elements. Fix this by introducing a
    m_NotForbidPoison matcher and using it here.

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

diff --git a/llvm/include/llvm/IR/PatternMatch.h b/llvm/include/llvm/IR/PatternMatch.h
index 1fee1901fabb..0b13b4aad9c3 100644
--- a/llvm/include/llvm/IR/PatternMatch.h
+++ b/llvm/include/llvm/IR/PatternMatch.h
@@ -350,8 +350,9 @@ template <int64_t Val> inline constantint_match<Val> m_ConstantInt() {

 /// This helper class is used to match constant scalars, vector splats,
 /// and fixed width vectors that satisfy a specified predicate.
-/// For fixed width vector constants, poison elements are ignored.
-template <typename Predicate, typename ConstantVal>
+/// For fixed width vector constants, poison elements are ignored if AllowPoison
+/// is true.
+template <typename Predicate, typename ConstantVal, bool AllowPoison>
 struct cstval_pred_ty : public Predicate {
   template <typename ITy> bool match(ITy *V) {
     if (const auto *CV = dyn_cast<ConstantVal>(V))
@@ -374,7 +375,7 @@ struct cstval_pred_ty : public Predicate {
           Constant *Elt = C->getAggregateElement(i);
           if (!Elt)
             return false;
-          if (isa<PoisonValue>(Elt))
+          if (AllowPoison && isa<PoisonValue>(Elt))
             continue;
           auto *CV = dyn_cast<ConstantVal>(Elt);
           if (!CV || !this->isValue(CV->getValue()))
@@ -389,12 +390,13 @@ struct cstval_pred_ty : public Predicate {
 };

 /// specialization of cstval_pred_ty for ConstantInt
-template <typename Predicate>
-using cst_pred_ty = cstval_pred_ty<Predicate, ConstantInt>;
+template <typename Predicate, bool AllowPoison = true>
+using cst_pred_ty = cstval_pred_ty<Predicate, ConstantInt, AllowPoison>;

 /// specialization of cstval_pred_ty for ConstantFP
 template <typename Predicate>
-using cstfp_pred_ty = cstval_pred_ty<Predicate, ConstantFP>;
+using cstfp_pred_ty = cstval_pred_ty<Predicate, ConstantFP,
+                                     /*AllowPoison=*/true>;

 /// This helper class is used to match scalar and vector constants that
 /// satisfy a specified predicate, and bind them to an APInt.
@@ -484,6 +486,10 @@ inline cst_pred_ty<is_all_ones> m_AllOnes() {
   return cst_pred_ty<is_all_ones>();
 }

+inline cst_pred_ty<is_all_ones, false> m_AllOnesForbidPoison() {
+  return cst_pred_ty<is_all_ones, false>();
+}
+
 struct is_maxsignedvalue {
   bool isValue(const APInt &C) { return C.isMaxSignedValue(); }
 };
@@ -2596,6 +2602,13 @@ m_Not(const ValTy &V) {
   return m_c_Xor(m_AllOnes(), V);
 }

+template <typename ValTy>
+inline BinaryOp_match<cst_pred_ty<is_all_ones, false>, ValTy, Instruction::Xor,
+                      true>
+m_NotForbidPoison(const ValTy &V) {
+  return m_c_Xor(m_AllOnesForbidPoison(), V);
+}
+
 /// Matches an SMin with LHS and RHS in either order.
 template <typename LHS, typename RHS>
 inline MaxMin_match<ICmpInst, LHS, RHS, smin_pred_ty, true>
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 73600206a55c..117eb7a1dcc9 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -1722,11 +1722,11 @@ static Instruction *foldSelectICmpEq(SelectInst &SI, ICmpInst *ICI,
       return match(CmpRHS, m_Zero()) && match(FalseVal, matchInner);

     if (NotMask == NotInner) {
-      return match(FalseVal,
-                   m_c_BinOp(OuterOpc, m_Not(matchInner), m_Specific(CmpRHS)));
+      return match(FalseVal, m_c_BinOp(OuterOpc, m_NotForbidPoison(matchInner),
+                                       m_Specific(CmpRHS)));
     } else if (NotMask == NotRHS) {
-      return match(FalseVal,
-                   m_c_BinOp(OuterOpc, matchInner, m_Not(m_Specific(CmpRHS))));
+      return match(FalseVal, m_c_BinOp(OuterOpc, matchInner,
+                                       m_NotForbidPoison(m_Specific(CmpRHS))));
     } else {
       return match(FalseVal,
                    m_c_BinOp(OuterOpc, matchInner, m_Specific(CmpRHS)));

[InstCombine] Miscompilation with poison vectors in `src_and_eq_C_xor_OrAndNotC`

Alive2: https://alive2.llvm.org/ce/z/yB3oAx
```ll
define <2 x i32> @src_and_eq_C_xor_OrAndNotC(<2 x i32> %0, <2 x i32> %1, <2 x i32> %2) {
entry:
  %and = and <2 x i32> %1, %0
  %cmp = icmp eq <2 x i32> %and, %2
  %xor = xor <2 x i32> %1, %0
  %or = or <2 x i32> %1, %0
  %not = xor <2 x i32> %2, <i32 -1, i32 poison>
  %and1 = and <2 x i32> %or, %not
  %cond = select <2 x i1> %cmp, <2 x i32> %xor, <2 x i32> %and1
  ret <2 x i32> %cond
}
```
```ll

----------------------------------------
define <2 x i32> @src_and_eq_C_xor_OrAndNotC(<2 x i32> %#0, <2 x i32> %#1, <2 x i32> %#2) {
entry:
  %and = and <2 x i32> %#1, %#0
  %cmp = icmp eq <2 x i32> %and, %#2
  %xor = xor <2 x i32> %#1, %#0
  %or = or <2 x i32> %#1, %#0
  %not = xor <2 x i32> %#2, { 4294967295, poison }
  %and1 = and <2 x i32> %or, %not
  %cond = select <2 x i1> %cmp, <2 x i32> %xor, <2 x i32> %and1
  ret <2 x i32> %cond
}
=>
define <2 x i32> @src_and_eq_C_xor_OrAndNotC(<2 x i32> %#0, <2 x i32> %#1, <2 x i32> %#2) nofree willreturn memory(none) {
entry:
  %or = or <2 x i32> %#1, %#0
  %not = xor <2 x i32> %#2, { 4294967295, poison }
  %and1 = and <2 x i32> %or, %not
  ret <2 x i32> %and1
}
Transformation doesn't verify!

ERROR: Target is more poisonous than source

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

Source:
<2 x i32> %and = < poison, #x00000000 (0) >
<2 x i1> %cmp = < poison, #x1 (1) >
<2 x i32> %xor = < poison, #x00000000 (0) >
<2 x i32> %or = < poison, #x00000000 (0) >
<2 x i32> %not = < poison, poison >
<2 x i32> %and1 = < poison, poison >
<2 x i32> %cond = < poison, #x00000000 (0) >

Target:
<2 x i32> %or = < poison, #x00000000 (0) >
<2 x i32> %not = < poison, poison >
<2 x i32> %and1 = < poison, poison >
Source value: < poison, #x00000000 (0) >
Target value: < poison, poison >

Summary:
  0 correct transformations
  1 incorrect transformations
  0 failed-to-prove transformations
  0 Alive2 errors
```

Found with https://github.com/dtcxzyw/llvm-tools.
cc @nikic

Looks like a recent issue introduced with https://github.com/llvm/llvm-project/pull/73362.

I'll not forget to create a testcase with poison.


commit e9e3a183d6d8d8729223b7131aa57fd9f02f0440
Author: Florian Hahn <flo@fhahn.com>
Date:   Sun Aug 18 12:51:17 2024 +0100

    [LV] Don't cost branches and conditions to empty blocks.

    Update the legacy cost model skip branches with successors blocks
    that are empty or only contain dead instructions, together with their
    conditions. Such branches and conditions won't result in any
    generated code and will be cleaned up by VPlan transforms.

    This fixes a difference between the legacy and VPlan-based cost model.

    When running LV in its usual pipeline position, such dead blocks should
    already have been cleaned up, but they might be generated manually or by
    fuzzers.

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

diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index 27e99694aafd..55c0ba3dd8f9 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -6730,9 +6730,12 @@ void LoopVectorizationCostModel::collectValuesToIgnore() {
     return RequiresScalarEpilogue &&
            !TheLoop->contains(cast<Instruction>(U)->getParent());
   };
+
+  LoopBlocksDFS DFS(TheLoop);
+  DFS.perform(LI);
   MapVector<Value *, SmallVector<Value *>> DeadInvariantStoreOps;
-  for (BasicBlock *BB : TheLoop->blocks())
-    for (Instruction &I : *BB) {
+  for (BasicBlock *BB : reverse(make_range(DFS.beginRPO(), DFS.endRPO())))
+    for (Instruction &I : reverse(*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;
@@ -6765,6 +6768,13 @@ void LoopVectorizationCostModel::collectValuesToIgnore() {
         Value *PointerOp = getLoadStorePointerOperand(&I);
         DeadInterleavePointerOps.push_back(PointerOp);
       }
+
+      // Queue branches for analysis. They are dead, if their successors only
+      // contain dead instructions.
+      if (auto *Br = dyn_cast<BranchInst>(&I)) {
+        if (Br->isConditional())
+          DeadOps.push_back(&I);
+      }
     }

   // Mark ops feeding interleave group members as free, if they are only used
@@ -6789,8 +6799,36 @@ void LoopVectorizationCostModel::collectValuesToIgnore() {
   // Mark ops that would be trivially dead and are only used by ignored
   // instructions as free.
   BasicBlock *Header = TheLoop->getHeader();
+
+  // Returns true if the block contains only dead instructions. Such blocks will
+  // be removed by VPlan-to-VPlan transforms and won't be considered by the
+  // VPlan-based cost model, so skip them in the legacy cost-model as well.
+  auto IsEmptyBlock = [this](BasicBlock *BB) {
+    return all_of(*BB, [this](Instruction &I) {
+      return ValuesToIgnore.contains(&I) || VecValuesToIgnore.contains(&I) ||
+             (isa<BranchInst>(&I) && !cast<BranchInst>(&I)->isConditional());
+    });
+  };
   for (unsigned I = 0; I != DeadOps.size(); ++I) {
     auto *Op = dyn_cast<Instruction>(DeadOps[I]);
+
+    // Check if the branch should be considered dead.
+    if (auto *Br = dyn_cast_or_null<BranchInst>(Op)) {
+      BasicBlock *ThenBB = Br->getSuccessor(0);
+      BasicBlock *ElseBB = Br->getSuccessor(1);
+      bool ThenEmpty = IsEmptyBlock(ThenBB);
+      bool ElseEmpty = IsEmptyBlock(ElseBB);
+      if ((ThenEmpty && ElseEmpty) ||
+          (ThenEmpty && ThenBB->getSingleSuccessor() == ElseBB &&
+           ElseBB->phis().empty()) ||
+          (ElseEmpty && ElseBB->getSingleSuccessor() == ThenBB &&
+           ThenBB->phis().empty())) {
+        VecValuesToIgnore.insert(Br);
+        DeadOps.push_back(Br->getCondition());
+      }
+      continue;
+    }
+
     // Skip any op that shouldn't be considered dead.
     if (!Op || !TheLoop->contains(Op) ||
         (isa<PHINode>(Op) && Op->getParent() == Header) ||

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

define void @block_with_dead_inst_1(ptr %src, i64 %N) #0 {
entry:
  br label %loop.header

loop.header:                                      ; preds = %loop.latch, %entry
  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ]
  %xor1315 = phi i16 [ 1, %entry ], [ %xor, %loop.latch ]
  %xor = xor i16 0, 0
  %gep = getelementptr i16, ptr %src, i64 %iv
  %l = load i16, ptr %gep, align 2
  %c = icmp eq i16 %l, 0
  br i1 %c, label %then, label %loop.latch

then:                                             ; preds = %loop.header
  %dead.gep = getelementptr i64, ptr %src, i64 %iv
  br label %loop.latch

loop.latch:                                       ; preds = %then, %loop.header
  store i16 %xor, ptr %gep, align 2
  %iv.next = add nsw i64 %iv, 3
  %0 = icmp eq i64 %iv.next, %N
  br i1 %0, label %exit, label %loop.header

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

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 @multiple_blocks_with_dead_insts_4(ptr %src, i64 %N) #0 {
entry:
  br label %loop.header

loop.header:                                      ; preds = %loop.latch, %entry
  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ]
  %xor1315 = phi i16 [ 1, %entry ], [ %xor, %loop.latch ]
  %xor = xor i16 0, 0
  %gep = getelementptr i16, ptr %src, i64 %iv
  %l = load i16, ptr %gep, align 2
  %c = icmp eq i16 %l, 0
  br i1 %c, label %then, label %else

then:                                             ; preds = %loop.header
  br label %then.1

then.1:                                           ; preds = %then
  %dead.gep.1 = getelementptr i64, ptr %src, i64 %iv
  br label %loop.latch

else:                                             ; preds = %loop.header
  %dead.gep.2 = getelementptr i64, ptr %src, i64 %iv
  br label %loop.latch

loop.latch:                                       ; preds = %else, %then.1
  store i16 %xor, ptr %gep, align 2
  %iv.next = add nsw i64 %iv, 3
  %ec = icmp eq i64 %iv.next, %N
  br i1 %ec, label %exit, label %loop.header

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

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 @empty_block_with_phi_1(ptr %src, i64 %N) #0 {
entry:
  br label %loop.header

loop.header:                                      ; preds = %loop.latch, %entry
  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ]
  %xor1315 = phi i32 [ 1, %entry ], [ %xor, %loop.latch ]
  %xor = xor i32 0, 0
  %gep = getelementptr i16, ptr %src, i64 %iv
  %l = load i16, ptr %gep, align 2
  %c = icmp eq i16 %l, 0
  br i1 %c, label %then, label %loop.latch

then:                                             ; preds = %loop.header
  br label %loop.latch

loop.latch:                                       ; preds = %then, %loop.header
  %p = phi i16 [ %l, %loop.header ], [ 99, %then ]
  store i16 %p, ptr %gep, align 2
  %iv.next = add nsw i64 %iv, 1
  %0 = icmp eq i64 %iv.next, %N
  br i1 %0, label %exit, label %loop.header

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

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 @multiple_blocks_with_dead_insts_3(ptr %src) #0 {
entry:
  br label %loop.header

loop.header:                                      ; preds = %loop.latch, %entry
  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ]
  %xor1315 = phi i16 [ 0, %entry ], [ %xor, %loop.latch ]
  %xor = xor i16 0, 0
  %gep = getelementptr i16, ptr %src, i64 %iv
  %l = load i16, ptr %gep, align 2
  %c = icmp eq i16 %l, 0
  br i1 %c, label %then, label %else

then:                                             ; preds = %loop.header
  %dead.gep.1 = getelementptr i64, ptr %src, i64 %iv
  br label %loop.latch

else:                                             ; preds = %loop.header
  %dead.gep.2 = getelementptr i64, ptr %src, i64 %iv
  br label %loop.latch

loop.latch:                                       ; preds = %else, %then
  store i16 %xor, ptr %gep, align 2
  %iv.next = add nsw i64 %iv, 3
  %ec = icmp eq i64 %iv.next, 1000
  br i1 %ec, label %exit, label %loop.header

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

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 @multiple_blocks_with_dead_inst_multiple_successors_5(ptr %src) #0 {
entry:
  br label %loop.header

loop.header:                                      ; preds = %loop.latch, %entry
  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ]
  %xor1315 = phi i16 [ 1, %entry ], [ %xor, %loop.latch ]
  %xor = xor i16 0, 0
  %gep = getelementptr i16, ptr %src, i64 %iv
  %l = load i16, ptr %gep, align 2
  %c = icmp eq i16 %l, 0
  br i1 %c, label %then, label %else

then:                                             ; preds = %loop.header
  br label %then.1

then.1:                                           ; preds = %then
  %dead.gep.1 = getelementptr i64, ptr %src, i64 %iv
  br label %loop.latch

else:                                             ; preds = %loop.header
  br label %else.2

else.2:                                           ; preds = %else
  %dead.gep.2 = getelementptr i64, ptr %src, i64 %iv
  br label %loop.latch

loop.latch:                                       ; preds = %else.2, %then.1
  store i16 %xor, ptr %gep, align 2
  %iv.next = add nsw i64 %iv, 3
  %ec = icmp eq i64 %iv.next, 1000
  br i1 %ec, label %exit, label %loop.header

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

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 @multiple_blocks_with_dead_inst_multiple_successors_6(ptr %src, i1 %ic, i64 %N) #0 {
entry:
  br label %loop.header

loop.header:                                      ; preds = %loop.latch, %entry
  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ]
  %xor1315 = phi i16 [ 1, %entry ], [ %xor, %loop.latch ]
  %xor = xor i16 0, 0
  %gep = getelementptr i16, ptr %src, i64 %iv
  %l = load i16, ptr %gep, align 2
  %c = icmp eq i16 %l, 0
  br i1 %c, label %then, label %else

then:                                             ; preds = %loop.header
  br i1 %ic, label %then.1, label %else

then.1:                                           ; preds = %then
  %dead.gep.1 = getelementptr i64, ptr %src, i64 %iv
  br label %loop.latch

else:                                             ; preds = %then, %loop.header
  br label %else.2

else.2:                                           ; preds = %else
  %dead.gep.2 = getelementptr i64, ptr %src, i64 %iv
  br label %loop.latch

loop.latch:                                       ; preds = %else.2, %then.1
  store i16 %xor, ptr %gep, align 2
  %iv.next = add nsw i64 %iv, 3
  %ec = icmp eq i64 %iv.next, %N
  br i1 %ec, label %exit, label %loop.header

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

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 @empty_block_with_phi_2(ptr %src, i64 %N) #0 {
entry:
  br label %loop.header

loop.header:                                      ; preds = %loop.latch, %entry
  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ]
  %xor1315 = phi i32 [ 1, %entry ], [ %xor, %loop.latch ]
  %xor = xor i32 0, 0
  %gep = getelementptr i16, ptr %src, i64 %iv
  %l = load i16, ptr %gep, align 2
  %c = icmp eq i16 %l, 0
  br i1 %c, label %loop.latch, label %else

else:                                             ; preds = %loop.header
  br label %loop.latch

loop.latch:                                       ; preds = %else, %loop.header
  %p = phi i16 [ %l, %loop.header ], [ 99, %else ]
  store i16 %p, ptr %gep, align 2
  %iv.next = add nsw i64 %iv, 1
  %0 = icmp eq i64 %iv.next, %N
  br i1 %0, label %exit, label %loop.header

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

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 @block_with_dead_inst_2(ptr %src) #0 {
entry:
  br label %loop.header

loop.header:                                      ; preds = %loop.latch, %entry
  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ]
  %xor1315 = phi i16 [ 0, %entry ], [ %xor, %loop.latch ]
  %xor = xor i16 0, 0
  %gep = getelementptr i16, ptr %src, i64 %iv
  %l = load i16, ptr %gep, align 2
  %c = icmp eq i16 %l, 0
  br i1 %c, label %loop.latch, label %else

else:                                             ; preds = %loop.header
  %dead.gep = getelementptr i64, ptr %src, i64 %iv
  br label %loop.latch

loop.latch:                                       ; preds = %else, %loop.header
  store i16 %xor, ptr %gep, align 2
  %iv.next = add nsw i64 %iv, 3
  %ec = icmp eq i64 %iv.next, 1000
  br i1 %ec, label %exit, label %loop.header

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

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

[VPlan] Assertion `VF.Width == Width && "VPlan cost model and legacy cost model disagreed"' failed.

Tested using 51d4980a133db12888207698e39c469cb7055cac

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

define void @f() #0 {
entry:
  br label %for.body

for.cond.cleanup:                                 ; preds = %cond.end7
  ret void

for.body:                                         ; preds = %cond.end7, %entry
  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %cond.end7 ]
  %xor1315 = phi i32 [ 0, %entry ], [ %xor, %cond.end7 ]
  %xor = xor i32 0, 0
  %arrayidx = getelementptr [1 x i16], ptr null, i64 0, i64 %indvars.iv
  %0 = load i16, ptr %arrayidx, align 2
  %tobool1.not = icmp eq i16 %0, 0
  br i1 %tobool1.not, label %cond.false, label %cond.end7

cond.false:                                       ; preds = %for.body
  %arrayidx3 = getelementptr [1 x i64], ptr null, i64 0, i64 %indvars.iv
  br label %cond.end7

cond.end7:                                        ; preds = %cond.false, %for.body
  %indvars.iv.next = add nsw i64 %indvars.iv, 3
  %1 = icmp eq i64 %indvars.iv.next, 0
  br i1 %1, label %for.cond.cleanup, label %for.body
}

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-smmpm,-experimental-smnpm,-experimental-ssnpm,-experimental-sspm,-experimental-ssqosid,-experimental-supm,-experimental-zacas,-experimental-zalasr,-experimental-zicfilp,-experimental-zicfiss,-h,-shcounterenw,-shgatpa,-shtvala,-shvsatpa,-shvstvala,-shvstvecd,-smaia,-smcdeleg,-smcsrind,-smepmp,-smstateen,-ssaia,-ssccfg,-ssccptr,-sscofpmf,-sscounterenw,-sscsrind,-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" }
```

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:10123: bool llvm::LoopVectorizePass::processLoop(llvm::Loop*): Assertion `VF.Width == Width && "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 "f"
 #0 0x00005e0a0dd8f3b0 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x2f1f3b0)
 #1 0x00005e0a0dd8c7cf llvm::sys::RunSignalHandlers() (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x2f1c7cf)
 #2 0x00005e0a0dd8c925 SignalHandler(int) Signals.cpp:0:0
 #3 0x000073a243a42520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #4 0x000073a243a969fc __pthread_kill_implementation ./nptl/pthread_kill.c:44:76
 #5 0x000073a243a969fc __pthread_kill_internal ./nptl/pthread_kill.c:78:10
 #6 0x000073a243a969fc pthread_kill ./nptl/pthread_kill.c:89:10
 #7 0x000073a243a42476 gsignal ./signal/../sysdeps/posix/raise.c:27:6
 #8 0x000073a243a287f3 abort ./stdlib/abort.c:81:7
 #9 0x000073a243a2871b _nl_load_domain ./intl/loadmsgcat.c:1177:9
#10 0x000073a243a39e96 (/lib/x86_64-linux-gnu/libc.so.6+0x39e96)
#11 0x00005e0a0cdaadd8 llvm::LoopVectorizePass::processLoop(llvm::Loop*) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x1f3add8)
#12 0x00005e0a0cdad991 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*) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x1f3d991)
#13 0x00005e0a0cdae110 llvm::LoopVectorizePass::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x1f3e110)
#14 0x00005e0a0bc1fda6 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+0xdafda6)
#15 0x00005e0a0dba750e 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+0x2d3750e)
#16 0x00005e0a0bc22f36 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+0xdb2f36)
#17 0x00005e0a0dba629b llvm::ModuleToFunctionPassAdaptor::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x2d3629b)
#18 0x00005e0a0bc1f286 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+0xdaf286)
#19 0x00005e0a0dba43ed 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+0x2d343ed)
#20 0x00005e0a0b4686b6 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+0x5f86b6)
#21 0x00005e0a0b45a2f1 optMain (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x5ea2f1)
#22 0x000073a243a29d90 __libc_start_call_main ./csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#23 0x000073a243a29e40 call_init ./csu/../csu/libc-start.c:128:20
#24 0x000073a243a29e40 __libc_start_main ./csu/../csu/libc-start.c:379:5
#25 0x00005e0a0b450185 _start (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x5e0185)
zsh: IOT instruction (core dumped)  /scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt
```

Godbolt: https://godbolt.org/z/TnYreKbqn

@fhahn

Found via fuzzer.

Another case with dead instructions that get simplified by VPlan-DCE :/

> Just to add a bit of context here: I'm hitting this assertion >300 times a day so I've allowlisted it in the fuzzer I run. There are likely other interesting cases where this assertion triggers but I don't have the bandwidth to deduplicate this failure to pull out those cases. :-(

@fhahn This assertion is triggering in a large number of fuzzer runs, and we have some reason to believe there are other failures be masked by this one.  (We have at least one instance of this found so far by accident.)  This needs to be either fixed or reverted so that tree is green.

Will look into a fix now that I'm back. The crash should not reproduce with `opt -passes='instcombine,simplifycfg,loop-vectorize'` for all instances of the same underlying issue.

@fhahn I feel like at this point this assertion is doing a lot more harm than good. It's very fragile, and doesn't seem to help in finding any genuine bugs, just incidental differences in simplification power.

I was also looking into this bug briefly, but couldn't quite figure out why we didn't choose to rip out the legacy costing.

If e9e3a183d6d8d8729223b7131aa57fd9f02f0440 was supposed to fix this, then I can confirm I am still seeing this assert.

If this is indeed something else or new, then I agree with @nikic that this assert is too fragile.

The assertion originally surfaced real differences that needed fixing; the fuzzer-generated issues over the last weeks mostly were due to unsimplified input, which is very difficult to completely match without actually iteratively simplifying. Seeing the recent https://github.com/llvm/llvm-project/issues/104714 with a C reproducer it was a bit surprising that dead loads (and subsequent dead blocks/conditions) survive until LoopVectorize in the default pipeline.

There will be a number of code changes over the next few weeks/months which may introduce unintended divergences the assert is supposed to catch. For that reason it would be beneficial to keep the assert.

Ideally we would only check if no extra simplifications have been applied on the selected VPlan, which should be possible to check once #103033 lands.

We could also guard it with an option, similar to InstCombine's fix point iteration assertion, which can also trigger asserts by default on valid IR input.

> If [e9e3a18](https://github.com/llvm/llvm-project/commit/e9e3a183d6d8d8729223b7131aa57fd9f02f0440) was supposed to fix this, then I can confirm I am still seeing this assert.
>

Could you share the reproducer somewhere? Would be good to check if this is due to the simplification issue mentioned above or a genuine divergence

> Could you share the reproducer somewhere? Would be good to check if this is due to the simplification issue mentioned above or a genuine divergence

This runs in the same assert with `opt -S -passes=loop-vectorize`:

```
target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32"
target triple = "aarch64-unknown-linux-gnu"

define void @foo() #0 {
entry:
  br label %for.body315.us.us

for.body315.us.us:                                ; preds = %cond.end388.us.us, %entry
  %indvars.iv10421 = phi i64 [ %indvars.iv.next1043, %cond.end388.us.us ], [ 0, %entry ]
  br i1 false, label %cond.end388.us.us, label %cond.true380.us.us

cond.true380.us.us:                               ; preds = %for.body315.us.us
  %0 = load i32, ptr null, align 4
  br label %cond.end388.us.us

cond.end388.us.us:                                ; preds = %cond.true380.us.us, %for.body315.us.us
  %indvars.iv.next1043 = add i64 %indvars.iv10421, 1
  %cmp313.us.us = icmp slt i64 %indvars.iv10421, 1
  br i1 %cmp313.us.us, label %for.body315.us.us, label %for.cond311.for.cond.cleanup314_crit_edge.loopexit, !llvm.loop !0

for.cond311.for.cond.cleanup314_crit_edge.loopexit: ; preds = %cond.end388.us.us
  ret void
}

attributes #0 = { "target-cpu"="neoverse-v2" }

!0 = distinct !{!0, !1, !2, !3}
!1 = !{!"llvm.loop.mustprogress"}
!2 = !{!"llvm.loop.vectorize.predicate.enable", i1 true}
!3 = !{!"llvm.loop.vectorize.enable", i1 true}
```