commit 40a72f8cc414726a8be234a260650fd62354da21
Author: Florian Hahn <flo@fhahn.com>
Date:   Fri Jun 14 22:16:51 2024 +0100

    [VPlan] Support extracting any lane of uniform value.

    If the value we are extracting a lane from is uniform, only the first
    lane will be set. Return lane 0 for any requested lane.

    This fixes a crash when trying to extract the last lane for a
    first-order recurrence resume value.

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

diff --git a/llvm/lib/Transforms/Vectorize/VPlan.cpp b/llvm/lib/Transforms/Vectorize/VPlan.cpp
index f17be451e684..348a2be5072b 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlan.cpp
@@ -231,6 +231,11 @@ Value *VPTransformState::get(VPValue *Def, const VPIteration &Instance) {
     return Data
         .PerPartScalars[Def][Instance.Part][Instance.Lane.mapToCacheIndex(VF)];
   }
+  if (!Instance.Lane.isFirstLane() &&
+      vputils::isUniformAfterVectorization(Def) &&
+      hasScalarValue(Def, {Instance.Part, VPLane::getFirstLane()})) {
+    return Data.PerPartScalars[Def][Instance.Part][0];
+  }

   assert(hasVectorValue(Def, Instance.Part));
   auto *VecPart = Data.PerPartOutput[Def][Instance.Part];
diff --git a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
index 7a482455473e..a3ff6395bb39 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
@@ -577,7 +577,8 @@ Value *VPInstruction::generatePerPart(VPTransformState &State, unsigned Part) {
       // When loop is unrolled without vectorizing, retrieve UF - Offset.
       Res = State.get(getOperand(0), State.UF - Offset);
     }
-    Res->setName(Name);
+    if (isa<ExtractElementInst>(Res))
+      Res->setName(Name);
     return Res;
   }
   case VPInstruction::LogicalAnd: {

opt -p loop-vectorize -prefer-predicate-over-epilogue=predicate-else-scalar-epilogue -S %s

target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
target triple = "arm64-apple-macosx14.0.0"

define i32 @chained_recurrences(i32 %x, i64 %y, ptr %src.1, i32 %z, ptr %src.2) #0 {
entry:
  br label %loop

loop:                                             ; preds = %loop, %entry
  %0 = phi i32 [ 0, %entry ], [ %3, %loop ]
  %1 = phi i32 [ 0, %entry ], [ %0, %loop ]
  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
  %sum.red = phi i32 [ 0, %entry ], [ %red.2, %loop ]
  %2 = add i64 %y, 1
  %gep.1 = getelementptr i32, ptr %src.1, i64 %2
  %3 = load i32, ptr %gep.1, align 4
  %or3 = or i32 %1, %x
  %iv.next = add i64 %iv, 1
  %shr = lshr i32 %x, 1
  %4 = shl i32 %or3, 1
  %5 = or i32 %4, 2
  %shl19 = shl i32 %x, 1
  %6 = or i32 %shr, %shl19
  %7 = or i32 %6, %5
  %8 = or i32 %7, %x
  %or20 = or i32 %z, %x
  %not = and i32 %or20, 1
  %and = xor i32 %not, 1
  %idx.ext.1 = zext i32 %and to i64
  %gep.2 = getelementptr i32, ptr %src.2, i64 %idx.ext.1
  %9 = load i32, ptr %gep.2, align 4
  %shr24 = lshr i32 %8, 1
  %idx.ext.2 = zext i32 %shr24 to i64
  %gep.3 = getelementptr i32, ptr %src.2, i64 %idx.ext.2
  %10 = load i32, ptr %gep.3, align 4
  %red.1 = or i32 %9, %sum.red
  %red.2 = or i32 %red.1, %10
  %ec = icmp eq i64 %iv, %y
  br i1 %ec, label %exit, label %loop

exit:                                             ; preds = %loop
  ret i32 %red.2
}

attributes #0 = { "target-features"="+sve" }

define double @test_resinking_required(ptr %p, ptr noalias %a, ptr noalias %b) {
Entry:
  br label %Loop

Loop:                                             ; preds = %Loop, %Entry
  %for.1 = phi double [ %l1, %Loop ], [ 0.000000e+00, %Entry ]
  %for.2 = phi double [ %l2, %Loop ], [ 0.000000e+00, %Entry ]
  %for.3 = phi double [ %for.2, %Loop ], [ 0.000000e+00, %Entry ]
  %iv = phi i64 [ %iv.next, %Loop ], [ 0, %Entry ]
  %USE_2_FORS = fdiv double %for.3, %for.1
  %div = fdiv double 0.000000e+00, %for.1
  %l1 = load double, ptr %a, align 8
  %iv.next = add nuw nsw i64 %iv, 1
  %l2 = load double, ptr %b, align 8
  store double %div, ptr %p, align 8
  %cond = icmp eq i64 %iv.next, 0
  br i1 %cond, label %End, label %Loop

End:                                              ; preds = %Loop
  %res.1 = fadd double %for.1, %for.2
  %res.2 = fadd double %res.1, %for.3
  ret double %res.2
}

define void @instruction_with_2_FOR_operands_and_multiple_other_uses_chain(ptr noalias %dst.1, ptr noalias %dst.2, ptr noalias %dst.3, ptr noalias %for.ptr.1, ptr noalias %for.ptr.2) {
bb:
  br label %loop

loop:                                             ; preds = %loop, %bb
  %for.1 = phi float [ 0.000000e+00, %bb ], [ %for.1.next, %loop ]
  %for.2 = phi float [ 0.000000e+00, %bb ], [ %for.2.next, %loop ]
  %iv = phi i64 [ 0, %bb ], [ %iv.next, %loop ]
  %for.1.use.1 = fmul fast float %for.1, 2.000000e+00
  %for.1.use.c = fmul fast float %for.1.use.1, 2.000000e+00
  %used.by.both = fmul fast float %for.1.use.c, %for.2
  %for.2.next = load float, ptr %for.ptr.2, align 4
  %for.1.use.3 = fadd fast float %for.1, 1.000000e+00
  %iv.next = add nuw nsw i64 %iv, 1
  %for.1.next = load float, ptr %for.ptr.1, align 4
  %gep.dst.1 = getelementptr inbounds float, ptr %dst.1, i64 %iv
  store float %used.by.both, ptr %gep.dst.1, align 4
  %gep.dst.2 = getelementptr inbounds float, ptr %dst.2, i64 %iv
  store float %for.1.use.1, ptr %gep.dst.2, align 4
  %gep.dst.3 = getelementptr inbounds float, ptr %dst.3, i64 %iv
  store float %for.1.use.3, ptr %gep.dst.3, align 4
  %ec = icmp slt i64 %iv, 1000
  br i1 %ec, label %loop, label %exit

exit:                                             ; preds = %loop
  ret void
}

define void @instruction_with_2_FOR_operands_and_multiple_other_uses(ptr noalias %dst.1, ptr noalias %dst.2, ptr noalias %dst.3, ptr noalias %for.ptr.1, ptr noalias %for.ptr.2) {
bb:
  br label %loop

loop:                                             ; preds = %loop, %bb
  %for.1 = phi float [ 0.000000e+00, %bb ], [ %for.1.next, %loop ]
  %for.2 = phi float [ 0.000000e+00, %bb ], [ %for.2.next, %loop ]
  %iv = phi i64 [ 0, %bb ], [ %iv.next, %loop ]
  %for.1.use.1 = fmul fast float %for.1, 2.000000e+00
  %used.by.both = fmul fast float %for.1, %for.2
  %for.2.next = load float, ptr %for.ptr.2, align 4
  %for.1.use.3 = fadd fast float %for.1, 1.000000e+00
  %iv.next = add nuw nsw i64 %iv, 1
  %for.1.next = load float, ptr %for.ptr.1, align 4
  %gep.dst.1 = getelementptr inbounds float, ptr %dst.1, i64 %iv
  store float %used.by.both, ptr %gep.dst.1, align 4
  %gep.dst.2 = getelementptr inbounds float, ptr %dst.2, i64 %iv
  store float %for.1.use.1, ptr %gep.dst.2, align 4
  %gep.dst.3 = getelementptr inbounds float, ptr %dst.3, i64 %iv
  store float %for.1.use.3, ptr %gep.dst.3, align 4
  %ec = icmp slt i64 %iv, 1000
  br i1 %ec, label %loop, label %exit

exit:                                             ; preds = %loop
  ret void
}

define void @instruction_with_2_FOR_operands(ptr noalias %A, ptr noalias %B, ptr noalias %C) {
bb:
  br label %bb13

bb13:                                             ; preds = %bb13, %bb
  %tmp37 = phi float [ %tmp60, %bb13 ], [ 0.000000e+00, %bb ]
  %tmp27 = phi float [ %tmp49, %bb13 ], [ 1.000000e+00, %bb ]
  %iv = phi i64 [ %iv.next, %bb13 ], [ 0, %bb ]
  %tmp38 = fmul fast float %tmp37, %tmp27
  %iv.next = add nuw nsw i64 %iv, 1
  %gep = getelementptr inbounds float, ptr %C, i64 %iv
  %tmp49 = load float, ptr %A, align 4
  %tmp60 = load float, ptr %B, align 4
  store float %tmp38, ptr %gep, align 4
  %tmp12 = icmp slt i64 %iv, 1000
  br i1 %tmp12, label %bb13, label %bb74

bb74:                                             ; preds = %bb13
  ret void
}

define void @test_pr54233_for_depend_on_each_other(ptr noalias %a, ptr noalias %b) {
entry:
  br label %loop

loop:                                             ; preds = %loop, %entry
  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
  %for.1 = phi i32 [ 0, %entry ], [ %for.1.next, %loop ]
  %for.2 = phi i32 [ 0, %entry ], [ %for.2.next, %loop ]
  %or = or i32 %for.2, 10
  %shl = shl i32 %for.2, %for.1
  %xor = xor i32 %shl, 255
  %and = and i32 %xor, %or
  %for.1.next = xor i32 12, %for.2
  %for.2.next = load i32, ptr %b, align 4
  %a.gep = getelementptr inbounds i32, ptr %a, i64 %iv
  store i32 %and, ptr %a.gep, align 4
  %iv.next = add nuw i64 %iv, 1
  %exitcond = icmp eq i64 %iv, 1000
  br i1 %exitcond, label %exit, label %loop

exit:                                             ; preds = %loop
  ret void
}

define void @test_pr54223_sink_after_insertion_order(ptr noalias %a, ptr noalias %b, ptr noalias %dst) {
entry:
  br label %loop

loop:                                             ; preds = %loop, %entry
  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
  %for.1 = phi float [ 0.000000e+00, %entry ], [ %for.1.next, %loop ]
  %for.2 = phi float [ 0.000000e+00, %entry ], [ %for.2.next, %loop ]
  %neg = fneg float %for.2
  %muladd = call float @llvm.fmuladd.f32(float %for.1, float %neg, float 0.000000e+00)
  %dst.gep = getelementptr inbounds float, ptr %dst, i64 %iv
  %iv.next = add nuw nsw i64 %iv, 1
  %for.1.next = load float, ptr %a, align 4
  %for.2.next = load float, ptr %b, align 4
  store float %muladd, ptr %dst.gep, align 4
  %exitcond.not = icmp eq i64 %iv.next, 10000
  br i1 %exitcond.not, label %exit, label %loop

exit:                                             ; preds = %loop
  ret void
}

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

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

opt < %s -passes=loop-vectorize -force-vector-width=4 -force-vector-interleave=2 -force-widen-divrem-via-safe-divisor=0 -S

opt < %s -passes=loop-vectorize -force-vector-width=1 -force-vector-interleave=2 -force-widen-divrem-via-safe-divisor=0 -S

opt < %s -passes=loop-vectorize -force-vector-width=4 -force-vector-interleave=1 -force-widen-divrem-via-safe-divisor=0 -S

target datalayout = "e-m:e-i64:64-i128:128-n32:64-S128"

define i32 @recurence_uniform_load(ptr %src, ptr noalias %dst) {
entry:
  br label %loop

loop:                                             ; preds = %loop, %entry
  %phi = phi i64 [ 0, %entry ], [ %add, %loop ]
  %recur = phi i32 [ 0, %entry ], [ %load, %loop ]
  %add = add i64 %phi, 1
  %load = load i32, ptr %src, align 4
  %icmp = icmp ult i64 %phi, 1
  br i1 %icmp, label %loop, label %exit

exit:                                             ; preds = %loop
  ret i32 0
}

