commit 645fb04a3389e69801d401e669eae9ee42d70217
Author: Yingwei Zheng <dtcxzyw2333@gmail.com>
Date:   Sat Jun 8 22:28:56 2024 +0800

    [Reassociate] Use uint64_t for repeat count (#94232)

    This patch relands #91469 and uses `uint64_t` for repeat count to avoid
    a miscompilation caused by overflow
    https://github.com/llvm/llvm-project/pull/91469#discussion_r1623925158.

diff --git a/llvm/lib/Transforms/Scalar/Reassociate.cpp b/llvm/lib/Transforms/Scalar/Reassociate.cpp
index c73d7c8d83be..f36e21b296bd 100644
--- a/llvm/lib/Transforms/Scalar/Reassociate.cpp
+++ b/llvm/lib/Transforms/Scalar/Reassociate.cpp
@@ -302,98 +302,7 @@ static BinaryOperator *LowerNegateToMultiply(Instruction *Neg) {
   return Res;
 }

-/// Returns k such that lambda(2^Bitwidth) = 2^k, where lambda is the Carmichael
-/// function. This means that x^(2^k) === 1 mod 2^Bitwidth for
-/// every odd x, i.e. x^(2^k) = 1 for every odd x in Bitwidth-bit arithmetic.
-/// Note that 0 <= k < Bitwidth, and if Bitwidth > 3 then x^(2^k) = 0 for every
-/// even x in Bitwidth-bit arithmetic.
-static unsigned CarmichaelShift(unsigned Bitwidth) {
-  if (Bitwidth < 3)
-    return Bitwidth - 1;
-  return Bitwidth - 2;
-}
-
-/// Add the extra weight 'RHS' to the existing weight 'LHS',
-/// reducing the combined weight using any special properties of the operation.
-/// The existing weight LHS represents the computation X op X op ... op X where
-/// X occurs LHS times.  The combined weight represents  X op X op ... op X with
-/// X occurring LHS + RHS times.  If op is "Xor" for example then the combined
-/// operation is equivalent to X if LHS + RHS is odd, or 0 if LHS + RHS is even;
-/// the routine returns 1 in LHS in the first case, and 0 in LHS in the second.
-static void IncorporateWeight(APInt &LHS, const APInt &RHS, unsigned Opcode) {
-  // If we were working with infinite precision arithmetic then the combined
-  // weight would be LHS + RHS.  But we are using finite precision arithmetic,
-  // and the APInt sum LHS + RHS may not be correct if it wraps (it is correct
-  // for nilpotent operations and addition, but not for idempotent operations
-  // and multiplication), so it is important to correctly reduce the combined
-  // weight back into range if wrapping would be wrong.
-
-  // If RHS is zero then the weight didn't change.
-  if (RHS.isMinValue())
-    return;
-  // If LHS is zero then the combined weight is RHS.
-  if (LHS.isMinValue()) {
-    LHS = RHS;
-    return;
-  }
-  // From this point on we know that neither LHS nor RHS is zero.
-
-  if (Instruction::isIdempotent(Opcode)) {
-    // Idempotent means X op X === X, so any non-zero weight is equivalent to a
-    // weight of 1.  Keeping weights at zero or one also means that wrapping is
-    // not a problem.
-    assert(LHS == 1 && RHS == 1 && "Weights not reduced!");
-    return; // Return a weight of 1.
-  }
-  if (Instruction::isNilpotent(Opcode)) {
-    // Nilpotent means X op X === 0, so reduce weights modulo 2.
-    assert(LHS == 1 && RHS == 1 && "Weights not reduced!");
-    LHS = 0; // 1 + 1 === 0 modulo 2.
-    return;
-  }
-  if (Opcode == Instruction::Add || Opcode == Instruction::FAdd) {
-    // TODO: Reduce the weight by exploiting nsw/nuw?
-    LHS += RHS;
-    return;
-  }
-
-  assert((Opcode == Instruction::Mul || Opcode == Instruction::FMul) &&
-         "Unknown associative operation!");
-  unsigned Bitwidth = LHS.getBitWidth();
-  // If CM is the Carmichael number then a weight W satisfying W >= CM+Bitwidth
-  // can be replaced with W-CM.  That's because x^W=x^(W-CM) for every Bitwidth
-  // bit number x, since either x is odd in which case x^CM = 1, or x is even in
-  // which case both x^W and x^(W - CM) are zero.  By subtracting off multiples
-  // of CM like this weights can always be reduced to the range [0, CM+Bitwidth)
-  // which by a happy accident means that they can always be represented using
-  // Bitwidth bits.
-  // TODO: Reduce the weight by exploiting nsw/nuw?  (Could do much better than
-  // the Carmichael number).
-  if (Bitwidth > 3) {
-    /// CM - The value of Carmichael's lambda function.
-    APInt CM = APInt::getOneBitSet(Bitwidth, CarmichaelShift(Bitwidth));
-    // Any weight W >= Threshold can be replaced with W - CM.
-    APInt Threshold = CM + Bitwidth;
-    assert(LHS.ult(Threshold) && RHS.ult(Threshold) && "Weights not reduced!");
-    // For Bitwidth 4 or more the following sum does not overflow.
-    LHS += RHS;
-    while (LHS.uge(Threshold))
-      LHS -= CM;
-  } else {
-    // To avoid problems with overflow do everything the same as above but using
-    // a larger type.
-    unsigned CM = 1U << CarmichaelShift(Bitwidth);
-    unsigned Threshold = CM + Bitwidth;
-    assert(LHS.getZExtValue() < Threshold && RHS.getZExtValue() < Threshold &&
-           "Weights not reduced!");
-    unsigned Total = LHS.getZExtValue() + RHS.getZExtValue();
-    while (Total >= Threshold)
-      Total -= CM;
-    LHS = Total;
-  }
-}
-
-using RepeatedValue = std::pair<Value*, APInt>;
+using RepeatedValue = std::pair<Value *, uint64_t>;

 /// Given an associative binary expression, return the leaf
 /// nodes in Ops along with their weights (how many times the leaf occurs).  The
@@ -475,7 +384,6 @@ static bool LinearizeExprTree(Instruction *I,
   assert((isa<UnaryOperator>(I) || isa<BinaryOperator>(I)) &&
          "Expected a UnaryOperator or BinaryOperator!");
   LLVM_DEBUG(dbgs() << "LINEARIZE: " << *I << '\n');
-  unsigned Bitwidth = I->getType()->getScalarType()->getPrimitiveSizeInBits();
   unsigned Opcode = I->getOpcode();
   assert(I->isAssociative() && I->isCommutative() &&
          "Expected an associative and commutative operation!");
@@ -490,8 +398,8 @@ static bool LinearizeExprTree(Instruction *I,
   // with their weights, representing a certain number of paths to the operator.
   // If an operator occurs in the worklist multiple times then we found multiple
   // ways to get to it.
-  SmallVector<std::pair<Instruction*, APInt>, 8> Worklist; // (Op, Weight)
-  Worklist.push_back(std::make_pair(I, APInt(Bitwidth, 1)));
+  SmallVector<std::pair<Instruction *, uint64_t>, 8> Worklist; // (Op, Weight)
+  Worklist.push_back(std::make_pair(I, 1));
   bool Changed = false;

   // Leaves of the expression are values that either aren't the right kind of
@@ -509,7 +417,7 @@ static bool LinearizeExprTree(Instruction *I,

   // Leaves - Keeps track of the set of putative leaves as well as the number of
   // paths to each leaf seen so far.
-  using LeafMap = DenseMap<Value *, APInt>;
+  using LeafMap = DenseMap<Value *, uint64_t>;
   LeafMap Leaves; // Leaf -> Total weight so far.
   SmallVector<Value *, 8> LeafOrder; // Ensure deterministic leaf output order.
   const DataLayout DL = I->getModule()->getDataLayout();
@@ -518,8 +426,8 @@ static bool LinearizeExprTree(Instruction *I,
   SmallPtrSet<Value *, 8> Visited; // For checking the iteration scheme.
 #endif
   while (!Worklist.empty()) {
-    std::pair<Instruction*, APInt> P = Worklist.pop_back_val();
-    I = P.first; // We examine the operands of this binary operator.
+    // We examine the operands of this binary operator.
+    auto [I, Weight] = Worklist.pop_back_val();

     if (isa<OverflowingBinaryOperator>(I)) {
       Flags.HasNUW &= I->hasNoUnsignedWrap();
@@ -528,7 +436,6 @@ static bool LinearizeExprTree(Instruction *I,

     for (unsigned OpIdx = 0; OpIdx < I->getNumOperands(); ++OpIdx) { // Visit operands.
       Value *Op = I->getOperand(OpIdx);
-      APInt Weight = P.second; // Number of paths to this operand.
       LLVM_DEBUG(dbgs() << "OPERAND: " << *Op << " (" << Weight << ")\n");
       assert(!Op->use_empty() && "No uses, so how did we get to it?!");

@@ -562,7 +469,8 @@ static bool LinearizeExprTree(Instruction *I,
                "In leaf map but not visited!");

         // Update the number of paths to the leaf.
-        IncorporateWeight(It->second, Weight, Opcode);
+        It->second += Weight;
+        assert(It->second >= Weight && "Weight overflows");

         // If we still have uses that are not accounted for by the expression
         // then it is not safe to modify the value.
@@ -625,10 +533,7 @@ static bool LinearizeExprTree(Instruction *I,
       // Node initially thought to be a leaf wasn't.
       continue;
     assert(!isReassociableOp(V, Opcode) && "Shouldn't be a leaf!");
-    APInt Weight = It->second;
-    if (Weight.isMinValue())
-      // Leaf already output or weight reduction eliminated it.
-      continue;
+    uint64_t Weight = It->second;
     // Ensure the leaf is only output once.
     It->second = 0;
     Ops.push_back(std::make_pair(V, Weight));
@@ -642,7 +547,7 @@ static bool LinearizeExprTree(Instruction *I,
   if (Ops.empty()) {
     Constant *Identity = ConstantExpr::getBinOpIdentity(Opcode, I->getType());
     assert(Identity && "Associative operation without identity!");
-    Ops.emplace_back(Identity, APInt(Bitwidth, 1));
+    Ops.emplace_back(Identity, 1);
   }

   return Changed;
@@ -1188,8 +1093,7 @@ Value *ReassociatePass::RemoveFactorFromExpression(Value *V, Value *Factor) {
   Factors.reserve(Tree.size());
   for (unsigned i = 0, e = Tree.size(); i != e; ++i) {
     RepeatedValue E = Tree[i];
-    Factors.append(E.second.getZExtValue(),
-                   ValueEntry(getRank(E.first), E.first));
+    Factors.append(E.second, ValueEntry(getRank(E.first), E.first));
   }

   bool FoundFactor = false;
@@ -2368,7 +2272,7 @@ void ReassociatePass::ReassociateExpression(BinaryOperator *I) {
   SmallVector<ValueEntry, 8> Ops;
   Ops.reserve(Tree.size());
   for (const RepeatedValue &E : Tree)
-    Ops.append(E.second.getZExtValue(), ValueEntry(getRank(E.first), E.first));
+    Ops.append(E.second, ValueEntry(getRank(E.first), E.first));

   LLVM_DEBUG(dbgs() << "RAIn:\t"; PrintOps(I, Ops); dbgs() << '\n');

define i4 @foo4x11(i4 %x) {
  %tmp1 = mul i4 %x, %x
  %tmp2 = mul i4 %tmp1, %x
  %tmp3 = mul i4 %tmp2, %x
  %tmp4 = mul i4 %tmp3, %x
  %tmp5 = mul i4 %tmp4, %x
  %tmp6 = mul i4 %tmp5, %x
  %tmp7 = mul i4 %tmp6, %x
  %tmp8 = mul i4 %tmp7, %x
  %tmp9 = mul i4 %tmp8, %x
  %tmp10 = mul i4 %tmp9, %x
  ret i4 %tmp10
}

define i3 @foo3x5_nsw(i3 %x) {
  %tmp1 = mul i3 %x, %x
  %tmp2 = mul i3 %tmp1, %x
  %tmp3 = mul i3 %tmp2, %x
  %tmp4 = mul nsw i3 %tmp3, %x
  ret i3 %tmp4
}

define i3 @foo3x5(i3 %x) {
  %tmp1 = mul i3 %x, %x
  %tmp2 = mul i3 %tmp1, %x
  %tmp3 = mul i3 %tmp2, %x
  %tmp4 = mul i3 %tmp3, %x
  ret i3 %tmp4
}

define i4 @foo4x10(i4 %x) {
  %tmp1 = mul i4 %x, %x
  %tmp2 = mul i4 %tmp1, %x
  %tmp3 = mul i4 %tmp2, %x
  %tmp4 = mul i4 %tmp3, %x
  %tmp5 = mul i4 %tmp4, %x
  %tmp6 = mul i4 %tmp5, %x
  %tmp7 = mul i4 %tmp6, %x
  %tmp8 = mul i4 %tmp7, %x
  %tmp9 = mul i4 %tmp8, %x
  ret i4 %tmp9
}

define i4 @foo4x13(i4 %x) {
  %tmp1 = mul i4 %x, %x
  %tmp2 = mul i4 %tmp1, %x
  %tmp3 = mul i4 %tmp2, %x
  %tmp4 = mul i4 %tmp3, %x
  %tmp5 = mul i4 %tmp4, %x
  %tmp6 = mul i4 %tmp5, %x
  %tmp7 = mul i4 %tmp6, %x
  %tmp8 = mul i4 %tmp7, %x
  %tmp9 = mul i4 %tmp8, %x
  %tmp10 = mul i4 %tmp9, %x
  %tmp11 = mul i4 %tmp10, %x
  %tmp12 = mul i4 %tmp11, %x
  ret i4 %tmp12
}

define i4 @foo4x8(i4 %x) {
  %tmp1 = mul i4 %x, %x
  %tmp2 = mul i4 %tmp1, %x
  %tmp3 = mul i4 %tmp2, %x
  %tmp4 = mul i4 %tmp3, %x
  %tmp5 = mul i4 %tmp4, %x
  %tmp6 = mul i4 %tmp5, %x
  %tmp7 = mul i4 %tmp6, %x
  ret i4 %tmp7
}

define i4 @foo4x12(i4 %x) {
  %tmp1 = mul i4 %x, %x
  %tmp2 = mul i4 %tmp1, %x
  %tmp3 = mul i4 %tmp2, %x
  %tmp4 = mul i4 %tmp3, %x
  %tmp5 = mul i4 %tmp4, %x
  %tmp6 = mul i4 %tmp5, %x
  %tmp7 = mul i4 %tmp6, %x
  %tmp8 = mul i4 %tmp7, %x
  %tmp9 = mul i4 %tmp8, %x
  %tmp10 = mul i4 %tmp9, %x
  %tmp11 = mul i4 %tmp10, %x
  ret i4 %tmp11
}

define i4 @foo4x15(i4 %x) {
  %tmp1 = mul i4 %x, %x
  %tmp2 = mul i4 %tmp1, %x
  %tmp3 = mul i4 %tmp2, %x
  %tmp4 = mul i4 %tmp3, %x
  %tmp5 = mul i4 %tmp4, %x
  %tmp6 = mul i4 %tmp5, %x
  %tmp7 = mul i4 %tmp6, %x
  %tmp8 = mul i4 %tmp7, %x
  %tmp9 = mul i4 %tmp8, %x
  %tmp10 = mul i4 %tmp9, %x
  %tmp11 = mul i4 %tmp10, %x
  %tmp12 = mul i4 %tmp11, %x
  %tmp13 = mul i4 %tmp12, %x
  %tmp14 = mul i4 %tmp13, %x
  ret i4 %tmp14
}

define i4 @foo4x9(i4 %x) {
  %tmp1 = mul i4 %x, %x
  %tmp2 = mul i4 %tmp1, %x
  %tmp3 = mul i4 %tmp2, %x
  %tmp4 = mul i4 %tmp3, %x
  %tmp5 = mul i4 %tmp4, %x
  %tmp6 = mul i4 %tmp5, %x
  %tmp7 = mul i4 %tmp6, %x
  %tmp8 = mul i4 %tmp7, %x
  ret i4 %tmp8
}

define i4 @foo4x14(i4 %x) {
  %tmp1 = mul i4 %x, %x
  %tmp2 = mul i4 %tmp1, %x
  %tmp3 = mul i4 %tmp2, %x
  %tmp4 = mul i4 %tmp3, %x
  %tmp5 = mul i4 %tmp4, %x
  %tmp6 = mul i4 %tmp5, %x
  %tmp7 = mul i4 %tmp6, %x
  %tmp8 = mul i4 %tmp7, %x
  %tmp9 = mul i4 %tmp8, %x
  %tmp10 = mul i4 %tmp9, %x
  %tmp11 = mul i4 %tmp10, %x
  %tmp12 = mul i4 %tmp11, %x
  %tmp13 = mul i4 %tmp12, %x
  ret i4 %tmp13
}

define i3 @foo3x6(i3 %x) {
  %tmp1 = mul i3 %x, %x
  %tmp2 = mul i3 %tmp1, %x
  %tmp3 = mul i3 %tmp2, %x
  %tmp4 = mul i3 %tmp3, %x
  %tmp5 = mul i3 %tmp4, %x
  ret i3 %tmp5
}

define i3 @foo3x7(i3 %x) {
  %tmp1 = mul i3 %x, %x
  %tmp2 = mul i3 %tmp1, %x
  %tmp3 = mul i3 %tmp2, %x
  %tmp4 = mul i3 %tmp3, %x
  %tmp5 = mul i3 %tmp4, %x
  %tmp6 = mul i3 %tmp5, %x
  ret i3 %tmp6
}

incorrect reassociation at low bitwidth

here's a function:
```llvm
define i3 @f(i3 %0) {
  %2 = mul i3 %0, %0
  %3 = mul i3 %2, %0
  %4 = mul i3 %3, %0
  %5 = mul nsw i3 %4, %0
  ret i3 %5
}
```

reassociate seems to be getting it wrong:
```
Johns-MacBook-Pro:reduce regehr$ ~/alive2-regehr/build/alive-tv reduced.ll -passes=reassociate

----------------------------------------
define i3 @f(i3 %#0) {
#1:
  %#2 = mul i3 %#0, %#0
  %#3 = mul i3 %#2, %#0
  %#4 = mul i3 %#3, %#0
  %#5 = mul nsw i3 %#4, %#0
  ret i3 %#5
}
=>
define i3 @f(i3 %#0) {
#1:
  %#2 = mul i3 %#0, %#0
  %#3 = mul nsw i3 %#2, %#0
  ret i3 %#3
}
Transformation doesn't verify!

ERROR: Target is more poisonous than source

Example:
i3 %#0 = #x6 (6, -2)

Source:
i3 %#2 = #x4 (4, -4)
i3 %#3 = #x0 (0)
i3 %#4 = #x0 (0)
i3 %#5 = #x0 (0)

Target:
i3 %#2 = #x4 (4, -4)
i3 %#3 = poison
Source value: #x0 (0)
Target value: poison

Summary:
  0 correct transformations
  1 incorrect transformations
  0 failed-to-prove transformations
  0 Alive2 errors
Johns-MacBook-Pro:reduce regehr$
```

cc @nunoplopes

Introduced by https://github.com/llvm/llvm-project/commit/d7aeefebd6b049f017711cd7c6ef5f217a17b673.


commit b72689a5cbd8645c183476cd87e32948308c5b64
Author: Florian Hahn <flo@fhahn.com>
Date:   Thu Jul 25 11:16:09 2024 +0100

    [LV] Ignore live-out users in cost model if scalar epilogue is required.

    Follow-up to ba8126b6fef79.

    If a scalar epilogue is required, users outside the loop won't use
    live-outs from the vector loop but from the scalar epilogue. Ignore them if
    that is the case.

    This fixes another case where the VPlan-based cost-model more accurately
    computes cost.

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

diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index b709ccc3c35a..224d98d5c4f9 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -6678,6 +6678,15 @@ void LoopVectorizationCostModel::collectValuesToIgnore() {

   SmallVector<Value *, 4> DeadInterleavePointerOps;
   SmallVector<Value *, 4> DeadOps;
+
+  // If a scalar epilogue is required, users outside the loop won't use
+  // live-outs from the vector loop but from the scalar epilogue. Ignore them if
+  // that is the case.
+  bool RequiresScalarEpilogue = requiresScalarEpilogue(true);
+  auto IsLiveOutDead = [this, RequiresScalarEpilogue](User *U) {
+    return RequiresScalarEpilogue &&
+           !TheLoop->contains(cast<Instruction>(U)->getParent());
+  };
   for (BasicBlock *BB : TheLoop->blocks())
     for (Instruction &I : *BB) {
       // Find all stores to invariant variables. Since they are going to sink
@@ -6693,8 +6702,9 @@ void LoopVectorizationCostModel::collectValuesToIgnore() {
       // Add instructions that would be trivially dead and are only used by
       // values already ignored to DeadOps to seed worklist.
       if (wouldInstructionBeTriviallyDead(&I, TLI) &&
-          all_of(I.users(), [this](User *U) {
-            return VecValuesToIgnore.contains(U) || ValuesToIgnore.contains(U);
+          all_of(I.users(), [this, IsLiveOutDead](User *U) {
+            return VecValuesToIgnore.contains(U) ||
+                   ValuesToIgnore.contains(U) || IsLiveOutDead(U);
           }))
         DeadOps.push_back(&I);

@@ -6727,16 +6737,22 @@ void LoopVectorizationCostModel::collectValuesToIgnore() {

   // Mark ops that would be trivially dead and are only used by ignored
   // instructions as free.
+  BasicBlock *Header = TheLoop->getHeader();
   for (unsigned I = 0; I != DeadOps.size(); ++I) {
     auto *Op = dyn_cast<Instruction>(DeadOps[I]);
     // Skip any op that shouldn't be considered dead.
     if (!Op || !TheLoop->contains(Op) ||
+        (isa<PHINode>(Op) && Op->getParent() == Header) ||
         !wouldInstructionBeTriviallyDead(Op, TLI) ||
-        any_of(Op->users(), [this](User *U) {
-          return !VecValuesToIgnore.contains(U) && !ValuesToIgnore.contains(U);
+        any_of(Op->users(), [this, IsLiveOutDead](User *U) {
+          return !VecValuesToIgnore.contains(U) && ValuesToIgnore.contains(U) &&
+                 !IsLiveOutDead(U);
         }))
       continue;

+    if (!TheLoop->contains(Op->getParent()))
+      continue;
+
     // If all of Op's users are in ValuesToIgnore, add it to ValuesToIgnore
     // which applies for both scalar and vector versions. Otherwise it is only
     // dead in vector versions, so only add it to VecValuesToIgnore.

opt -p loop-vectorize -mtriple riscv64-linux-gnu -mattr=+v,+f -S %s

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

define i8 @dead_live_out_due_to_scalar_epilogue_required(ptr %src, ptr %dst) {
entry:
  br label %loop

loop:                                             ; preds = %loop, %entry
  %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
  %idxprom = sext i32 %iv to i64
  %gep.src = getelementptr i8, ptr %src, i64 %idxprom
  %l = load i8, ptr %gep.src, align 1
  %gep.dst = getelementptr i8, ptr %dst, i64 %idxprom
  store i8 0, ptr %gep.dst, align 1
  %iv.next = add i32 %iv, 4
  %cmp = icmp ult i32 %iv, 1001
  br i1 %cmp, label %loop, label %exit

exit:                                             ; preds = %loop
  %r = phi i8 [ %l, %loop ]
  ret i8 %r
}

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

define void @dead_load(ptr %p, i16 %start) {
entry:
  %start.ext = sext i16 %start to i64
  br label %loop

loop:                                             ; preds = %loop, %entry
  %iv = phi i64 [ %start.ext, %entry ], [ %iv.next, %loop ]
  %gep = getelementptr i16, ptr %p, i64 %iv
  store i16 0, ptr %gep, align 2
  %l = load i16, ptr %gep, align 2
  %iv.next = add i64 %iv, 3
  %cmp = icmp slt i64 %iv, 111
  br i1 %cmp, label %loop, label %exit

exit:                                             ; preds = %loop
  ret void
}

opt -passes=loop-vectorize,dce,instcombine -mtriple riscv64-linux-gnu -mattr=+v -debug-only=loop-vectorize -scalable-vectorization=on -riscv-v-vector-bits-min=128 -disable-output < %s 2>&1

define void @vector_reverse_i64(ptr nocapture noundef writeonly %A, ptr nocapture noundef readonly %B, i32 noundef signext %n) {
entry:
  %cmp7 = icmp sgt i32 %n, 0
  br i1 %cmp7, label %for.body.preheader, label %for.cond.cleanup

for.body.preheader:                               ; preds = %entry
  %0 = zext i32 %n to i64
  br label %for.body

for.cond.cleanup:                                 ; preds = %for.body, %entry
  ret void

for.body:                                         ; preds = %for.body, %for.body.preheader
  %indvars.iv = phi i64 [ %0, %for.body.preheader ], [ %indvars.iv.next, %for.body ]
  %i.0.in8 = phi i32 [ %n, %for.body.preheader ], [ %i.0, %for.body ]
  %i.0 = add nsw i32 %i.0.in8, -1
  %idxprom = zext i32 %i.0 to i64
  %arrayidx = getelementptr inbounds i32, ptr %B, i64 %idxprom
  %1 = load i32, ptr %arrayidx, align 4
  %add9 = add i32 %1, 1
  %arrayidx3 = getelementptr inbounds i32, ptr %A, i64 %idxprom
  store i32 %add9, ptr %arrayidx3, align 4
  %cmp = icmp ugt i64 %indvars.iv, 1
  %indvars.iv.next = add nsw i64 %indvars.iv, -1
  br i1 %cmp, label %for.body, label %for.cond.cleanup, !llvm.loop !0
}

!0 = distinct !{!0, !1, !2, !3, !4}
!1 = !{!"llvm.loop.mustprogress"}
!2 = !{!"llvm.loop.vectorize.width", i32 4}
!3 = !{!"llvm.loop.vectorize.scalable.enable", i1 true}
!4 = !{!"llvm.loop.vectorize.enable", i1 true}

define void @vector_reverse_f32(ptr nocapture noundef writeonly %A, ptr nocapture noundef readonly %B, i32 noundef signext %n) {
entry:
  %cmp7 = icmp sgt i32 %n, 0
  br i1 %cmp7, label %for.body.preheader, label %for.cond.cleanup

for.body.preheader:                               ; preds = %entry
  %0 = zext i32 %n to i64
  br label %for.body

for.cond.cleanup:                                 ; preds = %for.body, %entry
  ret void

for.body:                                         ; preds = %for.body, %for.body.preheader
  %indvars.iv = phi i64 [ %0, %for.body.preheader ], [ %indvars.iv.next, %for.body ]
  %i.0.in8 = phi i32 [ %n, %for.body.preheader ], [ %i.0, %for.body ]
  %i.0 = add nsw i32 %i.0.in8, -1
  %idxprom = zext i32 %i.0 to i64
  %arrayidx = getelementptr inbounds float, ptr %B, i64 %idxprom
  %1 = load float, ptr %arrayidx, align 4
  %conv1 = fadd float %1, 1.000000e+00
  %arrayidx3 = getelementptr inbounds float, ptr %A, i64 %idxprom
  store float %conv1, ptr %arrayidx3, align 4
  %cmp = icmp ugt i64 %indvars.iv, 1
  %indvars.iv.next = add nsw i64 %indvars.iv, -1
  br i1 %cmp, label %for.body, label %for.cond.cleanup, !llvm.loop !0
}

!0 = distinct !{!0, !1, !2, !3, !4}
!1 = !{!"llvm.loop.mustprogress"}
!2 = !{!"llvm.loop.vectorize.width", i32 4}
!3 = !{!"llvm.loop.vectorize.scalable.enable", i1 true}
!4 = !{!"llvm.loop.vectorize.enable", i1 true}

[VPlan] VPlan cost model and legacy cost model disagreed

Related: #99701, #92555. @fhahn Please let me know if you'd prefer these assert triggering testcases to be all in the same issue or prefer a new issue when a new testcase is found.

Tested using llvm f719a339a89b

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

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

for.cond.cleanup:                                 ; preds = %for.body
  %.lcssa = phi i8 [ %1, %for.body ]
  ret i32 0

for.body:                                         ; preds = %for.body, %entry
  %l.011 = phi i32 [ 0, %entry ], [ %add, %for.body ]
  %idxprom = sext i32 %l.011 to i64
  %arrayidx1 = getelementptr [15 x i8], ptr %0, i64 0, i64 %idxprom
  %1 = load i8, ptr %arrayidx1, align 1
  %arrayidx3 = getelementptr [0 x i8], ptr null, i64 0, i64 %idxprom
  store i8 0, ptr %arrayidx3, align 1
  %add = add i32 %l.011, 4
  %cmp = icmp ult i32 %l.011, -9
  br i1 %cmp, label %for.body, label %for.cond.cleanup
}

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

Command/backtrace:
```
> /scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt -passes loop-vectorize reduced.ll -S
opt: /scratch/tc-testing/tc-compiler-fuzz-trunk/llvm/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp:10098: bool llvm::LoopVectorizePass::processLoop(llvm::Loop*): Assertion `VF.Width == Width && "VPlan cost model and legacy cost model disagreed"' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:
0.      Program arguments: /scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt -passes loop-vectorize reduced.ll -S
1.      Running pass "function(loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>)" on module "reduced.ll"
2.      Running pass "loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>" on function "main"
 #0 0x0000647de5790dd0 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x2f1ddd0)
 #1 0x0000647de578e1ef llvm::sys::RunSignalHandlers() (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x2f1b1ef)
 #2 0x0000647de578e345 SignalHandler(int) Signals.cpp:0:0
 #3 0x00007b2a02842520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #4 0x00007b2a028969fc __pthread_kill_implementation ./nptl/pthread_kill.c:44:76
 #5 0x00007b2a028969fc __pthread_kill_internal ./nptl/pthread_kill.c:78:10
 #6 0x00007b2a028969fc pthread_kill ./nptl/pthread_kill.c:89:10
 #7 0x00007b2a02842476 gsignal ./signal/../sysdeps/posix/raise.c:27:6
 #8 0x00007b2a028287f3 abort ./stdlib/abort.c:81:7
 #9 0x00007b2a0282871b _nl_load_domain ./intl/loadmsgcat.c:1177:9
#10 0x00007b2a02839e96 (/lib/x86_64-linux-gnu/libc.so.6+0x39e96)
#11 0x0000647de47acc98 llvm::LoopVectorizePass::processLoop(llvm::Loop*) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x1f39c98)
#12 0x0000647de47af851 llvm::LoopVectorizePass::runImpl(llvm::Function&, llvm::ScalarEvolution&, llvm::LoopInfo&, llvm::TargetTransformInfo&, llvm::DominatorTree&, llvm::BlockFrequencyInfo*, llvm::TargetLibraryInfo*, llvm::DemandedBits&, llvm::AssumptionCache&, llvm::LoopAccessInfoManager&, llvm::OptimizationRemarkEmitter&, llvm::ProfileSummaryInfo*) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x1f3c851)
#13 0x0000647de47affd0 llvm::LoopVectorizePass::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x1f3cfd0)
#14 0x0000647de3621ff6 llvm::detail::PassModel<llvm::Function, llvm::LoopVectorizePass, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0xdaeff6)
#15 0x0000647de55a8e7e llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x2d35e7e)
#16 0x0000647de3625186 llvm::detail::PassModel<llvm::Function, llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0xdb2186)
#17 0x0000647de55a7c0b llvm::ModuleToFunctionPassAdaptor::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x2d34c0b)
#18 0x0000647de36214d6 llvm::detail::PassModel<llvm::Module, llvm::ModuleToFunctionPassAdaptor, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0xdae4d6)
#19 0x0000647de55a5d5d llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x2d32d5d)
#20 0x0000647de2e6b5d6 llvm::runPassPipeline(llvm::StringRef, llvm::Module&, llvm::TargetMachine*, llvm::TargetLibraryInfoImpl*, llvm::ToolOutputFile*, llvm::ToolOutputFile*, llvm::ToolOutputFile*, llvm::StringRef, llvm::ArrayRef<llvm::PassPlugin>, llvm::ArrayRef<std::function<void (llvm::PassBuilder&)>>, llvm::opt_tool::OutputKind, llvm::opt_tool::VerifierKind, bool, bool, bool, bool, bool, bool, bool) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x5f85d6)
#21 0x0000647de2e5d211 optMain (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x5ea211)
#22 0x00007b2a02829d90 __libc_start_call_main ./csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#23 0x00007b2a02829e40 call_init ./csu/../csu/libc-start.c:128:20
#24 0x00007b2a02829e40 __libc_start_main ./csu/../csu/libc-start.c:379:5
#25 0x0000647de2e530a5 _start (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x5e00a5)
zsh: IOT instruction (core dumped)  /scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt
```

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

@patrick-rivos thanks for the report. I think it would be best to keep filing separate issues, as the underlying issues usually are different. Although the fuzzers may generate many instances of the same issue as was the case for https://github.com/llvm/llvm-project/issues/99701. Not sure if there's an easy way to catch that other than waiting for a day or so after filing the first issue.


commit a001e9718fd974859f2797a9f9ed7bf87d364e4f
Author: Nikita Popov <npopov@redhat.com>
Date:   Fri Jan 5 10:41:44 2024 +0100

    [SimplifyLibCalls] Don't try to manually reprocess calls

    The current code for reprocessing the result of fortified libcall
    simplifications is not correct, because we might simplify to an
    argument of the original call, and if that is again a libcall,
    mistakenly think that this is actually the simplification result.

    Instead of trying to fix this, simply remove the code entirely,
    because InstCombine nowadays correctly handles reprocessing of
    SimplifyLibCall results.

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

diff --git a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
index 760a626c8b6f..a7cd68e860e4 100644
--- a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
@@ -3735,26 +3735,8 @@ Value *LibCallSimplifier::optimizeCall(CallInst *CI, IRBuilderBase &Builder) {

   // Also try to simplify calls to fortified library functions.
   if (Value *SimplifiedFortifiedCI =
-          FortifiedSimplifier.optimizeCall(CI, Builder)) {
-    // Try to further simplify the result.
-    CallInst *SimplifiedCI = dyn_cast<CallInst>(SimplifiedFortifiedCI);
-    if (SimplifiedCI && SimplifiedCI->getCalledFunction()) {
-      // Ensure that SimplifiedCI's uses are complete, since some calls have
-      // their uses analyzed.
-      replaceAllUsesWith(CI, SimplifiedCI);
-
-      // Set insertion point to SimplifiedCI to guarantee we reach all uses
-      // we might replace later on.
-      IRBuilderBase::InsertPointGuard Guard(Builder);
-      Builder.SetInsertPoint(SimplifiedCI);
-      if (Value *V = optimizeStringMemoryLibCall(SimplifiedCI, Builder)) {
-        // If we were able to further simplify, remove the now redundant call.
-        substituteInParent(SimplifiedCI, V);
-        return V;
-      }
-    }
+          FortifiedSimplifier.optimizeCall(CI, Builder))
     return SimplifiedFortifiedCI;
-  }

   // Then check for known library functions.
   if (TLI->getLibFunc(*Callee, Func) && isLibFuncEmittable(M, TLI, Func)) {

[SimplifyLibCalls] Calling convention assertion fails

```llvm
; RUN: opt -S -passes=instcombine
define void @main(ptr %ptr) {
  %opendir = call fastcc ptr @opendir(ptr %ptr)
  %memset = call ptr @__memset_chk(ptr %opendir, i32 0, i64 596, i64 -1)
  ret void
}

declare ptr @__memset_chk(ptr, i32, i64, i64)

declare fastcc ptr @opendir(ptr)
```

> opt: /home/npopov/repos/llvm-project/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp:3488: Value *llvm::LibCallSimplifier::optimizeStringMemoryLibCall(CallInst *, IRBuilderBase &): Assertion `(ignoreCallingConv(Func) || TargetLibraryInfoImpl::isCallingConvCCompatible(CI)) && "Optimizing string/memory libcall would change the calling convention"' failed.

Encountered when building openjpeg2.


BoUpSLP::gather BoUpSLP::setInsertPointAfterBundle createFreeze createShuffle

commit 058ac837bc35419bbbb34f3206f5aa229c669811
Author: Alexey Bataev <a.bataev@outlook.com>
Date:   Mon Nov 11 10:48:15 2024 -0800

    [SLP]Use generic createShuffle for buildvector

    Use generic createShuffle function, which know how to adjust the vectors
    correctly, to avoid compiler crash when trying to build a buildvector as
    a shuffle

    Fixes #115732

diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index da8e0d8cc09a..1bf082d57b8b 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -3045,7 +3045,9 @@ private:

   /// \returns a vector from a collection of scalars in \p VL. if \p Root is not
   /// specified, the starting vector value is poison.
-  Value *gather(ArrayRef<Value *> VL, Value *Root, Type *ScalarTy);
+  Value *
+  gather(ArrayRef<Value *> VL, Value *Root, Type *ScalarTy,
+         function_ref<Value *(Value *, Value *, ArrayRef<int>)> CreateShuffle);

   /// \returns whether the VectorizableTree is fully vectorizable and will
   /// be beneficial even the tree height is tiny.
@@ -9167,8 +9169,9 @@ protected:
     int VF = Mask.size();
     if (auto *FTy = dyn_cast<FixedVectorType>(V1->getType()))
       VF = FTy->getNumElements();
-    if (V2 &&
-        !isUndefVector(V2, buildUseMask(VF, Mask, UseMask::SecondArg)).all()) {
+    if (V2 && !isUndefVector</*IsPoisonOnly=*/true>(
+                   V2, buildUseMask(VF, Mask, UseMask::SecondArg))
+                   .all()) {
       // Peek through shuffles.
       Value *Op1 = V1;
       Value *Op2 = V2;
@@ -13454,7 +13457,9 @@ void BoUpSLP::setInsertPointAfterBundle(const TreeEntry *E) {
   Builder.SetCurrentDebugLocation(Front->getDebugLoc());
 }

-Value *BoUpSLP::gather(ArrayRef<Value *> VL, Value *Root, Type *ScalarTy) {
+Value *BoUpSLP::gather(
+    ArrayRef<Value *> VL, Value *Root, Type *ScalarTy,
+    function_ref<Value *(Value *, Value *, ArrayRef<int>)> CreateShuffle) {
   // List of instructions/lanes from current block and/or the blocks which are
   // part of the current loop. These instructions will be inserted at the end to
   // make it possible to optimize loops and hoist invariant instructions out of
@@ -13560,7 +13565,7 @@ Value *BoUpSLP::gather(ArrayRef<Value *> VL, Value *Root, Type *ScalarTy) {
     if (isa<PoisonValue>(Vec)) {
       Vec = OriginalRoot;
     } else {
-      Vec = Builder.CreateShuffleVector(Root, Vec, Mask);
+      Vec = CreateShuffle(Root, Vec, Mask);
       if (auto *OI = dyn_cast<Instruction>(OriginalRoot);
           OI && OI->hasNUses(0))
         eraseInstruction(OI);
@@ -14022,7 +14027,10 @@ public:
   }
   Value *gather(ArrayRef<Value *> VL, unsigned MaskVF = 0,
                 Value *Root = nullptr) {
-    return R.gather(VL, Root, ScalarTy);
+    return R.gather(VL, Root, ScalarTy,
+                    [&](Value *V1, Value *V2, ArrayRef<int> Mask) {
+                      return createShuffle(V1, V2, Mask);
+                    });
   }
   Value *createFreeze(Value *V) { return Builder.CreateFreeze(V); }
   /// Finalize emission of the shuffles.

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

define void @test(i16 %arg) {
;
bb:
  %sitofp = sitofp i16 %arg to float
  %fadd = fadd float 0.000000e+00, 0.000000e+00
  %fsub = fsub float 0.000000e+00, %sitofp
  %fsub1 = fsub float 0.000000e+00, %sitofp
  %fsub2 = fsub float 0.000000e+00, %sitofp
  %sitofp3 = sitofp i16 0 to float
  %fsub4 = fsub float %fadd, %sitofp3
  store float %fsub4, ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 20), align 4
  %fsub5 = fsub float %fsub, %sitofp
  store float %fsub5, ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 24), align 4
  %fsub6 = fsub float %fsub1, %sitofp
  store float %fsub6, ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 28), align 4
  %fsub7 = fsub float %fsub2, %sitofp
  store float %fsub7, ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 32), align 4
  ret void
}

Assertion `isValidOperands(V1, V2, Mask) && "Invalid shuffle vector instruction operands!"' failed.

To reproduce run the test below with -passes=slp-vectorizer.
```
; 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(i16 %arg) gc "statepoint-example" {
bb:
  %sitofp = sitofp i16 %arg to float
  %fadd = fadd float 0.000000e+00, 0.000000e+00
  %fsub = fsub float 0.000000e+00, %sitofp
  %fsub1 = fsub float 0.000000e+00, %sitofp
  %fsub2 = fsub float 0.000000e+00, %sitofp
  %sitofp3 = sitofp i16 0 to float
  %fsub4 = fsub float %fadd, %sitofp3
  store float %fsub4, ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 20), align 4
  %fsub5 = fsub float %fsub, %sitofp
  store float %fsub5, ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 24), align 4
  %fsub6 = fsub float %fsub1, %sitofp
  store float %fsub6, ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 28), align 4
  %fsub7 = fsub float %fsub2, %sitofp
  store float %fsub7, ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 32), align 4
  ret void
}
```
Reproducer: https://godbolt.org/z/6h4xzhGa1
Stack dump:
```
0.	Program arguments: /opt/compiler-explorer/clang-assertions-trunk/bin/opt -o /app/output.s -S -passes=slp-vectorizer <source>
1.	Running pass "function(slp-vectorizer)" on module "<source>"
2.	Running pass "slp-vectorizer" on function "wombat"
 #0 0x00000000051494c8 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x51494c8)
 #1 0x0000000005146ebc SignalHandler(int) Signals.cpp:0:0
 #2 0x000072f583642520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #3 0x000072f5836969fc pthread_kill (/lib/x86_64-linux-gnu/libc.so.6+0x969fc)
 #4 0x000072f583642476 gsignal (/lib/x86_64-linux-gnu/libc.so.6+0x42476)
 #5 0x000072f5836287f3 abort (/lib/x86_64-linux-gnu/libc.so.6+0x287f3)
 #6 0x000072f58362871b (/lib/x86_64-linux-gnu/libc.so.6+0x2871b)
 #7 0x000072f583639e96 (/lib/x86_64-linux-gnu/libc.so.6+0x39e96)
 #8 0x0000000004eb74ce llvm::ShuffleVectorInst::ShuffleVectorInst(llvm::Value*, llvm::Value*, llvm::ArrayRef<int>, llvm::Twine const&, llvm::InsertPosition) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4eb74ce)
 #9 0x0000000000d09e93 llvm::IRBuilderBase::CreateShuffleVector(llvm::Value*, llvm::Value*, llvm::ArrayRef<int>, llvm::Twine const&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0xd09e93)
#10 0x00000000041a0bdd llvm::slpvectorizer::BoUpSLP::gather(llvm::ArrayRef<llvm::Value*>, llvm::Value*, llvm::Type*) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x41a0bdd)
#11 0x00000000041a13fc void llvm::function_ref<void (llvm::Value*&, llvm::SmallVectorImpl<int>&)>::callback_fn<llvm::Value* llvm::slpvectorizer::BoUpSLP::processBuildVector<llvm::slpvectorizer::BoUpSLP::ShuffleInstructionBuilder, llvm::Value*, llvm::IRBuilder<llvm::TargetFolder, llvm::IRBuilderDefaultInserter>, llvm::slpvectorizer::BoUpSLP>(llvm::slpvectorizer::BoUpSLP::TreeEntry const*, llvm::Type*, llvm::IRBuilder<llvm::TargetFolder, llvm::IRBuilderDefaultInserter>&, llvm::slpvectorizer::BoUpSLP&)::'lambda15'(llvm::Value*&, llvm::SmallVectorImpl<int>&)>(long, llvm::Value*&, llvm::SmallVectorImpl<int>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x41a13fc)
#12 0x00000000041a26b9 llvm::slpvectorizer::BoUpSLP::ShuffleInstructionBuilder::finalize(llvm::ArrayRef<int>, llvm::ArrayRef<std::pair<llvm::slpvectorizer::BoUpSLP::TreeEntry const*, unsigned int>>, llvm::ArrayRef<int>, unsigned int, llvm::function_ref<void (llvm::Value*&, llvm::SmallVectorImpl<int>&)>) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x41a26b9)
#13 0x00000000041d5335 llvm::Value* llvm::slpvectorizer::BoUpSLP::processBuildVector<llvm::slpvectorizer::BoUpSLP::ShuffleInstructionBuilder, llvm::Value*, llvm::IRBuilder<llvm::TargetFolder, llvm::IRBuilderDefaultInserter>, llvm::slpvectorizer::BoUpSLP>(llvm::slpvectorizer::BoUpSLP::TreeEntry const*, llvm::Type*, llvm::IRBuilder<llvm::TargetFolder, llvm::IRBuilderDefaultInserter>&, llvm::slpvectorizer::BoUpSLP&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x41d5335)
#14 0x00000000041e168e llvm::slpvectorizer::BoUpSLP::vectorizeTree(llvm::slpvectorizer::BoUpSLP::TreeEntry*, bool) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x41e168e)
#15 0x000000000420234a llvm::slpvectorizer::BoUpSLP::vectorizeTree(llvm::SmallDenseSet<llvm::Value*, 4u, llvm::DenseMapInfo<llvm::Value*, void>> const&, llvm::Instruction*) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x420234a)
#16 0x0000000004205c7d llvm::slpvectorizer::BoUpSLP::vectorizeTree() (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4205c7d)
#17 0x0000000004224402 llvm::SLPVectorizerPass::vectorizeStoreChain(llvm::ArrayRef<llvm::Value*>, llvm::slpvectorizer::BoUpSLP&, unsigned int, unsigned int, unsigned int&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4224402)
#18 0x0000000004225e6b 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
#19 0x0000000004227d98 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+0x4227d98)
#20 0x00000000042285e9 llvm::SLPVectorizerPass::vectorizeStoreChains(llvm::slpvectorizer::BoUpSLP&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x42285e9)
#21 0x0000000004229b35 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
#22 0x000000000422a63b llvm::SLPVectorizerPass::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x422a63b)
#23 0x0000000002f9948e 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+0x2f9948e)
#24 0x0000000004f47488 llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4f47488)
#25 0x0000000000e3bf3e 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+0xe3bf3e)
#26 0x0000000004f45eae llvm::ModuleToFunctionPassAdaptor::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4f45eae)
#27 0x0000000000e3b64e 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+0xe3b64e)
#28 0x0000000004f458e0 llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4f458e0)
#29 0x000000000091103a 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+0x91103a)
#30 0x000000000090399a optMain (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x90399a)
#31 0x000072f583629d90 (/lib/x86_64-linux-gnu/libc.so.6+0x29d90)
#32 0x000072f583629e40 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e40)
#33 0x00000000008fb41e _start (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x8fb41e)
Program terminated with signal: SIGSEGV
Compiler returned: 139
```

CC @alexey-bataev


commit ad9c0b369e86e75d56e229f294782a4eaf527226
Author: Alexey Bataev <a.bataev@outlook.com>
Date:   Mon Nov 18 13:49:04 2024 -0800

    [SLP]Check if the gathered loads form full vector before attempting build it

    Need to check that the number of gathered loads in the slice forms the
    build vector to avoid compiler crash.

    Fixes #116691

diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index 918d7663548f..dc0dffd9fcbf 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -6815,16 +6815,7 @@ void BoUpSLP::tryToVectorizeGatheredLoads(
         // Check if it is profitable to try vectorizing gathered loads. It is
         // profitable if we have more than 3 consecutive loads or if we have
         // less but all users are vectorized or deleted.
-        bool AllowToVectorize =
-            NumElts >= 3 ||
-            any_of(ValueToGatherNodes.at(Slice.front()),
-                   [=](const TreeEntry *TE) {
-                     return TE->Scalars.size() == 2 &&
-                            ((TE->Scalars.front() == Slice.front() &&
-                              TE->Scalars.back() == Slice.back()) ||
-                             (TE->Scalars.front() == Slice.back() &&
-                              TE->Scalars.back() == Slice.front()));
-                   });
+        bool AllowToVectorize = false;
         // Check if it is profitable to vectorize 2-elements loads.
         if (NumElts == 2) {
           bool IsLegalBroadcastLoad = TTI->isLegalBroadcastLoad(
@@ -6861,6 +6852,19 @@ void BoUpSLP::tryToVectorizeGatheredLoads(
             return true;
           };
           AllowToVectorize = CheckIfAllowed(Slice);
+        } else {
+          AllowToVectorize =
+              (NumElts >= 3 ||
+               any_of(ValueToGatherNodes.at(Slice.front()),
+                      [=](const TreeEntry *TE) {
+                        return TE->Scalars.size() == 2 &&
+                               ((TE->Scalars.front() == Slice.front() &&
+                                 TE->Scalars.back() == Slice.back()) ||
+                                (TE->Scalars.front() == Slice.back() &&
+                                 TE->Scalars.back() == Slice.front()));
+                      })) &&
+              hasFullVectorsOrPowerOf2(*TTI, Slice.front()->getType(),
+                                       Slice.size());
         }
         if (AllowToVectorize) {
           SmallVector<Value *> PointerOps;
@@ -6903,7 +6907,8 @@ void BoUpSLP::tryToVectorizeGatheredLoads(
       }
       // Mark masked gathers candidates as vectorized, if any.
       for (unsigned Cnt : MaskedGatherVectorized) {
-        ArrayRef<LoadInst *> Slice = ArrayRef(Loads).slice(Cnt, NumElts);
+        ArrayRef<LoadInst *> Slice = ArrayRef(Loads).slice(
+            Cnt, std::min<unsigned>(NumElts, Loads.size() - Cnt));
         ArrayRef<Value *> Values(
             reinterpret_cast<Value *const *>(Slice.begin()), Slice.size());
         Results.emplace_back(Values, LoadsState::ScatterVectorize);

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

@solid_ = external global [608 x i8]

define void @test(ptr noalias %0) {
;
.lr.ph1019:
  %1 = getelementptr i8, ptr %0, i64 8
  %2 = getelementptr i8, ptr %0, i64 32
  %3 = getelementptr i8, ptr %0, i64 128
  %4 = getelementptr i8, ptr %0, i64 200
  %5 = getelementptr i8, ptr %0, i64 208
  %6 = getelementptr i8, ptr %0, i64 232
  %7 = getelementptr i8, ptr %0, i64 288
  %8 = getelementptr i8, ptr %0, i64 320
  %9 = getelementptr i8, ptr %0, i64 304
  %10 = getelementptr i8, ptr %0, i64 424
  %11 = getelementptr i8, ptr %0, i64 480
  %12 = getelementptr i8, ptr %0, i64 504
  %13 = getelementptr i8, ptr %0, i64 632
  %14 = getelementptr i8, ptr %0, i64 720
  %15 = load double, ptr %1, align 8
  %16 = load double, ptr %2, align 8
  %17 = fadd double %16, %15
  %18 = load double, ptr %3, align 8
  %19 = load double, ptr %4, align 8
  %20 = load double, ptr %5, align 8
  %21 = load double, ptr %6, align 8
  %22 = fadd double %21, %20
  %23 = load double, ptr %7, align 8
  %24 = load double, ptr %8, align 8
  %25 = load double, ptr %9, align 8
  %26 = load double, ptr %10, align 8
  %27 = load double, ptr %11, align 8
  %28 = load double, ptr %12, align 8
  %29 = fadd double %28, %27
  %30 = fmul double %22, %18
  %31 = fmul double %30, 0.000000e+00
  %32 = fsub double 0.000000e+00, %25
  %33 = fmul double %32, 0.000000e+00
  %34 = fadd double %33, 0.000000e+00
  %35 = fmul double %34, 0.000000e+00
  %36 = fmul double %29, %26
  %37 = fmul double %36, 0.000000e+00
  %38 = fadd double %37, 0.000000e+00
  %39 = fsub double %17, %19
  %40 = fmul double %39, %23
  %41 = fmul double %40, 0.000000e+00
  %42 = load double, ptr %0, align 8
  %43 = load double, ptr %13, align 8
  %44 = fmul double %43, %31
  %45 = load double, ptr %14, align 8
  %46 = fmul double %35, 0.000000e+00
  %47 = fadd double %44, 0.000000e+00
  %48 = fmul double %45, %38
  %49 = fmul double %45, %41
  store double %46, ptr getelementptr inbounds (i8, ptr @solid_, i64 384), align 8
  store double %47, ptr getelementptr inbounds (i8, ptr @solid_, i64 408), align 8
  store double %48, ptr getelementptr inbounds (i8, ptr @solid_, i64 392), align 8
  store double %49, ptr getelementptr inbounds (i8, ptr @solid_, i64 400), align 8
  %.neg965 = fmul double %48, %24
  %reass.add993 = fadd double %.neg965, 0.000000e+00
  %50 = fadd double %42, %reass.add993
  %51 = fsub double 0.000000e+00, %50
  store double %51, ptr getelementptr inbounds (i8, ptr @solid_, i64 296), align 8
  %.neg969 = fmul double %49, 0.000000e+00
  %reass.add996 = fadd double %.neg969, 0.000000e+00
  %52 = fadd double %45, %reass.add996
  %53 = fsub double 0.000000e+00, %52
  store double %53, ptr getelementptr inbounds (i8, ptr @solid_, i64 304), align 8
  ret void
}

Crash in SLPVectorizer.cpp

I'm seeing a problem that shows up in the flang compiler when compiling a large, proprietary benchmark. Since the benchmark is proprietary, I can't include the source code in this bug report.

The problem happens in in the file `.../llvm-project/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp` in the function `BoUpSLP::tryToVectorizeGatheredLoads`.

In the code around line 6906, is the statement:

```
ArrayRef<LoadInst *> Slice = ArrayRef(Loads).slice(Cnt, NumElts);
```

The code for `slice()` is in `llvm-project/llvm/include/llvm/ADT/ArrayRef.h`. It contains the line:

```
assert(N+M <= size() && "Invalid specifier");
```

This assertion fails, and the compiler crashes.

I added debug code to `SLPVectorizer.cpp` to trace how the variables `Cnt` and `NumElts` got their values leading up to the point of failure. I've included the output of running the compiler on the test case in the file `log` along with the source code of the modified version of `SLPVectorizer.cpp` in the attached zip file.

At the point of failure, the value of `N` (which corresponds to `Cnt`) is 8. The value of `M` (passed from `NumElts`) is also 8. The call to `size()` returns 14. Since 8 + 8 is not less than or equal to 14, the assert fails and the compiler crashes.

I captured the LLVM IR of the original test case and included it below in the file `x13.f90.ll` in the attached zip file.

If you run this command after downloading `x13.f90.ll`, you'll see the error:

```
#!/bin/bash
../bin/clang -c -O3 -march=native -mllvm -locally-hot-callsite-threshold=4500 x13.f90.ll
```

I also ran the `x13.f90.ll` file through `llvm-reduce` using the following command:

```
llvm-reduce --test pcrash.sh x13.f90.ll
```

This produced a file called `reduced.ll` that I've included in the attached zip file. I've also included the log file `reduced.log` that shows what happend when you run the command:

```
#!/bin/bash
../bin/clang -c -O3 -march=native -mllvm -locally-hot-callsite-threshold=4500 reduced.ll
```

@alexey-bataev, please let me know if someone else should look at this or if I can help out by adding additional debug information.

[Archive.zip](https://github.com/user-attachments/files/17805978/Archive.zip)


commit f4974e09312afc9549fcfc0304b738d235da9eca
Author: Alexey Bataev <a.bataev@outlook.com>
Date:   Fri Nov 29 06:20:19 2024 -0800

    [SLP] Add a check for poison value in AShrChecker

    Need to check if the value in AShrChecker is a poison before casting it
    to instruction to avoid compiler crash

    Fixes #118030

diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index 48a8520a966f..7723442bc0fb 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -17799,6 +17799,8 @@ bool BoUpSLP::collectValuesToDemote(
     // original type and the sign bit of the truncate type are similar.
     auto AShrChecker = [&](unsigned BitWidth, unsigned OrigBitWidth) {
       return all_of(E.Scalars, [&](Value *V) {
+        if (isa<PoisonValue>(V))
+          return true;
         auto *I = cast<Instruction>(V);
         KnownBits AmtKnownBits = computeKnownBits(I->getOperand(1), *DL);
         unsigned ShiftedBits = OrigBitWidth - BitWidth;

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

define i32 @test(ptr %n, i32 %conv57, i1 %tobool5.not, i64 %bf.load14) {
;
entry:
  br i1 false, label %entry.if.end54_crit_edge, label %while.cond

entry.if.end54_crit_edge:
  br label %if.end54

tthread-pre-split:
  br label %t

t:
  %w.2 = phi i32 [ 1, %tthread-pre-split ], [ 0, %if.end83 ]
  br label %if.end7

t.u_crit_edge:
  br label %if.end7

if.end7:
  %w.4 = phi i32 [ %w.2, %t ], [ %w.2, %t.u_crit_edge ], [ %bf.cast25, %while.body ]
  %a.4 = phi i32 [ 0, %t ], [ %conv57, %t.u_crit_edge ], [ %bf.cast2910, %while.body ]
  %b.4 = phi i32 [ 0, %t ], [ 0, %t.u_crit_edge ], [ %bf.cast2910, %while.body ]
  %c.4 = phi i32 [ 0, %t ], [ 1, %t.u_crit_edge ], [ poison, %while.body ]
  br label %v

while.cond:
  %bf.load66.pre.pre1135 = phi i64 [ 0, %entry ], [ %spec.select, %if.end42 ]
  br i1 %tobool5.not, label %if.end54, label %while.body

while.body:
  %bf.ashr24 = ashr i64 %bf.load14, 33
  %bf.cast25 = trunc nsw i64 %bf.ashr24 to i32
  %bf.ashr28 = lshr i64 %bf.load14, 1
  %bf.cast2910 = trunc i64 %bf.ashr28 to i32
  br label %if.end7

if.end36:
  br label %v

v:
  %c.7 = phi i32 [ %c.4, %if.end7 ], [ 0, %if.end36 ]
  br i1 true, label %if.end42, label %v.if.end83_crit_edge

v.if.end83_crit_edge:
  br label %if.end83

if.end42:
  %tobool43.not = icmp eq i32 %b.4, 0
  %narrow = select i1 %tobool43.not, i32 0, i32 %w.4
  %spec.select = zext i32 %narrow to i64
  %bf.value48 = zext i32 %a.4 to i64
  store i64 %bf.value48, ptr %n, align 8
  store i32 %c.7, ptr %n, align 4
  br label %while.cond

if.end54:
  %bf.load66.pre.pre113125 = phi i64 [ %bf.load66.pre.pre1135, %while.cond ], [ poison, %entry.if.end54_crit_edge ]
  %0 = icmp eq i64 %bf.load66.pre.pre113125, 0
  br i1 %0, label %if.end83, label %ai.if.end76_crit_edge

ai.if.end76_crit_edge:
  br label %if.end83

if.end83:
  br label %t
}

clang crashes on valid code at -O{s,2,3} on x86_64-linux-gnu: Assertion `isa<To>(Val) && "cast<Ty>() argument of incompatible type!"' failed

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

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

```
[516] % clangtk -v
clang version 20.0.0git (https://github.com/llvm/llvm-project.git 5208bc3694473f9378fc0d98eeee63e5ad5c5f04)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /local/home/suz/suz-local/software/local/clang-trunk/bin
Build config: +assertions
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/11
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/12
Selected GCC installation: /usr/lib/gcc/x86_64-linux-gnu/12
Candidate multilib: .;@m64
Selected multilib: .;@m64
Found CUDA installation: /usr/local/cuda, version 11.8
[517] %
[517] % clangtk -O2 -w small.c
clang-20: /local/suz-local/software/clangbuild/llvm-project/llvm/include/llvm/Support/Casting.h:578: decltype(auto) llvm::cast(From*) [with To = llvm::Instruction; From = llvm::Value]: Assertion `isa<To>(Val) && "cast<Ty>() argument of incompatible type!"' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace, preprocessed source, and associated run script.
Stack dump:
0.	Program arguments: /local/home/suz/suz-local/software/local/clang-trunk/bin/clang-20 -cc1 -triple x86_64-unknown-linux-gnu -emit-obj -dumpdir a- -disable-free -clear-ast-before-backend -main-file-name small.c -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/local/suz-local/software/emitesting/bugs/20241125-clangtk-m64-O3-fpointer-tbaa-build-014338/delta -fcoverage-compilation-dir=/local/suz-local/software/emitesting/bugs/20241125-clangtk-m64-O3-fpointer-tbaa-build-014338/delta -resource-dir /local/home/suz/suz-local/software/local/clang-trunk/lib/clang/20 -I /usr/local/include -I /local/suz-local/software/local/include -internal-isystem /local/home/suz/suz-local/software/local/clang-trunk/lib/clang/20/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/12/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -w -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fcolor-diagnostics -vectorize-loops -vectorize-slp -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/small-99895f.o -x c small.c
1.	<eof> parser at end of file
2.	Optimizer
3.	Running pass "function<eager-inv>(float2int,lower-constant-intrinsics,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<O2>,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 "small.c"
4.	Running pass "slp-vectorizer" on function "main"
 #0 0x0000562e34749b50 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/local/home/suz/suz-local/software/local/clang-trunk/bin/clang-20+0x455db50)
 #1 0x0000562e34746f5f llvm::sys::RunSignalHandlers() (/local/home/suz/suz-local/software/local/clang-trunk/bin/clang-20+0x455af5f)
 #2 0x0000562e347470b5 SignalHandler(int) Signals.cpp:0:0
 #3 0x00007f99ac5bf520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #4 0x00007f99ac613a7c pthread_kill (/lib/x86_64-linux-gnu/libc.so.6+0x96a7c)
 #5 0x00007f99ac5bf476 gsignal (/lib/x86_64-linux-gnu/libc.so.6+0x42476)
 #6 0x00007f99ac5a57f3 abort (/lib/x86_64-linux-gnu/libc.so.6+0x287f3)
 #7 0x00007f99ac5a571b (/lib/x86_64-linux-gnu/libc.so.6+0x2871b)
 #8 0x00007f99ac5b6e96 (/lib/x86_64-linux-gnu/libc.so.6+0x39e96)
 #9 0x0000562e31712868 (/local/home/suz/suz-local/software/local/clang-trunk/bin/clang-20+0x1526868)
#10 0x0000562e3616cf4e llvm::slpvectorizer::BoUpSLP::collectValuesToDemote(llvm::slpvectorizer::BoUpSLP::TreeEntry const&, bool, unsigned int&, llvm::SmallVectorImpl<unsigned int>&, llvm::DenseSet<llvm::slpvectorizer::BoUpSLP::TreeEntry const*, llvm::DenseMapInfo<llvm::slpvectorizer::BoUpSLP::TreeEntry const*, void>>&, unsigned int&, bool&, bool) const::'lambda9'(unsigned int, unsigned int)::operator()(unsigned int, unsigned int) const::'lambda'(llvm::Value*)::operator()(llvm::Value*) const SLPVectorizer.cpp:0:0
#11 0x0000562e3616d208 bool llvm::function_ref<bool (unsigned int, unsigned int)>::callback_fn<llvm::slpvectorizer::BoUpSLP::collectValuesToDemote(llvm::slpvectorizer::BoUpSLP::TreeEntry const&, bool, unsigned int&, llvm::SmallVectorImpl<unsigned int>&, llvm::DenseSet<llvm::slpvectorizer::BoUpSLP::TreeEntry const*, llvm::DenseMapInfo<llvm::slpvectorizer::BoUpSLP::TreeEntry const*, void>>&, unsigned int&, bool&, bool) const::'lambda9'(unsigned int, unsigned int)>(long, unsigned int, unsigned int) SLPVectorizer.cpp:0:0
#12 0x0000562e361c72e9 llvm::slpvectorizer::BoUpSLP::collectValuesToDemote(llvm::slpvectorizer::BoUpSLP::TreeEntry const&, bool, unsigned int&, llvm::SmallVectorImpl<unsigned int>&, llvm::DenseSet<llvm::slpvectorizer::BoUpSLP::TreeEntry const*, llvm::DenseMapInfo<llvm::slpvectorizer::BoUpSLP::TreeEntry const*, void>>&, unsigned int&, bool&, bool) const::'lambda6'(unsigned int&, llvm::ArrayRef<llvm::slpvectorizer::BoUpSLP::TreeEntry const*>, llvm::function_ref<bool (unsigned int, unsigned int)>)::operator()(unsigned int&, llvm::ArrayRef<llvm::slpvectorizer::BoUpSLP::TreeEntry const*>, llvm::function_ref<bool (unsigned int, unsigned int)>) const SLPVectorizer.cpp:0:0
#13 0x0000562e361c6065 llvm::slpvectorizer::BoUpSLP::collectValuesToDemote(llvm::slpvectorizer::BoUpSLP::TreeEntry const&, bool, unsigned int&, llvm::SmallVectorImpl<unsigned int>&, llvm::DenseSet<llvm::slpvectorizer::BoUpSLP::TreeEntry const*, llvm::DenseMapInfo<llvm::slpvectorizer::BoUpSLP::TreeEntry const*, void>>&, unsigned int&, bool&, bool) const (/local/home/suz/suz-local/software/local/clang-trunk/bin/clang-20+0x5fda065)
#14 0x0000562e361c6d09 llvm::slpvectorizer::BoUpSLP::computeMinimumValueSizes()::'lambda0'(llvm::slpvectorizer::BoUpSLP::TreeEntry const&, bool, bool, unsigned int, unsigned int, bool, bool)::operator()(llvm::slpvectorizer::BoUpSLP::TreeEntry const&, bool, bool, unsigned int, unsigned int, bool, bool) const SLPVectorizer.cpp:0:0
#15 0x0000562e361db4e3 llvm::slpvectorizer::BoUpSLP::computeMinimumValueSizes() (/local/home/suz/suz-local/software/local/clang-trunk/bin/clang-20+0x5fef4e3)
#16 0x0000562e3623dc1e llvm::SLPVectorizerPass::tryToVectorizeList(llvm::ArrayRef<llvm::Value*>, llvm::slpvectorizer::BoUpSLP&, bool) (/local/home/suz/suz-local/software/local/clang-trunk/bin/clang-20+0x6051c1e)
#17 0x0000562e362427c0 bool tryToVectorizeSequence<llvm::Value>(llvm::SmallVectorImpl<llvm::Value*>&, llvm::function_ref<bool (llvm::Value*, llvm::Value*)>, llvm::function_ref<bool (llvm::Value*, llvm::Value*)>, llvm::function_ref<bool (llvm::ArrayRef<llvm::Value*>, bool)>, bool, llvm::slpvectorizer::BoUpSLP&) (.constprop.0) SLPVectorizer.cpp:0:0
#18 0x0000562e36244162 llvm::SLPVectorizerPass::vectorizeChainsInBlock(llvm::BasicBlock*, llvm::slpvectorizer::BoUpSLP&) (/local/home/suz/suz-local/software/local/clang-trunk/bin/clang-20+0x6058162)
#19 0x0000562e3624bc96 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
#20 0x0000562e3624c802 llvm::SLPVectorizerPass::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/local/home/suz/suz-local/software/local/clang-trunk/bin/clang-20+0x6060802)
#21 0x0000562e35c92cf6 llvm::detail::PassModel<llvm::Function, llvm::SLPVectorizerPass, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/local/home/suz/suz-local/software/local/clang-trunk/bin/clang-20+0x5aa6cf6)
#22 0x0000562e340cd78f llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/local/home/suz/suz-local/software/local/clang-trunk/bin/clang-20+0x3ee178f)
#23 0x0000562e31add026 llvm::detail::PassModel<llvm::Function, llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/local/home/suz/suz-local/software/local/clang-trunk/bin/clang-20+0x18f1026)
#24 0x0000562e340cbb1b llvm::ModuleToFunctionPassAdaptor::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/local/home/suz/suz-local/software/local/clang-trunk/bin/clang-20+0x3edfb1b)
#25 0x0000562e31adb986 llvm::detail::PassModel<llvm::Module, llvm::ModuleToFunctionPassAdaptor, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/local/home/suz/suz-local/software/local/clang-trunk/bin/clang-20+0x18ef986)
#26 0x0000562e340cc67d llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/local/home/suz/suz-local/software/local/clang-trunk/bin/clang-20+0x3ee067d)
#27 0x0000562e349f1d16 (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
#28 0x0000562e349f566c 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*) (/local/home/suz/suz-local/software/local/clang-trunk/bin/clang-20+0x480966c)
#29 0x0000562e350be425 clang::BackendConsumer::HandleTranslationUnit(clang::ASTContext&) (/local/home/suz/suz-local/software/local/clang-trunk/bin/clang-20+0x4ed2425)
#30 0x0000562e36cf2c7c clang::ParseAST(clang::Sema&, bool, bool) (/local/home/suz/suz-local/software/local/clang-trunk/bin/clang-20+0x6b06c7c)
#31 0x0000562e3539f2c9 clang::FrontendAction::Execute() (/local/home/suz/suz-local/software/local/clang-trunk/bin/clang-20+0x51b32c9)
#32 0x0000562e353190f5 clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) (/local/home/suz/suz-local/software/local/clang-trunk/bin/clang-20+0x512d0f5)
#33 0x0000562e354836b3 clang::ExecuteCompilerInvocation(clang::CompilerInstance*) (/local/home/suz/suz-local/software/local/clang-trunk/bin/clang-20+0x52976b3)
#34 0x0000562e316862d1 cc1_main(llvm::ArrayRef<char const*>, char const*, void*) (/local/home/suz/suz-local/software/local/clang-trunk/bin/clang-20+0x149a2d1)
#35 0x0000562e3167cc8a ExecuteCC1Tool(llvm::SmallVectorImpl<char const*>&, llvm::ToolContext const&) driver.cpp:0:0
#36 0x0000562e31681067 clang_main(int, char**, llvm::ToolContext const&) (/local/home/suz/suz-local/software/local/clang-trunk/bin/clang-20+0x1495067)
#37 0x0000562e31579a7b main (/local/home/suz/suz-local/software/local/clang-trunk/bin/clang-20+0x138da7b)
#38 0x00007f99ac5a6d90 (/lib/x86_64-linux-gnu/libc.so.6+0x29d90)
#39 0x00007f99ac5a6e40 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e40)
#40 0x0000562e3167c3b5 _start (/local/home/suz/suz-local/software/local/clang-trunk/bin/clang-20+0x14903b5)
clangtk: error: unable to execute command: Aborted
clangtk: error: clang frontend command failed due to signal (use -v to see invocation)
clang version 20.0.0git (https://github.com/llvm/llvm-project.git 5208bc3694473f9378fc0d98eeee63e5ad5c5f04)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /local/home/suz/suz-local/software/local/clang-trunk/bin
Build config: +assertions
clangtk: note: diagnostic msg:
********************

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

********************
[518] %
[518] % cat small.c
struct {
  int b : 31;
  int c : 6;
} f, g, j;
int d, e, h, i, k, l, m, n, o;
int main() {
  if (m) {
    short q = d;
    if (d)
    r:
      d = q;
    if (0) {
    s:
    t:
      if (h)
      u:
        o = g.c;
      if (n)
        goto v;
    }
    if (n)
      while (g.c) {
        if (e)
          k;
        int w = j.b, a, b = g.c, c = ~b;
        a = f.b;
        if (l) {
          c = 0 % 0;
          goto u;
        }
        if (a)
          goto s;
        l;
      v:
        if (i)
          goto ae;
        if (b)
          j.b = w;
        f.b = a;
        l = c;
      }
    short p = n;
    if (0) {
    ag:
      h = p;
      if (f.b)
        goto t;
    }
    if (j.b) {
    ae:
      e = 0;
    ai:
      if (q)
        goto r;
    }
  }
  if (j.b)
    goto ai;
  if (d)
    goto ag;
  return 0;
}
```


commit f70f1228035c9610de38e0e376afdacb647c4ad9
Author: Alexey Bataev <a.bataev@outlook.com>
Date:   Tue Jul 30 14:02:51 2024 -0700

    [SLP]Fix PR101213: Reuse extractelement, only if its vector operand comes before new vector value.

    When trying to reuse extractelement instruction, need to check that it
    is inserted into proper position. Its original vector operand should
    come before new vector value, otherwise new extractelement instruction
    must be generated.

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

diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index 6501a14d8778..cf87b8621027 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -13909,11 +13909,16 @@ Value *BoUpSLP::vectorizeTree(
         }
         if (!Ex) {
           // "Reuse" the existing extract to improve final codegen.
-          if (auto *ES = dyn_cast<ExtractElementInst>(Scalar)) {
+          if (auto *ES = dyn_cast<ExtractElementInst>(Scalar);
+              ES && isa<Instruction>(Vec)) {
             Value *V = ES->getVectorOperand();
             if (const TreeEntry *ETE = getTreeEntry(V))
               V = ETE->VectorizedValue;
-            Ex = Builder.CreateExtractElement(V, ES->getIndexOperand());
+            if (auto *IV = dyn_cast<Instruction>(V);
+                !IV || IV == Vec || IV->comesBefore(cast<Instruction>(Vec)))
+              Ex = Builder.CreateExtractElement(V, ES->getIndexOperand());
+            else
+              Ex = Builder.CreateExtractElement(Vec, Lane);
           } else if (ReplaceGEP) {
             // Leave the GEPs as is, they are free in most cases and better to
             // keep them as GEPs.

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

define void @test() {
bb:
  %0 = shufflevector <2 x ptr addrspace(1)> zeroinitializer, <2 x ptr addrspace(1)> zeroinitializer, <2 x i32> <i32 1, i32 0>
  %1 = extractelement <2 x ptr addrspace(1)> %0, i32 0
  %2 = extractelement <2 x ptr addrspace(1)> %0, i32 1
  br label %bb43

bb20:                                             ; No predecessors!
  br label %bb105

bb43:                                             ; preds = %bb51, %bb
  %phi441 = phi ptr addrspace(1) [ %4, %bb51 ], [ %2, %bb ]
  %phi452 = phi ptr addrspace(1) [ %5, %bb51 ], [ %1, %bb ]
  br i1 false, label %bb105, label %bb51

bb51:                                             ; preds = %bb54, %bb43
  %3 = phi <2 x ptr addrspace(1)> [ poison, %bb54 ], [ zeroinitializer, %bb43 ]
  %4 = extractelement <2 x ptr addrspace(1)> %3, i32 0
  %5 = extractelement <2 x ptr addrspace(1)> %3, i32 1
  br label %bb43

bb54:                                             ; No predecessors!
  br label %bb51

bb105:                                            ; preds = %bb43, %bb20
  %phi106 = phi ptr addrspace(1) [ %1, %bb20 ], [ null, %bb43 ]
  ret void
}

[SLPVectorizer] Instruction does not dominate all uses! LLVM ERROR: Broken module found, compilation aborted!

To reproduce run the following test with -passes slp-vectorizer -slp-threshold=-99999
[Test.ll.tgz](https://github.com/user-attachments/files/16431764/Test.ll.tgz)

Reproducer : https://godbolt.org/z/GW41a7WP6

Stack dump:
```
Instruction does not dominate all uses!
  %2 = shufflevector <2 x ptr addrspace(1)> %0, <2 x ptr addrspace(1)> poison, <2 x i32> <i32 1, i32 0>
  %1 = extractelement <2 x ptr addrspace(1)> %2, i32 0
LLVM ERROR: Broken module found, compilation aborted!
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:
0.	Program arguments: /opt/compiler-explorer/clang-assertions-trunk/bin/opt -o /app/output.s -S -passes slp-vectorizer -slp-threshold=-99999 <source>
1.	Running pass "verify" on module "<source>"
 #0 0x0000000004eff778 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4eff778)
 #1 0x0000000004efceec SignalHandler(int) Signals.cpp:0:0
 #2 0x00007c0269e42520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #3 0x00007c0269e969fc pthread_kill (/lib/x86_64-linux-gnu/libc.so.6+0x969fc)
 #4 0x00007c0269e42476 gsignal (/lib/x86_64-linux-gnu/libc.so.6+0x42476)
 #5 0x00007c0269e287f3 abort (/lib/x86_64-linux-gnu/libc.so.6+0x287f3)
 #6 0x00000000007b3ff7 llvm::json::operator==(llvm::json::Value const&, llvm::json::Value const&) (.cold) JSON.cpp:0:0
 #7 0x0000000004e396a8 (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4e396a8)
 #8 0x0000000004d360f0 llvm::VerifierPass::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4d360f0)
 #9 0x00000000008d865e llvm::detail::PassModel<llvm::Module, llvm::VerifierPass, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x8d865e)
#10 0x0000000004cf9c90 llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4cf9c90)
#11 0x00000000008e33d2 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+0x8e33d2)
#12 0x00000000008d62fc optMain (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x8d62fc)
#13 0x00007c0269e29d90 (/lib/x86_64-linux-gnu/libc.so.6+0x29d90)
#14 0x00007c0269e29e40 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e40)
#15 0x00000000008cd75e _start (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x8cd75e)
Program terminated with signal: SIGSEGV
Compiler returned: 139
```

@alexey-bataev Hi, is there a way to backport this fix for llvm 19, I tried just cherry picking f70f1228035c9610de38e0e376afdacb647c4ad9 but I ended up getting assertion failures of the form `/workspace/srcdir/llvm-project/llvm/lib/IR/Instruction.cpp:321: bool llvm::Instruction::comesBefore(const llvm::Instruction*) const: Assertion 'getParent() == Other->getParent() && "cross-BB instruction order comparison"' failed.'`.
I can create an IR reproducer for that failure if need be.
Thank you.

EDIT: Would just adding a check that they're in the same basic block work?

> @alexey-bataev Hi, is there a way to backport this fix for llvm 19, I tried just cherry picking [f70f122](https://github.com/llvm/llvm-project/commit/f70f1228035c9610de38e0e376afdacb647c4ad9) but I ended up getting assertion failures of the form `/workspace/srcdir/llvm-project/llvm/lib/IR/Instruction.cpp:321: bool llvm::Instruction::comesBefore(const llvm::Instruction*) const: Assertion 'getParent() == Other->getParent() && "cross-BB instruction order comparison"' failed.'`. I can create an IR reproducer for that failure if need be. Thank you.
>
> EDIT: Would just adding a check that they're in the same basic block work?

Yes, check for the same parent should fix it


commit 0b9f1cc024ca6c7e8d60524be07c0ddfcd08b23c
Author: Yingwei Zheng <dtcxzyw2333@gmail.com>
Date:   Thu Nov 7 15:53:51 2024 +0800

    [SCEV] Disallow simplifying phi(undef, X) to X (#115109)

    See the following case:
    ```
    @GlobIntONE = global i32 0, align 4

    define ptr @src() {
    entry:
      br label %for.body.peel.begin

    for.body.peel.begin:                              ; preds = %entry
      br label %for.body.peel

    for.body.peel:                                    ; preds = %for.body.peel.begin
      br i1 true, label %cleanup.peel, label %cleanup.loopexit.peel

    cleanup.loopexit.peel:                            ; preds = %for.body.peel
      br label %cleanup.peel

    cleanup.peel:                                     ; preds = %cleanup.loopexit.peel, %for.body.peel
      %retval.2.peel = phi ptr [ undef, %for.body.peel ], [ @GlobIntONE, %cleanup.loopexit.peel ]
      br i1 true, label %for.body.peel.next, label %cleanup7

    for.body.peel.next:                               ; preds = %cleanup.peel
      br label %for.body.peel.next1

    for.body.peel.next1:                              ; preds = %for.body.peel.next
      br label %entry.peel.newph

    entry.peel.newph:                                 ; preds = %for.body.peel.next1
      br label %for.body

    for.body:                                         ; preds = %cleanup, %entry.peel.newph
      %retval.0 = phi ptr [ %retval.2.peel, %entry.peel.newph ], [ %retval.2, %cleanup ]
      br i1 false, label %cleanup, label %cleanup.loopexit

    cleanup.loopexit:                                 ; preds = %for.body
      br label %cleanup

    cleanup:                                          ; preds = %cleanup.loopexit, %for.body
      %retval.2 = phi ptr [ %retval.0, %for.body ], [ @GlobIntONE, %cleanup.loopexit ]
      br i1 false, label %for.body, label %cleanup7.loopexit

    cleanup7.loopexit:                                ; preds = %cleanup
      %retval.2.lcssa.ph = phi ptr [ %retval.2, %cleanup ]
      br label %cleanup7

    cleanup7:                                         ; preds = %cleanup7.loopexit, %cleanup.peel
      %retval.2.lcssa = phi ptr [ %retval.2.peel, %cleanup.peel ], [ %retval.2.lcssa.ph, %cleanup7.loopexit ]
      ret ptr %retval.2.lcssa
    }

    define ptr @tgt() {
    entry:
      br label %for.body.peel.begin

    for.body.peel.begin:                              ; preds = %entry
      br label %for.body.peel

    for.body.peel:                                    ; preds = %for.body.peel.begin
      br i1 true, label %cleanup.peel, label %cleanup.loopexit.peel

    cleanup.loopexit.peel:                            ; preds = %for.body.peel
      br label %cleanup.peel

    cleanup.peel:                                     ; preds = %cleanup.loopexit.peel, %for.body.peel
      %retval.2.peel = phi ptr [ undef, %for.body.peel ], [ @GlobIntONE, %cleanup.loopexit.peel ]
      br i1 true, label %for.body.peel.next, label %cleanup7

    for.body.peel.next:                               ; preds = %cleanup.peel
      br label %for.body.peel.next1

    for.body.peel.next1:                              ; preds = %for.body.peel.next
      br label %entry.peel.newph

    entry.peel.newph:                                 ; preds = %for.body.peel.next1
      br label %for.body

    for.body:                                         ; preds = %cleanup, %entry.peel.newph
      br i1 false, label %cleanup, label %cleanup.loopexit

    cleanup.loopexit:                                 ; preds = %for.body
      br label %cleanup

    cleanup:                                          ; preds = %cleanup.loopexit, %for.body
      br i1 false, label %for.body, label %cleanup7.loopexit

    cleanup7.loopexit:                                ; preds = %cleanup
      %retval.2.lcssa.ph = phi ptr [ %retval.2.peel, %cleanup ]
      br label %cleanup7

    cleanup7:                                         ; preds = %cleanup7.loopexit, %cleanup.peel
      %retval.2.lcssa = phi ptr [ %retval.2.peel, %cleanup.peel ], [ %retval.2.lcssa.ph, %cleanup7.loopexit ]
      ret ptr %retval.2.lcssa
    }
    ```
    1. `simplifyInstruction(%retval.2.peel)` returns `@GlobIntONE`. Thus,
    `ScalarEvolution::createNodeForPHI` returns SCEV expr `@GlobIntONE` for
    `%retval.2.peel`.
    2. `SimplifyIndvar::replaceIVUserWithLoopInvariant` tries to replace the
    use of `%retval.2.peel` in `%retval.2.lcssa.ph` with `@GlobIntONE`.
    3. `simplifyLoopAfterUnroll -> simplifyLoopIVs -> SCEVExpander::expand`
    reuses `%retval.2.peel = phi ptr [ undef, %for.body.peel ], [
    @GlobIntONE, %cleanup.loopexit.peel ]` to generate code for
    `@GlobIntONE`. It is incorrect.

    This patch disallows simplifying `phi(undef, X)` to `X` by setting
    `CanUseUndef` to false.
    Closes https://github.com/llvm/llvm-project/issues/114879.

diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index 58e23e9556f1..b10811133770 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -6023,7 +6023,11 @@ const SCEV *ScalarEvolution::createNodeForPHI(PHINode *PN) {
   if (const SCEV *S = createAddRecFromPHI(PN))
     return S;

-  if (Value *V = simplifyInstruction(PN, {getDataLayout(), &TLI, &DT, &AC}))
+  // We do not allow simplifying phi (undef, X) to X here, to avoid reusing the
+  // phi node for X.
+  if (Value *V = simplifyInstruction(
+          PN, {getDataLayout(), &TLI, &DT, &AC, /*CtxI=*/nullptr,
+               /*UseInstrInfo=*/true, /*CanUseUndef=*/false}))
     return getSCEV(V);

   if (const SCEV *S = createNodeFromSelectLikePHI(PN))

opt -passes='loop(indvars,loop-deletion)' -verify-scev -S %s

define i8 @test_pr52023(i1 %c.1, i1 %c.2) {
entry:
  br label %loop.1

loop.1:                                           ; preds = %loop.1.latch, %entry
  %inc79 = phi i8 [ %inc.lcssa, %loop.1.latch ], [ 0, %entry ]
  br label %loop.2

loop.2:                                           ; preds = %loop.2.latch, %loop.1
  %inc6 = phi i8 [ %inc79, %loop.1 ], [ %inc, %loop.2.latch ]
  %inc = add i8 %inc6, 1
  br i1 %c.1, label %loop.2.latch, label %loop.1.latch

loop.2.latch:                                     ; preds = %loop.2
  br i1 false, label %loop.2, label %loop.1.latch

loop.1.latch:                                     ; preds = %loop.2.latch, %loop.2
  %inc.lcssa = phi i8 [ %inc, %loop.2.latch ], [ undef, %loop.2 ]
  br i1 %c.2, label %exit, label %loop.1

exit:                                             ; preds = %loop.1.latch
  %inc.lcssa.lcssa = phi i8 [ %inc.lcssa, %loop.1.latch ]
  ret i8 %inc.lcssa.lcssa
}

opt < %s -passes=indvars -S -indvars-predicate-loops=0

target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"

; Function Attrs: nounwind
define void @identityphi(i32 %limit) #0 {
entry:
  br label %loop

loop:                                             ; preds = %control, %entry
  %iv = phi i32 [ 0, %entry ], [ %iv.next, %control ]
  br i1 undef, label %if.then, label %control

if.then:                                          ; preds = %loop
  br label %control

control:                                          ; preds = %if.then, %loop
  %iv.next = phi i32 [ %iv, %loop ], [ undef, %if.then ]
  %cmp = icmp slt i32 %iv.next, %limit
  br i1 %cmp, label %loop, label %exit

exit:                                             ; preds = %control
  ret void
}

attributes #0 = { nounwind }

opt < %s -S -loop-reduce -mtriple=x86_64-- -mcpu=core2

; Function Attrs: nounwind ssp uwtable
define fastcc void @test3(ptr nocapture %u) #0 {
entry:
  br i1 undef, label %meshBB1, label %meshBB5

for.inc8.us.i:                                    ; preds = %for.body3.us.i
  br i1 undef, label %meshBB1, label %meshBB

for.body3.us.i:                                   ; preds = %meshBB, %for.body3.lr.ph.us.i
  %indvars.iv.i.SV.phi = phi i64 [ %indvars.iv.next.i, %meshBB ], [ 0, %for.body3.lr.ph.us.i ]
  %storemerge13.us.i.SV.phi = phi i32 [ 0, %meshBB ], [ 0, %for.body3.lr.ph.us.i ]
  %Opq.sa.calc12 = sub i32 undef, 227
  %0 = add nsw i64 %indvars.iv.i.SV.phi, %indvars.iv8.i.SV.phi26
  %1 = trunc i64 %0 to i32
  %mul.i.us.i = mul nsw i32 0, %1
  %arrayidx5.us.i = getelementptr inbounds double, ptr %u, i64 %indvars.iv.i.SV.phi
  %2 = load double, ptr %arrayidx5.us.i, align 8
  %indvars.iv.next.i = add i64 %indvars.iv.i.SV.phi, 1
  br i1 undef, label %for.inc8.us.i, label %meshBB

for.body3.lr.ph.us.i:                             ; preds = %meshBB1, %meshBB
  %indvars.iv8.i.SV.phi26 = phi i64 [ undef, %meshBB1 ], [ %indvars.iv8.i.SV.phi24, %meshBB ]
  %arrayidx.us.i = getelementptr inbounds double, ptr undef, i64 %indvars.iv8.i.SV.phi26
  %3 = add i64 %indvars.iv8.i.SV.phi26, 1
  br label %for.body3.us.i

for.inc8.us.i2:                                   ; preds = %meshBB5
  unreachable

eval_At_times_u.exit:                             ; preds = %meshBB5
  ret void

meshBB:                                           ; preds = %for.body3.us.i, %for.inc8.us.i
  %indvars.iv8.i.SV.phi24 = phi i64 [ undef, %for.body3.us.i ], [ %3, %for.inc8.us.i ]
  %meshStackVariable.phi = phi i32 [ %Opq.sa.calc12, %for.body3.us.i ], [ undef, %for.inc8.us.i ]
  br i1 undef, label %for.body3.lr.ph.us.i, label %for.body3.us.i

meshBB1:                                          ; preds = %for.inc8.us.i, %entry
  br label %for.body3.lr.ph.us.i

meshBB5:                                          ; preds = %entry
  br i1 undef, label %eval_At_times_u.exit, label %for.inc8.us.i2
}

attributes #0 = { nounwind ssp uwtable }

opt -S -passes=loop-unroll-full -unroll-full-max-count=1 %s

@GlobIntONE = external global i32, align 4

define ptr @test() {
entry:
  br label %for.body

for.body:                                         ; preds = %cleanup, %entry
  %retval.0 = phi ptr [ undef, %entry ], [ %retval.2, %cleanup ]
  %cmp1.not = phi i1 [ true, %entry ], [ false, %cleanup ]
  br i1 %cmp1.not, label %cleanup, label %cleanup.loopexit

cleanup.loopexit:                                 ; preds = %for.body
  br label %cleanup

cleanup:                                          ; preds = %cleanup.loopexit, %for.body
  %retval.2 = phi ptr [ %retval.0, %for.body ], [ @GlobIntONE, %cleanup.loopexit ]
  br i1 %cmp1.not, label %for.body, label %cleanup2

cleanup2:                                         ; preds = %cleanup
  %retval.2.lcssa = phi ptr [ %retval.2, %cleanup ]
  ret ptr %retval.2.lcssa
}

opt -passes=loop-vectorize -force-vector-width=4 -S %s

@dst = external global [32 x i16], align 1

define void @blend_uniform_iv(i1 %c) {
entry:
  br label %loop.header

loop.header:                                      ; preds = %loop.latch, %entry
  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ]
  br i1 %c, label %loop.next, label %loop.latch

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

loop.latch:                                       ; preds = %loop.next, %loop.header
  %blend = phi i64 [ poison, %loop.header ], [ %iv, %loop.next ]
  %dst.ptr = getelementptr inbounds [32 x i16], ptr @dst, i16 0, i64 %blend
  store i16 0, ptr %dst.ptr, align 2
  %iv.next = add nuw nsw i64 %iv, 1
  %cmp439 = icmp ult i64 %iv, 31
  br i1 %cmp439, label %loop.header, label %exit

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

@dst = external global [32 x i16], align 1

define void @blend_uniform_iv_trunc(i1 %c) {
entry:
  br label %loop.header

loop.header:                                      ; preds = %loop.latch, %entry
  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ]
  %iv.trunc.2 = trunc i64 %iv to i16
  br i1 %c, label %loop.next, label %loop.latch

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

loop.latch:                                       ; preds = %loop.next, %loop.header
  %blend = phi i16 [ poison, %loop.header ], [ %iv.trunc.2, %loop.next ]
  %dst.ptr = getelementptr inbounds [32 x i16], ptr @dst, i16 0, i16 %blend
  store i16 0, ptr %dst.ptr, align 2
  %iv.next = add nuw nsw i64 %iv, 1
  %cmp439 = icmp ult i64 %iv, 31
  br i1 %cmp439, label %loop.header, label %exit

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

WRONG code: GVN? Loop opts?

cat wrong0.i
```
int printf(const char *, ...);
unsigned int IntArr[6];
unsigned int GlobIntONE = 1, GlobIntZERO = 0;
const unsigned int *GlobIntPtr = 0;
unsigned long Res;
unsigned long *ResPtr = &Res;
const unsigned int **GlobIntPtrPTr = &GlobIntPtr;
unsigned int *func() {
  int *GlobIntONEPtr = &GlobIntONE;
  for (int Idx = 0; Idx <= 7; Idx += 1) {
    int Idx2 = 1;
    if (Idx > 0) {
      for (; Idx2 <= 7; Idx2 += 1)
        ;
      return GlobIntONEPtr;
    }
  }
  0 != &GlobIntONEPtr;
  return &GlobIntZERO;
}

int main() {
  IntArr[GlobIntZERO] = GlobIntZERO;
  *GlobIntPtrPTr = func();
  unsigned char Byte = *GlobIntPtr;
  *ResPtr = Byte;
  printf("checksum = %X\n", Res);
}
```

In the above file, func() should obviously should return GlobIntONEPtr, but it does not if compiled with '-fno-inline  -mllvm -unroll-full-max-count=1'.

```
clang -O0 -march=z16 wrong0.i -o a.out -w -fno-inline  ; ./a.out
checksum = 1

clang -O3 -march=z16 wrong0.i -o a.out -w -fno-inline  ; ./a.out
checksum = 1

clang -O3 -march=z16 wrong0.i -o a.out -w -fno-inline  -mllvm -unroll-full-max-count=1 ; ./a.out
checksum = 0

```
It may be that GVN does something wrong, as after it @func() is always returning ptr undef. Or it could very well be some of the loop optimizations that is run just before it.

A bisect shows that

```
d77067d08a3f56dc2d0e6c95bd2852c943df743a is the first bad commit
commit d77067d08a3f56dc2d0e6c95bd2852c943df743a
Author: Nikita Popov <npopov@redhat.com>
Date:   Wed Dec 6 14:17:18 2023 +0100

    [ValueTracking] Add dominating condition support in computeKnownBits() (#73662)

```
@nikic

Bisected to LoopUnrollFullPass:
```
; bin/opt -passes=loop-unroll-full -unroll-full-max-count=1 test.ll -S

@GlobIntONE = dso_local global i32 1, align 4
@GlobIntZERO = dso_local local_unnamed_addr global i32 0, align 4

define i32 @main() local_unnamed_addr {
entry:
  br label %for.body

for.body:                                         ; preds = %entry, %cleanup
  %retval.0 = phi ptr [ undef, %entry ], [ %retval.2, %cleanup ]
  %cmp1.not = phi i1 [ true, %entry ], [ false, %cleanup ]
  br i1 %cmp1.not, label %cleanup, label %for.cond2.preheader

for.cond2.preheader:                              ; preds = %for.body
  br label %cleanup.loopexit

cleanup.loopexit:                                 ; preds = %for.cond2.preheader
  br label %cleanup

cleanup:                                          ; preds = %cleanup.loopexit, %for.body
  %retval.2 = phi ptr [ %retval.0, %for.body ], [ @GlobIntONE, %cleanup.loopexit ]
  br i1 %cmp1.not, label %for.body, label %cleanup7

cleanup7:                                         ; preds = %cleanup
  %retval.2.lcssa = phi ptr [ %retval.2, %cleanup ]
  %res = load i32, ptr %retval.2.lcssa, align 4
  ret i32 %res
}
```
```
source_filename = "test.ll"

@GlobIntONE = dso_local global i32 1, align 4
@GlobIntZERO = dso_local local_unnamed_addr global i32 0, align 4

define i32 @main() local_unnamed_addr {
entry:
  br label %for.body.peel.begin

for.body.peel.begin:                              ; preds = %entry
  br label %for.body.peel

for.body.peel:                                    ; preds = %for.body.peel.begin
  br i1 true, label %cleanup.peel, label %for.cond2.preheader.peel

for.cond2.preheader.peel:                         ; preds = %for.body.peel
  br label %cleanup.loopexit.peel

cleanup.loopexit.peel:                            ; preds = %for.cond2.preheader.peel
  br label %cleanup.peel

cleanup.peel:                                     ; preds = %cleanup.loopexit.peel, %for.body.peel
  %retval.2.peel = phi ptr [ undef, %for.body.peel ], [ @GlobIntONE, %cleanup.loopexit.peel ]
  br i1 true, label %for.body.peel.next, label %cleanup7

for.body.peel.next:                               ; preds = %cleanup.peel
  br label %for.body.peel.next1

for.body.peel.next1:                              ; preds = %for.body.peel.next
  br label %entry.peel.newph

entry.peel.newph:                                 ; preds = %for.body.peel.next1
  br label %for.body

for.body:                                         ; preds = %cleanup, %entry.peel.newph
  br i1 false, label %cleanup, label %for.cond2.preheader

for.cond2.preheader:                              ; preds = %for.body
  br label %cleanup.loopexit

cleanup.loopexit:                                 ; preds = %for.cond2.preheader
  br label %cleanup

cleanup:                                          ; preds = %cleanup.loopexit, %for.body
  br i1 false, label %for.body, label %cleanup7.loopexit, !llvm.loop !0

cleanup7.loopexit:                                ; preds = %cleanup
  %retval.2.lcssa.ph = phi ptr [ %retval.2.peel, %cleanup ]
  br label %cleanup7

cleanup7:                                         ; preds = %cleanup7.loopexit, %cleanup.peel
  %retval.2.lcssa = phi ptr [ %retval.2.peel, %cleanup.peel ], [ %retval.2.lcssa.ph, %cleanup7.loopexit ]
  %res = load i32, ptr %retval.2.lcssa, align 4
  ret i32 %res
}

!0 = distinct !{!0, !1}
!1 = !{!"llvm.loop.peeled.count", i32 1}
```

`simplifyLoopAfterUnroll -> simplifyLoopIVs` causes the miscompilation: https://alive2.llvm.org/ce/z/yiBsZt
I will post a fix later.

The root cause is:
1. `simplifyInstruction(%retval.2.peel)` returns `@GlobIntONE`. Thus, `ScalarEvolution::createNodeForPHI` returns SCEV expr `@GlobIntONE` for `%retval.2.peel`.
2.  `SimplifyIndvar::replaceIVUserWithLoopInvariant` tries to replace the use of `%retval.2.peel` in `%retval.2.lcssa.ph` with `@GlobIntONE`.
3. `SCEVExpander::expand` reuses `%retval.2.peel = phi ptr [ undef, %for.body.peel ], [ @GlobIntONE, %cleanup.loopexit.peel ]` to generate code for `@GlobIntONE`. It is incorrect.

Two possible solutions:
1. Set `CanUseUndef` to false in `simplifyInstruction`.
2. Block this case in `ScalarEvolution::canReuseInstruction`.

@nikic @preames Any thoughts?

I think setting `CanUseUndef=false` would be the correct thing to do. The reverse replacement here is particularly fishy, but more generally, if we make an assumption about the value of undef at a particular use, we have to be consistent about that assumption, and SCEV cannot really guarantee that this is the case.