commit 2a6b09e0d3d3c1a05d3d5165202a6e68900974b1
Author: Florian Hahn <flo@fhahn.com>
Date:   Fri Oct 18 19:12:39 2024 -0700

    [LV] Use type from InsertPos for cost computation of interleave groups.

    Previously the legacy cost model would pick the type for the cost
    computation depending on the order of the members in the input IR.
    This is incompatible with the VPlan-based cost model (independent of
    original IR order) and also doesn't match code-gen, which uses the type
    of the insert position.

    Update the legacy cost model to use the type (and address space) from
    the Group's insert position.

    This brings the legacy cost model in line with the legacy cost model and
    fixes a divergence between both models.

    Note that the X86 cost model seems to assign different costs to groups
    with i64 and double types. Added a TODO to check.

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

diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index 857efbdf687c..ce0903b838aa 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -5738,14 +5738,15 @@ LoopVectorizationCostModel::getGatherScatterCost(Instruction *I,
 InstructionCost
 LoopVectorizationCostModel::getInterleaveGroupCost(Instruction *I,
                                                    ElementCount VF) {
-  Type *ValTy = getLoadStoreType(I);
-  auto *VectorTy = cast<VectorType>(ToVectorTy(ValTy, VF));
-  unsigned AS = getLoadStoreAddressSpace(I);
-  enum TTI::TargetCostKind CostKind = TTI::TCK_RecipThroughput;
-
   const auto *Group = getInterleavedAccessGroup(I);
   assert(Group && "Fail to get an interleaved access group.");

+  Instruction *InsertPos = Group->getInsertPos();
+  Type *ValTy = getLoadStoreType(InsertPos);
+  auto *VectorTy = cast<VectorType>(ToVectorTy(ValTy, VF));
+  unsigned AS = getLoadStoreAddressSpace(InsertPos);
+  enum TTI::TargetCostKind CostKind = TTI::TCK_RecipThroughput;
+
   unsigned InterleaveFactor = Group->getFactor();
   auto *WideVecTy = VectorType::get(ValTy, VF * InterleaveFactor);

@@ -5760,8 +5761,9 @@ LoopVectorizationCostModel::getInterleaveGroupCost(Instruction *I,
       (Group->requiresScalarEpilogue() && !isScalarEpilogueAllowed()) ||
       (isa<StoreInst>(I) && (Group->getNumMembers() < Group->getFactor()));
   InstructionCost Cost = TTI.getInterleavedMemoryOpCost(
-      I->getOpcode(), WideVecTy, Group->getFactor(), Indices, Group->getAlign(),
-      AS, CostKind, Legal->isMaskRequired(I), UseMaskForGaps);
+      InsertPos->getOpcode(), WideVecTy, Group->getFactor(), Indices,
+      Group->getAlign(), AS, CostKind, Legal->isMaskRequired(I),
+      UseMaskForGaps);

   if (Group->isReverse()) {
     // TODO: Add support for reversed masked interleaved access.
diff --git a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
index f4a1f58debba..41f13cc2d9a9 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
@@ -2958,11 +2958,20 @@ void VPInterleaveRecipe::print(raw_ostream &O, const Twine &Indent,

 InstructionCost VPInterleaveRecipe::computeCost(ElementCount VF,
                                                 VPCostContext &Ctx) const {
-  Instruction *I = getInsertPos();
+  Instruction *InsertPos = getInsertPos();
+  // Find the VPValue index of the interleave group. We need to skip gaps.
+  unsigned InsertPosIdx = 0;
+  for (unsigned Idx = 0; IG->getFactor(); ++Idx)
+    if (auto *Member = IG->getMember(Idx)) {
+      if (Member == InsertPos)
+        break;
+      InsertPosIdx++;
+    }
   Type *ValTy = Ctx.Types.inferScalarType(
-      getNumDefinedValues() > 0 ? getVPValue(0) : getStoredValues()[0]);
+      getNumDefinedValues() > 0 ? getVPValue(InsertPosIdx)
+                                : getStoredValues()[InsertPosIdx]);
   auto *VectorTy = cast<VectorType>(ToVectorTy(ValTy, VF));
-  unsigned AS = getLoadStoreAddressSpace(I);
+  unsigned AS = getLoadStoreAddressSpace(InsertPos);
   enum TTI::TargetCostKind CostKind = TTI::TCK_RecipThroughput;

   unsigned InterleaveFactor = IG->getFactor();
@@ -2976,8 +2985,8 @@ InstructionCost VPInterleaveRecipe::computeCost(ElementCount VF,

   // Calculate the cost of the whole interleaved group.
   InstructionCost Cost = Ctx.TTI.getInterleavedMemoryOpCost(
-      I->getOpcode(), WideVecTy, IG->getFactor(), Indices, IG->getAlign(), AS,
-      CostKind, getMask(), NeedsMaskForGaps);
+      InsertPos->getOpcode(), WideVecTy, IG->getFactor(), Indices,
+      IG->getAlign(), AS, CostKind, getMask(), NeedsMaskForGaps);

   if (!IG->isReverse())
     return Cost;

target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.15.0"

define void @geps_feeding_interleave_groups_with_reuse(ptr %arg, i64 %arg1, ptr %arg2) #0 {
entry:
  br label %loop

loop:                                             ; preds = %loop, %entry
  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
  %shl.iv.5 = shl i64 %iv, 5
  %gep.1 = getelementptr i8, ptr %arg, i64 %shl.iv.5
  %add.5 = or disjoint i64 %shl.iv.5, 16
  %gep.2 = getelementptr i8, ptr %arg, i64 %add.5
  %shl.iv.4 = shl i64 %iv, 4
  %gep.3 = getelementptr i8, ptr %arg2, i64 %shl.iv.4
  %l.1 = load float, ptr %gep.1, align 4
  %l.2 = load float, ptr %gep.2, align 4
  %add.1 = fadd float %l.1, %l.2
  %mul.1 = fmul float %add.1, 0.000000e+00
  store float %mul.1, ptr %gep.3, align 4
  %gep.4 = getelementptr i8, ptr %gep.1, i64 4
  %l.3 = load float, ptr %gep.4, align 4
  %gep.5 = getelementptr i8, ptr %gep.2, i64 4
  %l.4 = load float, ptr %gep.5, align 4
  %add.2 = fadd float %l.3, %l.4
  %mul.2 = fmul float %add.2, 0.000000e+00
  %gep.6 = getelementptr i8, ptr %gep.3, i64 4
  store float %mul.2, ptr %gep.6, align 4
  %gep.7 = getelementptr i8, ptr %gep.1, i64 8
  %l.5 = load float, ptr %gep.7, align 4
  %gep.8 = getelementptr i8, ptr %gep.2, i64 8
  %l.6 = load float, ptr %gep.8, align 4
  %add.3 = fadd float %l.5, %l.6
  %mul.3 = fmul float %add.3, 0.000000e+00
  %gep.9 = getelementptr i8, ptr %gep.3, i64 8
  store float %mul.3, ptr %gep.9, align 4
  %i27 = getelementptr i8, ptr %gep.1, i64 12
  %l.7 = load float, ptr %i27, align 4
  %gep.10 = getelementptr i8, ptr %gep.2, i64 12
  %l.8 = load float, ptr %gep.10, align 4
  %add.4 = fadd float %l.7, %l.8
  %mul.4 = fmul float %add.4, 0.000000e+00
  %gep.11 = getelementptr i8, ptr %gep.3, i64 12
  store float %mul.4, ptr %gep.11, align 4
  %iv.next = add i64 %iv, 1
  %ec = icmp eq i64 %iv, %arg1
  br i1 %ec, label %exit, label %loop

exit:                                             ; preds = %loop
  ret void
}

attributes #0 = { "target-features"="+sse4.2" }

target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.15.0"

define void @geps_feeding_interleave_groups_with_reuse2(ptr %A, ptr %B, i64 %N) #0 {
entry:
  br label %loop

loop:                                             ; preds = %loop, %entry
  %iv = phi i64 [ 0, %entry ], [ %iv.next.7, %loop ]
  %shr.1 = lshr exact i64 %iv, 1
  %gep.B = getelementptr nusw i32, ptr %B, i64 %shr.1
  %l = load i32, ptr %gep.B, align 4
  %gep.A = getelementptr i32, ptr %A, i64 %iv
  store i32 %l, ptr %gep.A, align 4
  %iv.next = or disjoint i64 %iv, 1
  %gep.A.1 = getelementptr i32, ptr %A, i64 %iv.next
  store i32 0, ptr %gep.A.1, align 4
  %iv.next.1 = or disjoint i64 %iv, 2
  %shr.2 = lshr exact i64 %iv.next.1, 1
  %gep.B.2 = getelementptr i32, ptr %B, i64 %shr.2
  %0 = load i32, ptr %gep.B.2, align 4
  %gep.A.2 = getelementptr i32, ptr %A, i64 %iv.next.1
  store i32 %0, ptr %gep.A.2, align 4
  %iv.next.2 = or disjoint i64 %iv, 3
  %gep.A.3 = getelementptr i32, ptr %A, i64 %iv.next.2
  store i32 0, ptr %gep.A.3, align 4
  %iv.next.3 = or disjoint i64 %iv, 4
  %gep.B.4 = getelementptr i32, ptr %B, i64 %iv
  %1 = load i32, ptr %gep.B.4, align 4
  %gep.A.4 = getelementptr i32, ptr %A, i64 %iv.next.3
  store i32 %1, ptr %gep.A.4, align 4
  %iv.next.4 = or disjoint i64 %iv, 5
  %gep.A.5 = getelementptr i32, ptr %A, i64 %iv.next.4
  store i32 0, ptr %gep.A.5, align 4
  %iv.next.5 = or disjoint i64 %iv, 6
  %gep.A.6 = getelementptr i32, ptr %A, i64 %iv.next.5
  store i32 0, ptr %gep.A.6, align 4
  %iv.next.6 = or disjoint i64 %iv, 7
  %gep.A.7 = getelementptr i32, ptr %A, i64 %iv.next.6
  store i32 0, ptr %gep.A.7, align 4
  %iv.next.7 = add nuw nsw i64 %iv, 8
  %ec = icmp eq i64 %iv, %N
  br i1 %ec, label %exit, label %loop

exit:                                             ; preds = %loop
  ret void
}

attributes #0 = { "min-legal-vector-width"="0" "target-cpu"="cascadelake" }

target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.15.0"

define void @interleave_store_double_i64_2(ptr %dst) {
entry:
  br label %loop

loop:                                             ; preds = %loop, %entry
  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
  %gep.1 = getelementptr { i64, double }, ptr %dst, i64 %iv, i32 1
  store double 0.000000e+00, ptr %gep.1, align 8
  %gep.0 = getelementptr { i64, double }, ptr %dst, i64 %iv
  store i64 %iv, ptr %gep.0, align 8
  %iv.next = add i64 %iv, 1
  %ec = icmp eq i64 %iv, 1
  br i1 %ec, label %exit, label %loop

exit:                                             ; preds = %loop
  ret void
}

target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.15.0"

define void @interleave_store_i64_double(ptr %dst) {
entry:
  br label %loop

loop:                                             ; preds = %loop, %entry
  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
  %gep.0 = getelementptr { double, i64 }, ptr %dst, i64 %iv
  store double 0.000000e+00, ptr %gep.0, align 8
  %gep.1 = getelementptr { double, i64 }, ptr %dst, i64 %iv, i32 1
  store i64 %iv, ptr %gep.1, align 8
  %iv.next = add i64 %iv, 1
  %ec = icmp eq i64 %iv, 1
  br i1 %ec, label %exit, label %loop

exit:                                             ; preds = %loop
  ret void
}

target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.15.0"

define void @test_free_instructions_feeding_geps_for_interleave_groups(ptr noalias %p.invar, ptr noalias %dst.1, ptr noalias %dst.2) {
entry:
  br label %loop

loop:                                             ; preds = %loop, %entry
  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
  %l.0 = load float, ptr %p.invar, align 4
  %iv.mul = shl i64 %iv, 2
  %gep.dst.19 = getelementptr float, ptr %dst.1, i64 %iv.mul
  store float %l.0, ptr %gep.dst.19, align 4
  %l.1 = load float, ptr %p.invar, align 4
  %add.1 = or disjoint i64 %iv.mul, 1
  %gep.dst.119 = getelementptr float, ptr %dst.1, i64 %add.1
  store float %l.1, ptr %gep.dst.119, align 4
  %add.2 = or disjoint i64 %iv.mul, 2
  %gep.dst.129 = getelementptr float, ptr %dst.1, i64 %add.2
  store float 0.000000e+00, ptr %gep.dst.129, align 4
  %add.3 = or disjoint i64 %iv.mul, 3
  %gep.dst.140 = getelementptr float, ptr %dst.1, i64 %add.3
  store float 0.000000e+00, ptr %gep.dst.140, align 4
  %l.2 = load float, ptr %p.invar, align 4
  %gep.dst.247 = getelementptr float, ptr %dst.2, i64 %iv.mul
  store float %l.2, ptr %gep.dst.247, align 4
  %gep.dst.255 = getelementptr float, ptr %dst.2, i64 %add.1
  store float 0.000000e+00, ptr %gep.dst.255, align 4
  %gep.dst.265 = getelementptr float, ptr %dst.2, i64 %add.2
  store float 0.000000e+00, ptr %gep.dst.265, align 4
  %gep.dst.276 = getelementptr float, ptr %dst.2, i64 %add.3
  store float 0.000000e+00, ptr %gep.dst.276, align 4
  %iv.next = add i64 %iv, 1
  %ec = icmp eq i64 %iv.next, 0
  br i1 %ec, label %exit, label %loop

exit:                                             ; preds = %loop
  ret void
}

target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.15.0"

define void @interleave_store_double_i64(ptr %dst) {
entry:
  br label %loop

loop:                                             ; preds = %loop, %entry
  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
  %gep.1 = getelementptr { double, i64 }, ptr %dst, i64 %iv, i32 1
  store i64 %iv, ptr %gep.1, align 8
  %gep.0 = getelementptr { double, i64 }, ptr %dst, i64 %iv
  store double 0.000000e+00, ptr %gep.0, align 8
  %iv.next = add i64 %iv, 1
  %ec = icmp eq i64 %iv, 1
  br i1 %ec, label %exit, label %loop

exit:                                             ; preds = %loop
  ret void
}

target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.15.0"

define void @interleave_store_i64_double_2(ptr %dst) {
entry:
  br label %loop

loop:                                             ; preds = %loop, %entry
  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
  %gep.0 = getelementptr { i64, double }, ptr %dst, i64 %iv
  store i64 %iv, ptr %gep.0, align 8
  %gep.1 = getelementptr { i64, double }, ptr %dst, i64 %iv, i32 1
  store double 0.000000e+00, ptr %gep.1, align 8
  %iv.next = add i64 %iv, 1
  %ec = icmp eq i64 %iv, 1
  br i1 %ec, label %exit, label %loop

exit:                                             ; preds = %loop
  ret void
}

[clang] Assertion in `llvm::LoopVectorizationPlanner::computeBestVF()`

When building the METIS (v5.1.0) library (GKLib) an assertion is thrown during LoopVectorize. This error was introduced within the past few days (see git sha of broken and working versions below).

#### Error:
```shell
clang: /mnt/thera/cicd/actions_work/ActionsRunner/ActionsRunner/trunk_repos/llvm-project/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp:7457: llvm::VectorizationFactor llvm::LoopVectorizationPlanner::computeBestVF(): Assertion `(BestFactor.Width == LegacyVF.Width || planContainsAdditionalSimplifications(getPlanFor(BestFactor.Width), CostCtx, OrigLoop)) && " VPlan cost model and legacy cost model disagreed"' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace, preprocessed source, and associated run script.
Stack dump:
0.      Program arguments: /share/contrib-modules/Core/llvm/2024-10-16/bin/clang -I/home/bcornill/libraries/metis-5.1.0/GKlib/. -I/home/bcornill/libraries/metis-5.1.0/GKlib/test -DLINUX -D_FILE_OFFSET_BITS=64 -DNDEBUG -DNDEBUG2 -DHAVE_EXECINFO_H -DHAVE_GETLINE -O3 -MD -MT CMakeFiles/GKlib.dir/blas.c.o -MF CMakeFiles/GKlib.dir/blas.c.o.d -o CMakeFiles/GKlib.dir/blas.c.o -c /home/bcornill/libraries/metis-5.1.0/GKlib/blas.c
1.      <eof> parser at end of file
2.      Optimizer
3.      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-verify-fixpoint>,simplifycfg<bonus-inst-threshold=1;forward-switch-cond;switch-range-to-icmp;switch-to-lookup;no-keep-loops;hoist-common-insts;no-hoist-loads-stores-with-cond-faulting;sink-common-insts;speculate-blocks;simplify-cond-branch;no-speculate-unpredictables>,slp-vectorizer,vector-combine,instcombine<max-iterations=1;no-verify-fixpoint>,loop-unroll<O3>,transform-warning,sroa<preserve-cfg>,infer-alignment,instcombine<max-iterations=1;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;hoist-loads-stores-with-cond-faulting;no-sink-common-insts;speculate-blocks;simplify-cond-branch;speculate-unpredictables>)" on module "/home/bcornill/libraries/metis-5.1.0/GKlib/blas.c"
4.      Running pass "loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>" on function "gk_dargmax_n"
 #0 0x00007fa15911cc8b llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/share/contrib-modules/Core/llvm/2024-10-16_20.0-0/bin/../lib/libLLVMSupport.so.20.0git+0x1c2c8b)
 #1 0x00007fa15911a664 llvm::sys::CleanupOnSignal(unsigned long) (/share/contrib-modules/Core/llvm/2024-10-16_20.0-0/bin/../lib/libLLVMSupport.so.20.0git+0x1c0664)
 #2 0x00007fa1590227f8 CrashRecoverySignalHandler(int) CrashRecoveryContext.cpp:0:0
 #3 0x00007fa1615e0dd0 __restore_rt sigaction.c:0:0
 #4 0x00007fa15821e70f raise (/lib64/libc.so.6+0x3770f)
 #5 0x00007fa158208b25 abort (/lib64/libc.so.6+0x21b25)
 #6 0x00007fa1582089f9 _nl_load_domain.cold.0 loadmsgcat.c:0:0
 #7 0x00007fa158216cc6 .annobin___GI___assert_fail.end assert.c:0:0
 #8 0x00007fa15db3af1b llvm::LoopVectorizationPlanner::computeBestVF() (/share/contrib-modules/Core/llvm/2024-10-16_20.0-0/bin/../lib/libLLVMVectorize.so.20.0git+0xb5f1b)
 #9 0x00007fa15db52d46 llvm::LoopVectorizePass::processLoop(llvm::Loop*) (/share/contrib-modules/Core/llvm/2024-10-16_20.0-0/bin/../lib/libLLVMVectorize.so.20.0git+0xcdd46)
#10 0x00007fa15db55ed1 llvm::LoopVectorizePass::runImpl(llvm::Function&) (/share/contrib-modules/Core/llvm/2024-10-16_20.0-0/bin/../lib/libLLVMVectorize.so.20.0git+0xd0ed1)
#11 0x00007fa15db56517 llvm::LoopVectorizePass::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/share/contrib-modules/Core/llvm/2024-10-16_20.0-0/bin/../lib/libLLVMVectorize.so.20.0git+0xd1517)
#12 0x00007fa155d90a9e llvm::detail::PassModel<llvm::Function, llvm::LoopVectorizePass, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/share/contrib-modules/Core/llvm/2024-10-16_20.0-0/bin/../lib/../lib/libLLVMPasses.so.20.0git+0x76a9e)
#13 0x00007fa15998eab7 llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/share/contrib-modules/Core/llvm/2024-10-16_20.0-0/bin/../lib/libLLVMCore.so.20.0git+0x323ab7)
#14 0x00007fa16434e17e llvm::detail::PassModel<llvm::Function, llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/share/contrib-modules/Core/llvm/2024-10-16_20.0-0/bin/../lib/libLLVMX86CodeGen.so.20.0git+0xa917e)
#15 0x00007fa15998ce55 llvm::ModuleToFunctionPassAdaptor::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/share/contrib-modules/Core/llvm/2024-10-16_20.0-0/bin/../lib/libLLVMCore.so.20.0git+0x321e55)
#16 0x00007fa16434e56e llvm::detail::PassModel<llvm::Module, llvm::ModuleToFunctionPassAdaptor, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/share/contrib-modules/Core/llvm/2024-10-16_20.0-0/bin/../lib/libLLVMX86CodeGen.so.20.0git+0xa956e)
#17 0x00007fa15998d9bc llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/share/contrib-modules/Core/llvm/2024-10-16_20.0-0/bin/../lib/libLLVMCore.so.20.0git+0x3229bc)
#18 0x00007fa15faab288 (anonymous namespace)::EmitAssemblyHelper::RunOptimizationPipeline(clang::BackendAction, std::unique_ptr<llvm::raw_pwrite_stream, std::default_delete<llvm::raw_pwrite_stream>>&, std::unique_ptr<llvm::ToolOutputFile, std::default_delete<llvm::ToolOutputFile>>&, clang::BackendConsumer*) BackendUtil.cpp:0:0
#19 0x00007fa15faaeb9c 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*) (/share/contrib-modules/Core/llvm/2024-10-16_20.0-0/bin/../lib/libclangCodeGen.so.20.0git+0x111b9c)
#20 0x00007fa15ffdd293 clang::BackendConsumer::HandleTranslationUnit(clang::ASTContext&) (/share/contrib-modules/Core/llvm/2024-10-16_20.0-0/bin/../lib/libclangCodeGen.so.20.0git+0x640293)
#21 0x00007fa150c5592c clang::ParseAST(clang::Sema&, bool, bool) (/share/contrib-modules/Core/llvm/2024-10-16_20.0-0/bin/../lib/../lib/libclangParse.so.20.0git+0x3c92c)
#22 0x00007fa15d75dee9 clang::FrontendAction::Execute() (/share/contrib-modules/Core/llvm/2024-10-16_20.0-0/bin/../lib/libclangFrontend.so.20.0git+0x138ee9)
#23 0x00007fa15d6ceb05 clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) (/share/contrib-modules/Core/llvm/2024-10-16_20.0-0/bin/../lib/libclangFrontend.so.20.0git+0xa9b05)
#24 0x00007fa1613cad83 clang::ExecuteCompilerInvocation(clang::CompilerInstance*) (/share/contrib-modules/Core/llvm/2024-10-16_20.0-0/bin/../lib/libclangFrontendTool.so.20.0git+0x4d83)
#25 0x00000000004141c7 cc1_main(llvm::ArrayRef<char const*>, char const*, void*) (/share/contrib-modules/Core/llvm/2024-10-16/bin/clang+0x4141c7)
#26 0x000000000040b96a ExecuteCC1Tool(llvm::SmallVectorImpl<char const*>&, llvm::ToolContext const&) driver.cpp:0:0
#27 0x00007fa15d135049 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::'lambda'()>(long) Job.cpp:0:0
#28 0x00007fa159022cb4 llvm::CrashRecoveryContext::RunSafely(llvm::function_ref<void ()>) (/share/contrib-modules/Core/llvm/2024-10-16_20.0-0/bin/../lib/libLLVMSupport.so.20.0git+0xc8cb4)
#29 0x00007fa15d13589e clang::driver::CC1Command::Execute(llvm::ArrayRef<std::optional<llvm::StringRef>>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>*, bool*) const (.part.0) Job.cpp:0:0
#30 0x00007fa15d0f22fc clang::driver::Compilation::ExecuteCommand(clang::driver::Command const&, clang::driver::Command const*&, bool) const (/share/contrib-modules/Core/llvm/2024-10-16_20.0-0/bin/../lib/libclangDriver.so.20.0git+0x922fc)
#31 0x00007fa15d0f33fd clang::driver::Compilation::ExecuteJobs(clang::driver::JobList const&, llvm::SmallVectorImpl<std::pair<int, clang::driver::Command const*>>&, bool) const (/share/contrib-modules/Core/llvm/2024-10-16_20.0-0/bin/../lib/libclangDriver.so.20.0git+0x933fd)
#32 0x00007fa15d1039c4 clang::driver::Driver::ExecuteCompilation(clang::driver::Compilation&, llvm::SmallVectorImpl<std::pair<int, clang::driver::Command const*>>&) (/share/contrib-modules/Core/llvm/2024-10-16_20.0-0/bin/../lib/libclangDriver.so.20.0git+0xa39c4)
#33 0x0000000000410b5b clang_main(int, char**, llvm::ToolContext const&) (/share/contrib-modules/Core/llvm/2024-10-16/bin/clang+0x410b5b)
#34 0x000000000040b074 main (/share/contrib-modules/Core/llvm/2024-10-16/bin/clang+0x40b074)
#35 0x00007fa15820a6a3 __libc_start_main (/lib64/libc.so.6+0x236a3)
#36 0x000000000040b0be _start (/share/contrib-modules/Core/llvm/2024-10-16/bin/clang+0x40b0be)
clang: error: clang frontend command failed with exit code 134 (use -v to see invocation)
clang version 20.0.0git (https://github.com/llvm/llvm-project ae68d532f810e217c747b10b26aeea3bb84c3844)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /share/contrib-modules/Core/llvm/2024-10-16_20.0-0/bin
Build config: +assertions
Configuration file: /share/contrib-modules/Core/llvm/2024-10-16_20.0-0/bin/clang.cfg
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/blas-9fe25d.c
clang: note: diagnostic msg: /tmp/blas-9fe25d.sh
clang: note: diagnostic msg:

********************
```
#### Reproducer:
[gklib-blas.tar.gz](https://github.com/user-attachments/files/17437550/gklib-blas.tar.gz)

#### Broken Versions:
```shell
>> clang --version
clang version 20.0.0git (https://github.com/llvm/llvm-project ae68d532f810e217c747b10b26aeea3bb84c3844)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /share/contrib-modules/Core/llvm/2024-10-16_20.0-0/bin
Build config: +assertions
Configuration file: /share/contrib-modules/Core/llvm/2024-10-16_20.0-0/bin/clang.cfg

>> clang --version
clang version 20.0.0git (https://github.com/llvm/llvm-project af90e7c5161de9a36af768dd5c9d73464e0eed64)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /share/contrib-modules/Core/llvm/2024-10-18_20.0-0/bin
Build config: +assertions
Configuration file: /share/contrib-modules/Core/llvm/2024-10-18_20.0-0/bin/clang.cfg
```

#### Working version:
```shell
>> clang --version
clang version 20.0.0git (https://github.com/llvm/llvm-project 48deb3568eb2452ff385b04b8f71c34121f47387)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /share/contrib-modules/Core/llvm/2024-10-13_20.0-0/bin
Build config: +assertions
Configuration file: /share/contrib-modules/Core/llvm/2024-10-13_20.0-0/bin/clang.cfg
```

Thanks, taking a look!


commit 709abacdc350d63c61888607edb28ce272daa0a0
Author: Alexey Bataev <a.bataev@outlook.com>
Date:   Fri Oct 18 13:54:30 2024 -0700

    [SLP]Check that operand of abs does not overflow before making it part of minbitwidth transformation

    Need to check that the operand of the abs intrinsic can be safely
    truncated before making it part of the minbitwidth transformation.

    Fixes #112577

diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index e7b52fbdcc3b..e1aa6127ac03 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -17224,9 +17224,25 @@ bool BoUpSLP::collectValuesToDemote(
                 MaskedValueIsZero(I->getOperand(1), Mask, SimplifyQuery(*DL)));
       });
     };
+    auto AbsChecker = [&](unsigned BitWidth, unsigned OrigBitWidth) {
+      assert(BitWidth <= OrigBitWidth && "Unexpected bitwidths!");
+      return all_of(E.Scalars, [&](Value *V) {
+        auto *I = cast<Instruction>(V);
+        unsigned SignBits = OrigBitWidth - BitWidth;
+        APInt Mask = APInt::getBitsSetFrom(OrigBitWidth, BitWidth - 1);
+        unsigned Op0SignBits =
+            ComputeNumSignBits(I->getOperand(0), *DL, 0, AC, nullptr, DT);
+        return SignBits <= Op0SignBits &&
+               ((SignBits != Op0SignBits &&
+                 !isKnownNonNegative(I->getOperand(0), SimplifyQuery(*DL))) ||
+                MaskedValueIsZero(I->getOperand(0), Mask, SimplifyQuery(*DL)));
+      });
+    };
     if (ID != Intrinsic::abs) {
       Operands.push_back(getOperandEntry(&E, 1));
       CallChecker = CompChecker;
+    } else {
+      CallChecker = AbsChecker;
     }
     InstructionCost BestCost =
         std::numeric_limits<InstructionCost::CostType>::max();

define i32 @test(i32 %n) {
entry:
  %n1 = add i32 %n, 1
  %zn1 = zext nneg i32 %n1 to i64
  %m1 = mul nuw nsw i64 %zn1, 273837369
  %a1 = call i64 @llvm.abs.i64(i64 %m1, i1 true)
  %t1 = trunc i64 %a1 to i32
  %n2 = add i32 %n, 2
  %zn2 = zext nneg i32 %n2 to i64
  %m2 = mul nuw nsw i64 %zn2, 273837369
  %a2 = call i64 @llvm.abs.i64(i64 %m2, i1 true)
  %t2 = trunc i64 %a2 to i32
  %res1 = add i32 %t1, %t2
  ret i32 %res1
}

; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i64 @llvm.abs.i64(i64, i1 immarg) #0

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

[SLP] SLP Vectorizer miscompile from reducing abs bitwidth

Bisected miscompile to this change https://github.com/llvm/llvm-project/commit/4a1c53f9fabbc18d436dcd4d5b572b82656fbbf9

Reduced internal test to this example:
https://godbolt.org/z/njWYP9exd
```llvm
define dso_local noundef i32 @test(i32 %n) local_unnamed_addr #0 {
entry:
  %n1 = add i32 %n, 1
  %zn1 = zext nneg i32 %n1 to i64
  %m1 = mul nuw nsw i64 %zn1, 273837369
  %a1 = call noundef i64 @llvm.abs.i64(i64 %m1, i1 true)
  %t1 = trunc i64 %a1 to i32
  %n2 = add i32 %n, 2
  %zn2 = zext nneg i32 %n2 to i64
  %m2 = mul nuw nsw i64 %zn2, 273837369
  %a2 = call noundef i64 @llvm.abs.i64(i64 %m2, i1 true)
  %t2 = trunc i64 %a2 to i32

  %res1 = add i32 %t1, %t2
  ret i32 %res1
}
```
Running slp vectorizer on it gives
```llvm
define dso_local noundef i32 @test(i32 %n) local_unnamed_addr {
  %0 = insertelement <2 x i32> poison, i32 %n, i32 0
  %1 = shufflevector <2 x i32> %0, <2 x i32> poison, <2 x i32> zeroinitializer
  %2 = add <2 x i32> %1, <i32 1, i32 2>
  %3 = mul <2 x i32> %2, <i32 273837369, i32 273837369>
  %4 = call <2 x i32> @llvm.abs.v2i32(<2 x i32> %3, i1 false)
  %5 = extractelement <2 x i32> %4, i32 0
  %6 = extractelement <2 x i32> %4, i32 1
  %res1 = add i32 %5, %6
  ret i32 %res1
}
```
which is incorrect. Counterexample by alive2:
https://alive2.llvm.org/ce/z/cEcY-u

Do we plan on backporting this to 19.x @alexey-bataev


commit 34777c238b117b52dd41a9d12e8b54fb83677a12
Author: Florian Hahn <flo@fhahn.com>
Date:   Tue Apr 16 21:24:24 2024 +0100

    [VPlan] Don't mark VPBlendRecipe as phi-like.

    VPBlendRecipes don't get lowered to phis and usually do not appear at
    the beginning of blocks, due to their masks appearing before them.

    This effectively relaxes an over-eager verifier message.

    Fixes https://github.com/llvm/llvm-project/issues/88297.
    Fixes https://github.com/llvm/llvm-project/issues/88804.

diff --git a/llvm/lib/Transforms/Vectorize/VPlanValue.h b/llvm/lib/Transforms/Vectorize/VPlanValue.h
index da3a768552fc..3f8d4f4fe7d6 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanValue.h
+++ b/llvm/lib/Transforms/Vectorize/VPlanValue.h
@@ -361,8 +361,8 @@ public:
     VPWidenMemoryInstructionSC,
     VPWidenSC,
     VPWidenSelectSC,
-    // START: Phi-like recipes. Need to be kept together.
     VPBlendSC,
+    // START: Phi-like recipes. Need to be kept together.
     VPWidenPHISC,
     VPPredInstPHISC,
     // START: SubclassID for recipes that inherit VPHeaderPHIRecipe.
@@ -376,7 +376,7 @@ public:
     VPReductionPHISC,
     // END: SubclassID for recipes that inherit VPHeaderPHIRecipe
     // END: Phi-like recipes
-    VPFirstPHISC = VPBlendSC,
+    VPFirstPHISC = VPWidenPHISC,
     VPFirstHeaderPHISC = VPCanonicalIVPHISC,
     VPLastHeaderPHISC = VPReductionPHISC,
     VPLastPHISC = VPReductionPHISC,

opt -p loop-vectorize -force-vector-width=4 -force-vector-interleave=1 -S %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-ni:1-p2:32:8:8:32-ni:2"

; Test with blend recipe in header VPBB, from
; https://github.com/llvm/llvm-project/issues/88297.
define i64 @pr88297() {
;
entry:
  br label %loop.header

loop.header:
  %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
  br i1 false, label %loop.latch, label %then

then:
  br label %loop.latch

loop.latch:
  %r = phi i64 [ 1, %then ], [ 0, %loop.header ]
  %iv.next = add i32 %iv, 1
  %icmp = icmp sgt i32 %iv, 1000
  br i1 %icmp, label %exit, label %loop.header

exit:
  %r.lcssa = phi i64 [ %r, %loop.latch ]
  ret i64 %r.lcssa
}

define i64 @pr88297_incoming_ops_reordered() {
;
entry:
  br label %loop.header

loop.header:
  %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
  br i1 false, label %loop.latch, label %then

then:
  br label %loop.latch

loop.latch:
  %r = phi i64 [ 0, %loop.header ], [ 1, %then ]
  %iv.next = add i32 %iv, 1
  %icmp = icmp sgt i32 %iv, 1000
  br i1 %icmp, label %exit, label %loop.header

exit:
  %r.lcssa = phi i64 [ %r, %loop.latch ]
  ret i64 %r.lcssa
}

define i64 @invar_cond(i1 %c) {
;
entry:
  br label %loop.header

loop.header:
  %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
  br i1 %c, label %loop.latch, label %then

then:
  br label %loop.latch

loop.latch:
  %r = phi i64 [ 1, %then ], [ 0, %loop.header ]
  %iv.next = add i32 %iv, 1
  %icmp = icmp sgt i32 %iv, 1000
  br i1 %icmp, label %exit, label %loop.header

exit:
  %r.lcssa = phi i64 [ %r, %loop.latch ]
  ret i64 %r.lcssa
}

define i64 @invar_cond_incoming_ops_reordered(i1 %c) {
;
entry:
  br label %loop.header

loop.header:
  %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
  br i1 %c, label %loop.latch, label %then

then:
  br label %loop.latch

loop.latch:
  %r = phi i64 [ 0, %loop.header ], [ 1, %then ]
  %iv.next = add i32 %iv, 1
  %icmp = icmp sgt i32 %iv, 1000
  br i1 %icmp, label %exit, label %loop.header

exit:
  %r.lcssa = phi i64 [ %r, %loop.latch ]
  ret i64 %r.lcssa
}
;.
;.

The following test fails when run 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 void @wombat() gc "statepoint-example" {
bb:
  br label %bb1

bb1:                                              ; preds = %bb2, %bb
  %phi = phi i32 [ %add, %bb2 ], [ 0, %bb ]
  br i1 false, label %bb2, label %bb4

bb2:                                              ; preds = %bb4, %bb1
  %phi3 = phi i64 [ 1, %bb4 ], [ 0, %bb1 ]
  %add = add i32 %phi, 1
  %icmp = icmp sgt i32 %phi, 0
  br i1 %icmp, label %bb5, label %bb1

bb4:                                              ; preds = %bb1
  br label %bb2

bb5:                                              ; preds = %bb2
  %phi6 = phi i64 [ %phi3, %bb2 ]
  ret void
}
```
Reproducer https://godbolt.org/z/9YW1o7qo6
Stack dump:
```
Found non-header PHI recipe in header VPBB: BLEND ir<%phi3> = ir<1> ir<0>/ir<false>
opt: /root/llvm-project/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp:8555: void llvm::LoopVectorizationPlanner::buildVPlansWithVPRecipes(llvm::ElementCount, llvm::ElementCount): Assertion `verifyVPlanIsValid(*Plan) && "VPlan is invalid"' 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 loop-vectorize <source>
 #0 0x0000000004d05ee8 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4d05ee8)
 #1 0x0000000004d0363c SignalHandler(int) Signals.cpp:0:0
 #2 0x00007f7623242520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #3 0x00007f76232969fc pthread_kill (/lib/x86_64-linux-gnu/libc.so.6+0x969fc)
 #4 0x00007f7623242476 gsignal (/lib/x86_64-linux-gnu/libc.so.6+0x42476)
 #5 0x00007f76232287f3 abort (/lib/x86_64-linux-gnu/libc.so.6+0x287f3)
 #6 0x00007f762322871b (/lib/x86_64-linux-gnu/libc.so.6+0x2871b)
 #7 0x00007f7623239e96 (/lib/x86_64-linux-gnu/libc.so.6+0x39e96)
 #8 0x0000000003de70b8 llvm::LoopVectorizationPlanner::buildVPlansWithVPRecipes(llvm::ElementCount, llvm::ElementCount) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x3de70b8)
 #9 0x0000000003dee731 llvm::LoopVectorizationPlanner::plan(llvm::ElementCount, unsigned int) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x3dee731)
#10 0x0000000003df18fe llvm::LoopVectorizePass::processLoop(llvm::Loop*) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x3df18fe)
#11 0x0000000003df4c6d 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+0x3df4c6d)
#12 0x0000000003df5e7b llvm::LoopVectorizePass::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x3df5e7b)
#13 0x0000000002d67f0e 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+0x2d67f0e)
#14 0x0000000000db3554 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+0xdb3554)
#15 0x0000000004b1663e llvm::ModuleToFunctionPassAdaptor::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4b1663e)
#16 0x0000000000d97cce 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+0xd97cce)
#17 0x0000000004b1454c llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4b1454c)
#18 0x00000000008c74f2 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+0x8c74f2)
#19 0x00000000008bad45 optMain (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x8bad45)
#20 0x00007f7623229d90 (/lib/x86_64-linux-gnu/libc.so.6+0x29d90)
#21 0x00007f7623229e40 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e40)
#22 0x00000000008b1aee _start (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x8b1aee)
Program terminated with signal: SIGSEGV
Compiler returned: 139
```


commit fac46469977da9c4e9c6eeaac21103c971190577
Author: Yingwei Zheng <dtcxzyw2333@gmail.com>
Date:   Sat Jan 4 17:23:57 2025 +0800

    [InstCombine] Check no wrap flags before folding icmp of GEPs with same indices (#121628)

    Alive2: https://alive2.llvm.org/ce/z/Dr3Sbe
    Closes https://github.com/llvm/llvm-project/issues/121581.

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index d6fdade25559..8b23583c5106 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -747,6 +747,8 @@ Instruction *InstCombinerImpl::foldGEPICmp(GEPOperator *GEPLHS, Value *RHS,
                         ConstantExpr::getPointerBitCastOrAddrSpaceCast(
                             cast<Constant>(RHS), Base->getType()));
   } else if (GEPOperator *GEPRHS = dyn_cast<GEPOperator>(RHS)) {
+    GEPNoWrapFlags NW = GEPLHS->getNoWrapFlags() & GEPRHS->getNoWrapFlags();
+
     // If the base pointers are different, but the indices are the same, just
     // compare the base pointer.
     if (PtrBase != GEPRHS->getOperand(0)) {
@@ -764,7 +766,8 @@ Instruction *InstCombinerImpl::foldGEPICmp(GEPOperator *GEPLHS, Value *RHS,

       // If all indices are the same, just compare the base pointers.
       Type *BaseType = GEPLHS->getOperand(0)->getType();
-      if (IndicesTheSame && CmpInst::makeCmpResultType(BaseType) == I.getType())
+      if (IndicesTheSame &&
+          CmpInst::makeCmpResultType(BaseType) == I.getType() && CanFold(NW))
         return new ICmpInst(Cond, GEPLHS->getOperand(0), GEPRHS->getOperand(0));

       // If we're comparing GEPs with two base pointers that only differ in type
@@ -804,7 +807,6 @@ Instruction *InstCombinerImpl::foldGEPICmp(GEPOperator *GEPLHS, Value *RHS,
       return transformToIndexedCompare(GEPLHS, RHS, Cond, DL, *this);
     }

-    GEPNoWrapFlags NW = GEPLHS->getNoWrapFlags() & GEPRHS->getNoWrapFlags();
     if (GEPLHS->getNumOperands() == GEPRHS->getNumOperands() &&
         GEPLHS->getSourceElementType() == GEPRHS->getSourceElementType()) {
       // If the GEPs only differ by one index, compare it.

[InstCombine] Incorrect fold of the comparison of GEPs

Alive2: https://alive2.llvm.org/ce/z/HRsqeW
```
define i1 @test(ptr %x, ptr %y) {
  %gep1 = getelementptr i8, ptr %x, i32 1
  %gep2 = getelementptr i8, ptr %y, i32 1
  %cmp = icmp ult ptr %gep1, %gep2
  ret i1 %cmp
}
```
```

----------------------------------------
define i1 @test(ptr %x, ptr %y) {
#0:
  %gep1 = gep ptr %x, 1 x i32 1
  %gep2 = gep ptr %y, 1 x i32 1
  %cmp = icmp ult ptr %gep1, %gep2
  ret i1 %cmp
}
=>
define i1 @test(ptr %x, ptr %y) {
#0:
  %cmp = icmp ult ptr %x, %y
  ret i1 %cmp
}
Transformation doesn't verify!

ERROR: Value mismatch

Example:
ptr %x = pointer(non-local, block_id=0, offset=-1) / Address=#xf
ptr %y = null

Source:
ptr %gep1 = null
ptr %gep2 = pointer(non-local, block_id=0, offset=1) / Address=#x1
i1 %cmp = #x1 (1)

SOURCE MEMORY STATE
===================
NON-LOCAL BLOCKS:
Block 0 >	size: 0	align: 1	alloc type: 0	alive: false	address: 0
Block 1 >	size: 1	align: 2	alloc type: 0	alive: true	address: 2
Block 2 >	size: 0	align: 1	alloc type: 0	alive: true	address: 3

Target:
i1 %cmp = #x0 (0)
Source value: #x1 (1)
Target value: #x0 (0)

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


commit d3dad7a74be50d90754bf5c072e1a2330e92712c
Author: Yingwei Zheng <dtcxzyw2333@gmail.com>
Date:   Mon May 6 16:30:07 2024 +0800

    [InstCombine] Fix miscompilation caused by #90436 (#91133)

    Proof: https://alive2.llvm.org/ce/z/iRnJ4i

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

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index c60a290ce72e..7092fb5e509b 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -1510,6 +1510,7 @@ InstCombinerImpl::foldICmpTruncWithTruncOrExt(ICmpInst &Cmp,
       std::swap(X, Y);
       Pred = Cmp.getSwappedPredicate(Pred);
     }
+    YIsSExt = !(NoWrapFlags & TruncInst::NoUnsignedWrap);
   }
   // Try to match icmp (trunc nuw X), (zext Y)
   else if (!Cmp.isSigned() &&

define i1 @trunc_equality_both_sext(i32 %x, i8 %y) {
  %xt = trunc nuw nsw i32 %x to i16
  %ye = sext i8 %y to i16
  %c = icmp ne i16 %xt, %ye
  ret i1 %c
}

define i1 @test_slt_nuw(i32 %x, i16 %y) {
  %conv1 = trunc nuw nsw i32 %x to i8
  %conv2 = trunc nuw nsw i16 %y to i8
  %cond = icmp slt i8 %conv1, %conv2
  ret i1 %cond
}

define i1 @test_ult_nuw(i32 %x, i16 %y) {
  %conv1 = trunc nuw nsw i32 %x to i8
  %conv2 = trunc nuw nsw i16 %y to i8
  %cond = icmp ult i8 %conv1, %conv2
  ret i1 %cond
}

define i1 @test_eq1(i32 %x, i16 %y) {
  %conv1 = trunc nsw i32 %x to i8
  %conv2 = trunc nsw i16 %y to i8
  %cond = icmp eq i8 %conv1, %conv2
  ret i1 %cond
}

define i1 @test_eq2(i32 %x, i16 %y) {
  %conv1 = trunc nsw i32 %x to i8
  %conv2 = trunc nsw i16 %y to i8
  %cond = icmp eq i8 %conv2, %conv1
  ret i1 %cond
}

[InstCombine] Miscompilation which converts `icmp eq (trunc nsw i64 X), (trunc nsw i32 Y)` into `icmp eq (zext i32 Y), X`

Reduced test case: https://alive2.llvm.org/ce/z/MLgA5x
```
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 @src() {
entry:
  br label %for.cond

for.cond:                                         ; preds = %if.end, %entry
  %storemerge = phi i32 [ 3, %entry ], [ %dec, %if.end ]
  %h = phi i32 [ 1, %entry ], [ %hres, %if.end ]
  %e = phi i32 [ 0, %entry ], [ -1, %if.end ]
  %tobool.not = icmp eq i32 %storemerge, 0
  br i1 %tobool.not, label %for.end9, label %for.body

for.body:                                         ; preds = %for.cond
  %cmp = icmp eq i32 %h, 5
  %conv1 = zext i1 %cmp to i64
  %conv2 = sext i32 %e to i64
  %cond.i = call i64 @llvm.umax.i64(i64 %conv1, i64 %conv2)
  %conv3 = trunc nsw i64 %cond.i to i16
  %conv4 = trunc nsw i32 %e to i16
  %sub.i = sub i16 %conv3, %conv4
  %tobool6.not = icmp eq i16 %sub.i, 0
  br i1 %tobool6.not, label %if.end, label %if.then

if.then:                                          ; preds = %for.body
  br label %if.end

if.end:                                           ; preds = %if.then, %for.body
  %hres = phi i32 [ 0, %if.then ], [ %h, %for.body ]
  %dec = add nsw i32 %storemerge, -1
  br label %for.cond

for.end9:                                         ; preds = %for.cond
  ret i32 %h
}

define i32 @tgt() {
entry:
  br label %for.cond

for.cond:                                         ; preds = %if.end, %entry
  %storemerge = phi i32 [ 3, %entry ], [ %dec, %if.end ]
  %h = phi i32 [ 1, %entry ], [ %hres, %if.end ]
  %e = phi i32 [ 0, %entry ], [ -1, %if.end ]
  %tobool.not = icmp eq i32 %storemerge, 0
  br i1 %tobool.not, label %for.end9, label %for.body

for.body:                                         ; preds = %for.cond
  %cmp = icmp eq i32 %h, 5
  %conv1 = zext i1 %cmp to i64
  %conv2 = sext i32 %e to i64
  %cond.i = call i64 @llvm.umax.i64(i64 %conv1, i64 %conv2)
  %0 = zext i32 %e to i64
  %tobool6.not = icmp eq i64 %cond.i, %0
  br i1 %tobool6.not, label %if.end, label %if.then

if.then:                                          ; preds = %for.body
  br label %if.end

if.end:                                           ; preds = %if.then, %for.body
  %hres = phi i32 [ 0, %if.then ], [ %h, %for.body ]
  %dec = add nsw i32 %storemerge, -1
  br label %for.cond

for.end9:                                         ; preds = %for.cond
  ret i32 %h
}
```

llvm version: de9b386f84b58ad0ffc12e221bc6d9161ca5b62d

Reduced test case: https://alive2.llvm.org/ce/z/ndR8PQ
```
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 i1 @src(i64 %x, i32 %y) {
  %conv1 = trunc nsw i64 %x to i16
  %conv2 = trunc nsw i32 %y to i16
  %cond = icmp eq i16 %conv1, %conv2
  ret i1 %cond
}

define i1 @tgt(i64 %x, i32 %y) {
  %1 = zext i32 %y to i64
  %cond = icmp eq i64 %1, %x
  ret i1 %cond
}
```

It should be caused by https://github.com/llvm/llvm-project/pull/90436.

I will post a fix later. cc @nikic

POC without DataLayout:
```
define i1 @test_eq(i32 %x, i16 %y) {
  %conv1 = trunc nsw i32 %x to i8
  %conv2 = trunc nsw i16 %y to i8
  %cond = icmp eq i8 %conv1, %conv2
  ret i1 %cond
}

define i1 @test_ult(i32 %x, i16 %y) {
  %conv1 = trunc nsw i32 %x to i8
  %conv2 = trunc nsw i16 %y to i8
  %cond = icmp ult i8 %conv1, %conv2
  ret i1 %cond
}

define i1 @test_slt(i32 %x, i16 %y) {
  %conv1 = trunc nsw i32 %x to i8
  %conv2 = trunc nsw i16 %y to i8
  %cond = icmp slt i8 %conv1, %conv2
  ret i1 %cond
}
```


commit 66eedd1dd370d22ddf994540c20848618d64d1a6
Author: hanbeom <kese111@gmail.com>
Date:   Thu Jan 11 17:34:30 2024 +0900

    [InstCombine] Fix worklist management in select fold (#77738)

    `InstCombine` uses `Worklist` to manage change history. `setOperand`,
    which was previously used to change the `Select` Instruction, does not,
    so it is `run` twice, which causes an `LLVM ERROR`.

    This problem is resolved by changing `setOperand` to `replaceOperand` as
    the change history will be registered in the Worklist.

    Fixes #77553.

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index ab55f235920a..21bfc91148bf 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -1704,11 +1704,11 @@ Instruction *InstCombinerImpl::foldSelectInstWithICmp(SelectInst &SI,
   if (CmpRHS != CmpLHS && isa<Constant>(CmpRHS) && !isa<Constant>(CmpLHS)) {
     if (CmpLHS == TrueVal && Pred == ICmpInst::ICMP_EQ) {
       // Transform (X == C) ? X : Y -> (X == C) ? C : Y
-      SI.setOperand(1, CmpRHS);
+      replaceOperand(SI, 1, CmpRHS);
       Changed = true;
     } else if (CmpLHS == FalseVal && Pred == ICmpInst::ICMP_NE) {
       // Transform (X != C) ? Y : X -> (X != C) ? Y : C
-      SI.setOperand(2, CmpRHS);
+      replaceOperand(SI, 2, CmpRHS);
       Changed = true;
     }
   }

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

define i32 @src_select_xxory_eq0_xorxy_y(i32 %x, i32 %y) {
  %xor = xor i32 %x, %y
  %xor0 = icmp eq i32 %xor, 0
  %cond = select i1 %xor0, i32 %xor, i32 %y
  ret i32 %cond
}

LLVM ERROR while InstCombine

```
$ bllvm0/bin/clang --version
clang version 18.0.0git (git@github.com:ParkHanbum/llvm-project.git a9f39ff2b628e38826d5b95c1e8ae3cb7c692de9)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /home/m/bllvm0/bin
```
my clang version.

IR that caused the error
```
define i32 @no_trans_select_xor_eq0_xor_and(i32 %x, i32 %y) {
; CHECK-LABEL: @no_trans_select_xor_eq0_xor_and(
; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT:    [[XOR0:%.*]] = icmp eq i32 [[XOR]], 0
; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X]], [[Y]]
; CHECK-NEXT:    [[COND:%.*]] = select i1 [[XOR0]], i32 [[XOR]], i32 [[AND]]
; CHECK-NEXT:    ret i32 [[COND]]
;
  %xor = xor i32 %x, %y
  %xor0 = icmp eq i32 %xor, 0
  %and = and i32 %x, %y
  %cond = select i1 %xor0, i32 %xor, i32 %and
  ret i32 %cond
}
```

and Debug message :
```
$ bllvm0/bin/opt -passes=instcombine temp.ll -debug
INSTCOMBINE ITERATION #1 on no_trans_select_xor_eq0_xor_and
ADD:   ret i32 %cond
ADD:   %cond = select i1 %xor0, i32 %xor, i32 %and
ADD:   %and = and i32 %x, %y
ADD:   %xor0 = icmp eq i32 %xor, 0
ADD:   %xor = xor i32 %x, %y
IC: Visiting:   %xor = xor i32 %x, %y
IC: Visiting:   %xor0 = icmp eq i32 %xor, 0
IC: Visiting:   %and = and i32 %x, %y
IC: Visiting:   %cond = select i1 %xor0, i32 %xor, i32 %and
IC: Mod =   %cond = select i1 %xor0, i32 %xor, i32 %and
    New =   %cond = select i1 %xor0, i32 0, i32 %and
ADD:   %cond = select i1 %xor0, i32 0, i32 %and
IC: Visiting:   %cond = select i1 %xor0, i32 0, i32 %and
IC: Visiting:   ret i32 %cond

INSTCOMBINE ITERATION #2 on no_trans_select_xor_eq0_xor_and
ADD:   ret i32 %cond
ADD:   %cond = select i1 %xor0, i32 0, i32 %and
ADD:   %and = and i32 %x, %y
ADD:   %xor0 = icmp eq i32 %xor, 0
ADD:   %xor = xor i32 %x, %y
IC: Visiting:   %xor = xor i32 %x, %y
IC: Visiting:   %xor0 = icmp eq i32 %xor, 0
IC: Old =   %xor0 = icmp eq i32 %xor, 0
    New =   <badref> = icmp eq i32 %x, %y
ADD:   %xor0 = icmp eq i32 %x, %y
IC: ERASE   %1 = icmp eq i32 %xor, 0
ADD DEFERRED:   %xor = xor i32 %x, %y
IC: ERASE   %xor = xor i32 %x, %y
IC: Visiting:   %xor0 = icmp eq i32 %x, %y
IC: Visiting:   %and = and i32 %x, %y
IC: Visiting:   %cond = select i1 %xor0, i32 0, i32 %and
IC: Visiting:   ret i32 %cond
LLVM ERROR: Instruction Combining did not reach a fixpoint after 1 iterations

```

If time isn't tight, I'd like to take on this issue.

The problem is likely that https://github.com/llvm/llvm-project/blob/084f1c2ee074a5ac8186ea4b5b181b48bf4621b6/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp#L1704-L1714 calls setOperand() instead of replaceOperand().

@nikic can I try this?

Sure.


commit 27bf45aa36386136db179c494358670a994a98a5
Author: Yingwei Zheng <dtcxzyw2333@gmail.com>
Date:   Sun Nov 10 17:07:25 2024 +0800

    [InstCombine] Fix poison safety of folding shufflevector into select (#115483)

    We are allowed to fold shufflevector into select iff the condition is
    guaranteed not to be poison or the RHS is a poison.
    Alive2: https://alive2.llvm.org/ce/z/28zEWR

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

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineVectorOps.cpp b/llvm/lib/Transforms/InstCombine/InstCombineVectorOps.cpp
index 454fe5a91d37..ede89b099e8d 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineVectorOps.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineVectorOps.cpp
@@ -2904,7 +2904,9 @@ Instruction *InstCombinerImpl::visitShuffleVectorInst(ShuffleVectorInst &SVI) {
     if (auto *SI = dyn_cast<SelectInst>(LHS)) {
       // We cannot do this fold for elementwise select since ShuffleVector is
       // not elementwise.
-      if (SI->getCondition()->getType()->isIntegerTy()) {
+      if (SI->getCondition()->getType()->isIntegerTy() &&
+          (isa<PoisonValue>(RHS) ||
+           isGuaranteedNotToBePoison(SI->getCondition()))) {
         if (Instruction *I = FoldOpIntoSelect(SVI, SI))
           return I;
       }

define <4 x i8> @shuf_cmp_may_be_poison(<4 x i8> %x, <4 x i8> %y, i1 %cmp) {
  %sel = select i1 %cmp, <4 x i8> %y, <4 x i8> <i8 0, i8 poison, i8 0, i8 poison>
  %shuf = shufflevector <4 x i8> %sel, <4 x i8> <i8 poison, i8 1, i8 poison, i8 3>, <4 x i32> <i32 0, i32 5, i32 2, i32 7>
  ret <4 x i8> %shuf
}

[InstCombine] folded select produces different result on a blended vector

Alive2 report: https://alive2.llvm.org/ce/z/73v-ug

```llvm
----------------------------------------
define <4 x i8> @sel_shuf_commute3.2(<4 x i8> %x, <4 x i8> %y, i1 %cmp) {
#0:
  %blend = shufflevector <4 x i8> { 0, 0, 0, 0 }, <4 x i8> %y, 0, 5, 2, 3
  %r = select i1 %cmp, <4 x i8> %y, <4 x i8> %blend
  %#1 = select <4 x i1> { 0, 1, 0, 1 }, <4 x i8> { 0, 1, 2, 3 }, <4 x i8> %r
  ret <4 x i8> %#1
}
=>
define <4 x i8> @sel_shuf_commute3.2(<4 x i8> %x, <4 x i8> %y, i1 %cmp) {
#0:
  %#1 = shufflevector <4 x i8> %y, <4 x i8> { poison, 1, poison, 3 }, 0, 5, 2, 7
  %#2 = select i1 %cmp, <4 x i8> %#1, <4 x i8> { 0, 1, 0, 3 }
  ret <4 x i8> %#2
}
Transformation doesn't verify!

ERROR: Target is more poisonous than source

Example:
<4 x i8> %x = < poison, poison, poison, poison >
<4 x i8> %y = < poison, poison, poison, poison >
i1 %cmp = poison

Source:
<4 x i8> %blend = < #x00 (0), poison, #x00 (0), #x00 (0) >
<4 x i8> %r = < poison, poison, poison, poison >
<4 x i8> %#1 = < poison, #x01 (1), poison, #x03 (3) >

Target:
<4 x i8> %#1 = < poison, #x01 (1), poison, #x03 (3) >
<4 x i8> %#2 = < poison, poison, poison, poison >
Source value: < poison, #x01 (1), poison, #x03 (3) >
Target value: < poison, poison, poison, poison >

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


VPBlendRecipe clone getIncomingValue getMask getNumIncomingValues

commit c83698367125703827f1b739393f006c399cb213
Author: Florian Hahn <flo@fhahn.com>
Date:   Tue Apr 9 11:14:05 2024 +0100

    [VPlan] Remove unused first mask op from VPBlendRecipe. (#87770)

    VPBlendRecipe does not use the first mask operand. Removing it allows
    VPlan-based DCE to remove unused mask computations.

    This also fixes #87410, where unused Not VPInstructions are considered
    having only their first lane demanded, but some of their operands
    providing a vector value due to other users.

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

    PR: https://github.com/llvm/llvm-project/pull/87770

diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index fd54faf17ca3..5535cc55e932 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -8221,6 +8221,8 @@ VPBlendRecipe *VPRecipeBuilder::tryToBlend(PHINode *Phi,
   // builder. At this point we generate the predication tree. There may be
   // duplications since this is a simple recursive scan, but future
   // optimizations will clean it up.
+  // TODO: At the moment the first mask is always skipped, but it would be
+  // better to skip the most expensive mask.
   SmallVector<VPValue *, 2> OperandsWithMask;

   for (unsigned In = 0; In < NumIncoming; In++) {
@@ -8233,6 +8235,8 @@ VPBlendRecipe *VPRecipeBuilder::tryToBlend(PHINode *Phi,
              "Distinct incoming values with one having a full mask");
       break;
     }
+    if (In == 0)
+      continue;
     OperandsWithMask.push_back(EdgeMask);
   }
   return new VPBlendRecipe(Phi, OperandsWithMask);
diff --git a/llvm/lib/Transforms/Vectorize/VPlan.h b/llvm/lib/Transforms/Vectorize/VPlan.h
index 5f6334b974cf..5dc905a3c407 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.h
+++ b/llvm/lib/Transforms/Vectorize/VPlan.h
@@ -1932,14 +1932,12 @@ public:
 class VPBlendRecipe : public VPSingleDefRecipe {
 public:
   /// The blend operation is a User of the incoming values and of their
-  /// respective masks, ordered [I0, M0, I1, M1, ...]. Note that a single value
-  /// might be incoming with a full mask for which there is no VPValue.
+  /// respective masks, ordered [I0, I1, M1, I2, M2, ...]. Note that the first
+  /// incoming value does not have a mask associated.
   VPBlendRecipe(PHINode *Phi, ArrayRef<VPValue *> Operands)
       : VPSingleDefRecipe(VPDef::VPBlendSC, Operands, Phi, Phi->getDebugLoc()) {
-    assert(Operands.size() > 0 &&
-           ((Operands.size() == 1) || (Operands.size() % 2 == 0)) &&
-           "Expected either a single incoming value or a positive even number "
-           "of operands");
+    assert((Operands.size() + 1) % 2 == 0 &&
+           "Expected an odd number of operands");
   }

   VPRecipeBase *clone() override {
@@ -1949,15 +1947,20 @@ public:

   VP_CLASSOF_IMPL(VPDef::VPBlendSC)

-  /// Return the number of incoming values, taking into account that a single
+  /// Return the number of incoming values, taking into account that the first
   /// incoming value has no mask.
   unsigned getNumIncomingValues() const { return (getNumOperands() + 1) / 2; }

   /// Return incoming value number \p Idx.
-  VPValue *getIncomingValue(unsigned Idx) const { return getOperand(Idx * 2); }
+  VPValue *getIncomingValue(unsigned Idx) const {
+    return Idx == 0 ? getOperand(0) : getOperand(Idx * 2 - 1);
+  }

   /// Return mask number \p Idx.
-  VPValue *getMask(unsigned Idx) const { return getOperand(Idx * 2 + 1); }
+  VPValue *getMask(unsigned Idx) const {
+    assert(Idx > 0 && "First index has no mask associated.");
+    return getOperand(Idx * 2);
+  }

   /// Generate the phi/select nodes.
   void execute(VPTransformState &State) override;
diff --git a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
index 2438e4dae3eb..625319954e9b 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
@@ -1513,6 +1513,8 @@ void VPBlendRecipe::print(raw_ostream &O, const Twine &Indent,
     for (unsigned I = 0, E = getNumIncomingValues(); I < E; ++I) {
       O << " ";
       getIncomingValue(I)->printAsOperand(O, SlotTracker);
+      if (I == 0)
+        continue;
       O << "/";
       getMask(I)->printAsOperand(O, SlotTracker);
     }

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

define void @test_not_first_lane_only_constant(ptr %A, ptr noalias %B) {
entry:
  br label %loop.header

loop.header:                                      ; preds = %loop.latch, %entry
  %iv = phi i16 [ 0, %entry ], [ %iv.next, %loop.latch ]
  %gep.A = getelementptr inbounds i16, ptr %A, i16 %iv
  br i1 false, label %loop.latch, label %else.1

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

then.2:                                           ; preds = %else.1
  br label %else.2

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

loop.latch:                                       ; preds = %else.2, %loop.header
  %merge = phi ptr [ %B, %else.2 ], [ poison, %loop.header ]
  %l = load i16, ptr %merge, align 2
  %iv.next = add i16 %iv, 1
  store i16 %l, ptr %gep.A, align 2
  %c.2 = icmp eq i16 %iv.next, 1000
  br i1 %c.2, label %exit, label %loop.header

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

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

define void @test_not_first_lane_only_wide_compare(ptr %A, ptr noalias %B, i16 %x, i16 %y) {
entry:
  br label %loop.header

loop.header:                                      ; preds = %loop.latch, %entry
  %iv = phi i16 [ 0, %entry ], [ %iv.next, %loop.latch ]
  %gep.A = getelementptr inbounds i16, ptr %A, i16 %iv
  %l.0 = load i16, ptr %gep.A, align 2
  %c.0 = icmp ult i16 %l.0, %x
  br i1 %c.0, label %loop.latch, label %else.1

else.1:                                           ; preds = %loop.header
  %c.1 = icmp ult i16 %l.0, %y
  br i1 %c.1, label %then.2, label %else.2

then.2:                                           ; preds = %else.1
  br label %else.2

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

loop.latch:                                       ; preds = %else.2, %loop.header
  %merge = phi ptr [ %B, %else.2 ], [ poison, %loop.header ]
  %l = load i16, ptr %merge, align 2
  %iv.next = add i16 %iv, 1
  store i16 %l, ptr %gep.A, align 2
  %c.2 = icmp eq i16 %iv.next, 1000
  br i1 %c.2, label %exit, label %loop.header

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

[LoopVectorize][VPlan] Assertion "Trying to access a single scalar per part but has multiple scalars per part." failed.

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

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

for.body.i:                                       ; preds = %if.end.i, %entry
  %q.0139.i = phi i16 [ 0, %entry ], [ %add.i, %if.end.i ]
  %idxprom.i = sext i16 0 to i64
  br i1 false, label %if.end.i, label %if.then.i

if.then.i:                                        ; preds = %for.body.i
  br i1 false, label %cond.end41.i, label %cond.end41.i

cond.end41.i:                                     ; preds = %if.then.i, %if.then.i
  br label %if.end.i

if.end.i:                                         ; preds = %cond.end41.i, %for.body.i
  %.in.i = phi ptr [ null, %cond.end41.i ], [ poison, %for.body.i ]
  %0 = load i16, ptr %.in.i, align 2
  %add.i = add i16 %q.0139.i, 1
  %tobool.not.i = icmp eq i16 %add.i, 0
  br i1 %tobool.not.i, label %m.exit, label %for.body.i

m.exit:                                           ; preds = %if.end.i
  %.lcssa = phi i16 [ %0, %if.end.i ]
  ret i32 0
}

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

Backtrace:
```
opt: /scratch/tc-testing/tc-apr-2/llvm/llvm/lib/Transforms/Vectorize/VPlan.cpp:249: llvm::Value* llvm::VPTransformState::get(llvm::VPValue*, unsigned int, bool): Assertion `(VF.isScalar() || Def->isLiveIn() || (hasScalarValue(Def, VPIteration(Part, 0)) && Data.PerPartScalars[Def][Part].size() == 1)) && "Trying to access a single scalar per part but has multiple scalars " "per part."' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:
0.      Program arguments: /scratch/tc-testing/tc-apr-2/build-rv64gcv/build-llvm-linux/bin/opt --passes=loop-vectorize reduced.ll
 #0 0x00005ed60f56eb60 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/scratch/tc-testing/tc-apr-2/build-rv64gcv/build-llvm-linux/bin/opt+0x2d84b60)
 #1 0x00005ed60f56bf6f llvm::sys::RunSignalHandlers() (/scratch/tc-testing/tc-apr-2/build-rv64gcv/build-llvm-linux/bin/opt+0x2d81f6f)
 #2 0x00005ed60f56c0c5 SignalHandler(int) Signals.cpp:0:0
 #3 0x00007f973de42520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #4 0x00007f973de969fc __pthread_kill_implementation ./nptl/pthread_kill.c:44:76
 #5 0x00007f973de969fc __pthread_kill_internal ./nptl/pthread_kill.c:78:10
 #6 0x00007f973de969fc pthread_kill ./nptl/pthread_kill.c:89:10
 #7 0x00007f973de42476 gsignal ./signal/../sysdeps/posix/raise.c:27:6
 #8 0x00007f973de287f3 abort ./stdlib/abort.c:81:7
 #9 0x00007f973de2871b _nl_load_domain ./intl/loadmsgcat.c:1177:9
#10 0x00007f973de39e96 (/lib/x86_64-linux-gnu/libc.so.6+0x39e96)
#11 0x00005ed60e6cbb72 llvm::VPTransformState::get(llvm::VPValue*, unsigned int, bool) (/scratch/tc-testing/tc-apr-2/build-rv64gcv/build-llvm-linux/bin/opt+0x1ee1b72)
#12 0x00005ed60e6fa9a6 llvm::VPInstruction::generatePerPart(llvm::VPTransformState&, unsigned int) (/scratch/tc-testing/tc-apr-2/build-rv64gcv/build-llvm-linux/bin/opt+0x1f109a6)
#13 0x00005ed60e6fbbdf llvm::VPInstruction::execute(llvm::VPTransformState&) (/scratch/tc-testing/tc-apr-2/build-rv64gcv/build-llvm-linux/bin/opt+0x1f11bdf)
#14 0x00005ed60e6d74ff llvm::VPBasicBlock::execute(llvm::VPTransformState*) (/scratch/tc-testing/tc-apr-2/build-rv64gcv/build-llvm-linux/bin/opt+0x1eed4ff)
#15 0x00005ed60e6cd9e0 llvm::VPRegionBlock::execute(llvm::VPTransformState*) (/scratch/tc-testing/tc-apr-2/build-rv64gcv/build-llvm-linux/bin/opt+0x1ee39e0)
#16 0x00005ed60e6d90e6 llvm::VPlan::execute(llvm::VPTransformState*) (/scratch/tc-testing/tc-apr-2/build-rv64gcv/build-llvm-linux/bin/opt+0x1eef0e6)
#17 0x00005ed60e5d76f3 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*) (/scratch/tc-testing/tc-apr-2/build-rv64gcv/build-llvm-linux/bin/opt+0x1ded6f3)
#18 0x00005ed60e5e9718 llvm::LoopVectorizePass::processLoop(llvm::Loop*) (/scratch/tc-testing/tc-apr-2/build-rv64gcv/build-llvm-linux/bin/opt+0x1dff718)
#19 0x00005ed60e5eb73e 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-apr-2/build-rv64gcv/build-llvm-linux/bin/opt+0x1e0173e)
#20 0x00005ed60e5ec88d llvm::LoopVectorizePass::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/scratch/tc-testing/tc-apr-2/build-rv64gcv/build-llvm-linux/bin/opt+0x1e0288d)
#21 0x00005ed60d4f3276 llvm::detail::PassModel<llvm::Function, llvm::LoopVectorizePass, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/scratch/tc-testing/tc-apr-2/build-rv64gcv/build-llvm-linux/bin/opt+0xd09276)
#22 0x00005ed60f395141 llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/scratch/tc-testing/tc-apr-2/build-rv64gcv/build-llvm-linux/bin/opt+0x2bab141)
#23 0x00005ed60d4eabd6 llvm::detail::PassModel<llvm::Function, llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/scratch/tc-testing/tc-apr-2/build-rv64gcv/build-llvm-linux/bin/opt+0xd00bd6)
#24 0x00005ed60f393e3b llvm::ModuleToFunctionPassAdaptor::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/scratch/tc-testing/tc-apr-2/build-rv64gcv/build-llvm-linux/bin/opt+0x2ba9e3b)
#25 0x00005ed60d4f2dc6 llvm::detail::PassModel<llvm::Module, llvm::ModuleToFunctionPassAdaptor, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/scratch/tc-testing/tc-apr-2/build-rv64gcv/build-llvm-linux/bin/opt+0xd08dc6)
#26 0x00005ed60f391cb1 llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/scratch/tc-testing/tc-apr-2/build-rv64gcv/build-llvm-linux/bin/opt+0x2ba7cb1)
#27 0x00005ed60cd6cce5 llvm::runPassPipeline(llvm::StringRef, llvm::Module&, llvm::TargetMachine*, llvm::TargetLibraryInfoImpl*, llvm::ToolOutputFile*, llvm::ToolOutputFile*, llvm::ToolOutputFile*, llvm::StringRef, llvm::ArrayRef<llvm::PassPlugin>, llvm::ArrayRef<std::function<void (llvm::PassBuilder&)>>, llvm::opt_tool::OutputKind, llvm::opt_tool::VerifierKind, bool, bool, bool, bool, bool, bool, bool) (/scratch/tc-testing/tc-apr-2/build-rv64gcv/build-llvm-linux/bin/opt+0x582ce5)
#28 0x00005ed60cd5f316 optMain (/scratch/tc-testing/tc-apr-2/build-rv64gcv/build-llvm-linux/bin/opt+0x575316)
#29 0x00007f973de29d90 __libc_start_call_main ./csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#30 0x00007f973de29e40 call_init ./csu/../csu/libc-start.c:128:20
#31 0x00007f973de29e40 __libc_start_main ./csu/../csu/libc-start.c:379:5
#32 0x00005ed60cd54f95 _start (/scratch/tc-testing/tc-apr-2/build-rv64gcv/build-llvm-linux/bin/opt+0x56af95)
zsh: IOT instruction (core dumped)  /scratch/tc-testing/tc-apr-2/build-rv64gcv/build-llvm-linux/bin/opt
```
Godbolt: https://godbolt.org/z/jYWea8z4q

Found via fuzzer.


commit b8741cc185e89a95c9161218084f7c8b5578cf96
Author: Florian Hahn <flo@fhahn.com>
Date:   Fri Jul 19 10:33:07 2024 +0100

    [VPlan] Relax assertion retrieving a scalar from VPTransformState::get.

    The current assertion VPTransformState::get when retrieving a single
    scalar only does not account for cases where a def has multiple users,
    some demanding all scalar lanes, some demanding only a single scalar.

    For an example, see the modified test case. Relax the assertion by also
    allowing requesting scalar lanes only when the Def doesn't have only its
    first lane used.

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

diff --git a/llvm/lib/Transforms/Vectorize/VPlan.cpp b/llvm/lib/Transforms/Vectorize/VPlan.cpp
index 83a035fb4df8..58de6256900f 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlan.cpp
@@ -254,6 +254,7 @@ Value *VPTransformState::get(VPValue *Def, const VPIteration &Instance) {
 Value *VPTransformState::get(VPValue *Def, unsigned Part, bool NeedsScalar) {
   if (NeedsScalar) {
     assert((VF.isScalar() || Def->isLiveIn() || hasVectorValue(Def, Part) ||
+            !vputils::onlyFirstLaneUsed(Def) ||
             (hasScalarValue(Def, VPIteration(Part, 0)) &&
              Data.PerPartScalars[Def][Part].size() == 1)) &&
            "Trying to access a single scalar per part but has multiple scalars "

opt -p loop-vectorize -mtriple=s390x-unknown-linux -mcpu=z16 -S %s

target datalayout = "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64"

@src = external global [8 x i32], align 4

define void @test_scalar_iv_steps_used_by_replicate_and_first_lane_only_vpinst(ptr noalias %dst, ptr noalias %src.1) {
entry:
  br label %loop.header

loop.header:                                      ; preds = %loop.latch, %entry
  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ]
  %mul.iv = mul nsw i64 %iv, 4
  %gep.src.1 = getelementptr inbounds i8, ptr %src.1, i64 %mul.iv
  %l.1 = load i8, ptr %gep.src.1, align 1
  %c = icmp eq i8 %l.1, 0
  br i1 %c, label %then, label %loop.latch

then:                                             ; preds = %loop.header
  %iv.or = or disjoint i64 %iv, 4
  %gep.src = getelementptr inbounds [8 x i32], ptr @src, i64 0, i64 %iv.or
  %l.2 = load i32, ptr %gep.src, align 4
  store i32 %l.2, ptr %dst, align 4
  br label %loop.latch

loop.latch:                                       ; preds = %then, %loop.header
  %iv.next = add nuw nsw i64 %iv, 1
  %ec = icmp eq i64 %iv.next, 4
  br i1 %ec, label %exit, label %loop.header

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

LoopVectorizer asserts:  Assertion `(VF.isScalar() || Def->isLiveIn() || (hasScalarValue(Def, VPIteration(Part, 0)) && Data.PerPartScalars[Def][Part].size() == 1)) && "Trying to access a single scalar per part but has multiple scalars " "per part.

[tc_crash35_aftercreduce.ll.tar.gz](https://github.com/llvm/llvm-project/files/14988465/tc_crash35_aftercreduce.ll.tar.gz)

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

VPlan.cpp:253: llvm::Value* llvm::VPTransformState::get(llvm::VPValue*, unsigned int, bool): Assertion `(VF.isScalar() || Def->isLiveIn() || (hasScalarValue(Def, VPIteration(Part, 0)) && Data.PerPartScalars[Def][Part].size() == 1)) && "Trying to access a single scalar per part but has multiple scalars " "per part."' failed.

@fhahn

Should be fixed now, sorry for the delay @JonPsson1 !


commit 380beaec8633bad0148aec02f03a85d9a59b2a2d
Author: Gabriel Baraldi <baraldigabriel@gmail.com>
Date:   Tue Jul 2 09:15:51 2024 -0300

    Fix potential crash in SLPVectorizer caused by missing check (#95937)

    I'm not super familiar with this code, but it seems that we were just
    missing a check.

    The original code that triggered this did not have uselistorders but
    llvm-reduce created them and it reproduces the same issue in a way more
    compact way.

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

diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index c4876bb92a1c..868e9e2687f5 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -835,11 +835,11 @@ static InstructionsState getSameOpcode(ArrayRef<Value *> VL,
         auto *CallBase = cast<CallInst>(IBase);
         if (Call->getCalledFunction() != CallBase->getCalledFunction())
           return InstructionsState(VL[BaseIndex], nullptr, nullptr);
-        if (Call->hasOperandBundles() &&
+        if (Call->hasOperandBundles() && (!CallBase->hasOperandBundles() ||
             !std::equal(Call->op_begin() + Call->getBundleOperandsStartIndex(),
                         Call->op_begin() + Call->getBundleOperandsEndIndex(),
                         CallBase->op_begin() +
-                            CallBase->getBundleOperandsStartIndex()))
+                            CallBase->getBundleOperandsStartIndex())))
           return InstructionsState(VL[BaseIndex], nullptr, nullptr);
         Intrinsic::ID ID = getVectorIntrinsicIDForCall(Call, &TLI);
         if (ID != BaseID)

opt < %s -passes=slp-vectorizer -S -pass-remarks-missed=slp-vectorizer 2>&1

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

; This test has UB but the crash in #95016 only happens with it
define void @uselistorder_test() {
;
  %max1 = call double @llvm.maximum.f64(double 0.000000e+00, double 0.000000e+00) [ "a_list"(ptr null) ]
  %add1 = fadd double %max1, 0.000000e+00
  %mul1 = fmul double 0.000000e+00, %add1
  %mul2 = fmul double %mul1, 0.000000e+00
  %sel1 = select i1 false, double 0.000000e+00, double %mul2
  %max2 = call double @llvm.maximum.f64(double 0.000000e+00, double 0.000000e+00)
  %add2 = fadd double %max2, 0.000000e+00
  %mul3 = fmul double 0.000000e+00, %add2
  %mul4 = fmul double %mul3, 0.000000e+00
  %sel2 = select i1 false, double 0.000000e+00, double %mul4
  %mul5 = fmul double %sel2, 0.000000e+00
  %add3 = fadd double 0.000000e+00, %mul5
  %gep1 = getelementptr { double, [1 x [2 x double]] }, ptr null, i64 0, i32 1
  store double %add3, ptr %gep1, align 8
  %mul6 = fmul double %sel1, 0.000000e+00
  %add4 = fadd double %mul6, 0.000000e+00
  store double %add4, ptr null, align 8
  ret void
}

declare double @llvm.maximum.f64(double, double) #0

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

SLPVectorizer (hasOperandBundles() && "Don't call otherwise!") assertion trigger with verified module

SLPVectorize asserts while optimizing the following module
```llvm-ir
target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128-ni:10:11:12:13"
target triple = "arm64-apple-darwin23.5.0"

define swiftcc void @julia_multiparameter_a_res_17823() {
top:
  %0 = call double @llvm.maximum.f64(double 0.000000e+00, double 0.000000e+00) [ "jl_roots"(ptr null) ]
  %1 = fadd double %0, 0.000000e+00
  %2 = fmul double 0.000000e+00, %1
  %3 = fmul double %2, 0.000000e+00
  %4 = select i1 false, double 0.000000e+00, double %3
  %5 = call double @llvm.maximum.f64(double 0.000000e+00, double 0.000000e+00)
  %6 = fadd double %5, 0.000000e+00
  %7 = fmul double 0.000000e+00, %6
  %8 = fmul double %7, 0.000000e+00
  %9 = select i1 false, double 0.000000e+00, double %8
  %10 = fmul double %9, 0.000000e+00
  %11 = fadd double 0.000000e+00, %10
  %12 = getelementptr { double, [1 x [2 x double]] }, ptr null, i64 0, i32 1
  store double %11, ptr %12, align 8
  %13 = fmul double %4, 0.000000e+00
  %14 = fadd double %13, 0.000000e+00
  store double %14, ptr null, align 8
  ret void
}

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

; uselistorder directives
uselistorder ptr @llvm.maximum.f64, { 1, 0 }

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

This also seems to trigger on godbolt on whatever version of trunk they have there
https://godbolt.org/z/favErWG5K

stacktrace:
>  #0 0x0000000004e258c8 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4e258c8)
 #1 0x0000000004e2301c SignalHandler(int) Signals.cpp:0:0
 #2 0x00007c7148042520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #3 0x00007c71480969fc pthread_kill (/lib/x86_64-linux-gnu/libc.so.6+0x969fc)
 #4 0x00007c7148042476 gsignal (/lib/x86_64-linux-gnu/libc.so.6+0x42476)
 #5 0x00007c71480287f3 abort (/lib/x86_64-linux-gnu/libc.so.6+0x287f3)
 #6 0x00007c714802871b (/lib/x86_64-linux-gnu/libc.so.6+0x2871b)
 #7 0x00007c7148039e96 (/lib/x86_64-linux-gnu/libc.so.6+0x39e96)
 #8 0x0000000003ee5e8f (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x3ee5e8f)
 #9 0x0000000003f5e546 getSameOpcode(llvm::ArrayRef<llvm::Value*>, llvm::TargetLibraryInfo const&, unsigned int) (.constprop.1) SLPVectorizer.cpp:0:0
#10 0x0000000003f67928 llvm::slpvectorizer::BoUpSLP::LookAheadHeuristics::getShallowScore(llvm::Value*, llvm::Value*, llvm::Instruction*, llvm::Instruction*, llvm::ArrayRef<llvm::Value*>) const (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x3f67928)
#11 0x0000000003f67de0 llvm::slpvectorizer::BoUpSLP::LookAheadHeuristics::getScoreAtLevelRec(llvm::Value*, llvm::Value*, llvm::Instruction*, llvm::Instruction*, int, llvm::ArrayRef<llvm::Value*>) const (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x3f67de0)
#12 0x0000000003f6aaf5 llvm::slpvectorizer::BoUpSLP::VLOperands::getBestOperand(unsigned int, int, int, llvm::ArrayRef<llvm::slpvectorizer::BoUpSLP::VLOperands::ReorderingMode>, llvm::ArrayRef<llvm::Value*>) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x3f6aaf5)
#13 0x0000000003f6bfcb llvm::slpvectorizer::BoUpSLP::VLOperands::reorder() (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x3f6bfcb)
#14 0x0000000003f6c4f6 llvm::slpvectorizer::BoUpSLP::reorderInputsAccordingToOpcode(llvm::ArrayRef<llvm::Value*>, llvm::SmallVectorImpl<llvm::Value*>&, llvm::SmallVectorImpl<llvm::Value*>&, llvm::slpvectorizer::BoUpSLP const&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x3f6c4f6)
#15 0x0000000003f702f4 llvm::slpvectorizer::BoUpSLP::buildTree_rec(llvm::ArrayRef<llvm::Value*>, unsigned int, llvm::slpvectorizer::BoUpSLP::EdgeInfo const&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x3f702f4)
#16 0x0000000003f70392 llvm::slpvectorizer::BoUpSLP::buildTree_rec(llvm::ArrayRef<llvm::Value*>, unsigned int, llvm::slpvectorizer::BoUpSLP::EdgeInfo const&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x3f70392)
#17 0x0000000003f70362 llvm::slpvectorizer::BoUpSLP::buildTree_rec(llvm::ArrayRef<llvm::Value*>, unsigned int, llvm::slpvectorizer::BoUpSLP::EdgeInfo const&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x3f70362)
#18 0x0000000003f7022b llvm::slpvectorizer::BoUpSLP::buildTree_rec(llvm::ArrayRef<llvm::Value*>, unsigned int, llvm::slpvectorizer::BoUpSLP::EdgeInfo const&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x3f7022b)
#19 0x0000000003f70362 llvm::slpvectorizer::BoUpSLP::buildTree_rec(llvm::ArrayRef<llvm::Value*>, unsigned int, llvm::slpvectorizer::BoUpSLP::EdgeInfo const&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x3f70362)
#20 0x0000000003f70362 llvm::slpvectorizer::BoUpSLP::buildTree_rec(llvm::ArrayRef<llvm::Value*>, unsigned int, llvm::slpvectorizer::BoUpSLP::EdgeInfo const&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x3f70362)
#21 0x0000000003f6fe47 llvm::slpvectorizer::BoUpSLP::buildTree_rec(llvm::ArrayRef<llvm::Value*>, unsigned int, llvm::slpvectorizer::BoUpSLP::EdgeInfo const&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x3f6fe47)
#22 0x0000000003f71b59 llvm::slpvectorizer::BoUpSLP::buildTree(llvm::ArrayRef<llvm::Value*>) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x3f71b59)
#23 0x0000000003f94622 llvm::SLPVectorizerPass::vectorizeStoreChain(llvm::ArrayRef<llvm::Value*>, llvm::slpvectorizer::BoUpSLP&, unsigned int, unsigned int, unsigned int&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x3f94622)
#24 0x0000000003f95fb0 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
#25 0x0000000003f97e88 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>>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x3f97e88)
#26 0x0000000003f985b3 llvm::SLPVectorizerPass::vectorizeStoreChains(llvm::slpvectorizer::BoUpSLP&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x3f985b3)
#27 0x0000000003f9970f 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
#28 0x0000000003f9a163 llvm::SLPVectorizerPass::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x3f9a163)
#29 0x0000000002e1013e 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+0x2e1013e)
#30 0x0000000004c2e64c llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4c2e64c)
#31 0x0000000000db3bce 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+0xdb3bce)
#32 0x0000000004c2cf8e llvm::ModuleToFunctionPassAdaptor::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4c2cf8e)
#33 0x0000000000db563e 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+0xdb563e)
#34 0x0000000004c2ae9c llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4c2ae9c)
#35 0x00000000008d7b32 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+0x8d7b32)
#36 0x00000000008cacdc optMain (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x8cacdc)
#37 0x00007c7148029d90 (/lib/x86_64-linux-gnu/libc.so.6+0x29d90)
#38 0x00007c7148029e40 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e40)
#39 0x00000000008c212e _start (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x8c212e)


commit f9369cc602272796c15de1065a782f812e791df3
Author: Florian Hahn <flo@fhahn.com>
Date:   Mon Jan 6 22:40:41 2025 +0000

    [VPlan] Make sure last IV increment value is available if needed.

    Legalize extract-from-ends using uniform VPReplicateRecipe of wide
    inductions to use regular VPReplicateRecipe, so the correct end value
    is available.

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

diff --git a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
index 395287bde76f..3e3f5adf73a0 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
@@ -562,21 +562,63 @@ createScalarIVSteps(VPlan &Plan, InductionDescriptor::InductionKind Kind,
   return Builder.createScalarIVSteps(InductionOpcode, FPBinOp, BaseIV, Step);
 }

+static SmallVector<VPUser *> collectUsersRecursively(VPValue *V) {
+  SetVector<VPUser *> Users(V->user_begin(), V->user_end());
+  for (unsigned I = 0; I != Users.size(); ++I) {
+    VPRecipeBase *Cur = cast<VPRecipeBase>(Users[I]);
+    if (isa<VPHeaderPHIRecipe>(Cur))
+      continue;
+    for (VPValue *V : Cur->definedValues())
+      Users.insert(V->user_begin(), V->user_end());
+  }
+  return Users.takeVector();
+}
+
 /// Legalize VPWidenPointerInductionRecipe, by replacing it with a PtrAdd
 /// (IndStart, ScalarIVSteps (0, Step)) if only its scalar values are used, as
 /// VPWidenPointerInductionRecipe will generate vectors only. If some users
 /// require vectors while other require scalars, the scalar uses need to extract
 /// the scalars from the generated vectors (Note that this is different to how
-/// int/fp inductions are handled). Also optimize VPWidenIntOrFpInductionRecipe,
-/// if any of its users needs scalar values, by providing them scalar steps
-/// built on the canonical scalar IV and update the original IV's users. This is
-/// an optional optimization to reduce the needs of vector extracts.
+/// int/fp inductions are handled). Legalize extract-from-ends using uniform
+/// VPReplicateRecipe of wide inductions to use regular VPReplicateRecipe, so
+/// the correct end value is available. Also optimize
+/// VPWidenIntOrFpInductionRecipe, if any of its users needs scalar values, by
+/// providing them scalar steps built on the canonical scalar IV and update the
+/// original IV's users. This is an optional optimization to reduce the needs of
+/// vector extracts.
 static void legalizeAndOptimizeInductions(VPlan &Plan) {
+  using namespace llvm::VPlanPatternMatch;
   SmallVector<VPRecipeBase *> ToRemove;
   VPBasicBlock *HeaderVPBB = Plan.getVectorLoopRegion()->getEntryBasicBlock();
   bool HasOnlyVectorVFs = !Plan.hasVF(ElementCount::getFixed(1));
   VPBuilder Builder(HeaderVPBB, HeaderVPBB->getFirstNonPhi());
   for (VPRecipeBase &Phi : HeaderVPBB->phis()) {
+    auto *PhiR = dyn_cast<VPHeaderPHIRecipe>(&Phi);
+    if (!PhiR)
+      break;
+
+    // Check if any uniform VPReplicateRecipes using the phi recipe are used by
+    // ExtractFromEnd. Those must be replaced by a regular VPReplicateRecipe to
+    // ensure the final value is available.
+    // TODO: Remove once uniformity analysis is done on VPlan.
+    for (VPUser *U : collectUsersRecursively(PhiR)) {
+      auto *ExitIRI = dyn_cast<VPIRInstruction>(U);
+      VPValue *Op;
+      if (!ExitIRI || !match(ExitIRI->getOperand(0),
+                             m_VPInstruction<VPInstruction::ExtractFromEnd>(
+                                 m_VPValue(Op), m_VPValue())))
+        continue;
+      auto *RepR = dyn_cast<VPReplicateRecipe>(Op);
+      if (!RepR || !RepR->isUniform())
+        continue;
+      assert(!RepR->isPredicated() && "RepR must not be predicated");
+      Instruction *I = RepR->getUnderlyingInstr();
+      auto *Clone =
+          new VPReplicateRecipe(I, RepR->operands(), /*IsUniform*/ false);
+      Clone->insertAfter(RepR);
+      RepR->replaceAllUsesWith(Clone);
+    }
+
     // Replace wide pointer inductions which have only their scalars used by
     // PtrAdd(IndStart, ScalarIVSteps (0, Step)).
     if (auto *PtrIV = dyn_cast<VPWidenPointerInductionRecipe>(&Phi)) {
@@ -1086,18 +1128,6 @@ bool VPlanTransforms::adjustFixedOrderRecurrences(VPlan &Plan,
   return true;
 }

-static SmallVector<VPUser *> collectUsersRecursively(VPValue *V) {
-  SetVector<VPUser *> Users(V->user_begin(), V->user_end());
-  for (unsigned I = 0; I != Users.size(); ++I) {
-    VPRecipeBase *Cur = cast<VPRecipeBase>(Users[I]);
-    if (isa<VPHeaderPHIRecipe>(Cur))
-      continue;
-    for (VPValue *V : Cur->definedValues())
-      Users.insert(V->user_begin(), V->user_end());
-  }
-  return Users.takeVector();
-}
-
 void VPlanTransforms::clearReductionWrapFlags(VPlan &Plan) {
   for (VPRecipeBase &R :
        Plan.getVectorLoopRegion()->getEntryBasicBlock()->phis()) {

opt -S -passes=loop-vectorize -force-vector-interleave=1 -force-vector-width=2 < %s

opt -S -passes=loop-vectorize -force-vector-interleave=2 -force-vector-width=1 < %s

define i32 @test_iv_uniform_with_outside_use_scev_simplification(ptr %dst) {
entry:
  %step.1 = sext i8 0 to i32
  %step.2 = add nsw i32 %step.1, 1
  br label %loop

loop:                                             ; preds = %loop, %entry
  %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
  %gep.dst = getelementptr inbounds i16, ptr %dst, i32 %iv
  store i16 0, ptr %gep.dst, align 2
  %iv.next = add i32 %step.2, %iv
  %cmp.i = icmp slt i32 %iv.next, 8
  br i1 %cmp.i, label %loop, label %e.exit

e.exit:                                           ; preds = %loop
  %res = phi i32 [ %iv.next, %loop ]
  ret i32 %res
}

[clang] Miscompilation at -O2/3

This code prints 8 at `-O0/1` and prints 1 at `-O2/3`:

```c
int printf(const char *, ...);
static char a;
static char *b = &a;
static int c;
short d;
void e() {
  short f[8];
  char **g[] = {&b, &b};
  c = 0;
  for (; c < 8; c = 81 + 462704684 + *b - 462704765 + c + 1)
    f[c] = 0;
  d = f[5];
}
int main() {
  e();
  printf("%d\n", c);
}
```

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

Bisected to https://github.com/llvm/llvm-project/commit/df4a615c988f3ae56f7e68a7df86acb60f16493a, which was committed by @fhahn

Reduced testcase: https://alive2.llvm.org/ce/z/6Bg63G
```
; bin/opt -passes=loop-vectorize 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 i32 @src() {
entry:
  %f.i = alloca [8 x i16], align 16
  %conv.i = sext i8 0 to i32
  %invariant.op.i = add nsw i32 %conv.i, 1
  br label %for.body.i

for.body.i:                                       ; preds = %for.body.i, %entry
  %0 = phi i32 [ 0, %entry ], [ %add2.reass.i, %for.body.i ]
  %idxprom.i = sext i32 %0 to i64
  %arrayidx.i = getelementptr [8 x i16], ptr %f.i, i64 0, i64 %idxprom.i
  store i16 0, ptr %arrayidx.i, align 2
  %add2.reass.i = add i32 %invariant.op.i, %0
  %cmp.i = icmp slt i32 %add2.reass.i, 8
  br i1 %cmp.i, label %for.body.i, label %e.exit

e.exit:                                           ; preds = %for.body.i
  %add2.reass.i.lcssa = phi i32 [ %add2.reass.i, %for.body.i ]
  ret i32 %add2.reass.i.lcssa
}
```

Looking into it now, thanks

Thank God! clang19 works as expected.