Assertion `hasVectorValue(Def, Instance.Part)' failed.

To reproduce run the following test opt with -passes loop-vectorize:
```
; ModuleID = './reduced.ll'
source_filename = "./reduced.ll"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128-ni:1-p2:32:8:8:32-ni:2"
target triple = "x86_64-unknown-linux-gnu"

define i32 @wombat() gc "statepoint-example" {
bb:
  br label %bb2

bb1:                                              ; preds = %bb2
  ret i32 0

bb2:                                              ; preds = %bb2, %bb
  %phi = phi i64 [ 0, %bb ], [ %add, %bb2 ]
  %phi3 = phi i32 [ 0, %bb ], [ %load, %bb2 ]
  %add = add i64 %phi, 1
  %load = load i32, ptr addrspace(1) null, align 4
  %icmp = icmp ult i64 %phi, 1
  br i1 %icmp, label %bb2, label %bb1
}
```
Reproducer: https://godbolt.org/z/cv7Tf3vba

Stack dump:
```
0.	Program arguments: /opt/compiler-explorer/clang-assertions-trunk/bin/opt -o /app/output.s -S -passes loop-vectorize <source>
 #0 0x0000000004e41688 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4e41688)
 #1 0x0000000004e3eddc SignalHandler(int) Signals.cpp:0:0
 #2 0x00007ec2abe42520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #3 0x00007ec2abe969fc pthread_kill (/lib/x86_64-linux-gnu/libc.so.6+0x969fc)
 #4 0x00007ec2abe42476 gsignal (/lib/x86_64-linux-gnu/libc.so.6+0x42476)
 #5 0x00007ec2abe287f3 abort (/lib/x86_64-linux-gnu/libc.so.6+0x287f3)
 #6 0x00007ec2abe2871b (/lib/x86_64-linux-gnu/libc.so.6+0x2871b)
 #7 0x00007ec2abe39e96 (/lib/x86_64-linux-gnu/libc.so.6+0x39e96)
 #8 0x0000000003fecdce (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x3fecdce)
 #9 0x0000000004008abe llvm::VPInstruction::generatePerPart(llvm::VPTransformState&, unsigned int) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4008abe)
#10 0x000000000400ae5e llvm::VPInstruction::execute(llvm::VPTransformState&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x400ae5e)
#11 0x0000000003fe5fbf llvm::VPBasicBlock::executeRecipes(llvm::VPTransformState*, llvm::BasicBlock*) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x3fe5fbf)
#12 0x0000000003fe9cb0 llvm::VPBasicBlock::execute(llvm::VPTransformState*) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x3fe9cb0)
#13 0x0000000003feda3e llvm::VPlan::execute(llvm::VPTransformState*) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x3feda3e)
#14 0x0000000003eda4e5 llvm::LoopVectorizationPlanner::executePlan(llvm::ElementCount, unsigned int, llvm::VPlan&, llvm::InnerLoopVectorizer&, llvm::DominatorTree*, bool, llvm::DenseMap<llvm::SCEV const*, llvm::Value*, llvm::DenseMapInfo<llvm::SCEV const*, void>, llvm::detail::DenseMapPair<llvm::SCEV const*, llvm::Value*>> const*) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x3eda4e5)
#15 0x0000000003eef18b llvm::LoopVectorizePass::processLoop(llvm::Loop*) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x3eef18b)
#16 0x0000000003ef1a4d 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*) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x3ef1a4d)
#17 0x0000000003ef2c5b llvm::LoopVectorizePass::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x3ef2c5b)
#18 0x0000000002e0679e llvm::detail::PassModel<llvm::Function, llvm::LoopVectorizePass, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x2e0679e)
#19 0x0000000004c49a6c llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4c49a6c)
#20 0x0000000000dbabee 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+0xdbabee)
#21 0x0000000004c483ae llvm::ModuleToFunctionPassAdaptor::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4c483ae)
#22 0x0000000000dbc65e 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+0xdbc65e)
#23 0x0000000004c462bc llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4c462bc)
#24 0x00000000008db912 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+0x8db912)
#25 0x00000000008ceabc optMain (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x8ceabc)
#26 0x00007ec2abe29d90 (/lib/x86_64-linux-gnu/libc.so.6+0x29d90)
#27 0x00007ec2abe29e40 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e40)
#28 0x00000000008c5f0e _start (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x8c5f0e)
Program terminated with signal: SIGSEGV
Compiler returned: 139
```

cc @fhahn


commit a1b1c4a6d1d52916c5d885170a5f54632d579cdc
Author: Nikita Popov <npopov@redhat.com>
Date:   Wed Apr 24 10:56:26 2024 +0900

    [InstCombine] Fix miscompile in negation of select (#89698)

    Swapping the operands of a select is not valid if one hand is more
    poisonous that the other, because the negation zero contains poison
    elements.

    Fix this by adding an extra parameter to isKnownNegation() to forbid
    poison elements.

    I've implemented this using manual checks to avoid needing four variants
    for the NeedsNSW/AllowPoison combinations. Maybe there is a better way
    to do this...

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

diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h
index a2fa8f6064e1..571e44cdac26 100644
--- a/llvm/include/llvm/Analysis/ValueTracking.h
+++ b/llvm/include/llvm/Analysis/ValueTracking.h
@@ -131,7 +131,8 @@ bool isKnownNonZero(const Value *V, const SimplifyQuery &Q, unsigned Depth = 0);
 /// Currently can recoginze Value pair:
 /// 1: <X, Y> if X = sub (0, Y) or Y = sub (0, X)
 /// 2: <X, Y> if X = sub (A, B) and Y = sub (B, A)
-bool isKnownNegation(const Value *X, const Value *Y, bool NeedNSW = false);
+bool isKnownNegation(const Value *X, const Value *Y, bool NeedNSW = false,
+                     bool AllowPoison = true);

 /// Returns true if the give value is known to be non-negative.
 bool isKnownNonNegative(const Value *V, const SimplifyQuery &SQ,
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 21e3f8a4cc52..7501f78ca23b 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -8042,17 +8042,27 @@ static SelectPatternResult matchMinMax(CmpInst::Predicate Pred,
   return {SPF_UNKNOWN, SPNB_NA, false};
 }

-bool llvm::isKnownNegation(const Value *X, const Value *Y, bool NeedNSW) {
+bool llvm::isKnownNegation(const Value *X, const Value *Y, bool NeedNSW,
+                           bool AllowPoison) {
   assert(X && Y && "Invalid operand");

-  // X = sub (0, Y) || X = sub nsw (0, Y)
-  if ((!NeedNSW && match(X, m_Sub(m_ZeroInt(), m_Specific(Y)))) ||
-      (NeedNSW && match(X, m_NSWNeg(m_Specific(Y)))))
+  auto IsNegationOf = [&](const Value *X, const Value *Y) {
+    if (!match(X, m_Neg(m_Specific(Y))))
+      return false;
+
+    auto *BO = cast<BinaryOperator>(X);
+    if (NeedNSW && !BO->hasNoSignedWrap())
+      return false;
+
+    auto *Zero = cast<Constant>(BO->getOperand(0));
+    if (!AllowPoison && !Zero->isNullValue())
+      return false;
+
     return true;
+  };

-  // Y = sub (0, X) || Y = sub nsw (0, X)
-  if ((!NeedNSW && match(Y, m_Sub(m_ZeroInt(), m_Specific(X)))) ||
-      (NeedNSW && match(Y, m_NSWNeg(m_Specific(X)))))
+  // X = -Y or Y = -X
+  if (IsNegationOf(X, Y) || IsNegationOf(Y, X))
     return true;

   // X = sub (A, B), Y = sub (B, A) || X = sub nsw (A, B), Y = sub nsw (B, A)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineNegator.cpp b/llvm/lib/Transforms/InstCombine/InstCombineNegator.cpp
index d697f361dec0..ed2a98ba4ae4 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineNegator.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineNegator.cpp
@@ -320,7 +320,8 @@ std::array<Value *, 2> Negator::getSortedOperandsOfBinOp(Instruction *I) {
     return NegatedPHI;
   }
   case Instruction::Select: {
-    if (isKnownNegation(I->getOperand(1), I->getOperand(2))) {
+    if (isKnownNegation(I->getOperand(1), I->getOperand(2), /*NeedNSW=*/false,
+                        /*AllowPoison=*/false)) {
       // Of one hand of select is known to be negation of another hand,
       // just swap the hands around.
       auto *NewSelect = cast<SelectInst>(I->clone());

define <2 x i32> @negate_select_of_negation_poison(<2 x i1> %c, <2 x i32> %x) {
  %neg = sub <2 x i32> <i32 0, i32 poison>, %x
  %sel = select <2 x i1> %c, <2 x i32> %neg, <2 x i32> %x
  %neg2 = sub <2 x i32> zeroinitializer, %sel
  ret <2 x i32> %neg2
}

define i8 @dont_negate_ordinary_select(i8 %x, i8 %y, i8 %z, i1 %c) {
  %t0 = select i1 %c, i8 %x, i8 %y
  %t1 = sub i8 %z, %t0
  ret i8 %t1
}

miscompile of vector double-negation + select by InstCombine

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

this:
```llvm
define <4 x i32> @f(<4 x i32> %0) {
  %2 = sub <4 x i32> zeroinitializer, %0
  %3 = select <4 x i1> <i1 false, i1 true, i1 poison, i1 poison>, <4 x i32> %2, <4 x i32> %0
  %4 = sub <4 x i32> zeroinitializer, %3
  ret <4 x i32> %4
}
```
is being optimized to:
```llvm
define <4 x i32> @f(<4 x i32> %0) {
  ret <4 x i32> %0
}
```
here's Alive's work explaining why this is wrong:
```
ERROR: Value mismatch

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

Source:
<4 x i32> %#2 = < #xffffffff (4294967295, -1), poison, poison, poison >
<4 x i32> %#3 = < #x00000001 (1), poison, poison, poison >
<4 x i32> %#4 = < #xffffffff (4294967295, -1), poison, poison, poison >

Target:
Source value: < #xffffffff (4294967295, -1), poison, poison, poison >
Target value: < #x00000001 (1), poison, poison, poison >
```

cc @nunoplopes @hatsunespica

I think the problem is this code in Negator::visitImpl.

```
  case Instruction::Select: {
    if (isKnownNegation(I->getOperand(1), I->getOperand(2))) {
      // Of one hand of select is known to be negation of another hand,
      // just swap the hands around.
      auto *NewSelect = cast<SelectInst>(I->clone());
      // Just swap the operands of the select.
      NewSelect->swapValues();
      // Don't swap prof metadata, we didn't change the branch behavior.
      NewSelect->setName(I->getName() + ".neg");
      Builder.Insert(NewSelect);
      return NewSelect;
    }
```

The IR at the time of that code running was
```
%2 = sub <4 x i32> <i32 poison, i32 0, i32 0, i32 0>, %0
%3 = select <4 x i1> <i1 false, i1 true, i1 poison, i1 poison>, <4 x i32> %2, <4 x i32> %0
%4 = sub <4 x i32> zeroinitializer, %3
```

So operand element 0 of %2 is poison. This occurred because element 0 isn't selected so SimplifiedDemandedVectorElts replaced with poison.

Once Negator swaps the operands, now element 1 of %2 is never selected so we end up with `sub <4 x i32> poison, %0`

It doesn't look like swapping the operands of the select is poison safe.

CC @nikic

Yeah, that analysis sounds right to me. With that in mind, a more direct test case would be:
```llvm
define <2 x i32> @f(<2 x i1> %c, <2 x i32> %x) {
  %neg = sub <2 x i32> <i32 0, i32 poison>, %x
  %sel = select <2 x i1> %c, <2 x i32> %neg, <2 x i32> %x
  %neg2 = sub <2 x i32> zeroinitializer, %sel
  ret <2 x i32> %neg2
}
```

> off topic but do we want an llvm-reduce pass that shrinks vectors? and maybe also shrinks lane sizes? if so I could work on that sort of thing this summer

Sounds great to me. I think some SLPVectorizer testcases that involve 16 or even 32 lanes should be further reduced.


commit 26d3cd1d07ae3fc8312feb2ab3a3a86414f28c70
Author: XChy <xxs_chy@outlook.com>
Date:   Tue Jan 16 18:45:44 2024 +0800

    [MoveAutoInit] Ignore unreachable basicblocks and handle catchswitch (#78232)

    Fixes #78049
    This patch has done:
    - Ignore unreachable predecessors when looking for nearest common
    dominator.
    - Check catchswitch with `getFirstNonPHI`, instead of
    `getFirstInsertionPt`. The latter skips EHPad.

diff --git a/llvm/lib/Transforms/Utils/MoveAutoInit.cpp b/llvm/lib/Transforms/Utils/MoveAutoInit.cpp
index a977ad87b79f..9a5dba219cee 100644
--- a/llvm/lib/Transforms/Utils/MoveAutoInit.cpp
+++ b/llvm/lib/Transforms/Utils/MoveAutoInit.cpp
@@ -164,6 +164,9 @@ static bool runMoveAutoInit(Function &F, DominatorTree &DT, MemorySSA &MSSA) {
         if (TransitiveSuccessors.count(Pred))
           continue;

+        if (!DT.isReachableFromEntry(Pred))
+          continue;
+
         DominatingPredecessor =
             DominatingPredecessor
                 ? DT.findNearestCommonDominator(DominatingPredecessor, Pred)
@@ -178,9 +181,10 @@ static bool runMoveAutoInit(Function &F, DominatorTree &DT, MemorySSA &MSSA) {

     // CatchSwitchInst blocks can only have one instruction, so they are not
     // good candidates for insertion.
-    while (isa<CatchSwitchInst>(UsersDominator->getFirstInsertionPt())) {
+    while (isa<CatchSwitchInst>(UsersDominator->getFirstNonPHI())) {
       for (BasicBlock *Pred : predecessors(UsersDominator))
-        UsersDominator = DT.findNearestCommonDominator(UsersDominator, Pred);
+        if (DT.isReachableFromEntry(Pred))
+          UsersDominator = DT.findNearestCommonDominator(UsersDominator, Pred);
     }

     // We finally found a place where I can be moved while not introducing extra

opt < %s -S -passes='move-auto-init' -verify-memoryssa

declare void @dummy()

declare void @dummy1()

define void @test() personality ptr @dummy {
entry:
  %p = alloca [2 x i16], i32 0, align 2
  store i32 0, ptr %p, align 2, !annotation !0
  br label %middle

middle:                                           ; preds = %entry
  %call = invoke ptr @dummy()
          to label %clean unwind label %catchbb

clean:                                            ; preds = %middle
  ret void

catchbb:                                          ; preds = %middle
  %cs = catchswitch within none [label %pad, label %pad1] unwind to caller

pad:                                              ; preds = %catchbb
  %c = catchpad within %cs [i32 0]
  call void @dummy1()
  ret void

pad1:                                             ; preds = %catchbb
  %c1 = catchpad within %cs [i32 0]
  call void @dummy1()
  ret void
}

!0 = !{!"auto-init"}

target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"

define void @foo(i32 %x) {
entry:
  %buffer = alloca [80 x i32], align 16
  call void @llvm.memset.p0.i64(ptr align 16 %buffer, i8 -86, i64 320, i1 false), !annotation !0
  br label %do.body

do.body:                                          ; preds = %do.cond, %entry
  %x.addr.0 = phi i32 [ %x, %entry ], [ %dec, %do.cond ]
  %arrayidx = getelementptr inbounds [80 x i32], ptr %buffer, i64 0, i64 0
  call void @dump(ptr %arrayidx)
  br label %do.cond

do.cond:                                          ; preds = %do.body
  %dec = add nsw i32 %x.addr.0, -1
  %tobool = icmp ne i32 %x.addr.0, 0
  br i1 %tobool, label %do.body, label %do.end

do.end:                                           ; preds = %do.cond
  ret void
}

; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: write)
declare void @llvm.memset.p0.i64(ptr nocapture writeonly, i8, i64, i1 immarg) #0

declare void @dump(ptr)

attributes #0 = { nocallback nofree nounwind willreturn memory(argmem: write) }

!0 = !{!"auto-init"}

target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"

; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: write)
declare void @llvm.memset.p0.i64(ptr nocapture writeonly, i8, i64, i1 immarg) #0

declare void @dump(ptr)

define void @bar(i32 %x, i32 %y) {
entry:
  %buffer = alloca [80 x i32], align 16
  call void @llvm.memset.p0.i64(ptr align 16 %buffer, i8 -86, i64 320, i1 false), !annotation !0
  %tobool = icmp ne i32 %y, 0
  br i1 %tobool, label %if.then, label %if.end

if.then:                                          ; preds = %entry
  %add = add nsw i32 %x, %y
  br label %do.body

do.body:                                          ; preds = %do.cond, %if.then
  %x.addr.0 = phi i32 [ %add, %if.then ], [ %dec, %do.cond ]
  %arrayidx = getelementptr inbounds [80 x i32], ptr %buffer, i64 0, i64 0
  call void @dump(ptr %arrayidx)
  br label %do.cond

do.cond:                                          ; preds = %do.body
  %dec = add nsw i32 %x.addr.0, -1
  %tobool1 = icmp ne i32 %x.addr.0, 0
  br i1 %tobool1, label %do.body, label %do.end

do.end:                                           ; preds = %do.cond
  br label %if.end

if.end:                                           ; preds = %do.end, %entry
  ret void
}

attributes #0 = { nocallback nofree nounwind willreturn memory(argmem: write) }

!0 = !{!"auto-init"}

[MoveAutoInit] Assertion `NodeB && "B must be in the tree"' failed.

opt -O3 -sroa-skip-mem2reg -enable-dfa-jump-thread tc_dt.ll
[tc_dt.tar.gz](https://github.com/llvm/llvm-project/files/13928836/tc_dt.tar.gz)

GenericDomTree.h:501: NodeT* llvm::DominatorTreeBase<NodeT, IsPostDom>::findNearestCommonDominator(NodeT*, NodeT*) const [with NodeT = llvm::BasicBlock;
bool IsPostDom = false]: Assertion `NodeB && "B must be in the tree"' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.

Reduced test case attached, but have not looked into it. Adding people high in the log...

Reduced the test case and pipeline a bit more:

opt -S -o - -passes='dfa-jump-threading,move-auto-init' reduced.ll

With reduced.ll being
```
define void @func_1() {
entry:
  %l_2586 = alloca [2 x i16], i32 0, align 2
  store i32 0, ptr %l_2586, align 2, !annotation !0
  br label %lbl_2844.preheader

lbl_2844.preheader:                               ; preds = %entry
  br label %lbl_2844

lbl_2844:                                         ; preds = %cleanup1473, %lbl_2844.preheader
  call void null()
  br label %cleanup1473

for.end516:                                       ; No predecessors!
  br label %cleanup1473

cleanup1473:                                      ; preds = %for.end516, %lbl_2844
  %cleanup.dest.slot.0 = phi i32 [ 0, %for.end516 ], [ 17, %lbl_2844 ]
  switch i32 %cleanup.dest.slot.0, label %cleanup1829 [
    i32 0, label %if.end1787
    i32 17, label %lbl_2844
  ]

if.end1787:                                       ; preds = %cleanup1473
  %cmp1789.not = icmp ult ptr null, %l_2586
  unreachable

cleanup1829:                                      ; preds = %cleanup1473
  ret void
}

!0 = !{!"auto-init"}

```

> It seems that DFAJumpThreading broke the dominator tree analysis.

In fact, *MoveAutoInit* should be to blame. This pass doesn't handle unreachable predecessors correctly. A reduced version without `DFAJumpThreading`:
```llvm
declare void @dummy()

define void @func_1() {
entry:
  %p = alloca [2 x i16], i32 0, align 2
  store i32 0, ptr %p, align 2, !annotation !0
  br i1 true, label %loop, label %usebb

loop:
  call void @dummy()
  br label %loop

a:
  br label %loop

b:
  br label %loop

usebb:
  %use_p = icmp ult ptr null, %p
  ret void
}

!0 = !{!"auto-init"}
```

And after looking into the source, I found that this pass doesn't handle `catchswitch` well too. For example:
```llvm
declare void @dummy()

declare void @dummy1()

define void @func_1() personality ptr @dummy {
entry:
  %p = alloca [2 x i16], i32 0, align 2
  store i32 0, ptr %p, align 2, !annotation !0
  %call = invoke ptr @dummy() to label %clean unwind label %catchbb

unreachable:
  %call1 = invoke ptr @dummy() to label %clean unwind label %catchbb

clean:
  ret void

catchbb:
  %cs = catchswitch within none [label %pad, label %pad1] unwind to caller

pad:
  %c = catchpad within %cs [ptr null, i32 0, ptr null]
  call void @dummy1()
  ret void

pad1:
  %c1 = catchpad within %cs [ptr null, i32 0, ptr null]
  call void @dummy1()
  ret void
}

!0 = !{!"auto-init"}
```


commit a4aa6bc8fc2130761b8db5db4748059127662785
Author: Alexey Bataev <a.bataev@outlook.com>
Date:   Fri Aug 30 10:17:31 2024 -0700

    [SLP]Fix PR106667: carefully look for operand nodes.

    If the operand node has the same scalars as one of the vectorized nodes,
    the compiler could miss this and incorrectly request minbitwidth data
    for the wrong node. It may lead to a compiler crash, because the
      vectorized node might have different minbw result.

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

diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index 4c0a1c4c094b..e9785ef9ded2 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -2864,6 +2864,12 @@ private:
   /// avoid issues with def-use order.
   Value *vectorizeTree(TreeEntry *E, bool PostponedPHIs);

+  TreeEntry *getMatchedVectorizedOperand(const TreeEntry *E, unsigned NodeIdx);
+  const TreeEntry *getMatchedVectorizedOperand(const TreeEntry *E,
+                                               unsigned NodeIdx) const {
+    return const_cast<BoUpSLP *>(this)->getMatchedVectorizedOperand(E, NodeIdx);
+  }
+
   /// Vectorize a single entry in the tree, the \p Idx-th operand of the entry
   /// \p E.
   /// \param PostponedPHIs true, if need to postpone emission of phi nodes to
@@ -6964,6 +6970,55 @@ void BoUpSLP::buildTree_rec(ArrayRef<Value *> VL, unsigned Depth,
     }
   }

+  // Check if this is a duplicate of another entry.
+  if (TreeEntry *E = getTreeEntry(S.OpValue)) {
+    LLVM_DEBUG(dbgs() << "SLP: \tChecking bundle: " << *S.OpValue << ".\n");
+    if (!E->isSame(VL)) {
+      auto It = MultiNodeScalars.find(S.OpValue);
+      if (It != MultiNodeScalars.end()) {
+        auto *TEIt = find_if(It->getSecond(),
+                             [&](TreeEntry *ME) { return ME->isSame(VL); });
+        if (TEIt != It->getSecond().end())
+          E = *TEIt;
+        else
+          E = nullptr;
+      } else {
+        E = nullptr;
+      }
+    }
+    if (!E) {
+      if (!doesNotNeedToBeScheduled(S.OpValue)) {
+        LLVM_DEBUG(dbgs() << "SLP: Gathering due to partial overlap.\n");
+        if (TryToFindDuplicates(S))
+          newTreeEntry(VL, std::nullopt /*not vectorized*/, S, UserTreeIdx,
+                       ReuseShuffleIndices);
+        return;
+      }
+      SmallPtrSet<const TreeEntry *, 4> Nodes;
+      Nodes.insert(getTreeEntry(S.OpValue));
+      for (const TreeEntry *E : MultiNodeScalars.lookup(S.OpValue))
+        Nodes.insert(E);
+      SmallPtrSet<Value *, 8> Values(VL.begin(), VL.end());
+      if (any_of(Nodes, [&](const TreeEntry *E) {
+            return all_of(E->Scalars,
+                          [&](Value *V) { return Values.contains(V); });
+          })) {
+        LLVM_DEBUG(dbgs() << "SLP: Gathering due to full overlap.\n");
+        if (TryToFindDuplicates(S))
+          newTreeEntry(VL, std::nullopt /*not vectorized*/, S, UserTreeIdx,
+                       ReuseShuffleIndices);
+        return;
+      }
+    } else {
+      // Record the reuse of the tree node.  FIXME, currently this is only used
+      // to properly draw the graph rather than for the actual vectorization.
+      E->UserTreeIndices.push_back(UserTreeIdx);
+      LLVM_DEBUG(dbgs() << "SLP: Perfect diamond merge at " << *S.OpValue
+                        << ".\n");
+      return;
+    }
+  }
+
   // Gather if we hit the RecursionMaxDepth, unless this is a load (or z/sext of
   // a load), in which case peek through to include it in the tree, without
   // ballooning over-budget.
@@ -7095,55 +7150,6 @@ void BoUpSLP::buildTree_rec(ArrayRef<Value *> VL, unsigned Depth,
   // We now know that this is a vector of instructions of the same type from
   // the same block.

-  // Check if this is a duplicate of another entry.
-  if (TreeEntry *E = getTreeEntry(S.OpValue)) {
-    LLVM_DEBUG(dbgs() << "SLP: \tChecking bundle: " << *S.OpValue << ".\n");
-    if (!E->isSame(VL)) {
-      auto It = MultiNodeScalars.find(S.OpValue);
-      if (It != MultiNodeScalars.end()) {
-        auto *TEIt = find_if(It->getSecond(),
-                             [&](TreeEntry *ME) { return ME->isSame(VL); });
-        if (TEIt != It->getSecond().end())
-          E = *TEIt;
-        else
-          E = nullptr;
-      } else {
-        E = nullptr;
-      }
-    }
-    if (!E) {
-      if (!doesNotNeedToBeScheduled(S.OpValue)) {
-        LLVM_DEBUG(dbgs() << "SLP: Gathering due to partial overlap.\n");
-        if (TryToFindDuplicates(S))
-          newTreeEntry(VL, std::nullopt /*not vectorized*/, S, UserTreeIdx,
-                       ReuseShuffleIndices);
-        return;
-      }
-      SmallPtrSet<const TreeEntry *, 4> Nodes;
-      Nodes.insert(getTreeEntry(S.OpValue));
-      for (const TreeEntry *E : MultiNodeScalars.lookup(S.OpValue))
-        Nodes.insert(E);
-      SmallPtrSet<Value *, 8> Values(VL.begin(), VL.end());
-      if (any_of(Nodes, [&](const TreeEntry *E) {
-            return all_of(E->Scalars,
-                          [&](Value *V) { return Values.contains(V); });
-          })) {
-        LLVM_DEBUG(dbgs() << "SLP: Gathering due to full overlap.\n");
-        if (TryToFindDuplicates(S))
-          newTreeEntry(VL, std::nullopt /*not vectorized*/, S, UserTreeIdx,
-                       ReuseShuffleIndices);
-        return;
-      }
-    } else {
-      // Record the reuse of the tree node.  FIXME, currently this is only used
-      // to properly draw the graph rather than for the actual vectorization.
-      E->UserTreeIndices.push_back(UserTreeIdx);
-      LLVM_DEBUG(dbgs() << "SLP: Perfect diamond merge at " << *S.OpValue
-                        << ".\n");
-      return;
-    }
-  }
-
   // Check that none of the instructions in the bundle are already in the tree.
   for (Value *V : VL) {
     if ((!IsScatterVectorizeUserTE && !isa<Instruction>(V)) ||
@@ -9362,22 +9368,8 @@ public:

 const BoUpSLP::TreeEntry *BoUpSLP::getOperandEntry(const TreeEntry *E,
                                                    unsigned Idx) const {
-  Value *Op = E->getOperand(Idx).front();
-  if (const TreeEntry *TE = getTreeEntry(Op)) {
-    if (find_if(TE->UserTreeIndices, [&](const EdgeInfo &EI) {
-          return EI.EdgeIdx == Idx && EI.UserTE == E;
-        }) != TE->UserTreeIndices.end())
-      return TE;
-    auto MIt = MultiNodeScalars.find(Op);
-    if (MIt != MultiNodeScalars.end()) {
-      for (const TreeEntry *TE : MIt->second) {
-        if (find_if(TE->UserTreeIndices, [&](const EdgeInfo &EI) {
-              return EI.EdgeIdx == Idx && EI.UserTE == E;
-            }) != TE->UserTreeIndices.end())
-          return TE;
-      }
-    }
-  }
+  if (const TreeEntry *VE = getMatchedVectorizedOperand(E, Idx))
+    return VE;
   const auto *It =
       find_if(VectorizableTree, [&](const std::unique_ptr<TreeEntry> &TE) {
         return TE->isGather() &&
@@ -12521,10 +12513,9 @@ public:
   }
 };

-Value *BoUpSLP::vectorizeOperand(TreeEntry *E, unsigned NodeIdx,
-                                 bool PostponedPHIs) {
-  ValueList &VL = E->getOperand(NodeIdx);
-  const unsigned VF = VL.size();
+BoUpSLP::TreeEntry *BoUpSLP::getMatchedVectorizedOperand(const TreeEntry *E,
+                                                         unsigned NodeIdx) {
+  ArrayRef<Value *> VL = E->getOperand(NodeIdx);
   InstructionsState S = getSameOpcode(VL, *TLI);
   // Special processing for GEPs bundle, which may include non-gep values.
   if (!S.getOpcode() && VL.front()->getType()->isPointerTy()) {
@@ -12532,109 +12523,113 @@ Value *BoUpSLP::vectorizeOperand(TreeEntry *E, unsigned NodeIdx,
     if (It != VL.end())
       S = getSameOpcode(*It, *TLI);
   }
-  if (S.getOpcode()) {
-    auto CheckSameVE = [&](const TreeEntry *VE) {
-      return VE->isSame(VL) &&
-             (any_of(VE->UserTreeIndices,
-                     [E, NodeIdx](const EdgeInfo &EI) {
-                       return EI.UserTE == E && EI.EdgeIdx == NodeIdx;
-                     }) ||
-              any_of(VectorizableTree,
-                     [E, NodeIdx, VE](const std::unique_ptr<TreeEntry> &TE) {
-                       return TE->isOperandGatherNode({E, NodeIdx}) &&
-                              VE->isSame(TE->Scalars);
-                     }));
+  if (!S.getOpcode())
+    return nullptr;
+  auto CheckSameVE = [&](const TreeEntry *VE) {
+    return VE->isSame(VL) &&
+           (any_of(VE->UserTreeIndices,
+                   [E, NodeIdx](const EdgeInfo &EI) {
+                     return EI.UserTE == E && EI.EdgeIdx == NodeIdx;
+                   }) ||
+            any_of(VectorizableTree,
+                   [E, NodeIdx, VE](const std::unique_ptr<TreeEntry> &TE) {
+                     return TE->isOperandGatherNode(
+                                {const_cast<TreeEntry *>(E), NodeIdx}) &&
+                            VE->isSame(TE->Scalars);
+                   }));
+  };
+  TreeEntry *VE = getTreeEntry(S.OpValue);
+  if (VE && CheckSameVE(VE))
+    return VE;
+  auto It = MultiNodeScalars.find(S.OpValue);
+  if (It != MultiNodeScalars.end()) {
+    auto *I = find_if(It->getSecond(), [&](const TreeEntry *TE) {
+      return TE != VE && CheckSameVE(TE);
+    });
+    if (I != It->getSecond().end())
+      return *I;
+  }
+  return nullptr;
+}
+
+Value *BoUpSLP::vectorizeOperand(TreeEntry *E, unsigned NodeIdx,
+                                 bool PostponedPHIs) {
+  ValueList &VL = E->getOperand(NodeIdx);
+  const unsigned VF = VL.size();
+  if (TreeEntry *VE = getMatchedVectorizedOperand(E, NodeIdx)) {
+    auto FinalShuffle = [&](Value *V, ArrayRef<int> Mask) {
+      // V may be affected by MinBWs.
+      // We want ShuffleInstructionBuilder to correctly support REVEC. The key
+      // factor is the number of elements, not their type.
+      Type *ScalarTy = cast<VectorType>(V->getType())->getElementType();
+      unsigned NumElements = getNumElements(VL.front()->getType());
+      ShuffleInstructionBuilder ShuffleBuilder(
+          NumElements != 1 ? FixedVectorType::get(ScalarTy, NumElements)
+                           : ScalarTy,
+          Builder, *this);
+      ShuffleBuilder.add(V, Mask);
+      SmallVector<std::pair<const TreeEntry *, unsigned>> SubVectors(
+          E->CombinedEntriesWithIndices.size());
+      transform(E->CombinedEntriesWithIndices, SubVectors.begin(),
+                [&](const auto &P) {
+                  return std::make_pair(VectorizableTree[P.first].get(),
+                                        P.second);
+                });
+      return ShuffleBuilder.finalize(std::nullopt, SubVectors);
     };
-    TreeEntry *VE = getTreeEntry(S.OpValue);
-    bool IsSameVE = VE && CheckSameVE(VE);
-    if (!IsSameVE) {
-      auto It = MultiNodeScalars.find(S.OpValue);
-      if (It != MultiNodeScalars.end()) {
-        auto *I = find_if(It->getSecond(), [&](const TreeEntry *TE) {
-          return TE != VE && CheckSameVE(TE);
-        });
-        if (I != It->getSecond().end()) {
-          VE = *I;
-          IsSameVE = true;
-        }
-      }
-    }
-    if (IsSameVE) {
-      auto FinalShuffle = [&](Value *V, ArrayRef<int> Mask) {
-        // V may be affected by MinBWs.
-        // We want ShuffleInstructionBuilder to correctly support REVEC. The key
-        // factor is the number of elements, not their type.
-        Type *ScalarTy = cast<VectorType>(V->getType())->getElementType();
-        unsigned NumElements = getNumElements(VL.front()->getType());
-        ShuffleInstructionBuilder ShuffleBuilder(
-            NumElements != 1 ? FixedVectorType::get(ScalarTy, NumElements)
-                             : ScalarTy,
-            Builder, *this);
-        ShuffleBuilder.add(V, Mask);
-        SmallVector<std::pair<const TreeEntry *, unsigned>> SubVectors(
-            E->CombinedEntriesWithIndices.size());
-        transform(E->CombinedEntriesWithIndices, SubVectors.begin(),
-                  [&](const auto &P) {
-                    return std::make_pair(VectorizableTree[P.first].get(),
-                                          P.second);
-                  });
-        return ShuffleBuilder.finalize(std::nullopt, SubVectors);
-      };
-      Value *V = vectorizeTree(VE, PostponedPHIs);
-      if (VF * getNumElements(VL[0]->getType()) !=
-          cast<FixedVectorType>(V->getType())->getNumElements()) {
-        if (!VE->ReuseShuffleIndices.empty()) {
-          // Reshuffle to get only unique values.
-          // If some of the scalars are duplicated in the vectorization
-          // tree entry, we do not vectorize them but instead generate a
-          // mask for the reuses. But if there are several users of the
-          // same entry, they may have different vectorization factors.
-          // This is especially important for PHI nodes. In this case, we
-          // need to adapt the resulting instruction for the user
-          // vectorization factor and have to reshuffle it again to take
-          // only unique elements of the vector. Without this code the
-          // function incorrectly returns reduced vector instruction with
-          // the same elements, not with the unique ones.
-
-          // block:
-          // %phi = phi <2 x > { .., %entry} {%shuffle, %block}
-          // %2 = shuffle <2 x > %phi, poison, <4 x > <1, 1, 0, 0>
-          // ... (use %2)
-          // %shuffle = shuffle <2 x> %2, poison, <2 x> {2, 0}
-          // br %block
-          SmallVector<int> Mask(VF, PoisonMaskElem);
-          for (auto [I, V] : enumerate(VL)) {
-            if (isa<PoisonValue>(V))
-              continue;
-            Mask[I] = VE->findLaneForValue(V);
-          }
-          V = FinalShuffle(V, Mask);
-        } else {
-          assert(VF < cast<FixedVectorType>(V->getType())->getNumElements() &&
-                 "Expected vectorization factor less "
-                 "than original vector size.");
-          SmallVector<int> UniformMask(VF, 0);
-          std::iota(UniformMask.begin(), UniformMask.end(), 0);
-          V = FinalShuffle(V, UniformMask);
+    Value *V = vectorizeTree(VE, PostponedPHIs);
+    if (VF * getNumElements(VL[0]->getType()) !=
+        cast<FixedVectorType>(V->getType())->getNumElements()) {
+      if (!VE->ReuseShuffleIndices.empty()) {
+        // Reshuffle to get only unique values.
+        // If some of the scalars are duplicated in the vectorization
+        // tree entry, we do not vectorize them but instead generate a
+        // mask for the reuses. But if there are several users of the
+        // same entry, they may have different vectorization factors.
+        // This is especially important for PHI nodes. In this case, we
+        // need to adapt the resulting instruction for the user
+        // vectorization factor and have to reshuffle it again to take
+        // only unique elements of the vector. Without this code the
+        // function incorrectly returns reduced vector instruction with
+        // the same elements, not with the unique ones.
+
+        // block:
+        // %phi = phi <2 x > { .., %entry} {%shuffle, %block}
+        // %2 = shuffle <2 x > %phi, poison, <4 x > <1, 1, 0, 0>
+        // ... (use %2)
+        // %shuffle = shuffle <2 x> %2, poison, <2 x> {2, 0}
+        // br %block
+        SmallVector<int> Mask(VF, PoisonMaskElem);
+        for (auto [I, V] : enumerate(VL)) {
+          if (isa<PoisonValue>(V))
+            continue;
+          Mask[I] = VE->findLaneForValue(V);
         }
-      }
-      // Need to update the operand gather node, if actually the operand is not a
-      // vectorized node, but the buildvector/gather node, which matches one of
-      // the vectorized nodes.
-      if (find_if(VE->UserTreeIndices, [&](const EdgeInfo &EI) {
-            return EI.UserTE == E && EI.EdgeIdx == NodeIdx;
-          }) == VE->UserTreeIndices.end()) {
-        auto *It = find_if(
-            VectorizableTree, [&](const std::unique_ptr<TreeEntry> &TE) {
-              return TE->isGather() &&
-                     TE->UserTreeIndices.front().UserTE == E &&
-                     TE->UserTreeIndices.front().EdgeIdx == NodeIdx;
-            });
-        assert(It != VectorizableTree.end() && "Expected gather node operand.");
-        (*It)->VectorizedValue = V;
-      }
-      return V;
+        V = FinalShuffle(V, Mask);
+      } else {
+        assert(VF < cast<FixedVectorType>(V->getType())->getNumElements() &&
+               "Expected vectorization factor less "
+               "than original vector size.");
+        SmallVector<int> UniformMask(VF, 0);
+        std::iota(UniformMask.begin(), UniformMask.end(), 0);
+        V = FinalShuffle(V, UniformMask);
+      }
+    }
+    // Need to update the operand gather node, if actually the operand is not a
+    // vectorized node, but the buildvector/gather node, which matches one of
+    // the vectorized nodes.
+    if (find_if(VE->UserTreeIndices, [&](const EdgeInfo &EI) {
+          return EI.UserTE == E && EI.EdgeIdx == NodeIdx;
+        }) == VE->UserTreeIndices.end()) {
+      auto *It =
+          find_if(VectorizableTree, [&](const std::unique_ptr<TreeEntry> &TE) {
+            return TE->isGather() && TE->UserTreeIndices.front().UserTE == E &&
+                   TE->UserTreeIndices.front().EdgeIdx == NodeIdx;
+          });
+      assert(It != VectorizableTree.end() && "Expected gather node operand.");
+      (*It)->VectorizedValue = V;
     }
+    return V;
   }

   // Find the corresponding gather entry and vectorize it.

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

[SLPVectorizer] Assertion `CastInst::castIsValid(opc, C, Ty) && "Invalid constantexpr cast!"' failed.

Reproducer: https://godbolt.org/z/PeoMv3Tsn
```
; 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"

define void @main(ptr %p) {
entry:
  %conv548.2.i.13 = zext i32 0 to i64
  %and551.2.i.13 = and i64 0, %conv548.2.i.13
  %conv548.3.i.13 = zext i32 0 to i64
  %and551.3.i.13 = and i64 0, %conv548.3.i.13
  %0 = trunc i64 %and551.2.i.13 to i32
  %conv54.2.i.14 = and i32 %0, 0
  %conv548.2.i.14 = zext i32 %conv54.2.i.14 to i64
  %and551.2.i.14 = and i64 %and551.2.i.13, %conv548.2.i.14
  %1 = trunc i64 %and551.3.i.13 to i32
  %conv54.3.i.14 = and i32 %1, 0
  %conv548.3.i.14 = zext i32 %conv54.3.i.14 to i64
  %and551.3.i.14 = and i64 %and551.3.i.13, %conv548.3.i.14
  %and551.2.i.15 = and i64 %and551.2.i.14, 0
  %and551.3.i.15 = and i64 %and551.3.i.14, 0
  %and551.2.i.16 = and i64 %and551.2.i.15, 0
  %and551.3.i.16 = and i64 %and551.3.i.15, 0
  %and551.2.i.17 = and i64 %and551.2.i.16, 0
  %and551.3.i.17 = and i64 %and551.3.i.16, 0
  %and551.2.i.18 = and i64 %and551.2.i.17, 0
  %and551.3.i.18 = and i64 %and551.3.i.17, 0
  %and551.2.i.19 = and i64 %and551.2.i.18, 0
  %and551.3.i.19 = and i64 %and551.3.i.18, 0
  %and551.2.i.20 = and i64 %and551.2.i.19, 0
  %and551.3.i.20 = and i64 %and551.3.i.19, 0
  %and551.2.i.21 = and i64 %and551.2.i.20, 0
  %and551.3.i.21 = and i64 %and551.3.i.20, 0
  %gep1 = getelementptr inbounds i8, ptr %p, i64 16
  %gep2 = getelementptr inbounds i8, ptr %p, i64 24
  store i64 %and551.2.i.21, ptr %gep1, align 16
  store i64 %and551.3.i.21, ptr %gep2, align 8
  ret void
}
```
```
opt: /home/dtcxzyw/WorkSpace/Projects/compilers/llvm-project/llvm/lib/IR/Constants.cpp:2202: static llvm::Constant* llvm::ConstantExpr::getCast(unsigned int, llvm::Constant*, llvm::Type*, bool): Assertion `CastInst::castIsValid(opc, C, Ty) && "Invalid constantexpr cast!"' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:
0.      Program arguments: bin/opt -passes=slp-vectorizer reduced.ll -S
1.      Running pass "function(slp-vectorizer)" on module "reduced.ll"
2.      Running pass "slp-vectorizer" on function "main"
 #0 0x00007c5d3e8138d2 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/libLLVMSupport.so.20.0git+0x2138d2)
 #1 0x00007c5d3e81079f llvm::sys::RunSignalHandlers() (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/libLLVMSupport.so.20.0git+0x21079f)
 #2 0x00007c5d3e8108e5 SignalHandler(int) Signals.cpp:0:0
 #3 0x00007c5d3e242520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #4 0x00007c5d3e2969fc __pthread_kill_implementation ./nptl/pthread_kill.c:44:76
 #5 0x00007c5d3e2969fc __pthread_kill_internal ./nptl/pthread_kill.c:78:10
 #6 0x00007c5d3e2969fc pthread_kill ./nptl/pthread_kill.c:89:10
 #7 0x00007c5d3e242476 gsignal ./signal/../sysdeps/posix/raise.c:27:6
 #8 0x00007c5d3e2287f3 abort ./stdlib/abort.c:81:7
 #9 0x00007c5d3e22871b _nl_load_domain ./intl/loadmsgcat.c:1177:9
#10 0x00007c5d3e239e96 (/lib/x86_64-linux-gnu/libc.so.6+0x39e96)
#11 0x00007c5d36fb0c4d llvm::ConstantExpr::getCast(unsigned int, llvm::Constant*, llvm::Type*, bool) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMCore.so.20.0git+0x1b0c4d)
#12 0x00007c5d394573b5 llvm::IRBuilderBase::CreateCast(llvm::Instruction::CastOps, llvm::Value*, llvm::Type*, llvm::Twine const&) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMVectorize.so.20.0git+0x573b5)
#13 0x00007c5d395ab173 llvm::slpvectorizer::BoUpSLP::vectorizeTree(llvm::slpvectorizer::BoUpSLP::TreeEntry*, bool) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMVectorize.so.20.0git+0x1ab173)
#14 0x00007c5d395acf1e llvm::slpvectorizer::BoUpSLP::vectorizeOperand(llvm::slpvectorizer::BoUpSLP::TreeEntry*, unsigned int, bool) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMVectorize.so.20.0git+0x1acf1e)
#15 0x00007c5d395a7a13 llvm::slpvectorizer::BoUpSLP::vectorizeTree(llvm::slpvectorizer::BoUpSLP::TreeEntry*, bool) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMVectorize.so.20.0git+0x1a7a13)
#16 0x00007c5d395acf1e llvm::slpvectorizer::BoUpSLP::vectorizeOperand(llvm::slpvectorizer::BoUpSLP::TreeEntry*, unsigned int, bool) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMVectorize.so.20.0git+0x1acf1e)
#17 0x00007c5d395a7cbb llvm::slpvectorizer::BoUpSLP::vectorizeTree(llvm::slpvectorizer::BoUpSLP::TreeEntry*, bool) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMVectorize.so.20.0git+0x1a7cbb)
#18 0x00007c5d395acf1e llvm::slpvectorizer::BoUpSLP::vectorizeOperand(llvm::slpvectorizer::BoUpSLP::TreeEntry*, unsigned int, bool) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMVectorize.so.20.0git+0x1acf1e)
#19 0x00007c5d395a7a41 llvm::slpvectorizer::BoUpSLP::vectorizeTree(llvm::slpvectorizer::BoUpSLP::TreeEntry*, bool) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMVectorize.so.20.0git+0x1a7a41)
#20 0x00007c5d395acf1e llvm::slpvectorizer::BoUpSLP::vectorizeOperand(llvm::slpvectorizer::BoUpSLP::TreeEntry*, unsigned int, bool) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMVectorize.so.20.0git+0x1acf1e)
#21 0x00007c5d395a7a13 llvm::slpvectorizer::BoUpSLP::vectorizeTree(llvm::slpvectorizer::BoUpSLP::TreeEntry*, bool) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMVectorize.so.20.0git+0x1a7a13)
#22 0x00007c5d395acf1e llvm::slpvectorizer::BoUpSLP::vectorizeOperand(llvm::slpvectorizer::BoUpSLP::TreeEntry*, unsigned int, bool) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMVectorize.so.20.0git+0x1acf1e)
#23 0x00007c5d395a7a13 llvm::slpvectorizer::BoUpSLP::vectorizeTree(llvm::slpvectorizer::BoUpSLP::TreeEntry*, bool) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMVectorize.so.20.0git+0x1a7a13)
#24 0x00007c5d395acf1e llvm::slpvectorizer::BoUpSLP::vectorizeOperand(llvm::slpvectorizer::BoUpSLP::TreeEntry*, unsigned int, bool) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMVectorize.so.20.0git+0x1acf1e)
#25 0x00007c5d395a7a13 llvm::slpvectorizer::BoUpSLP::vectorizeTree(llvm::slpvectorizer::BoUpSLP::TreeEntry*, bool) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMVectorize.so.20.0git+0x1a7a13)
#26 0x00007c5d395acf1e llvm::slpvectorizer::BoUpSLP::vectorizeOperand(llvm::slpvectorizer::BoUpSLP::TreeEntry*, unsigned int, bool) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMVectorize.so.20.0git+0x1acf1e)
#27 0x00007c5d395a7a13 llvm::slpvectorizer::BoUpSLP::vectorizeTree(llvm::slpvectorizer::BoUpSLP::TreeEntry*, bool) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMVectorize.so.20.0git+0x1a7a13)
#28 0x00007c5d395acf1e llvm::slpvectorizer::BoUpSLP::vectorizeOperand(llvm::slpvectorizer::BoUpSLP::TreeEntry*, unsigned int, bool) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMVectorize.so.20.0git+0x1acf1e)
#29 0x00007c5d395a7a13 llvm::slpvectorizer::BoUpSLP::vectorizeTree(llvm::slpvectorizer::BoUpSLP::TreeEntry*, bool) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMVectorize.so.20.0git+0x1a7a13)
#30 0x00007c5d395acf1e llvm::slpvectorizer::BoUpSLP::vectorizeOperand(llvm::slpvectorizer::BoUpSLP::TreeEntry*, unsigned int, bool) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMVectorize.so.20.0git+0x1acf1e)
#31 0x00007c5d395a7a13 llvm::slpvectorizer::BoUpSLP::vectorizeTree(llvm::slpvectorizer::BoUpSLP::TreeEntry*, bool) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMVectorize.so.20.0git+0x1a7a13)
#32 0x00007c5d395acf1e llvm::slpvectorizer::BoUpSLP::vectorizeOperand(llvm::slpvectorizer::BoUpSLP::TreeEntry*, unsigned int, bool) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMVectorize.so.20.0git+0x1acf1e)
#33 0x00007c5d395a7a13 llvm::slpvectorizer::BoUpSLP::vectorizeTree(llvm::slpvectorizer::BoUpSLP::TreeEntry*, bool) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMVectorize.so.20.0git+0x1a7a13)
#34 0x00007c5d395acf1e llvm::slpvectorizer::BoUpSLP::vectorizeOperand(llvm::slpvectorizer::BoUpSLP::TreeEntry*, unsigned int, bool) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMVectorize.so.20.0git+0x1acf1e)
#35 0x00007c5d395a8f65 llvm::slpvectorizer::BoUpSLP::vectorizeTree(llvm::slpvectorizer::BoUpSLP::TreeEntry*, bool) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMVectorize.so.20.0git+0x1a8f65)
#36 0x00007c5d395ae278 llvm::slpvectorizer::BoUpSLP::vectorizeTree(llvm::MapVector<llvm::Value*, llvm::SmallVector<llvm::Instruction*, 2u>, llvm::DenseMap<llvm::Value*, unsigned int, llvm::DenseMapInfo<llvm::Value*, void>, llvm::detail::DenseMapPair<llvm::Value*, unsigned int>>, llvm::SmallVector<std::pair<llvm::Value*, llvm::SmallVector<llvm::Instruction*, 2u>>, 0u>> const&, llvm::SmallVectorImpl<std::pair<llvm::Value*, llvm::Value*>>&, llvm::Instruction*) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMVectorize.so.20.0git+0x1ae278)
#37 0x00007c5d395b207c llvm::slpvectorizer::BoUpSLP::vectorizeTree() (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMVectorize.so.20.0git+0x1b207c)
#38 0x00007c5d395c7cac llvm::SLPVectorizerPass::vectorizeStoreChain(llvm::ArrayRef<llvm::Value*>, llvm::slpvectorizer::BoUpSLP&, unsigned int, unsigned int, unsigned int&) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMVectorize.so.20.0git+0x1c7cac)
#39 0x00007c5d395c9637 llvm::SLPVectorizerPass::vectorizeStores(llvm::ArrayRef<llvm::StoreInst*>, llvm::slpvectorizer::BoUpSLP&, llvm::DenseSet<std::tuple<llvm::Value*, llvm::Value*, llvm::Value*, llvm::Value*, unsigned int>, llvm::DenseMapInfo<std::tuple<llvm::Value*, llvm::Value*, llvm::Value*, llvm::Value*, unsigned int>, void>>&)::'lambda'(std::set<std::pair<unsigned int, int>, llvm::SLPVectorizerPass::vectorizeStores(llvm::ArrayRef<llvm::StoreInst*>, llvm::slpvectorizer::BoUpSLP&, llvm::DenseSet<std::tuple<llvm::Value*, llvm::Value*, llvm::Value*, llvm::Value*, unsigned int>, llvm::DenseMapInfo<std::tuple<llvm::Value*, llvm::Value*, llvm::Value*, llvm::Value*, unsigned int>, void>>&)::StoreDistCompare, std::allocator<std::pair<unsigned int, int>>> const&)::operator()(std::set<std::pair<unsigned int, int>, llvm::SLPVectorizerPass::vectorizeStores(llvm::ArrayRef<llvm::StoreInst*>, llvm::slpvectorizer::BoUpSLP&, llvm::DenseSet<std::tuple<llvm::Value*, llvm::Value*, llvm::Value*, llvm::Value*, unsigned int>, llvm::DenseMapInfo<std::tuple<llvm::Value*, llvm::Value*, llvm::Value*, llvm::Value*, unsigned int>, void>>&)::StoreDistCompare, std::allocator<std::pair<unsigned int, int>>> const&) const SLPVectorizer.cpp:0:0
#40 0x00007c5d395cb92c llvm::SLPVectorizerPass::vectorizeStores(llvm::ArrayRef<llvm::StoreInst*>, llvm::slpvectorizer::BoUpSLP&, llvm::DenseSet<std::tuple<llvm::Value*, llvm::Value*, llvm::Value*, llvm::Value*, unsigned int>, llvm::DenseMapInfo<std::tuple<llvm::Value*, llvm::Value*, llvm::Value*, llvm::Value*, unsigned int>, void>>&) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMVectorize.so.20.0git+0x1cb92c)
#41 0x00007c5d395cc20f llvm::SLPVectorizerPass::vectorizeStoreChains(llvm::slpvectorizer::BoUpSLP&) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMVectorize.so.20.0git+0x1cc20f)
#42 0x00007c5d395cd30f llvm::SLPVectorizerPass::runImpl(llvm::Function&, llvm::ScalarEvolution*, llvm::TargetTransformInfo*, llvm::TargetLibraryInfo*, llvm::AAResults*, llvm::LoopInfo*, llvm::DominatorTree*, llvm::AssumptionCache*, llvm::DemandedBits*, llvm::OptimizationRemarkEmitter*) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMVectorize.so.20.0git+0x1cd30f)
#43 0x00007c5d395cdf86 llvm::SLPVectorizerPass::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMVectorize.so.20.0git+0x1cdf86)
#44 0x00007c5d39ed4015 llvm::detail::PassModel<llvm::Function, llvm::SLPVectorizerPass, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMPasses.so.20.0git+0xd4015)
#45 0x00007c5d371546ed llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMCore.so.20.0git+0x3546ed)
#46 0x00007c5d3d4d7f35 llvm::detail::PassModel<llvm::Function, llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMX86CodeGen.so.20.0git+0xd7f35)
#47 0x00007c5d37153256 llvm::ModuleToFunctionPassAdaptor::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMCore.so.20.0git+0x353256)
#48 0x00007c5d3d4d88f5 llvm::detail::PassModel<llvm::Module, llvm::ModuleToFunctionPassAdaptor, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMX86CodeGen.so.20.0git+0xd88f5)
#49 0x00007c5d3715121a llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMCore.so.20.0git+0x35121a)
#50 0x00007c5d3eb12fc7 llvm::runPassPipeline(llvm::StringRef, llvm::Module&, llvm::TargetMachine*, llvm::TargetLibraryInfoImpl*, llvm::ToolOutputFile*, llvm::ToolOutputFile*, llvm::ToolOutputFile*, llvm::StringRef, llvm::ArrayRef<llvm::PassPlugin>, llvm::ArrayRef<std::function<void (llvm::PassBuilder&)>>, llvm::opt_tool::OutputKind, llvm::opt_tool::VerifierKind, bool, bool, bool, bool, bool, bool, bool) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/libLLVMOptDriver.so.20.0git+0x2cfc7)
#51 0x00007c5d3eb1e962 optMain (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/libLLVMOptDriver.so.20.0git+0x38962)
#52 0x00007c5d3e229d90 __libc_start_call_main ./csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#53 0x00007c5d3e229e40 call_init ./csu/../csu/libc-start.c:128:20
#54 0x00007c5d3e229e40 __libc_start_main ./csu/../csu/libc-start.c:379:5
#55 0x00005949b291d095 _start (bin/opt+0x1095)
Aborted (core dumped)
```

cc @alexey-bataev

Related PR: https://github.com/llvm/llvm-project/pull/103216


commit 87663fdab9d0e7bcc0b963ea078da9e2eb574908
Author: Yingwei Zheng <dtcxzyw2333@gmail.com>
Date:   Sun Sep 15 18:38:06 2024 +0800

     [VectorCombine] Don't shrink lshr if the shamt is not less than bitwidth (#108705)

    Consider the following case:
    ```
    define <2 x i32> @test(<2 x i64> %vec.ind16, <2 x i32> %broadcast.splat20) {
      %19 = icmp eq <2 x i64> %vec.ind16, zeroinitializer
      %20 = zext <2 x i1> %19 to <2 x i32>
      %21 = lshr <2 x i32> %20, %broadcast.splat20
      ret <2 x i32> %21
    }
    ```
    After https://github.com/llvm/llvm-project/pull/104606, we shrink the
    lshr into:
    ```
    define <2 x i32> @test(<2 x i64> %vec.ind16, <2 x i32> %broadcast.splat20) {
      %1 = icmp eq <2 x i64> %vec.ind16, zeroinitializer
      %2 = trunc <2 x i32> %broadcast.splat20 to <2 x i1>
      %3 = lshr <2 x i1> %1, %2
      %4 = zext <2 x i1> %3 to <2 x i32>
      ret <2 x i32> %4
    }
    ```
    It is incorrect since `lshr i1 X, 1` returns `poison`.
    This patch adds additional check on the shamt operand. The lshr will get
    shrunk iff we ensure that the shamt is less than bitwidth of the smaller
    type. As `computeKnownBits(&I, *DL).countMaxActiveBits() > BW` always
    evaluates to true for `lshr(zext(X), Y)`, this check will only apply to
    bitwise logical instructions.

    Alive2: https://alive2.llvm.org/ce/z/j_RmTa
    Fixes https://github.com/llvm/llvm-project/issues/108698.

diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
index d7afe2f426d3..58701bfa60a3 100644
--- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
+++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
@@ -2597,11 +2597,19 @@ bool VectorCombine::shrinkType(llvm::Instruction &I) {
   auto *SmallTy = cast<FixedVectorType>(ZExted->getType());
   unsigned BW = SmallTy->getElementType()->getPrimitiveSizeInBits();

-  // Check that the expression overall uses at most the same number of bits as
-  // ZExted
-  KnownBits KB = computeKnownBits(&I, *DL);
-  if (KB.countMaxActiveBits() > BW)
-    return false;
+  if (I.getOpcode() == Instruction::LShr) {
+    // Check that the shift amount is less than the number of bits in the
+    // smaller type. Otherwise, the smaller lshr will return a poison value.
+    KnownBits ShAmtKB = computeKnownBits(I.getOperand(1), *DL);
+    if (ShAmtKB.getMaxValue().uge(BW))
+      return false;
+  } else {
+    // Check that the expression overall uses at most the same number of bits as
+    // ZExted
+    KnownBits KB = computeKnownBits(&I, *DL);
+    if (KB.countMaxActiveBits() > BW)
+      return false;
+  }

   // Calculate costs of leaving current IR as it is and moving ZExt operation
   // later, along with adding truncates if needed
@@ -2628,7 +2636,7 @@ bool VectorCombine::shrinkType(llvm::Instruction &I) {
       return false;

     // Check if we can propagate ZExt through its other users
-    KB = computeKnownBits(UI, *DL);
+    KnownBits KB = computeKnownBits(UI, *DL);
     if (KB.countMaxActiveBits() > BW)
       return false;

target triple = "aarch64"

define <2 x i32> @pr108698(<2 x i64> %x, <2 x i32> %y) {
  %cmp = icmp eq <2 x i64> %x, zeroinitializer
  %ext = zext <2 x i1> %cmp to <2 x i32>
  %lshr = lshr <2 x i32> %ext, %y
  ret <2 x i32> %lshr
}

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

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

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

```
[691] % clangtk -v
clang version 20.0.0git (https://github.com/llvm/llvm-project.git 223e2efa5e886502a9467b7ef700ebce9b7886e8)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /local/suz-local/software/local/clang-trunk/bin
Build config: +assertions
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/10
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/11
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/9
Selected GCC installation: /usr/lib/gcc/x86_64-linux-gnu/11
Candidate multilib: .;@m64
Selected multilib: .;@m64
[692] %
[692] % clangtk -O1 small.c; ./a.out
[693] %
[693] % clangtk -O2 small.c
[694] % ./a.out
Aborted
[695] %
[695] % cat small.c
char a[8];
int b = 1, c;
int main() {
  for (; c < 8; c++)
    a[c] = !c >> b;
  if (a[0] != 0)
    __builtin_abort();
  return 0;
}
```

Reproducer: https://alive2.llvm.org/ce/z/5SkPZS
```
; bin/opt -passes=vector-combine test.ll -S

target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

define <2 x i32> @test(<2 x i64> %vec.ind16, <2 x i32> %broadcast.splat20) {
  %19 = icmp eq <2 x i64> %vec.ind16, zeroinitializer
  %20 = zext <2 x i1> %19 to <2 x i32>
  %21 = lshr <2 x i32> %20, %broadcast.splat20
  ret <2 x i32> %21
}
```
```
define <2 x i32> @test(<2 x i64> %vec.ind16, <2 x i32> %broadcast.splat20) {
  %1 = icmp eq <2 x i64> %vec.ind16, zeroinitializer
  %2 = trunc <2 x i32> %broadcast.splat20 to <2 x i1>
  %3 = lshr <2 x i1> %1, %2
  %4 = zext <2 x i1> %3 to <2 x i32>
  ret <2 x i32> %4
}
```

Related PR: https://github.com/llvm/llvm-project/pull/104606


commit 97088b2ab2184ad4bd64f59fba0b92b70468b10d
Author: Orlando Cazalet-Hyams <orlando.hyams@sony.com>
Date:   Tue Feb 13 11:35:28 2024 +0000

    [RemoveDIs][ValueMapper] Remap DIAssignIDs in DPValues  (#81595)

    Fix crash raised in comments for 5c9f7682b090124d9a8b69f92d3f7c269dca25fc

diff --git a/llvm/lib/Transforms/Utils/ValueMapper.cpp b/llvm/lib/Transforms/Utils/ValueMapper.cpp
index a8ae3ee3b251..93a4c829df06 100644
--- a/llvm/lib/Transforms/Utils/ValueMapper.cpp
+++ b/llvm/lib/Transforms/Utils/ValueMapper.cpp
@@ -552,6 +552,7 @@ void Mapper::remapDPValue(DPValue &V) {
       V.setKillAddress();
     else if (NewAddr)
       V.setAddress(NewAddr);
+    V.setAssignId(cast<DIAssignID>(mapMetadata(V.getAssignID())));
   }

   // Find Value operands and remap those.

opt --try-experimental-debuginfo-iterators -passes=ipsccp %s -S -o -

;; Check the dbg.assign DIAssignID operand gets remapped after cloning.

;

; Function Attrs: mustprogress nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare void @llvm.dbg.declare(metadata, metadata, metadata)

define void @inv_txfm_add_dct_dct_4x4_c() {
entry:
  call void @inv_txfm_add_c(ptr @dav1d_inv_dct4_1d_c)
  ret void
}

declare void @llvm.memset.p0.i64(ptr nocapture writeonly, i8, i64, i1 immarg)

; Function Attrs: noinline
define void @inv_txfm_add_c(ptr %first_1d_fn) #2 {
entry:
  %tmp = alloca [4096 x i32], i32 0, align 16, !DIAssignID !5
  tail call void @llvm.dbg.assign(metadata i1 undef, metadata !6, metadata !DIExpression(), metadata !5, metadata ptr %tmp, metadata !DIExpression()), !dbg !16
  call void @llvm.memset.p0.i64(ptr %tmp, i8 0, i64 0, i1 false), !DIAssignID !17
  call void %first_1d_fn(ptr null, i64 0, i32 0, i32 0)
  ret void
}

declare void @dav1d_inv_dct4_1d_c(ptr, i64, i32, i32)

declare void @llvm.dbg.assign(metadata, metadata, metadata, metadata, metadata, metadata)

attributes #2 = { noinline }

!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!3, !4}

!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !2, splitDebugInlining: false, nameTableKind: GNU)
!1 = !DIFile(filename: "itx_tmpl.c", directory: ".")
!2 = !{}
!3 = !{i32 2, !"Debug Info Version", i32 3}
!4 = !{i32 7, !"debug-info-assignment-tracking", i1 true}
!5 = distinct !DIAssignID()
!6 = !DILocalVariable(name: "tmp", scope: !7, file: !1, line: 78, type: !10)
!7 = distinct !DISubprogram(name: "inv_txfm_add_c", scope: !1, file: !1, line: 41, type: !8, scopeLine: 45, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2)
!8 = distinct !DISubroutineType(types: !9)
!9 = !{null}
!10 = !DICompositeType(tag: DW_TAG_array_type, baseType: !11, size: 131072, elements: !2)
!11 = !DIDerivedType(tag: DW_TAG_typedef, name: "int32_t", file: !12, line: 26, baseType: !13)
!12 = !DIFile(filename: "stdint-intn.h", directory: ".")
!13 = !DIDerivedType(tag: DW_TAG_typedef, name: "__int32_t", file: !14, line: 41, baseType: !15)
!14 = !DIFile(filename: "types.h", directory: ".")
!15 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
!16 = !DILocation(line: 0, scope: !7)
!17 = distinct !DIAssignID()

Clang frontend command failed to build lib/vsprintf.c in Linux kernel

```
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace, preprocessed source, and associated run script.
Stack dump:
0.	Program arguments: clang -Wp,-MMD,lib/.vsprintf.o.d -nostdinc -I./arch/x86/include -I./arch/x86/include/generated -I./include -I./arch/x86/include/uapi -I./arch/x86/include/generated/uapi -I./include/uapi -I./include/generated/uapi -include ./include/linux/compiler-version.h -include ./include/linux/kconfig.h -include ./include/linux/compiler_types.h -D__KERNEL__ --target=x86_64-linux-gnu -fintegrated-as -Werror=unknown-warning-option -Werror=ignored-optimization-argument -Werror=option-ignored -Werror=unused-command-line-argument -fmacro-prefix-map=./= -std=gnu11 -fshort-wchar -funsigned-char -fno-common -fno-PIE -fno-strict-aliasing -mno-sse -mno-mmx -mno-sse2 -mno-3dnow -mno-avx -fcf-protection=none -m64 -falign-loops=1 -mno-80387 -mno-fp-ret-in-387 -mstack-alignment=8 -mskip-rax-setup -mtune=generic -mno-red-zone -mcmodel=kernel -Wno-sign-compare -fno-asynchronous-unwind-tables -mretpoline-external-thunk -mindirect-branch-cs-prefix -mfunction-return=thunk-extern -mharden-sls=all -fpatchable-function-entry=16,16 -fno-delete-null-pointer-checks -O2 -fstack-protector-strong -fno-omit-frame-pointer -fno-optimize-sibling-calls -ftrivial-auto-var-init=zero -fno-stack-clash-protection -fzero-call-used-regs=used-gpr -DCC_USING_NOP_MCOUNT -DCC_USING_FENTRY -falign-functions=16 -fstrict-flex-arrays=3 -fno-strict-overflow -fno-stack-check -Wall -Wundef -Werror=implicit-function-declaration -Werror=implicit-int -Werror=return-type -Werror=strict-prototypes -Wno-format-security -Wno-trigraphs -Wno-frame-address -Wno-address-of-packed-member -Wmissing-declarations -Wmissing-prototypes -Wframe-larger-than=1024 -Wno-gnu -Wno-unused-but-set-variable -Wno-unused-const-variable -Wvla -Wno-pointer-sign -Wcast-function-type -Wimplicit-fallthrough -Werror=date-time -Werror=incompatible-pointer-types -Wenum-conversion -Wno-unused-but-set-variable -Wno-unused-const-variable -Wno-format-overflow -Wno-format-truncation -Wno-pointer-to-enum-cast -Wno-tautological-constant-out-of-range-compare -Wno-unaligned-access -Wno-cast-function-type-strict -Wno-missing-field-initializers -Wno-type-limits -Wno-shift-negative-value -Wno-initializer-overrides -Wno-sign-compare -g -gdwarf-5 -fsanitize=array-bounds -fsanitize=shift -fsanitize=bool -fsanitize=enum -DKBUILD_MODFILE=\"lib/vsprintf\" -DKBUILD_BASENAME=\"vsprintf\" -DKBUILD_MODNAME=\"vsprintf\" -D__KBUILD_MODNAME=kmod_vsprintf -c -o lib/vsprintf.o lib/vsprintf.c
1.	<eof> parser at end of file
2.	Code generation
3.	Running pass 'Function Pass Manager' on module 'lib/vsprintf.c'.
4.	Running pass 'Assignment Tracking Analysis' on function '@ip4_string'
 #0 0x000055fc39a6be88 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/home/eve/Downloads/llvm-project/build2/bin/clang-19+0x2d82e88)
 #1 0x000055fc39a69c6e llvm::sys::RunSignalHandlers() (/home/eve/Downloads/llvm-project/build2/bin/clang-19+0x2d80c6e)
 #2 0x000055fc399e7729 CrashRecoverySignalHandler(int) CrashRecoveryContext.cpp:0:0
 #3 0x00007f7639a42990 (/lib/x86_64-linux-gnu/libc.so.6+0x42990)
 #4 0x000055fc39484775 (anonymous namespace)::AssignmentTrackingLowering::run(FunctionVarLocsBuilder*) AssignmentTrackingAnalysis.cpp:0:0
 #5 0x000055fc3947f3fe analyzeFunction(llvm::Function&, llvm::DataLayout const&, FunctionVarLocsBuilder*) AssignmentTrackingAnalysis.cpp:0:0
 #6 0x000055fc3947fdcd llvm::AssignmentTrackingAnalysis::runOnFunction(llvm::Function&) (/home/eve/Downloads/llvm-project/build2/bin/clang-19+0x2796dcd)
 #7 0x000055fc395bab96 llvm::FPPassManager::runOnFunction(llvm::Function&) (/home/eve/Downloads/llvm-project/build2/bin/clang-19+0x28d1b96)
 #8 0x000055fc395c1a23 llvm::FPPassManager::runOnModule(llvm::Module&) (/home/eve/Downloads/llvm-project/build2/bin/clang-19+0x28d8a23)
 #9 0x000055fc395bb807 llvm::legacy::PassManagerImpl::run(llvm::Module&) (/home/eve/Downloads/llvm-project/build2/bin/clang-19+0x28d2807)
#10 0x000055fc39c161b6 clang::EmitBackendOutput(clang::DiagnosticsEngine&, clang::HeaderSearchOptions const&, clang::CodeGenOptions const&, clang::TargetOptions const&, clang::LangOptions const&, llvm::StringRef, llvm::Module*, clang::BackendAction, llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>, std::unique_ptr<llvm::raw_pwrite_stream, std::default_delete<llvm::raw_pwrite_stream>>, clang::BackendConsumer*) (/home/eve/Downloads/llvm-project/build2/bin/clang-19+0x2f2d1b6)
#11 0x000055fc3a09fed5 clang::BackendConsumer::HandleTranslationUnit(clang::ASTContext&) (/home/eve/Downloads/llvm-project/build2/bin/clang-19+0x33b6ed5)
#12 0x000055fc3b7248f6 clang::ParseAST(clang::Sema&, bool, bool) (/home/eve/Downloads/llvm-project/build2/bin/clang-19+0x4a3b8f6)
#13 0x000055fc3a316d86 clang::FrontendAction::Execute() (/home/eve/Downloads/llvm-project/build2/bin/clang-19+0x362dd86)
#14 0x000055fc3a28c654 clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) (/home/eve/Downloads/llvm-project/build2/bin/clang-19+0x35a3654)
#15 0x000055fc3a3d293e clang::ExecuteCompilerInvocation(clang::CompilerInstance*) (/home/eve/Downloads/llvm-project/build2/bin/clang-19+0x36e993e)
#16 0x000055fc37b20c3c cc1_main(llvm::ArrayRef<char const*>, char const*, void*) (/home/eve/Downloads/llvm-project/build2/bin/clang-19+0xe37c3c)
#17 0x000055fc37b1dc71 ExecuteCC1Tool(llvm::SmallVectorImpl<char const*>&, llvm::ToolContext const&) driver.cpp:0:0
#18 0x000055fc3a0e9eb9 void llvm::function_ref<void ()>::callback_fn<clang::driver::CC1Command::Execute(llvm::ArrayRef<std::optional<llvm::StringRef>>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>*, bool*) const::$_0>(long) Job.cpp:0:0
#19 0x000055fc399e750c llvm::CrashRecoveryContext::RunSafely(llvm::function_ref<void ()>) (/home/eve/Downloads/llvm-project/build2/bin/clang-19+0x2cfe50c)
#20 0x000055fc3a0e9906 clang::driver::CC1Command::Execute(llvm::ArrayRef<std::optional<llvm::StringRef>>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>*, bool*) const (/home/eve/Downloads/llvm-project/build2/bin/clang-19+0x3400906)
#21 0x000055fc3a0abd57 clang::driver::Compilation::ExecuteCommand(clang::driver::Command const&, clang::driver::Command const*&, bool) const (/home/eve/Downloads/llvm-project/build2/bin/clang-19+0x33c2d57)
#22 0x000055fc3a0ac1fe clang::driver::Compilation::ExecuteJobs(clang::driver::JobList const&, llvm::SmallVectorImpl<std::pair<int, clang::driver::Command const*>>&, bool) const (/home/eve/Downloads/llvm-project/build2/bin/clang-19+0x33c31fe)
#23 0x000055fc3a0ca5df clang::driver::Driver::ExecuteCompilation(clang::driver::Compilation&, llvm::SmallVectorImpl<std::pair<int, clang::driver::Command const*>>&) (/home/eve/Downloads/llvm-project/build2/bin/clang-19+0x33e15df)
#24 0x000055fc37b1d338 clang_main(int, char**, llvm::ToolContext const&) (/home/eve/Downloads/llvm-project/build2/bin/clang-19+0xe34338)
#25 0x000055fc37b2b8d7 main (/home/eve/Downloads/llvm-project/build2/bin/clang-19+0xe428d7)
#26 0x00007f7639a28150 __libc_start_call_main ./csu/../sysdeps/nptl/libc_start_call_main.h:74:3
#27 0x00007f7639a28209 call_init ./csu/../csu/libc-start.c:128:20
#28 0x00007f7639a28209 __libc_start_main ./csu/../csu/libc-start.c:347:5
#29 0x000055fc37b1a4b5 _start (/home/eve/Downloads/llvm-project/build2/bin/clang-19+0xe314b5)
clang: error: clang frontend command failed with exit code 139 (use -v to see invocation)
clang version 19.0.0git (https://github.com/llvm/llvm-project.git 3bdc4c702dfdd1f2fb513943f034d49bb79ded29)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /home/eve/Downloads/llvm-project/build2/bin
clang: note: diagnostic msg:
********************

PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT:
Preprocessed source(s) and associated run script(s) are located at:
clang: note: diagnostic msg: /tmp/vsprintf-e230c3.c
clang: note: diagnostic msg: /tmp/vsprintf-e230c3.sh
clang: note: diagnostic msg:

********************

```
[vsprintf-e230c3.zip](https://github.com/llvm/llvm-project/files/14254556/vsprintf-e230c3.zip)

This issue occurs at commit:
```
commit 3bdc4c702dfdd1f2fb513943f034d49bb79ded29 (HEAD -> main, origin/main, origin/HEAD)
Author: Kevin Frei <kevinfrei@users.noreply.github.com>
Date:   Mon Feb 12 16:57:02 2024 -0800
```

This issue does not occur at commit:
```
commit 63b414e4977d6e19f05947c88f57cd127fa328e3
Author: Vlad Serebrennikov <serebrennikov.vladislav@gmail.com>
Date:   Sun Feb 11 15:01:18 2024 +0300
```
Edit: this issue also occurs at commit:
```
commit 13d60ce2f262ef9055389908b63824e53b3054a1 (HEAD)
Author: Amir Ayupov <aaupov@fb.com>
Date:   Mon Feb 12 14:51:15 2024 -0800
```
This issue does not occur at commit:
```
commit f5fd0deb2371d0bae3bef2563f50e005a140fc6d (HEAD)
Author: Joseph Huber <huberjn@outlook.com>
Date:   Mon Feb 12 08:14:54 2024 -0600
```

CC'ing @nathanchance for awareness.

Caused by 5c9f7682b090124d9a8b69f92d3f7c269dca25fc, which was reverted in bc66e0cf9feb8f3c38fa2e33850b6c6e5477fb21 and forward fixed by 97088b2ab2184ad4bd64f59fba0b92b70468b10d. I can confirm that there is no crash at 5e3c7e3aa48356a62a4b70d5d9d3e4ddd055a390.


commit d65ff3e9364536f9e0bd5f1c1bace626c256a2ad
Author: Alexey Bataev <a.bataev@outlook.com>
Date:   Wed Sep 4 05:12:17 2024 -0700

    [SLP]Fix PR107198: add a check for empty complex type

    Need to check if the complex type is empty before trying to dig in,
    trying to find vectorizable type

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

diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index 19b95cf473e9..a2af7f4e1b01 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -7780,6 +7780,8 @@ unsigned BoUpSLP::canMapToVector(Type *T) const {
   Type *EltTy = T;

   while (isa<StructType, ArrayType, FixedVectorType>(EltTy)) {
+    if (EltTy->isEmptyTy())
+      return 0;
     if (auto *ST = dyn_cast<StructType>(EltTy)) {
       // Check that struct is homogeneous.
       for (const auto *Ty : ST->elements())

Crash on slp-vectorizer

When running `/opt/llvm-19/bin/opt -O3 -S bug.ll` opt crashes with the following:

(tested on 19 rc2 and rc4 and 18)
```
/opt/llvm-19/bin/llvm-config --version
19.1.0-rc2

/opt/llvm-19/bin/opt: WARNING: failed to create target machine for 'arm64-apple-darwin23.6.0': unable to get target for 'arm64-apple-darwin23.6.0', see --version and --triple.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:
0.	Program arguments: /opt/llvm-19/bin/opt -O3 -S bug.ll
1.	Running pass "function<eager-inv>(float2int,lower-constant-intrinsics,chr,loop(loop-rotate<header-duplication;no-prepare-for-lto>,loop-deletion),loop-distribute,inject-tli-mappings,loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>,infer-alignment,loop-load-elim,instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,simplifycfg<bonus-inst-threshold=1;forward-switch-cond;switch-range-to-icmp;switch-to-lookup;no-keep-loops;hoist-common-insts;sink-common-insts;speculate-blocks;simplify-cond-branch;no-speculate-unpredictables>,slp-vectorizer,vector-combine,instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,loop-unroll<O3>,transform-warning,sroa<preserve-cfg>,infer-alignment,instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,loop-mssa(licm<allowspeculation>),alignment-from-assumptions,loop-sink,instsimplify,div-rem-pairs,tailcallelim,simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch;speculate-unpredictables>)" on module "lol.ll"
2.	Running pass "slp-vectorizer" on function "bug"
 #0 0x00005558779163f7 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) /home/admin/repos/llvm-project/llvm/lib/Support/Unix/Signals.inc:723:13
 #1 0x0000555877914570 llvm::sys::RunSignalHandlers() /home/admin/repos/llvm-project/llvm/lib/Support/Signals.cpp:106:18
 #2 0x0000555877916d9a SignalHandler(int) /home/admin/repos/llvm-project/llvm/lib/Support/Unix/Signals.inc:413:1
 #3 0x00007fb7b7e5b050 (/lib/x86_64-linux-gnu/libc.so.6+0x3c050)
 #4 0x0000555878d08ae0 llvm::slpvectorizer::BoUpSLP::canMapToVector(llvm::Type*) const /home/admin/repos/llvm-project/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp:0:0
 #5 0x0000555878d3ca29 llvm::SLPVectorizerPass::vectorizeInsertValueInst(llvm::InsertValueInst*, llvm::BasicBlock*, llvm::slpvectorizer::BoUpSLP&, bool) /home/admin/repos/llvm-project/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp:18336:8
 #6 0x0000555878d3d459 llvm::SLPVectorizerPass::vectorizeInserts(llvm::SmallSetVector<llvm::Instruction*, 8u>&, llvm::BasicBlock*, llvm::slpvectorizer::BoUpSLP&) /home/admin/repos/llvm-project/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp:0:11
 #7 0x0000555878d3e35b llvm::SLPVectorizerPass::vectorizeChainsInBlock(llvm::BasicBlock*, llvm::slpvectorizer::BoUpSLP&)::$_172::operator()(bool) const /home/admin/repos/llvm-project/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp:18847:20
 #8 0x0000555878d34039 llvm::SLPVectorizerPass::vectorizeChainsInBlock(llvm::BasicBlock*, llvm::slpvectorizer::BoUpSLP&) /home/admin/repos/llvm-project/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp:18963:18
 #9 0x0000555878d31968 llvm::SLPVectorizerPass::runImpl(llvm::Function&, llvm::ScalarEvolution*, llvm::TargetTransformInfo*, llvm::TargetLibraryInfo*, llvm::AAResults*, llvm::LoopInfo*, llvm::DominatorTree*, llvm::AssumptionCache*, llvm::DemandedBits*, llvm::OptimizationRemarkEmitter*) /home/admin/repos/llvm-project/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp:15865:13
#10 0x0000555878d31431 llvm::SLPVectorizerPass::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) /home/admin/repos/llvm-project/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp:15796:18
#11 0x0000555878921dfd llvm::detail::PassModel<llvm::Function, llvm::SLPVectorizerPass, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) /home/admin/repos/llvm-project/llvm/include/llvm/IR/PassManagerInternal.h:90:5
#12 0x0000555877ab570d llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) /home/admin/repos/llvm-project/llvm/include/llvm/IR/PassManagerImpl.h:85:8
#13 0x00005558785d887d llvm::detail::PassModel<llvm::Function, llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) /home/admin/repos/llvm-project/llvm/include/llvm/IR/PassManagerInternal.h:90:5
#14 0x0000555877ab94f0 llvm::ModuleToFunctionPassAdaptor::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) /home/admin/repos/llvm-project/llvm/lib/IR/PassManager.cpp:129:23
#15 0x00005558785d86cd llvm::detail::PassModel<llvm::Module, llvm::ModuleToFunctionPassAdaptor, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) /home/admin/repos/llvm-project/llvm/include/llvm/IR/PassManagerInternal.h:90:5
#16 0x0000555877ab44ed llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) /home/admin/repos/llvm-project/llvm/include/llvm/IR/PassManagerImpl.h:85:8
#17 0x00005558788ca8c9 llvm::SmallPtrSetImplBase::isSmall() const /home/admin/repos/llvm-project/llvm/include/llvm/ADT/SmallPtrSet.h:197:33
#18 0x00005558788ca8c9 llvm::SmallPtrSetImplBase::~SmallPtrSetImplBase() /home/admin/repos/llvm-project/llvm/include/llvm/ADT/SmallPtrSet.h:84:10
#19 0x00005558788ca8c9 llvm::PreservedAnalyses::~PreservedAnalyses() /home/admin/repos/llvm-project/llvm/include/llvm/IR/Analysis.h:111:7
#20 0x00005558788ca8c9 llvm::runPassPipeline(llvm::StringRef, llvm::Module&, llvm::TargetMachine*, llvm::TargetLibraryInfoImpl*, llvm::ToolOutputFile*, llvm::ToolOutputFile*, llvm::ToolOutputFile*, llvm::StringRef, llvm::ArrayRef<llvm::PassPlugin>, llvm::ArrayRef<std::function<void (llvm::PassBuilder&)>>, llvm::opt_tool::OutputKind, llvm::opt_tool::VerifierKind, bool, bool, bool, bool, bool, bool, bool) /home/admin/repos/llvm-project/llvm/tools/opt/NewPMDriver.cpp:547:3
#21 0x00005558778e5779 optMain /home/admin/repos/llvm-project/llvm/tools/opt/optdriver.cpp:739:12
#22 0x00007fb7b7e4624a (/lib/x86_64-linux-gnu/libc.so.6+0x2724a)
#23 0x00007fb7b7e46305 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x27305)
#24 0x00005558778dfd21 _start (/opt/llvm-19/bin/opt+0xf17d21)
Segmentation fault
```

```llvmir
; ModuleID = 'LLVMDialectModule'
source_filename = "LLVMDialectModule"
target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
target triple = "arm64-apple-darwin23.6.0"

define { { {}, {}, {}, {}, {}, {}, {} } } @"bug"({ {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, { {}, {}, {}, {}, {}, {}, {} }, { {} } } %0) {
  %2 = extractvalue { {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, { {}, {}, {}, {}, {}, {}, {} }, { {} } } %0, 18
  %3 = insertvalue { { {}, {}, {}, {}, {}, {}, {} } } undef, { {}, {}, {}, {}, {}, {}, {} } %2, 0
  ret { { {}, {}, {}, {}, {}, {}, {} } } %3
}

!llvm.module.flags = !{!0}

!0 = !{i32 2, !"Debug Info Version", i32 3}
```

one question, will this be included in llvm 19?

Not sure, it is not an immediate regression from 18 to 19, and it is too late, I think, to include it into 19