VPWidenLoadEVLRecipe::execute VPWidenLoadEVLRecipe::print VPWidenStoreEVLRecipe::execute VPWidenStoreEVLRecipe::print

commit a068b974b199b0e7350da2d9506adc7df3995ce3
Author: Elvis Wang <elvis.wang@sifive.com>
Date:   Thu Sep 26 07:10:25 2024 +0800

    [VPlan] Implement VPWidenLoad/StoreEVLRecipe::computeCost().  (#109644)

    Currently the EVL recipes transfer the tail masking to the EVL.
    But in the legacy cost model, the mask exist and will calculate the
    instruction cost of the mask.
    To fix the difference between the VPlan-based cost model and the legacy
    cost model, we always calculate the instruction cost for the mask in the
    EVL recipes.

    Note that we should remove the mask cost in the EVL recipes when we
    don't need to compare to the legacy cost model.

    This patch also fixes #109468.

diff --git a/llvm/lib/Transforms/Vectorize/VPlan.h b/llvm/lib/Transforms/Vectorize/VPlan.h
index bbcfaf9e19cd..23a24ce293ef 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.h
+++ b/llvm/lib/Transforms/Vectorize/VPlan.h
@@ -2709,6 +2709,10 @@ struct VPWidenLoadEVLRecipe final : public VPWidenMemoryRecipe, public VPValue {
   /// Generate the wide load or gather.
   void execute(VPTransformState &State) override;

+  /// Return the cost of this VPWidenLoadEVLRecipe.
+  InstructionCost computeCost(ElementCount VF,
+                              VPCostContext &Ctx) const override;
+
 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
   /// Print the recipe.
   void print(raw_ostream &O, const Twine &Indent,
@@ -2787,6 +2791,10 @@ struct VPWidenStoreEVLRecipe final : public VPWidenMemoryRecipe {
   /// Generate the wide store or scatter.
   void execute(VPTransformState &State) override;

+  /// Return the cost of this VPWidenStoreEVLRecipe.
+  InstructionCost computeCost(ElementCount VF,
+                              VPCostContext &Ctx) const override;
+
 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
   /// Print the recipe.
   void print(raw_ostream &O, const Twine &Indent,
diff --git a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
index dacba152611c..9a0aefb898e5 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
@@ -2267,6 +2267,31 @@ void VPWidenLoadEVLRecipe::execute(VPTransformState &State) {
   State.set(this, Res);
 }

+InstructionCost VPWidenLoadEVLRecipe::computeCost(ElementCount VF,
+                                                  VPCostContext &Ctx) const {
+  if (!Consecutive || IsMasked)
+    return VPWidenMemoryRecipe::computeCost(VF, Ctx);
+
+  // We need to use the getMaskedMemoryOpCost() instead of getMemoryOpCost()
+  // here because the EVL recipes using EVL to replace the tail mask. But in the
+  // legacy model, it will always calculate the cost of mask.
+  // TODO: Using getMemoryOpCost() instead of getMaskedMemoryOpCost when we
+  // don't need to compare to the legacy cost model.
+  Type *Ty = ToVectorTy(getLoadStoreType(&Ingredient), VF);
+  const Align Alignment =
+      getLoadStoreAlignment(const_cast<Instruction *>(&Ingredient));
+  unsigned AS =
+      getLoadStoreAddressSpace(const_cast<Instruction *>(&Ingredient));
+  TTI::TargetCostKind CostKind = TTI::TCK_RecipThroughput;
+  InstructionCost Cost = Ctx.TTI.getMaskedMemoryOpCost(
+      Ingredient.getOpcode(), Ty, Alignment, AS, CostKind);
+  if (!Reverse)
+    return Cost;
+
+  return Cost + Ctx.TTI.getShuffleCost(TargetTransformInfo::SK_Reverse,
+                                       cast<VectorType>(Ty), {}, CostKind, 0);
+}
+
 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
 void VPWidenLoadEVLRecipe::print(raw_ostream &O, const Twine &Indent,
                                  VPSlotTracker &SlotTracker) const {
@@ -2363,6 +2388,31 @@ void VPWidenStoreEVLRecipe::execute(VPTransformState &State) {
   State.addMetadata(NewSI, SI);
 }

+InstructionCost VPWidenStoreEVLRecipe::computeCost(ElementCount VF,
+                                                   VPCostContext &Ctx) const {
+  if (!Consecutive || IsMasked)
+    return VPWidenMemoryRecipe::computeCost(VF, Ctx);
+
+  // We need to use the getMaskedMemoryOpCost() instead of getMemoryOpCost()
+  // here because the EVL recipes using EVL to replace the tail mask. But in the
+  // legacy model, it will always calculate the cost of mask.
+  // TODO: Using getMemoryOpCost() instead of getMaskedMemoryOpCost when we
+  // don't need to compare to the legacy cost model.
+  Type *Ty = ToVectorTy(getLoadStoreType(&Ingredient), VF);
+  const Align Alignment =
+      getLoadStoreAlignment(const_cast<Instruction *>(&Ingredient));
+  unsigned AS =
+      getLoadStoreAddressSpace(const_cast<Instruction *>(&Ingredient));
+  TTI::TargetCostKind CostKind = TTI::TCK_RecipThroughput;
+  InstructionCost Cost = Ctx.TTI.getMaskedMemoryOpCost(
+      Ingredient.getOpcode(), Ty, Alignment, AS, CostKind);
+  if (!Reverse)
+    return Cost;
+
+  return Cost + Ctx.TTI.getShuffleCost(TargetTransformInfo::SK_Reverse,
+                                       cast<VectorType>(Ty), {}, CostKind, 0);
+}
+
 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
 void VPWidenStoreEVLRecipe::print(raw_ostream &O, const Twine &Indent,
                                   VPSlotTracker &SlotTracker) const {

opt < %s --prefer-predicate-over-epilogue=predicate-dont-vectorize --passes=loop-vectorize -mcpu=sifive-p470 -mattr=+v,+f -force-tail-folding-style=data-with-evl -S

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

define void @lshift_significand(i32 %n, ptr nocapture writeonly %dst) {
entry:
  %cmp1.peel = icmp eq i32 %n, 0
  %spec.select = select i1 %cmp1.peel, i64 2, i64 0
  br label %loop

loop:                                             ; preds = %loop, %entry
  %iv = phi i64 [ %spec.select, %entry ], [ %iv.next, %loop ]
  %0 = sub nuw nsw i64 1, %iv
  %arrayidx13 = getelementptr i64, ptr %dst, i64 %0
  store i64 0, ptr %arrayidx13, align 8
  %iv.next = add nuw nsw i64 %iv, 1
  %exitcond.not = icmp eq i64 %iv.next, 3
  br i1 %exitcond.not, label %exit, label %loop

exit:                                             ; preds = %loop
  ret void
}

[LV][VPlan] Crash due to disagreements on the VPlan cost v.s. legacy cost model

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

define void @lshift_significand(i32 %n, ptr %0) {
entry:
  br label %for.cond

for.cond:                                         ; preds = %for.cond, %entry
  %i.0 = phi i32 [ 0, %entry ], [ 2, %for.cond ]
  %add = or i32 %n, %i.0
  %cmp1 = icmp eq i32 %add, 0
  br i1 %cmp1, label %for.cond, label %for.cond7

for.cond7:                                        ; preds = %for.body9, %for.cond
  %i.1 = phi i32 [ %i.0, %for.cond ], [ %inc15, %for.body9 ]
  %cmp8 = icmp ult i32 %i.1, 3
  br i1 %cmp8, label %for.body9, label %for.end16

for.body9:                                        ; preds = %for.cond7
  %sub11 = sub nuw i32 1, %i.1
  %idxprom12 = zext i32 %sub11 to i64
  %arrayidx13 = getelementptr [3 x i64], ptr %0, i64 0, i64 %idxprom12
  store i64 0, ptr %arrayidx13, align 8
  %inc15 = add i32 %i.1, 1
  br label %for.cond7

for.end16:                                        ; preds = %for.cond7
  ret void
}
```
And this command:
``` bash
opt -mcpu=sifive-p470 -O3 -prefer-predicate-over-epilogue=predicate-dont-vectorize -force-tail-folding-style=data-with-evl input.ll -disable-output
```
We'll get the following assertion:
```
llvm/lib/Transforms/Vectorize/LoopVectorize.cpp:7386: VectorizationFactor llvm::LoopVectorizationPlanner::computeBestVF(): Assertion `(BestFactor.Width == LegacyVF.Width || planContainsAdditionalSimplifications(getPlanFor(BestFactor.Width), CostCtx, OrigLoop)) && " VPlan cost model and legacy cost model disagreed"' failed.
```

Preliminary investigation shows that this is caused by the disagreement on (reverse) widen store's cost. First, this is the trace for VPlan's cost model:
```
LV: Scalar loop costs: 4.
Cost of 1 for VF vscale x 1: induction instruction   %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
Cost of 0 for VF vscale x 1: induction instruction   %indvars.iv = phi i64 [ %spec.select, %entry ], [ %indvars.iv.next, %for.body9 ]
Cost of 1 for VF vscale x 1: exit condition instruction   %exitcond.not = icmp eq i64 %indvars.iv.next, 3
Cost of 0 for VF vscale x 1: EMIT vp<%4> = CANONICAL-INDUCTION ir<0>, vp<%12>
Cost of 0 for VF vscale x 1: EXPLICIT-VECTOR-LENGTH-BASED-IV-PHI vp<%5> = phi ir<0>, vp<%11>
Cost of 0 for VF vscale x 1: EMIT vp<%6> = EXPLICIT-VECTOR-LENGTH vp<%5>, vp<%3>
Cost of 0 for VF vscale x 1: vp<%7> = DERIVED-IV ir<%spec.select> + vp<%5> * ir<1>
Cost of 0 for VF vscale x 1: vp<%8> = SCALAR-STEPS vp<%7>, ir<1>
Cost of 1 for VF vscale x 1: CLONE ir<%1> = sub nuw nsw ir<1>, vp<%8>
Cost of 0 for VF vscale x 1: CLONE ir<%arrayidx13> = getelementptr ir<%0>, ir<0>, ir<%1>
Cost of 0 for VF vscale x 1: vp<%9> = vector-pointer (reverse) ir<%arrayidx13>
Cost of 8 for VF vscale x 1: WIDEN vp.store vp<%9>, ir<0>, vp<%6>
Cost of 0 for VF vscale x 1: SCALAR-CAST vp<%10> = zext vp<%6> to i64
Cost of 0 for VF vscale x 1: EMIT vp<%11> = add vp<%10>, vp<%5>
Cost of 0 for VF vscale x 1: EMIT vp<%12> = add vp<%4>, vp<%0>
Cost of 0 for VF vscale x 1: EMIT branch-on-count vp<%12>, vp<%1>
Cost of 0 for VF vscale x 1: vector loop backedge
Cost for VF vscale x 1: 11
Cost of 1 for VF vscale x 2: induction instruction   %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
Cost of 0 for VF vscale x 2: induction instruction   %indvars.iv = phi i64 [ %spec.select, %entry ], [ %indvars.iv.next, %for.body9 ]
Cost of 1 for VF vscale x 2: exit condition instruction   %exitcond.not = icmp eq i64 %indvars.iv.next, 3
Cost of 0 for VF vscale x 2: EMIT vp<%4> = CANONICAL-INDUCTION ir<0>, vp<%12>
Cost of 0 for VF vscale x 2: EXPLICIT-VECTOR-LENGTH-BASED-IV-PHI vp<%5> = phi ir<0>, vp<%11>
Cost of 0 for VF vscale x 2: EMIT vp<%6> = EXPLICIT-VECTOR-LENGTH vp<%5>, vp<%3>
Cost of 0 for VF vscale x 2: vp<%7> = DERIVED-IV ir<%spec.select> + vp<%5> * ir<1>
Cost of 0 for VF vscale x 2: vp<%8> = SCALAR-STEPS vp<%7>, ir<1>
Cost of 1 for VF vscale x 2: CLONE ir<%1> = sub nuw nsw ir<1>, vp<%8>
Cost of 0 for VF vscale x 2: CLONE ir<%arrayidx13> = getelementptr ir<%0>, ir<0>, ir<%1>
Cost of 0 for VF vscale x 2: vp<%9> = vector-pointer (reverse) ir<%arrayidx13>
Cost of 14 for VF vscale x 2: WIDEN vp.store vp<%9>, ir<0>, vp<%6>
Cost of 0 for VF vscale x 2: SCALAR-CAST vp<%10> = zext vp<%6> to i64
Cost of 0 for VF vscale x 2: EMIT vp<%11> = add vp<%10>, vp<%5>
Cost of 0 for VF vscale x 2: EMIT vp<%12> = add vp<%4>, vp<%0>
Cost of 0 for VF vscale x 2: EMIT branch-on-count vp<%12>, vp<%1>
Cost of 0 for VF vscale x 2: vector loop backedge
Cost for VF vscale x 2: 17
```
With VPlan's cost model, we will eventually choose scalar loop, because when VF=vscale x 1, the final cost is `ceil(11 / 2) = 6`; when VF=vscale x 2, the final cost is `ceil(17 / 4) = 5`. Both of them are larger than the scalar cost, 4.

While with the legacy cost model:
```
LV: Found an estimated cost of 0 for VF 1 For instruction:   %indvars.iv = phi i64 [ %spec.select, %entry ], [ %indvars.iv.next, %for.body9 ]
LV: Found an estimated cost of 1 for VF 1 For instruction:   %1 = sub nuw nsw i64 1, %indvars.iv
LV: Found an estimated cost of 0 for VF 1 For instruction:   %arrayidx13 = getelementptr [3 x i64], ptr %0, i64 0, i64 %1
LV: Found an estimated cost of 1 for VF 1 For instruction:   store i64 0, ptr %arrayidx13, align 8
LV: Found an estimated cost of 1 for VF 1 For instruction:   %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
LV: Found an estimated cost of 1 for VF 1 For instruction:   %exitcond.not = icmp eq i64 %indvars.iv.next, 3
LV: Found an estimated cost of 0 for VF 1 For instruction:   br i1 %exitcond.not, label %for.end16, label %for.body9
LV: Scalar loop costs: 4.
LV: Found an estimated cost of 0 for VF vscale x 1 For instruction:   %indvars.iv = phi i64 [ %spec.select, %entry ], [ %indvars.iv.next, %for.body9 ]
LV: Found an estimated cost of 1 for VF vscale x 1 For instruction:   %1 = sub nuw nsw i64 1, %indvars.iv
LV: Found an estimated cost of 0 for VF vscale x 1 For instruction:   %arrayidx13 = getelementptr [3 x i64], ptr %0, i64 0, i64 %1
LV: Found an estimated cost of 7 for VF vscale x 1 For instruction:   store i64 0, ptr %arrayidx13, align 8
LV: Found an estimated cost of 1 for VF vscale x 1 For instruction:   %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
LV: Found an estimated cost of 1 for VF vscale x 1 For instruction:   %exitcond.not = icmp eq i64 %indvars.iv.next, 3
LV: Found an estimated cost of 0 for VF vscale x 1 For instruction:   br i1 %exitcond.not, label %for.end16, label %for.body9
LV: Vector loop of width vscale x 1 costs: 5 (assuming a minimum vscale of 2).
LV: Found an estimated cost of 0 for VF vscale x 2 For instruction:   %indvars.iv = phi i64 [ %spec.select, %entry ], [ %indvars.iv.next, %for.body9 ]
LV: Found an estimated cost of 1 for VF vscale x 2 For instruction:   %1 = sub nuw nsw i64 1, %indvars.iv
LV: Found an estimated cost of 0 for VF vscale x 2 For instruction:   %arrayidx13 = getelementptr [3 x i64], ptr %0, i64 0, i64 %1
LV: Found an estimated cost of 13 for VF vscale x 2 For instruction:   store i64 0, ptr %arrayidx13, align 8
LV: Found an estimated cost of 1 for VF vscale x 2 For instruction:   %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
LV: Found an estimated cost of 1 for VF vscale x 2 For instruction:   %exitcond.not = icmp eq i64 %indvars.iv.next, 3
LV: Found an estimated cost of 0 for VF vscale x 2 For instruction:   br i1 %exitcond.not, label %for.end16, label %for.body9
LV: Vector loop of width vscale x 2 costs: 4 (assuming a minimum vscale of 2).
LV: Selecting VF: vscale x 2.
```
We will eventually choose VF=vscale x 2.

The key difference is the cost of `store i64 0, ptr %arrayidx13, align 8` v.s. cost of `WIDEN vp.store vp<%9>, ir<0>, vp<%6>`, where the latter is larger than the former by 1.

In both cases (the store instruction in VPlan cost model v.s. legacy cost model) their costs are computed by the base cost of store + the cost of shuffle due to being reverse store. I used debugger to confirm that they used the same shuffle cost, which means that for some reason, VPlan's cost model yield a slightly higher cost for store than that in the legacy cost model.

It seems that  the legacy cost model using `getMaskedMemoryOpCost` to query the instruction cost. But in the VPlan-based cost model using `getMemoryOpCost`.

In this case, the mask in the  `VPWidenStoreEVLRecipe` is false since it is using the EVL recipe.
The legacy cost model will not check the tail folding type so it will using `getMaskedMemoryOpCost` instead of `getMemoryOpCost` . And the `MaskedMemoryCost` is slightly smaller than non-mask version.

Open a PR to fix this issue. #109644

We remove the shuffle cost when the value stored by reversed vector  is loop invariant.

CC @fhahn


commit 2c094ac761912eea0d7e8ccb140bc647b5378bdf
Author: Yingwei Zheng <dtcxzyw2333@gmail.com>
Date:   Wed Nov 20 21:15:26 2024 +0800

    [InstCombine] Drop range attributes in `foldBitCeil` (#116641)

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

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 28dbca027037..2526ce7704ab 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -3466,7 +3466,8 @@ static bool isSafeToRemoveBitCeilSelect(ICmpInst::Predicate Pred, Value *Cond0,
 // Note that the select is optimized away while the shift count is masked with
 // 31.  We handle some variations of the input operand like std::bit_ceil(X +
 // 1).
-static Instruction *foldBitCeil(SelectInst &SI, IRBuilderBase &Builder) {
+static Instruction *foldBitCeil(SelectInst &SI, IRBuilderBase &Builder,
+                                InstCombinerImpl &IC) {
   Type *SelType = SI.getType();
   unsigned BitWidth = SelType->getScalarSizeInBits();

@@ -3501,6 +3502,10 @@ static Instruction *foldBitCeil(SelectInst &SI, IRBuilderBase &Builder) {
   // single hardware instruction as opposed to BitWidth - CTLZ, where BitWidth
   // is an integer constant.  Masking with BitWidth-1 comes free on some
   // hardware as part of the shift instruction.
+
+  // Drop range attributes and re-infer them in the next iteration.
+  cast<Instruction>(Ctlz)->dropPoisonGeneratingAnnotations();
+  IC.addToWorklist(cast<Instruction>(Ctlz));
   Value *Neg = Builder.CreateNeg(Ctlz);
   Value *Masked =
       Builder.CreateAnd(Neg, ConstantInt::get(SelType, BitWidth - 1));
@@ -4148,7 +4153,7 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
   if (sinkNotIntoOtherHandOfLogicalOp(SI))
     return &SI;

-  if (Instruction *I = foldBitCeil(SI, Builder))
+  if (Instruction *I = foldBitCeil(SI, Builder, *this))
     return I;

   if (Instruction *I = foldSelectToCmp(SI))

define i32 @test_drop_range_attr(i32 %x) {
  %ctlz = call range(i32 1, 33) i32 @llvm.ctlz.i32(i32 %x, i1 false)
  %sub = sub i32 32, %ctlz
  %shl = shl i32 1, %sub
  %dec = add i32 %x, -1
  %ult = icmp ult i32 %dec, -2
  %sel = select i1 %ult, i32 %shl, i32 1
  ret i32 %sel
}

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

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

define i32 @pr91691_keep_nsw(i32 %0) {
  %2 = sub nsw i32 -2, %0
  %3 = tail call i32 @llvm.ctlz.i32(i32 %2, i1 false)
  %4 = sub i32 32, %3
  %5 = shl i32 1, %4
  %6 = icmp ult i32 %0, -2
  %7 = select i1 %6, i32 %5, i32 1
  ret i32 %7
}

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

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

[InstCombine] `range` attribute should be dropped in `foldBitCeil`

Reproducer: https://alive2.llvm.org/ce/z/NQTmkh (Please use latest alive2 with https://github.com/AliveToolkit/alive2/pull/1097)
```
define i32 @src(i32 %x) {
  %ctlz = call range(i32 1, 33) i32 @llvm.ctlz.i32(i32 %x, i1 false)
  %sub = sub i32 32, %ctlz
  %shl = shl i32 1, %sub
  %dec = add i32 %x, -1
  %ult = icmp ult i32 %dec, -2
  %sel = select i1 %ult, i32 %shl, i32 1
  ret i32 %sel
}

define i32 @tgt(i32 %x) {
  %ctlz = call range(i32 1, 33) i32 @llvm.ctlz.i32(i32 %x, i1 false)
  %1 = sub nsw i32 0, %ctlz
  %2 = and i32 %1, 31
  %sel = shl nuw i32 1, %2
  ret i32 %sel
}
```
```
----------------------------------------
define i32 @src(i32 %x) {
#0:
  %ctlz = ctlz i32 %x, 0
  %#range_0_%ctlz = !range i32 %ctlz, i32 1, i32 33
  %sub = sub i32 32, %#range_0_%ctlz
  %shl = shl i32 1, %sub
  %dec = add i32 %x, 4294967295
  %ult = icmp ult i32 %dec, 4294967294
  %sel = select i1 %ult, i32 %shl, i32 1
  ret i32 %sel
}
=>
define i32 @tgt(i32 %x) {
#0:
  %ctlz = ctlz i32 %x, 0
  %#range_0_%ctlz = !range i32 %ctlz, i32 1, i32 33
  %#1 = sub nsw i32 0, %#range_0_%ctlz
  %#2 = and i32 %#1, 31
  %sel = shl nuw i32 1, %#2
  ret i32 %sel
}
Transformation doesn't verify!

ERROR: Target is more poisonous than source

Example:
i32 %x = #xffffffff (4294967295, -1)

Source:
i32 %ctlz = #x00000000 (0)
i32 %#range_0_%ctlz = poison
i32 %sub = poison
i32 %shl = poison
i32 %dec = #xfffffffe (4294967294, -2)
i1 %ult = #x0 (0)
i32 %sel = #x00000001 (1)

Target:
i32 %ctlz = #x00000000 (0)
i32 %#range_0_%ctlz = poison
i32 %#1 = poison
i32 %#2 = poison
i32 %sel = poison
Source value: #x00000001 (1)
Target value: poison
```


commit 6309440c218778db027306826993e484eab2be17
Author: Yingwei Zheng <dtcxzyw2333@gmail.com>
Date:   Sun Apr 21 22:41:32 2024 +0800

     [InstCombine] Fix unexpected overwriting in `foldSelectWithSRem` (#89539)

    Fixes #89516

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 0262af28068b..73600206a55c 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -2720,7 +2720,7 @@ static Instruction *foldSelectWithSRem(SelectInst &SI, InstCombinerImpl &IC,
   // %cnd = icmp slt i32 %rem, 0
   // %add = add i32 %rem, %n
   // %sel = select i1 %cnd, i32 %add, i32 %rem
-  if (match(TrueVal, m_Add(m_Value(RemRes), m_Value(Remainder))) &&
+  if (match(TrueVal, m_Add(m_Specific(RemRes), m_Value(Remainder))) &&
       match(RemRes, m_SRem(m_Value(Op), m_Specific(Remainder))) &&
       IC.isKnownToBeAPowerOfTwo(Remainder, /*OrZero*/ true) &&
       FalseVal == RemRes)

define i32 @rem_euclid_pow2_false_arm_folded(i32 %n) {
  %rem = srem i32 %n, 2
  %nonneg = icmp sge i32 %rem, 0
  %res = select i1 %nonneg, i32 %rem, i32 1
  ret i32 %res
}

define i8 @pr89516(i8 %n, i8 %x) {
  %cond = icmp slt i8 %x, 0
  %pow2 = shl nuw i8 1, %n
  %srem = srem i8 1, %pow2
  %add = add nuw i8 %srem, %pow2
  %res = select i1 %cond, i8 %add, i8 %srem
  ret i8 %res
}

miscompile of vanilla integer code by InstCombine

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

this function:
```llvm
define i8 @f(i8 %0, i8 %1) {
  %3 = icmp slt i8 %1, 0
  %4 = shl i8 1, %0
  %5 = srem i8 1, %4
  %6 = add i8 %5, %4
  %7 = select i1 %3, i8 %6, i8 %5
  ret i8 %7
}
```
is getting mis-optimized to:
```llvm
define i8 @f(i8 %0, i8 %1) {
  %3 = icmp ne i8 %0, 0
  %4 = zext i1 %3 to i8
  ret i8 %4
}
```
here I'll just give Alive's work:
```
Example:
i8 %#0 = #x00 (0)
i8 %#1 = #xff (255, -1)

Source:
i1 %#3 = #x1 (1)
i8 %#4 = #x01 (1)
i8 %#5 = #x00 (0)
i8 %#6 = #x01 (1)
i8 %#7 = #x01 (1)

Target:
i1 %#3 = #x0 (0)
i8 %#4 = #x00 (0)
Source value: #x01 (1)
Target value: #x00 (0)
```

cc @nunoplopes @hatsunespica


commit 441f94f4bdf6e2b9747ec12194c595098d9c3a5b
Author: Alexey Bataev <a.bataev@outlook.com>
Date:   Wed Aug 7 04:09:55 2024 -0700

    [SLP]Fix PR102279: check the tracked values for extractelements, not the original values

    If the reduced value was replaced by the extractelement instruction
    during vectorization and we attempt to check if this is so, need to
    check the tracked value, not the original (deleted) instruction.
    Otherwise, the compiler may crash

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

diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index c9335b7a89e1..1fee06d145b9 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -17336,27 +17336,23 @@ public:
       // Try to handle shuffled extractelements.
       if (S.getOpcode() == Instruction::ExtractElement && !S.isAltShuffle() &&
           I + 1 < E) {
-        InstructionsState NextS = getSameOpcode(ReducedVals[I + 1], TLI);
-        if (NextS.getOpcode() == Instruction::ExtractElement &&
-            !NextS.isAltShuffle()) {
-          SmallVector<Value *> CommonCandidates(Candidates);
-          for (Value *RV : ReducedVals[I + 1]) {
-            Value *RdxVal = TrackedVals.find(RV)->second;
-            // Check if the reduction value was not overriden by the
-            // extractelement instruction because of the vectorization and
-            // exclude it, if it is not compatible with other values.
-            if (auto *Inst = dyn_cast<Instruction>(RdxVal))
-              if (!NextS.getOpcode() || !NextS.isOpcodeOrAlt(Inst))
-                continue;
-            CommonCandidates.push_back(RdxVal);
-            TrackedToOrig.try_emplace(RdxVal, RV);
-          }
-          SmallVector<int> Mask;
-          if (isFixedVectorShuffle(CommonCandidates, Mask)) {
-            ++I;
-            Candidates.swap(CommonCandidates);
-            ShuffledExtracts = true;
-          }
+        SmallVector<Value *> CommonCandidates(Candidates);
+        for (Value *RV : ReducedVals[I + 1]) {
+          Value *RdxVal = TrackedVals.find(RV)->second;
+          // Check if the reduction value was not overriden by the
+          // extractelement instruction because of the vectorization and
+          // exclude it, if it is not compatible with other values.
+          auto *Inst = dyn_cast<ExtractElementInst>(RdxVal);
+          if (!Inst)
+            continue;
+          CommonCandidates.push_back(RdxVal);
+          TrackedToOrig.try_emplace(RdxVal, RV);
+        }
+        SmallVector<int> Mask;
+        if (isFixedVectorShuffle(CommonCandidates, Mask)) {
+          ++I;
+          Candidates.swap(CommonCandidates);
+          ShuffledExtracts = true;
         }
       }

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

define void @test() {
bb:
  br label %bb1

bb1:                                              ; preds = %bb1, %bb
  %phi = phi i32 [ 0, %bb ], [ %mul9, %bb1 ]
  %phi2 = phi i32 [ 0, %bb ], [ 0, %bb1 ]
  %trunc = trunc i64 0 to i32
  %mul = mul i32 0, %trunc
  %mul3 = mul i32 %trunc, %phi
  %mul4 = mul i32 %mul3, %mul
  %mul5 = mul i32 %mul4, %mul
  %trunc6 = trunc i64 0 to i32
  %mul7 = mul i32 0, %trunc6
  %mul8 = mul i32 %mul5, %mul7
  %mul9 = mul i32 %mul8, %mul7
  br label %bb1
}

opt -S --passes=slp-vectorizer -mtriple=x86_64-sie-ps5 < %s

define void @tes() {
entry:
  %0 = extractelement <2 x i1> zeroinitializer, i64 0
  %1 = extractelement <2 x i1> zeroinitializer, i64 0
  %2 = fcmp ole <2 x double> zeroinitializer, zeroinitializer
  %3 = extractelement <2 x i1> %2, i64 0
  %4 = extractelement <2 x i1> zeroinitializer, i64 0
  br label %5

5:                                                ; preds = %entry
  %6 = select i1 false, i1 false, i1 false
  %7 = select i1 %6, i1 %0, i1 false
  %8 = select i1 %7, i1 %1, i1 false
  %9 = select i1 %8, i1 false, i1 false
  %10 = select i1 %9, i1 %3, i1 false
  %11 = select i1 %10, i1 %4, i1 false
  br i1 %11, label %12, label %13

12:                                               ; preds = %5
  ret void

13:                                               ; preds = %5
  ret void
}

Crash in getSameOpcode(llvm::ArrayRef<llvm::Value*>, llvm::TargetLibraryInfo const&, unsigned int)

 To reproduce run the test below with `-passes slp-vectorizer -slp-threshold=-99999`
```
; 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() #0 gc "statepoint-example" {
bb:
  br label %bb1

bb1:                                              ; preds = %bb1, %bb
  %phi = phi i32 [ 0, %bb ], [ %mul9, %bb1 ]
  %phi2 = phi i32 [ 0, %bb ], [ 0, %bb1 ]
  %trunc = trunc i64 0 to i32
  %mul = mul i32 0, %trunc
  %mul3 = mul i32 %trunc, %phi
  %mul4 = mul i32 %mul3, %mul
  %mul5 = mul i32 %mul4, %mul
  %trunc6 = trunc i64 0 to i32
  %mul7 = mul i32 0, %trunc6
  %mul8 = mul i32 %mul5, %mul7
  %mul9 = mul i32 %mul8, %mul7
  br label %bb1
}

```
Reproducer: https://godbolt.org/z/sqEov8n9h

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 "function(slp-vectorizer)" on module "<source>"
2.	Running pass "slp-vectorizer" on function "wombat"
 #0 0x0000000004f2ff18 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4f2ff18)
 #1 0x0000000004f2d68c SignalHandler(int) Signals.cpp:0:0
 #2 0x00007a3cdfe42520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #3 0x000000000403fb8a getSameOpcode(llvm::ArrayRef<llvm::Value*>, llvm::TargetLibraryInfo const&, unsigned int) (.constprop.1) SLPVectorizer.cpp:0:0
 #4 0x000000000406b0a4 (anonymous namespace)::HorizontalReduction::tryToReduce(llvm::slpvectorizer::BoUpSLP&, llvm::DataLayout const&, llvm::TargetTransformInfo*, llvm::TargetLibraryInfo const&) SLPVectorizer.cpp:0:0
 #5 0x000000000406dab4 llvm::SLPVectorizerPass::vectorizeHorReduction(llvm::PHINode*, llvm::Instruction*, llvm::BasicBlock*, llvm::slpvectorizer::BoUpSLP&, llvm::TargetTransformInfo*, llvm::SmallVectorImpl<llvm::WeakTrackingVH>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x406dab4)
 #6 0x00000000040720f8 llvm::SLPVectorizerPass::vectorizeRootInstruction(llvm::PHINode*, llvm::Instruction*, llvm::BasicBlock*, llvm::slpvectorizer::BoUpSLP&, llvm::TargetTransformInfo*) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x40720f8)
 #7 0x00000000040763be llvm::SLPVectorizerPass::vectorizeChainsInBlock(llvm::BasicBlock*, llvm::slpvectorizer::BoUpSLP&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x40763be)
 #8 0x000000000407c648 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
 #9 0x000000000407d11b llvm::SLPVectorizerPass::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x407d11b)
#10 0x0000000002e7f61e 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+0x2e7f61e)
#11 0x0000000004d2d348 llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4d2d348)
#12 0x0000000000de6cce 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+0xde6cce)
#13 0x0000000004d2bd3e llvm::ModuleToFunctionPassAdaptor::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4d2bd3e)
#14 0x0000000000de731e 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+0xde731e)
#15 0x0000000004d29ea0 llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4d29ea0)
#16 0x00000000008e4312 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+0x8e4312)
#17 0x00000000008d723c optMain (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x8d723c)
#18 0x00007a3cdfe29d90 (/lib/x86_64-linux-gnu/libc.so.6+0x29d90)
#19 0x00007a3cdfe29e40 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e40)
#20 0x00000000008ce6ae _start (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x8ce6ae)
Program terminated with signal: SIGSEGV
Compiler returned: 139
```

CC @alexey-bataev


commit 17fb3e82f6c950267bb01cc2fd2a84b0d9e9d0d8
Author: Florian Hahn <flo@fhahn.com>
Date:   Tue Apr 23 11:50:25 2024 +0100

    [VPlan] Skip extending ICmp results in trunateToMinimalBitwidth.

    Results of icmp don't need extending after truncating their operands, as
    the result will always be i1. Skip them during extending.

    Fixes https://github.com/llvm/llvm-project/issues/79742
    Fixes https://github.com/llvm/llvm-project/issues/85185

diff --git a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
index 007dc3f89b3f..9580dc4a27f6 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
@@ -1031,7 +1031,9 @@ void VPlanTransforms::truncateToMinimalBitwidths(
       if (auto *VPW = dyn_cast<VPRecipeWithIRFlags>(&R))
         VPW->dropPoisonGeneratingFlags();

-      if (OldResSizeInBits != NewResSizeInBits) {
+      using namespace llvm::VPlanPatternMatch;
+      if (OldResSizeInBits != NewResSizeInBits &&
+          !match(&R, m_Binary<Instruction::ICmp>(m_VPValue(), m_VPValue()))) {
         // Extend result to original width.
         auto *Ext =
             new VPWidenCastRecipe(Instruction::ZExt, ResultVPV, OldResTy);
@@ -1040,8 +1042,9 @@ void VPlanTransforms::truncateToMinimalBitwidths(
         Ext->setOperand(0, ResultVPV);
         assert(OldResSizeInBits > NewResSizeInBits && "Nothing to shrink?");
       } else
-        assert(cast<VPWidenRecipe>(&R)->getOpcode() == Instruction::ICmp &&
-               "Only ICmps should not need extending the result.");
+        assert(
+            match(&R, m_Binary<Instruction::ICmp>(m_VPValue(), m_VPValue())) &&
+            "Only ICmps should not need extending the result.");

       assert(!isa<VPWidenStoreRecipe>(&R) && "stores cannot be narrowed");
       if (isa<VPWidenLoadRecipe>(&R))

opt -p loop-vectorize -force-vector-width=4 -force-vector-interleave=1 -S %s

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

define i32 @test_icmp_and_op_zext(ptr %dst, i64 %a) {
entry:
  %and = and i64 %a, 7304878031173690989
  br label %loop

loop:                                             ; preds = %loop, %entry
  %iv = phi i16 [ 1, %entry ], [ %iv.next, %loop ]
  %c = icmp ne i64 %and, 0
  %c.ext = zext i1 %c to i64
  %or = or i64 %and, %c.ext
  %or.trunc = trunc i64 %or to i8
  %gep = getelementptr i8, ptr %dst, i16 %iv
  store i8 %or.trunc, ptr %gep, align 1
  %iv.next = add i16 %iv, 1
  %ec = icmp eq i16 %iv.next, 1000
  br i1 %ec, label %exit, label %loop

exit:                                             ; preds = %loop
  ret i32 0
}

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

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

loop:                                             ; preds = %loop, %entry
  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
  %gep.src.1 = getelementptr inbounds i16, ptr %src.1, i64 %iv
  %i2 = load i16, ptr %gep.src.1, align 2
  %i3 = sext i16 %i2 to i32
  %c.1 = icmp sgt i32 0, %i3
  %gep.src.2 = getelementptr inbounds i8, ptr %src.2, i64 %iv
  %i4 = load i8, ptr %gep.src.2, align 2
  %i5 = zext i8 %i4 to i32
  %i6 = select i1 %c.1, i32 0, i32 %i5
  %i7 = and i32 %i6, 0
  %i8 = trunc nuw nsw i32 %i7 to i16
  %gep.dst = getelementptr inbounds i16, ptr %dst, i64 %iv
  store i16 %i8, ptr %gep.dst, align 2
  %iv.next = add nsw i64 %iv, 1
  %ec = icmp eq i64 %iv.next, 1000
  br i1 %ec, label %exit, label %loop

exit:                                             ; preds = %loop
  ret void
}

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

define i32 @test_icmp_constant_op_zext(ptr %dst) {
entry:
  br label %loop

loop:                                             ; preds = %loop, %entry
  %iv = phi i16 [ 1, %entry ], [ %iv.next, %loop ]
  %c = icmp ne i64 7304878031173690989, 0
  %c.ext = zext i1 %c to i64
  %or = or i64 7304878031173690989, %c.ext
  %or.trunc = trunc i64 %or to i8
  %gep = getelementptr i8, ptr %dst, i16 %iv
  store i8 %or.trunc, ptr %gep, align 1
  %iv.next = add i16 %iv, 1
  %ec = icmp eq i16 %iv.next, 1000
  br i1 %ec, label %exit, label %loop

exit:                                             ; preds = %loop
  ret i32 0
}

llvm crash on loop-vectorize: Assertion `OldResSizeInBits > NewResSizeInBits && "Nothing to shrink?"' failed.

llvm crashes on the following IR.

Bisected to 822c749aec69ace75bd3923a4c850e2fd2e34fb1, which was committed by @fhahn

Compiler explorer: https://godbolt.org/z/rWj9dhvPo

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

define void @i(i64 %0) {
entry:
  %conv = sext i16 1 to i32
  br label %for.body

for.body:                                         ; preds = %for.body, %entry
  %1 = phi i32 [ 0, %entry ], [ %inc, %for.body ]
  %tobool.not.i = icmp eq i64 %0, 0
  %..i = select i1 %tobool.not.i, i32 0, i32 0
  %cmp = icmp eq i32 %..i, 0
  %conv1 = zext i1 %tobool.not.i to i32
  %or = or i32 %conv1, %conv
  %cmp2 = icmp slt i32 %or, 7
  %conv4 = zext i1 %cmp2 to i64
  store i64 %conv4, ptr null, align 8
  %inc = add i32 %1, 1
  %tobool.not = icmp eq i32 %inc, 0
  br i1 %tobool.not, label %for.cond.for.end_crit_edge, label %for.body

for.cond.for.end_crit_edge:                       ; preds = %for.body
  ret void
}
```

```console
% opt -passes=loop-vectorize reduced.ll
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:
0.	Program arguments: /zdata/shaoli/compilers/ccbuilder-compilers/clang-822c749aec69ace75bd3923a4c850e2fd2e34fb1/bin/opt -disable-output -passes=loop-vectorize reduced.ll
 #0 0x00007f5302fedeff llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/zdata/shaoli/compilers/ccbuilder-compilers/clang-822c749aec69ace75bd3923a4c850e2fd2e34fb1/bin/../lib/libLLVM-18git.so+0x902eff)
 #1 0x00007f5302feb654 SignalHandler(int) Signals.cpp:0:0
 #2 0x00007f5302300090 (/lib/x86_64-linux-gnu/libc.so.6+0x43090)
 #3 0x00007f5304a458f0 llvm::InnerLoopVectorizer::truncateToMinimalBitwidths(llvm::VPTransformState&) (/zdata/shaoli/compilers/ccbuilder-compilers/clang-822c749aec69ace75bd3923a4c850e2fd2e34fb1/bin/../lib/libLLVM-18git.so+0x235a8f0)
 #4 0x00007f5304a49d95 llvm::InnerLoopVectorizer::fixVectorizedLoop(llvm::VPTransformState&, llvm::VPlan&) (/zdata/shaoli/compilers/ccbuilder-compilers/clang-822c749aec69ace75bd3923a4c850e2fd2e34fb1/bin/../lib/libLLVM-18git.so+0x235ed95)
 #5 0x00007f5304a4abb1 llvm::LoopVectorizationPlanner::executePlan(llvm::ElementCount, unsigned int, llvm::VPlan&, llvm::InnerLoopVectorizer&, llvm::DominatorTree*, bool, llvm::DenseMap<llvm::SCEV const*, llvm::Value*, llvm::DenseMapInfo<llvm::SCEV const*, void>, llvm::detail::DenseMapPair<llvm::SCEV const*, llvm::Value*>>*) (/zdata/shaoli/compilers/ccbuilder-compilers/clang-822c749aec69ace75bd3923a4c850e2fd2e34fb1/bin/../lib/libLLVM-18git.so+0x235fbb1)
 #6 0x00007f5304a4d564 llvm::LoopVectorizePass::processLoop(llvm::Loop*) (/zdata/shaoli/compilers/ccbuilder-compilers/clang-822c749aec69ace75bd3923a4c850e2fd2e34fb1/bin/../lib/libLLVM-18git.so+0x2362564)
 #7 0x00007f5304a4fbdd 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*) (/zdata/shaoli/compilers/ccbuilder-compilers/clang-822c749aec69ace75bd3923a4c850e2fd2e34fb1/bin/../lib/libLLVM-18git.so+0x2364bdd)
 #8 0x00007f5304a50e20 llvm::LoopVectorizePass::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/zdata/shaoli/compilers/ccbuilder-compilers/clang-822c749aec69ace75bd3923a4c850e2fd2e34fb1/bin/../lib/libLLVM-18git.so+0x2365e20)
 #9 0x00007f5305e0d916 llvm::detail::PassModel<llvm::Function, llvm::LoopVectorizePass, llvm::PreservedAnalyses, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/zdata/shaoli/compilers/ccbuilder-compilers/clang-822c749aec69ace75bd3923a4c850e2fd2e34fb1/bin/../lib/libLLVM-18git.so+0x3722916)
#10 0x00007f53031fd3fd llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/zdata/shaoli/compilers/ccbuilder-compilers/clang-822c749aec69ace75bd3923a4c850e2fd2e34fb1/bin/../lib/libLLVM-18git.so+0xb123fd)
#11 0x00007f5305e069f6 llvm::detail::PassModel<llvm::Function, llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>, llvm::PreservedAnalyses, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/zdata/shaoli/compilers/ccbuilder-compilers/clang-822c749aec69ace75bd3923a4c850e2fd2e34fb1/bin/../lib/libLLVM-18git.so+0x371b9f6)
#12 0x00007f53031fbc8d llvm::ModuleToFunctionPassAdaptor::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/zdata/shaoli/compilers/ccbuilder-compilers/clang-822c749aec69ace75bd3923a4c850e2fd2e34fb1/bin/../lib/libLLVM-18git.so+0xb10c8d)
#13 0x00007f5305e0d696 llvm::detail::PassModel<llvm::Module, llvm::ModuleToFunctionPassAdaptor, llvm::PreservedAnalyses, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/zdata/shaoli/compilers/ccbuilder-compilers/clang-822c749aec69ace75bd3923a4c850e2fd2e34fb1/bin/../lib/libLLVM-18git.so+0x3722696)
#14 0x00007f53031f9c0d llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/zdata/shaoli/compilers/ccbuilder-compilers/clang-822c749aec69ace75bd3923a4c850e2fd2e34fb1/bin/../lib/libLLVM-18git.so+0xb0ec0d)
#15 0x0000555c5281fcb5 llvm::runPassPipeline(llvm::StringRef, llvm::Module&, llvm::TargetMachine*, llvm::TargetLibraryInfoImpl*, llvm::ToolOutputFile*, llvm::ToolOutputFile*, llvm::ToolOutputFile*, llvm::StringRef, llvm::ArrayRef<llvm::PassPlugin>, llvm::opt_tool::OutputKind, llvm::opt_tool::VerifierKind, bool, bool, bool, bool, bool, bool, bool) (/zdata/shaoli/compilers/ccbuilder-compilers/clang-822c749aec69ace75bd3923a4c850e2fd2e34fb1/bin/opt+0x25cb5)
#16 0x0000555c52813876 main (/zdata/shaoli/compilers/ccbuilder-compilers/clang-822c749aec69ace75bd3923a4c850e2fd2e34fb1/bin/opt+0x19876)
#17 0x00007f53022e1083 __libc_start_main /build/glibc-wuryBv/glibc-2.31/csu/../csu/libc-start.c:342:3
#18 0x0000555c5281451e _start (/zdata/shaoli/compilers/ccbuilder-compilers/clang-822c749aec69ace75bd3923a4c850e2fd2e34fb1/bin/opt+0x1a51e)
[1]    1975861 segmentation fault   -disable-output -passes=loop-vectorize reduced.ll
```

This IR is reduced from
```C
long a, b;
int c, d, f;
static long *e = &b;
static short g = 5;
int h() {
  if (a)
    return 0;
  return 5;
}
void i() {
  int j;
  long **k = &e;
  for (; d; d++) {
    j = h();
    *e = 6 >= (g | (j + c == 0));
  }
  j =  &k || 1;
  short *l[6];
  l[f] = &g;
}
int main() {}
```


commit 889215a30ed60474e573f9632d1fa362dfa1b04e
Author: Alexey Bataev <a.bataev@outlook.com>
Date:   Thu Dec 26 05:09:51 2024 -0800

    [SLP]Followup fix for the poisonous logical op in reductions

    If the VectorizedTree still may generate poisonous value, but it is not
    the original operand of the reduction op, need to check if Res still the
    operand, to generate correct code.

    Fixes #114905

diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index 57f3016fbe1e..e9fc89fa242a 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -19821,21 +19821,21 @@ public:
         Builder.SetCurrentDebugLocation(
             cast<Instruction>(ReductionOps.front().front())->getDebugLoc());
         if (AnyBoolLogicOp) {
-
-          if (auto It = ReducedValsToOps.find(VectorizedTree);
-              It == ReducedValsToOps.end() ||
+          auto It = ReducedValsToOps.find(VectorizedTree);
+          auto It1 = ReducedValsToOps.find(Res);
+          if ((It == ReducedValsToOps.end() && It1 == ReducedValsToOps.end()) ||
               isGuaranteedNotToBePoison(VectorizedTree, AC) ||
-              any_of(It->getSecond(), [&](Instruction *I) {
-                return isBoolLogicOp(I) &&
-                       getRdxOperand(I, 0) == VectorizedTree;
-              })) {
+              (It != ReducedValsToOps.end() &&
+               any_of(It->getSecond(), [&](Instruction *I) {
+                 return isBoolLogicOp(I) &&
+                        getRdxOperand(I, 0) == VectorizedTree;
+               }))) {
             ;
-          } else if (auto It = ReducedValsToOps.find(Res);
-                     It == ReducedValsToOps.end() ||
-                     isGuaranteedNotToBePoison(Res, AC) ||
-                     any_of(It->getSecond(), [&](Instruction *I) {
+          } else if (isGuaranteedNotToBePoison(Res, AC) ||
+                     (It1 != ReducedValsToOps.end() &&
+                     any_of(It1->getSecond(), [&](Instruction *I) {
                        return isBoolLogicOp(I) && getRdxOperand(I, 0) == Res;
-                     })) {
+                     }))) {
             std::swap(VectorizedTree, Res);
           } else {
             VectorizedTree = Builder.CreateFreeze(VectorizedTree);

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

opt < %s -passes=slp-vectorizer -mtriple=x86_64-- -mattr=avx512vl -S

define i1 @logical_or_icmp_extra_op(<4 x i32> %x, <4 x i32> %y, i1 %c) {
  %x0 = extractelement <4 x i32> %x, i32 0
  %x1 = extractelement <4 x i32> %x, i32 1
  %x2 = extractelement <4 x i32> %x, i32 2
  %x3 = extractelement <4 x i32> %x, i32 3
  %y0 = extractelement <4 x i32> %y, i32 0
  %y1 = extractelement <4 x i32> %y, i32 1
  %y2 = extractelement <4 x i32> %y, i32 2
  %y3 = extractelement <4 x i32> %y, i32 3
  %d0 = icmp slt i32 %x0, %y0
  %d1 = icmp slt i32 %x1, %y1
  %d2 = icmp slt i32 %x2, %y2
  %d3 = icmp slt i32 %x3, %y3
  %s3 = select i1 %c, i1 true, i1 %c
  %s4 = select i1 %s3, i1 true, i1 %d0
  %s5 = select i1 %s4, i1 true, i1 %d1
  %s6 = select i1 %s5, i1 true, i1 %d2
  %s7 = select i1 %s6, i1 true, i1 %d3
  ret i1 %s7
}

define i1 @logical_and_icmp_extra_op(<4 x i32> %x, <4 x i32> %y, i1 %c) {
  %x0 = extractelement <4 x i32> %x, i32 0
  %x1 = extractelement <4 x i32> %x, i32 1
  %x2 = extractelement <4 x i32> %x, i32 2
  %x3 = extractelement <4 x i32> %x, i32 3
  %y0 = extractelement <4 x i32> %y, i32 0
  %y1 = extractelement <4 x i32> %y, i32 1
  %y2 = extractelement <4 x i32> %y, i32 2
  %y3 = extractelement <4 x i32> %y, i32 3
  %d0 = icmp slt i32 %x0, %y0
  %d1 = icmp slt i32 %x1, %y1
  %d2 = icmp slt i32 %x2, %y2
  %d3 = icmp slt i32 %x3, %y3
  %s3 = select i1 %c, i1 %c, i1 false
  %s4 = select i1 %s3, i1 %d0, i1 false
  %s5 = select i1 %s4, i1 %d1, i1 false
  %s6 = select i1 %s5, i1 %d2, i1 false
  %s7 = select i1 %s6, i1 %d3, i1 false
  ret i1 %s7
}

define i1 @test(<4 x i32> %x) {
  %x0 = extractelement <4 x i32> %x, i32 0
  %x1 = extractelement <4 x i32> %x, i32 -1
  %x2 = extractelement <4 x i32> %x, i32 2
  %x3 = extractelement <4 x i32> %x, i32 3
  %1 = icmp ugt i32 %x0, 0
  %c1 = icmp slt i32 %x1, 0
  %c2 = icmp sgt i32 %x2, 0
  %c3 = icmp slt i32 %x3, 0
  %s1 = select i1 %1, i1 %c1, i1 false
  %s2 = select i1 %s1, i1 %c3, i1 false
  %s3 = select i1 %s2, i1 %c3, i1 false
  ret i1 %s3
}

wrong folding of `select`s in slp-vectorizer

Alive2 report: https://alive2.llvm.org/ce/z/jEopx9

```llvm
----------------------------------------
define i1 @logical_and_icmp_diff_preds.2(<4 x i32> %x) {
#0:
  %x0 = extractelement <4 x i32> %x, i32 0
  %x1 = extractelement <4 x i32> %x, i32 4294967295
  %x3 = extractelement <4 x i32> %x, i32 3
  %#1 = icmp ugt i32 %x0, 0
  %c1 = icmp slt i32 %x1, 0
  %c3 = icmp slt i32 %x3, 0
  %s1 = select i1 %#1, i1 %c1, i1 0
  %s2 = select i1 %s1, i1 %c3, i1 0
  %s3 = select i1 %s2, i1 %c3, i1 0
  ret i1 %s3
}
=>
define i1 @logical_and_icmp_diff_preds.2(<4 x i32> %x) {
#0:
  %x0 = extractelement <4 x i32> %x, i32 0
  %x1 = extractelement <4 x i32> %x, i32 4294967295
  %x3 = extractelement <4 x i32> %x, i32 3
  %#1 = icmp ugt i32 %x0, 0
  %c1 = icmp slt i32 %x1, 0
  %c3 = icmp slt i32 %x3, 0
  %op.rdx = select i1 %c3, i1 %c1, i1 0
  %op.rdx1 = select i1 %op.rdx, i1 %#1, i1 0
  ret i1 %op.rdx1
}
Transformation doesn't verify!

ERROR: Target is more poisonous than source

Example:
<4 x i32> %x = < #x00000000 (0), #x00000000 (0), #x00000000 (0), #xffffffff (4294967295, -1) >

Source:
i32 %x0 = #x00000000 (0)
i32 %x1 = poison
i32 %x3 = #xffffffff (4294967295, -1)
i1 %#1 = #x0 (0)
i1 %c1 = poison
i1 %c3 = #x1 (1)
i1 %s1 = #x0 (0)
i1 %s2 = #x0 (0)
i1 %s3 = #x0 (0)

Target:
i32 %x0 = #x00000000 (0)
i32 %x1 = poison
i32 %x3 = #xffffffff (4294967295, -1)
i1 %#1 = #x0 (0)
i1 %c1 = poison
i1 %c3 = #x1 (1)
i1 %op.rdx = poison
i1 %op.rdx1 = poison
Source value: #x0 (0)
Target value: poison

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

Alive2 is still not happy with the fix:
```llvm
define i1 @test(<4 x i32> %x) {
  %x0 = extractelement <4 x i32> %x, i32 0
  %x1 = extractelement <4 x i32> %x, i32 4294967295
  %x3 = extractelement <4 x i32> %x, i32 3
  %#1 = icmp ugt i32 %x0, 0
  %c1 = icmp slt i32 %x1, 0
  %c3 = icmp slt i32 %x3, 0
  %s1 = select i1 %#1, i1 %c1, i1 0
  %s2 = select i1 %s1, i1 %c3, i1 0
  %s3 = select i1 %s2, i1 %c3, i1 0
  ret i1 %s3
}
=>
define i1 @test(<4 x i32> %x) {
  %x0 = extractelement <4 x i32> %x, i32 0
  %x1 = extractelement <4 x i32> %x, i32 4294967295
  %x3 = extractelement <4 x i32> %x, i32 3
  %#1 = icmp ugt i32 %x0, 0
  %c1 = icmp slt i32 %x1, 0
  %c3 = icmp slt i32 %x3, 0
  %#2 = freeze i1 %c3
  %op.rdx = select i1 %#2, i1 %c1, i1 0
  %op.rdx1 = select i1 %op.rdx, i1 %#1, i1 0
  ret i1 %op.rdx1
}
Transformation doesn't verify!

ERROR: Target is more poisonous than source

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

Source:
i32 %x0 = #x00000000 (0)
i32 %x1 = poison
i32 %x3 = #xffffffff (4294967295, -1)
i1 %#1 = #x0 (0)
i1 %c1 = poison
i1 %c3 = #x1 (1)
i1 %s1 = #x0 (0)
i1 %s2 = #x0 (0)
i1 %s3 = #x0 (0)

Target:
i32 %x0 = #x00000000 (0)
i32 %x1 = poison
i32 %x3 = #xffffffff (4294967295, -1)
i1 %#1 = #x0 (0)
i1 %c1 = poison
i1 %c3 = #x1 (1)
i1 %#2 = #x1 (1)
i1 %op.rdx = poison
i1 %op.rdx1 = poison
Source value: #x0 (0)
Target value: poison
```


commit 9de327c94d0c995803b6485fb28ac4cad1e53bbe
Author: Florian Hahn <flo@fhahn.com>
Date:   Wed Oct 2 20:16:41 2024 +0100

    [LV] Generalize predication checks from 2c8836c899 for operands.

    This fixes another case where the VPlan-based and legacy cost models
    disagree. If any of the operands is predicated, it can't be trivially
    hoisted and we should consider the cost for evaluating it each loop
    iteration.

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

diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index de3b981a4fe3..6e082b1c134d 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -6551,14 +6551,17 @@ LoopVectorizationCostModel::getInstructionCost(Instruction *I,
       Op2 = cast<SCEVConstant>(PSE.getSCEV(Op2))->getValue();
     }
     auto Op2Info = TTI.getOperandInfo(Op2);
-    auto IsInvariant = [this](Value *Op) {
+    std::function<bool(Value *)> IsInvariant =
+        [this, &IsInvariant](Value *Op) -> bool {
       if (!Legal->isInvariant(Op))
         return false;
-      // Consider Op2 invariant, if it is not a predicated instruction in the
-      // loop. In that case, it is not trivially hoistable.
+      // Consider Op2invariant, if it or its operands aren't predicated
+      // instruction in the loop. In that case, it is not trivially hoistable.
       return !isa<Instruction>(Op) ||
              !TheLoop->contains(cast<Instruction>(Op)) ||
-             !isPredicatedInst(cast<Instruction>(Op));
+             (!isPredicatedInst(cast<Instruction>(Op)) &&
+              all_of(cast<Instruction>(Op)->operands(),
+                     [&IsInvariant](Value *Op) { return IsInvariant(Op); }));
     };
     if (Op2Info.Kind == TargetTransformInfo::OK_AnyValue && IsInvariant(Op2))
       Op2Info.Kind = TargetTransformInfo::OK_UniformValue;

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

define void @predicated_urem_shl_cost(ptr %A, i32 %x, i1 %c) {
entry:
  br label %loop.header

loop.header:                                      ; preds = %loop.latch, %entry
  %iv = phi i32 [ 1, %entry ], [ %iv.next, %loop.latch ]
  %gep = getelementptr inbounds i32, ptr %A, i32 %iv
  %l = load i32, ptr %gep, align 4
  br i1 %c, label %then, label %loop.latch

then:                                             ; preds = %loop.header
  %rem = urem i32 2, %x
  %shl = shl i32 %l, %rem
  br label %loop.latch

loop.latch:                                       ; preds = %then, %loop.header
  %p = phi i32 [ 0, %loop.header ], [ %shl, %then ]
  store i32 %p, ptr %gep, align 4
  %iv.next = add i32 %iv, 1
  %ec = icmp eq i32 %iv, 0
  br i1 %ec, label %exit, label %loop.header

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

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

define void @test_wide_shift_uses_predicated_invariant_instruction(i32 %d, i1 %c, ptr %dst) {
entry:
  br label %loop.header

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

else:                                             ; preds = %loop.header
  %rem = urem i32 100, %d
  %sext = shl i32 %rem, 12
  %shl.i = shl i32 999, %sext
  br label %loop.latch

loop.latch:                                       ; preds = %else, %loop.header
  %p = phi i32 [ %shl.i, %else ], [ 0, %loop.header ]
  %gep = getelementptr inbounds i32, ptr %dst, i32 %iv
  store i32 %p, ptr %gep, align 4
  %iv.next = add i32 %iv, 1
  %ec = icmp eq i32 %iv.next, 100
  br i1 %ec, label %exit, label %loop.header

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

clang crashes on valid code at -O{2,3} on x86_64-linux-gnu: Assertion `(BestFactor.Width == LegacyVF.Width || planContainsAdditionalSimplifications(getPlanFor(BestFactor.Width), CostCtx, OrigLoop)) && " VPlan cost model and legacy cost model disagreed"' failed

Compiler Explorer: https://godbolt.org/z/9K4a3Pr7j

```
[508] % clangtk -v
clang version 20.0.0git (https://github.com/llvm/llvm-project.git 223e2efa5e886502a9467b7ef700ebce9b7886e8)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /local/suz-local/software/local/clang-trunk/bin
Build config: +assertions
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/10
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/11
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/9
Selected GCC installation: /usr/lib/gcc/x86_64-linux-gnu/11
Candidate multilib: .;@m64
Selected multilib: .;@m64
[509] %
[509] % clangtk -O2 small.c
clang-20: /local/suz-local/software/clangbuild/llvm-project/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp:7390: llvm::VectorizationFactor llvm::LoopVectorizationPlanner::computeBestVF(): Assertion `(BestFactor.Width == LegacyVF.Width || planContainsAdditionalSimplifications(getPlanFor(BestFactor.Width), CostCtx, OrigLoop)) && " VPlan cost model and legacy cost model disagreed"' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace, preprocessed source, and associated run script.
Stack dump:
0.	Program arguments: /local/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/20240914-clangtk-m64-O3-build-061621/delta -fcoverage-compilation-dir=/local/suz-local/software/emitesting/bugs/20240914-clangtk-m64-O3-build-061621/delta -resource-dir /local/suz-local/software/local/clang-trunk/lib/clang/20 -I /usr/local/include -I /local/suz-local/software/local/include -internal-isystem /local/suz-local/software/local/clang-trunk/lib/clang/20/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/11/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -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-34578e.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 "loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>" on function "main"
 #0 0x000055ba1845c4ff llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/local/suz-local/software/local/clang-trunk/bin/clang-20+0x43484ff)
 #1 0x000055ba18459a34 SignalHandler(int) Signals.cpp:0:0
 #2 0x00007fbbfabd4420 __restore_rt (/lib/x86_64-linux-gnu/libpthread.so.0+0x14420)
 #3 0x00007fbbfa60b00b raise /build/glibc-LcI20x/glibc-2.31/signal/../sysdeps/unix/sysv/linux/raise.c:51:1
 #4 0x00007fbbfa5ea859 abort /build/glibc-LcI20x/glibc-2.31/stdlib/abort.c:81:7
 #5 0x00007fbbfa5ea729 get_sysdep_segment_value /build/glibc-LcI20x/glibc-2.31/intl/loadmsgcat.c:509:8
 #6 0x00007fbbfa5ea729 _nl_load_domain /build/glibc-LcI20x/glibc-2.31/intl/loadmsgcat.c:970:34
 #7 0x00007fbbfa5fbfd6 (/lib/x86_64-linux-gnu/libc.so.6+0x33fd6)
 #8 0x000055ba19db5fcb llvm::LoopVectorizationPlanner::computeBestVF() (/local/suz-local/software/local/clang-trunk/bin/clang-20+0x5ca1fcb)
 #9 0x000055ba19dd169a llvm::LoopVectorizePass::processLoop(llvm::Loop*) (/local/suz-local/software/local/clang-trunk/bin/clang-20+0x5cbd69a)
#10 0x000055ba19dd42d1 llvm::LoopVectorizePass::runImpl(llvm::Function&) (/local/suz-local/software/local/clang-trunk/bin/clang-20+0x5cc02d1)
#11 0x000055ba19dd4943 llvm::LoopVectorizePass::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/local/suz-local/software/local/clang-trunk/bin/clang-20+0x5cc0943)
#12 0x000055ba19946a06 llvm::detail::PassModel<llvm::Function, llvm::LoopVectorizePass, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/local/suz-local/software/local/clang-trunk/bin/clang-20+0x5832a06)
#13 0x000055ba17dec0d1 llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/local/suz-local/software/local/clang-trunk/bin/clang-20+0x3cd80d1)
#14 0x000055ba15926546 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/suz-local/software/local/clang-trunk/bin/clang-20+0x1812546)
#15 0x000055ba17deaa3d llvm::ModuleToFunctionPassAdaptor::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/local/suz-local/software/local/clang-trunk/bin/clang-20+0x3cd6a3d)
#16 0x000055ba15925216 llvm::detail::PassModel<llvm::Module, llvm::ModuleToFunctionPassAdaptor, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/local/suz-local/software/local/clang-trunk/bin/clang-20+0x1811216)
#17 0x000055ba17dea471 llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/local/suz-local/software/local/clang-trunk/bin/clang-20+0x3cd6471)
#18 0x000055ba18713673 (anonymous namespace)::EmitAssemblyHelper::RunOptimizationPipeline(clang::BackendAction, std::unique_ptr<llvm::raw_pwrite_stream, std::default_delete<llvm::raw_pwrite_stream>>&, std::unique_ptr<llvm::ToolOutputFile, std::default_delete<llvm::ToolOutputFile>>&, clang::BackendConsumer*) BackendUtil.cpp:0:0
#19 0x000055ba187167f8 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/suz-local/software/local/clang-trunk/bin/clang-20+0x46027f8)
#20 0x000055ba18decf5c clang::BackendConsumer::HandleTranslationUnit(clang::ASTContext&) (/local/suz-local/software/local/clang-trunk/bin/clang-20+0x4cd8f5c)
#21 0x000055ba1ac8966c clang::ParseAST(clang::Sema&, bool, bool) (/local/suz-local/software/local/clang-trunk/bin/clang-20+0x6b7566c)
#22 0x000055ba18ded378 clang::CodeGenAction::ExecuteAction() (/local/suz-local/software/local/clang-trunk/bin/clang-20+0x4cd9378)
#23 0x000055ba1908a659 clang::FrontendAction::Execute() (/local/suz-local/software/local/clang-trunk/bin/clang-20+0x4f76659)
#24 0x000055ba1900c07e clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) (/local/suz-local/software/local/clang-trunk/bin/clang-20+0x4ef807e)
#25 0x000055ba191772b6 clang::ExecuteCompilerInvocation(clang::CompilerInstance*) (/local/suz-local/software/local/clang-trunk/bin/clang-20+0x50632b6)
#26 0x000055ba154f2b15 cc1_main(llvm::ArrayRef<char const*>, char const*, void*) (/local/suz-local/software/local/clang-trunk/bin/clang-20+0x13deb15)
#27 0x000055ba154ebbba ExecuteCC1Tool(llvm::SmallVectorImpl<char const*>&, llvm::ToolContext const&) driver.cpp:0:0
#28 0x000055ba154ef58e clang_main(int, char**, llvm::ToolContext const&) (/local/suz-local/software/local/clang-trunk/bin/clang-20+0x13db58e)
#29 0x000055ba153dd43b main (/local/suz-local/software/local/clang-trunk/bin/clang-20+0x12c943b)
#30 0x00007fbbfa5ec083 __libc_start_main /build/glibc-LcI20x/glibc-2.31/csu/../csu/libc-start.c:342:3
#31 0x000055ba154eb64e _start (/local/suz-local/software/local/clang-trunk/bin/clang-20+0x13d764e)
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 223e2efa5e886502a9467b7ef700ebce9b7886e8)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /local/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-682958.c
clangtk: note: diagnostic msg: /tmp/small-682958.sh
clangtk: note: diagnostic msg:

********************
[510] %
[510] % cat small.c
short a, b, c, d;
unsigned short e;
int main() {
  for (; d; d++) {
    e = a + b;
    c = b > 3 || e > b ? e : e << b;
    c = c ? 2 / c : 0;
    b = 1;
  }
  return 0;
}
```


commit 40a647fc7dc6048c92e2d580b61f5feca0785980
Author: Yingwei Zheng <dtcxzyw2333@gmail.com>
Date:   Fri Nov 15 09:15:37 2024 +0800

    [IndVarSimplify] Drop samesign flags after narrowing compares (#116263)

    Samesign flag cannot be preserved after narrowing the compare since the
    position of the sign bit is changed.

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

diff --git a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
index 2b2d516a7079..8a3e0bc3eb97 100644
--- a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
+++ b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
@@ -1530,6 +1530,8 @@ bool IndVarSimplify::canonicalizeExitCondition(Loop *L) {
           L->getLoopPreheader()->getTerminator()->getIterator());
       ICmp->setOperand(Swapped ? 1 : 0, LHSOp);
       ICmp->setOperand(Swapped ? 0 : 1, NewRHS);
+      // Samesign flag cannot be preserved after narrowing the compare.
+      ICmp->setSameSign(false);
       if (LHS->use_empty())
         DeadInsts.push_back(LHS);
     };

opt -passes=indvars -S < %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"

define i8 @test_drop_icmp_samesign(i1 %cond, i32 range(i32 0, 32) %x) {
entry:
  br i1 %cond, label %for.body, label %else

else:                                             ; preds = %entry
  %call1 = call i8 @callee()
  br label %exit

for.body:                                         ; preds = %for.body, %entry
  %call2 = call i8 @callee()
  %ext = zext i8 %call2 to i32
  %cond2 = icmp samesign ugt i32 %x, %ext
  br i1 %cond2, label %for.body, label %exit

exit:                                             ; preds = %for.body, %else
  %res = phi i8 [ %call1, %else ], [ %call2, %for.body ]
  ret i8 %res
}

declare i8 @callee()

[IndVarSimplify] samesign flag should be dropped after narrowing

Found with https://github.com/dtcxzyw/llvm-ub-aware-interpreter.
Reproducer: https://alive2.llvm.org/ce/z/fcnvLv
```
; bin/opt -passes=indvars test.ll -S
define i8 @test(i1 %cond, i32 range(i32 0, 32) %x) {
entry:
  br i1 %cond, label %for.body, label %else

else:
  %call1 = call i8 @callee()
  br label %exit

for.body:
  %call2 = call i8 @callee()
  %ext = zext i8 %call2 to i32
  %cond2 = icmp samesign ugt i32 %x, %ext
  br i1 %cond2, label %for.body, label %exit

exit:
  %res = phi i8 [ %call1, %else ], [ %call2, %for.body ]
  ret i8 %res
}
```
```

----------------------------------------
declare i8 @callee()

define i8 @test(i1 %cond, i32 %x) {
init:
  %#range_0_%x = !range i32 %x, i32 0, i32 32
  br label %entry

entry:
  br i1 %cond, label %for.body, label %else

else:
  %call1 = call i8 @callee()
  br label %exit

for.body:
  %call2 = call i8 @callee()
  %ext = zext i8 %call2 to i32
  %cond2 = icmp samesign ugt i32 %#range_0_%x, %ext
  br i1 %cond2, label %for.body, label %exit

exit:
  %res = phi i8 [ %call1, %else ], [ %call2, %for.body ]
  ret i8 %res
}
=>
declare i8 @callee()

define i8 @test(i1 %cond, i32 %x) {
init:
  %#range_0_%x = !range i32 %x, i32 0, i32 32
  br label %entry

entry:
  br i1 %cond, label %for.body.preheader, label %else

else:
  %call1 = call i8 @callee()
  br label %exit

for.body.preheader:
  %#0 = trunc i32 %#range_0_%x to i8
  br label %for.body

for.body:
  %call2 = call i8 @callee()
  %cond2 = icmp samesign ugt i8 %#0, %call2
  br i1 %cond2, label %for.body, label %exit.loopexit

exit.loopexit:
  %call2.lcssa = phi i8 [ %call2, %for.body ]
  br label %exit

exit:
  %res = phi i8 [ %call1, %else ], [ %call2.lcssa, %exit.loopexit ]
  ret i8 %res
}
Transformation doesn't verify!

ERROR: Source is more defined than target

Example:
i1 %cond = #x1 (1)
i32 %x = #x00000000 (0)

Source:
i32 %#range_0_%x = #x00000000 (0)
  >> Jump to %entry
  >> Jump to %for.body
i8 %call2 = #x80 (128, -128)
i32 %ext = #x00000080 (128)
i1 %cond2 = #x0 (0)
  >> Jump to %exit
i8 %res = #x80 (128, -128)

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

Target:
i32 %#range_0_%x = #x00000000 (0)
  >> Jump to %entry
  >> Jump to %for.body.preheader
i8 %#0 = #x00 (0)
  >> Jump to %for.body
i8 %call2 = #x80 (128, -128)
i1 %cond2 = poison
UB triggered on br

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


commit 2b3b405b09a0d965a4aff1f92958418ddbf1e7f6
Author: Florian Hahn <flo@fhahn.com>
Date:   Thu Jul 4 11:44:50 2024 +0100

    [LV] Don't vectorize first-order recurrence with VF <vscale x 1 x ..>

    The assertion added as part of https://github.com/llvm/llvm-project/pull/93395
    surfaced cases where first-order recurrences are vectorized with
    <vscale x 1 x ..>. If vscale is 1, then we are unable to extract the
    penultimate value (second to last lane). Previously this case got
    mis-compiled, trying to extract from an invalid lane (-1)
    https://llvm.godbolt.org/z/3adzYYcf9.

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

diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index f9c0c66e6e0a..d7b0240fd8a8 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -6813,6 +6813,11 @@ LoopVectorizationCostModel::getInstructionCost(Instruction *I, ElementCount VF,

     // First-order recurrences are replaced by vector shuffles inside the loop.
     if (VF.isVector() && Legal->isFixedOrderRecurrence(Phi)) {
+      // For <vscale x 1 x i64>, if vscale = 1 we are unable to extract the
+      // penultimate value of the recurrence.
+      // TODO: Consider vscale_range info.
+      if (VF.isScalable() && VF.getKnownMinValue() == 1)
+        return InstructionCost::getInvalid();
       SmallVector<int> Mask(VF.getKnownMinValue());
       std::iota(Mask.begin(), Mask.end(), VF.getKnownMinValue() - 1);
       return TTI.getShuffleCost(TargetTransformInfo::SK_Splice,

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

; Make sure we do not pick <vscale x 1 x i64> as VF for a loop with a
; first-order recurrence.
define i64 @pr97452_scalable_vf1_for(ptr %src) #0 {
;
entry:
  br label %loop

loop:
  %for = phi i64 [ 0, %entry ], [ %l, %loop ]
  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
  %iv.next = add i64 %iv, 1
  %gep = getelementptr inbounds i64, ptr %src, i64 %iv
  %l = load i64, ptr %gep, align 8
  %ec = icmp eq i64 %iv, 22
  br i1 %ec, label %exit, label %loop

exit:
  %res = phi i64 [ %for, %loop ]
  ret i64 %res
}

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

opt -p loop-vectorize -scalable-vectorization=on -force-vector-width=1 -force-target-supports-scalable-vectors=true -S %s

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

define i64 @pr97452_scalable_vf1_for_live_out(ptr %src) {
;
entry:
  br label %loop

loop:
  %for = phi i64 [ 0, %entry ], [ %l, %loop ]
  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
  %iv.next = add i64 %iv, 1
  %gep = getelementptr inbounds i64, ptr %src, i64 %iv
  %l = load i64, ptr %gep, align 8
  %ec = icmp eq i64 %iv, 22
  br i1 %ec, label %exit, label %loop

exit:
  %res = phi i64 [ %for, %loop ]
  ret i64 %res
}

define void @pr97452_scalable_vf1_for_no_live_out(ptr %src, ptr noalias %dst) {
;
entry:
  br label %loop

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

exit:
  ret void
}

[LoopVectorize] Assertion `Offset <= State.VF.getKnownMinValue() && "invalid offset to extract from"' failed.

Reduced 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() #0 {
entry:
  br label %for.body

for.cond.cleanup:                                 ; preds = %for.body
  %.lcssa17 = phi i64 [ %0, %for.body ]
  ret i32 0

for.body:                                         ; preds = %for.body, %entry
  %0 = phi i64 [ 0, %entry ], [ %1, %for.body ]
  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
  %indvars.iv.next = add i64 %indvars.iv, 1
  %1 = load i64, ptr null, align 8
  %exitcond.not = icmp eq i64 %indvars.iv, 22
  br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
}

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

Command/backtrace:
```bash
> /scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt -passes=loop-vectorize reduced.ll
WARNING: You're attempting to print out a bitcode file.
This is inadvisable as it may cause display problems. If
you REALLY want to taste LLVM bitcode first-hand, you
can force output with the `-f' option.

opt: /scratch/tc-testing/tc-compiler-fuzz-trunk/llvm/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp:569: llvm::Value* llvm::VPInstruction::generatePerPart(llvm::VPTransformState&, unsigned int): Assertion `Offset <= State.VF.getKnownMinValue() && "invalid offset to extract from"' 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
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 0x000055972ae01800 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x2ed2800)
 #1 0x000055972adfec0f llvm::sys::RunSignalHandlers() (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x2ecfc0f)
 #2 0x000055972adfed65 SignalHandler(int) Signals.cpp:0:0
 #3 0x0000728161442520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #4 0x00007281614969fc __pthread_kill_implementation ./nptl/pthread_kill.c:44:76
 #5 0x00007281614969fc __pthread_kill_internal ./nptl/pthread_kill.c:78:10
 #6 0x00007281614969fc pthread_kill ./nptl/pthread_kill.c:89:10
 #7 0x0000728161442476 gsignal ./signal/../sysdeps/posix/raise.c:27:6
 #8 0x00007281614287f3 abort ./stdlib/abort.c:81:7
 #9 0x000072816142871b _nl_load_domain ./intl/loadmsgcat.c:1177:9
#10 0x0000728161439e96 (/lib/x86_64-linux-gnu/libc.so.6+0x39e96)
#11 0x0000559729f62d80 llvm::VPInstruction::generatePerPart(llvm::VPTransformState&, unsigned int) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x2033d80)
#12 0x0000559729f63155 llvm::VPInstruction::execute(llvm::VPTransformState&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x2034155)
#13 0x0000559729f2de47 llvm::VPBasicBlock::executeRecipes(llvm::VPTransformState*, llvm::BasicBlock*) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x1ffee47)
#14 0x0000559729f2e141 llvm::VPIRBasicBlock::execute(llvm::VPTransformState*) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x1fff141)
#15 0x0000559729f30286 llvm::VPlan::execute(llvm::VPTransformState*) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x2001286)
#16 0x0000559729e2380a llvm::LoopVectorizationPlanner::executePlan(llvm::ElementCount, unsigned int, llvm::VPlan&, llvm::InnerLoopVectorizer&, llvm::DominatorTree*, bool, llvm::DenseMap<llvm::SCEV const*, llvm::Value*, llvm::DenseMapInfo<llvm::SCEV const*, void>, llvm::detail::DenseMapPair<llvm::SCEV const*, llvm::Value*>> const*) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x1ef480a)
#17 0x0000559729e34a7c llvm::LoopVectorizePass::processLoop(llvm::Loop*) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x1f05a7c)
#18 0x0000559729e36f7e 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+0x1f07f7e)
#19 0x0000559729e380a0 llvm::LoopVectorizePass::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x1f090a0)
#20 0x0000559728cc6dc6 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+0xd97dc6)
#21 0x000055972ac1ce46 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+0x2cede46)
#22 0x0000559728cc9f56 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+0xd9af56)
#23 0x000055972ac1bbcb llvm::ModuleToFunctionPassAdaptor::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x2cecbcb)
#24 0x0000559728cc6526 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+0xd97526)
#25 0x000055972ac19d02 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+0x2cead02)
#26 0x0000559728520136 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+0x5f1136)
#27 0x0000559728511d51 optMain (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x5e2d51)
#28 0x0000728161429d90 __libc_start_call_main ./csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#29 0x0000728161429e40 call_init ./csu/../csu/libc-start.c:128:20
#30 0x0000728161429e40 __libc_start_main ./csu/../csu/libc-start.c:379:5
#31 0x0000559728507b85 _start (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x5d8b85)
zsh: IOT instruction (core dumped)  /scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt
```
Godbolt: https://godbolt.org/z/ojz8sMa1r

Found via fuzzer

Bisected to #93395
cc: @fhahn

Thanks for the test case. Should be fixed now. The assertion highlighted a case where we previously miscompiled for the case where VF is <vscale x 1 x ..>; in that case we are unable to extract the penultimate value (second-to-last) if vscale = 1


commit 534f8569a3c9fccfd5cbc5f632b63ad0cf711098
Author: Nikita Popov <npopov@redhat.com>
Date:   Mon Jun 17 15:36:55 2024 +0200

    [InstCombine] Don't preserve context across div

    We can't preserve the context across a non-speculatable instruction,
    as this might introduce a trap. Alternatively, we could also
    insert all the replacement instruction at the use-site, but that
    would be a more intrusive change for the sake of this edge case.

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

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
index 1b4c319032ca..6a6bdba3fa70 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
@@ -291,10 +291,12 @@ static bool canEvaluateTruncated(Value *V, Type *Ty, InstCombinerImpl &IC,
     uint32_t BitWidth = Ty->getScalarSizeInBits();
     assert(BitWidth < OrigBitWidth && "Unexpected bitwidths!");
     APInt Mask = APInt::getBitsSetFrom(OrigBitWidth, BitWidth);
-    if (IC.MaskedValueIsZero(I->getOperand(0), Mask, 0, CxtI) &&
-        IC.MaskedValueIsZero(I->getOperand(1), Mask, 0, CxtI)) {
-      return canEvaluateTruncated(I->getOperand(0), Ty, IC, CxtI) &&
-             canEvaluateTruncated(I->getOperand(1), Ty, IC, CxtI);
+    // Do not preserve the original context instruction. Simplifying div/rem
+    // based on later context may introduce a trap.
+    if (IC.MaskedValueIsZero(I->getOperand(0), Mask, 0, I) &&
+        IC.MaskedValueIsZero(I->getOperand(1), Mask, 0, I)) {
+      return canEvaluateTruncated(I->getOperand(0), Ty, IC, I) &&
+             canEvaluateTruncated(I->getOperand(1), Ty, IC, I);
     }
     break;
   }

[InstCombine] Wrong value truncation due to incorrect analysis of iv known bits

```llvm
define void @src(i32 %0, ptr %p, i1 %cnd) {
entry:
  br i1 %cnd, label %header, label %exit

header:                                           ; preds = %latch, %entry
  %iv = phi i32 [ %iv.next, %latch ], [ 256, %entry ]
  %iv.trunc = trunc i32 %iv to i16
  %div = udiv i16 11, %iv.trunc
  br i1 %cnd, label %loop1, label %loop0

loop0:                                            ; preds = %header
  %load = load i32, ptr %p, align 4
  br label %loop1

loop1:                                            ; preds = %loop0, %header
  %v = phi i32 [ %load, %loop0 ], [ 0, %header ]
  store i32 %v, ptr %p, align 4
  %guard = icmp ugt i32 %iv, 10
  br i1 %guard, label %latch, label %loop2

loop2:                                            ; preds = %loop1
  %div.trunc = trunc i16 %div to i8
  store i8 %div.trunc, ptr %p, align 1
  br label %latch

latch:                                            ; preds = %loop2, %loop1
  %iv.next = add nuw nsw i32 %iv, 1
  %exitcond = icmp ugt i32 %iv, 300
  br i1 %exitcond, label %exit, label %header

exit:                                             ; preds = %latch
  ret void
}
```
If we run `instcombine` pass on this example, it will convert `trunc i32 %iv to i16` into `trunc i32 %iv to i8` to avoid cast:
https://godbolt.org/z/ze4E45ThT

But this transformation is wrong, because on the first iteration `%iv` is equal to 256, and the 8 bits trunc makes it equal to `0`. This give us a division by zero on the next instruction: `%div = udiv i16 11, %iv.trunc`.

It seems that the problematic patch is https://github.com/llvm/llvm-project/pull/73662

@nikic Could you please take a look?

> May be false positive in Alive2 as well?

You need `-src-unroll` and `-tgt-unroll` for loops :)
https://alive2.llvm.org/ce/z/Vh4zAU

> Just out of curiosity, did you fine-tune the iterations in a particular way, or some trial-and-error? (I had tried a few ones before and didn’t manage to have the UB triggered)

I just full unrolled the loop :)
```
%iv.next = add nuw nsw i32 %iv, 1
%exitcond = icmp ugt i32 %iv, 300
```

> I just full unrolled the loop :)

Definitely makes sense, thanks!

Reduced test case:
```llvm
define void @src(i32 %x) {
  %x.trunc = trunc i32 %x to i16
  %div = udiv i16 11, %x.trunc
  %cmp = icmp ult i32 %x, 256
  br i1 %cmp, label %loop, label %exit

loop:
  %trunc = trunc i16 %div to i8
  call void @use(i8 %trunc)
  br label %loop

exit:
  ret void
}

declare void @use(i8)
```

The issue is that canEvaluateTruncated() preserves context instruction across non-speculatable operations.


commit e56e9dd8adca2e86f22783bf5e745ee1ba7ead5f
Author: Alexey Bataev <a.bataev@outlook.com>
Date:   Fri Oct 18 13:32:41 2024 -0700

    [SLP]Fix minbitwidth emission and analysis for freeze instruction

    Need to add minbw emission and analysis for freeze instruction to fix
    incorrect signedness propagation.

    Fixes #112460

diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index 53632efe913e..e7b52fbdcc3b 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -14953,6 +14953,12 @@ Value *BoUpSLP::vectorizeTree(TreeEntry *E, bool PostponedPHIs) {
         return E->VectorizedValue;
       }

+      if (Op->getType() != VecTy) {
+        assert((It != MinBWs.end() || getOperandEntry(E, 0)->isGather() ||
+                MinBWs.contains(getOperandEntry(E, 0))) &&
+               "Expected item in MinBWs.");
+        Op = Builder.CreateIntCast(Op, VecTy, GetOperandSignedness(0));
+      }
       Value *V = Builder.CreateFreeze(Op);
       V = FinalShuffle(V, E);

@@ -17095,6 +17101,8 @@ bool BoUpSLP::collectValuesToDemote(
     return TryProcessInstruction(
         BitWidth, {getOperandEntry(&E, 0), getOperandEntry(&E, 1)});
   }
+  case Instruction::Freeze:
+    return TryProcessInstruction(BitWidth, getOperandEntry(&E, 0));
   case Instruction::Shl: {
     // If we are truncating the result of this SHL, and if it's a shift of an
     // inrange amount, we can always perform a SHL in a smaller type.

define i32 @test(i1 %.b, i8 %conv18, i32 %k.promoted61) {
  %not..b79 = xor i1 %.b, true
  %1 = zext i1 %not..b79 to i8
  %cmp.i51 = icmp eq i8 %1, 0
  %cond.i55 = freeze i8 %1
  %.cmp = icmp ugt i8 %cond.i55, %conv18
  %.urem = select i1 %.cmp, i8 0, i8 %cond.i55
  %2 = sub nuw i8 %conv18, %.urem
  %cond.in.i = select i1 %cmp.i51, i8 %conv18, i8 %2
  %not..b80 = xor i1 %.b, true
  %3 = zext i1 %not..b80 to i8
  %cmp.i51.1 = icmp eq i8 %3, 0
  %cond.i55.1 = freeze i8 %3
  %.cmp.1 = icmp ugt i8 %cond.i55.1, %conv18
  %.urem.1 = select i1 %.cmp.1, i8 0, i8 %cond.i55.1
  %4 = sub nuw i8 %conv18, %.urem.1
  %cond.in.i.1 = select i1 %cmp.i51.1, i8 %conv18, i8 %4
  %not..b81 = xor i1 %.b, true
  %5 = zext i1 %not..b81 to i8
  %cmp.i51.2 = icmp eq i8 %5, 0
  %cond.i55.2 = freeze i8 %5
  %.cmp.2 = icmp ugt i8 %cond.i55.2, %conv18
  %.urem.2 = select i1 %.cmp.2, i8 0, i8 %cond.i55.2
  %6 = sub nuw i8 %conv18, %.urem.2
  %cond.in.i.2 = select i1 %cmp.i51.2, i8 %conv18, i8 %6
  %not..b = xor i1 %.b, true
  %7 = zext i1 %not..b to i8
  %cmp.i51.3 = icmp eq i8 %7, 0
  %cond.i55.3 = freeze i8 %7
  %.cmp.3 = icmp ugt i8 %cond.i55.3, %conv18
  %.urem.3 = select i1 %.cmp.3, i8 0, i8 %cond.i55.3
  %8 = sub nuw i8 %conv18, %.urem.3
  %cond.in.i.3 = select i1 %cmp.i51.3, i8 %conv18, i8 %8
  %conv26 = zext nneg i8 %cond.in.i to i32
  %or = or i32 %k.promoted61, %conv26
  %conv26.1 = zext nneg i8 %cond.in.i.1 to i32
  %or.1 = or i32 %or, %conv26.1
  %conv26.2 = zext nneg i8 %cond.in.i.2 to i32
  %or.2 = or i32 %or.1, %conv26.2
  %conv26.3 = zext nneg i8 %cond.in.i.3 to i32
  %or.3 = or i32 %or.2, %conv26.3
  ret i32 %or.3
}

[SLPVectorizer] Miscompilation at -O2

Reproducer: https://alive2.llvm.org/ce/z/Tw0oUm
```
; bin/opt -passes=slp-vectorizer test.ll -S
define i32 @src(i1 %.b, i8 %conv18, i32 %k.promoted61) {
  %not..b79 = xor i1 %.b, true
  %3 = zext i1 %not..b79 to i8
  %cmp.i51 = icmp eq i8 %3, 0
  %cond.i55.frozen = freeze i8 %3
  %.cmp = icmp ugt i8 %cond.i55.frozen, %conv18
  %.urem = select i1 %.cmp, i8 0, i8 %cond.i55.frozen
  %4 = sub nuw i8 %conv18, %.urem
  %cond.in.i = select i1 %cmp.i51, i8 %conv18, i8 %4
  %not..b80 = xor i1 %.b, true
  %5 = zext i1 %not..b80 to i8
  %cmp.i51.1 = icmp eq i8 %5, 0
  %cond.i55.frozen.1 = freeze i8 %5
  %.cmp.1 = icmp ugt i8 %cond.i55.frozen.1, %conv18
  %.urem.1 = select i1 %.cmp.1, i8 0, i8 %cond.i55.frozen.1
  %6 = sub nuw i8 %conv18, %.urem.1
  %cond.in.i.1 = select i1 %cmp.i51.1, i8 %conv18, i8 %6
  %not..b81 = xor i1 %.b, true
  %7 = zext i1 %not..b81 to i8
  %cmp.i51.2 = icmp eq i8 %7, 0
  %cond.i55.frozen.2 = freeze i8 %7
  %.cmp.2 = icmp ugt i8 %cond.i55.frozen.2, %conv18
  %.urem.2 = select i1 %.cmp.2, i8 0, i8 %cond.i55.frozen.2
  %8 = sub nuw i8 %conv18, %.urem.2
  %cond.in.i.2 = select i1 %cmp.i51.2, i8 %conv18, i8 %8
  %not..b = xor i1 %.b, true
  %9 = zext i1 %not..b to i8
  %cmp.i51.3 = icmp eq i8 %9, 0
  %cond.i55.frozen.3 = freeze i8 %9
  %.cmp.3 = icmp ugt i8 %cond.i55.frozen.3, %conv18
  %.urem.3 = select i1 %.cmp.3, i8 0, i8 %cond.i55.frozen.3
  %10 = sub nuw i8 %conv18, %.urem.3
  %cond.in.i.3 = select i1 %cmp.i51.3, i8 %conv18, i8 %10
  %conv26 = zext nneg i8 %cond.in.i to i32
  %or = or i32 %k.promoted61, %conv26
  %conv26.1 = zext nneg i8 %cond.in.i.1 to i32
  %or.1 = or i32 %or, %conv26.1
  %conv26.2 = zext nneg i8 %cond.in.i.2 to i32
  %or.2 = or i32 %or.1, %conv26.2
  %conv26.3 = zext nneg i8 %cond.in.i.3 to i32
  %or.3 = or i32 %or.2, %conv26.3
  ret i32 %or.3
}
```
```
define i32 @src(i1 %.b, i8 %conv18, i32 %k.promoted61) {
  %1 = insertelement <4 x i1> poison, i1 %.b, i32 0
  %2 = shufflevector <4 x i1> %1, <4 x i1> poison, <4 x i32> zeroinitializer
  %3 = xor <4 x i1> %2, <i1 true, i1 true, i1 true, i1 true>
  %4 = zext <4 x i1> %3 to <4 x i8>
  %5 = icmp eq <4 x i8> %4, zeroinitializer
  %6 = freeze <4 x i1> %3
  %7 = sext <4 x i1> %6 to <4 x i8>
  %8 = insertelement <4 x i8> poison, i8 %conv18, i32 0
  %9 = shufflevector <4 x i8> %8, <4 x i8> poison, <4 x i32> zeroinitializer
  %10 = icmp ugt <4 x i8> %7, %9
  %11 = select <4 x i1> %10, <4 x i8> zeroinitializer, <4 x i8> %7
  %12 = sub nuw <4 x i8> %9, %11
  %13 = select <4 x i1> %5, <4 x i8> %9, <4 x i8> %12
  %14 = zext <4 x i8> %13 to <4 x i32>
  %15 = call i32 @llvm.vector.reduce.or.v4i32(<4 x i32> %14)
  %op.rdx = or i32 %15, %k.promoted61
  ret i32 %op.rdx
}
```
```
Transformation doesn't verify!

ERROR: Value mismatch

Example:
i1 %.b = #x0 (0)
i8 %conv18 = #x01 (1)
i32 %k.promoted61 = #x00000000 (0)

Source:
i1 %not..b79 = #x1 (1)
i8 %#1 = #x01 (1)
i1 %cmp.i51 = #x0 (0)
i8 %cond.i55.frozen = #x01 (1)
i1 %.cmp = #x0 (0)
i8 %.urem = #x01 (1)
i8 %#2 = #x00 (0)
i8 %cond.in.i = #x00 (0)
i1 %not..b80 = #x1 (1)
i8 %#3 = #x01 (1)
i1 %cmp.i51.1 = #x0 (0)
i8 %cond.i55.frozen.1 = #x01 (1)
i1 %.cmp.1 = #x0 (0)
i8 %.urem.1 = #x01 (1)
i8 %#4 = #x00 (0)
i8 %cond.in.i.1 = #x00 (0)
i1 %not..b81 = #x1 (1)
i8 %#5 = #x01 (1)
i1 %cmp.i51.2 = #x0 (0)
i8 %cond.i55.frozen.2 = #x01 (1)
i1 %.cmp.2 = #x0 (0)
i8 %.urem.2 = #x01 (1)
i8 %#6 = #x00 (0)
i8 %cond.in.i.2 = #x00 (0)
i1 %not..b = #x1 (1)
i8 %#7 = #x01 (1)
i1 %cmp.i51.3 = #x0 (0)
i8 %cond.i55.frozen.3 = #x01 (1)
i1 %.cmp.3 = #x0 (0)
i8 %.urem.3 = #x01 (1)
i8 %#8 = #x00 (0)
i8 %cond.in.i.3 = #x00 (0)
i32 %conv26 = #x00000000 (0)
i32 %or = #x00000000 (0)
i32 %conv26.1 = #x00000000 (0)
i32 %or.1 = #x00000000 (0)
i32 %conv26.2 = #x00000000 (0)
i32 %or.2 = #x00000000 (0)
i32 %conv26.3 = #x00000000 (0)
i32 %or.3 = #x00000000 (0)

Target:
<4 x i1> %#1 = < #x0 (0), poison, poison, poison >
<4 x i1> %#2 = < #x0 (0), #x0 (0), #x0 (0), #x0 (0) >
<4 x i1> %#3 = < #x1 (1), #x1 (1), #x1 (1), #x1 (1) >
<4 x i8> %#4 = < #x01 (1), #x01 (1), #x01 (1), #x01 (1) >
<4 x i1> %#5 = < #x0 (0), #x0 (0), #x0 (0), #x0 (0) >
<4 x i1> %#6 = < #x1 (1), #x1 (1), #x1 (1), #x1 (1) >
<4 x i8> %#7 = < #xff (255, -1), #xff (255, -1), #xff (255, -1), #xff (255, -1) >
<4 x i8> %#8 = < #x01 (1), poison, poison, poison >
<4 x i8> %#9 = < #x01 (1), #x01 (1), #x01 (1), #x01 (1) >
<4 x i1> %#10 = < #x1 (1), #x1 (1), #x1 (1), #x1 (1) >
<4 x i8> %#11 = < #x00 (0), #x00 (0), #x00 (0), #x00 (0) >
<4 x i8> %#12 = < #x01 (1), #x01 (1), #x01 (1), #x01 (1) >
<4 x i8> %#13 = < #x01 (1), #x01 (1), #x01 (1), #x01 (1) >
<4 x i32> %#14 = < #x00000001 (1), #x00000001 (1), #x00000001 (1), #x00000001 (1) >
i32 %#15 = #x00000001 (1)
i32 %op.rdx = #x00000001 (1)
Source value: #x00000000 (0)
Target value: #x00000001 (1)
```

llvm version: 69f7758ddba662b63667507f2c472c008909dd7e
cc @alexey-bataev


commit 137d706739653304294adef84ed758e3e498d975
Author: Julian Nagele <j.nagele@apple.com>
Date:   Wed Jan 22 18:36:37 2025 +0000

    [SCEV] Do not attempt to collect loop guards for loops without predecessor. (#123662)

    Attempting to collect loop guards for loops without a predecessor can
    lead to non-terminating recursion trying to construct a SCEV.

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

diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index 7673c3548175..210c7cab965e 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -15328,6 +15328,8 @@ ScalarEvolution::LoopGuards::collect(const Loop *L, ScalarEvolution &SE) {
   BasicBlock *Header = L->getHeader();
   BasicBlock *Pred = L->getLoopPredecessor();
   LoopGuards Guards(SE);
+  if (!Pred)
+    return Guards;
   SmallPtrSet<const BasicBlock *, 8> VisitedBlocks;
   collectFromBlock(SE, Guards, Header, Pred, VisitedBlocks);
   return Guards;

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

[SCEV] Another SEGV/stack overflow in LoopGuards

Similar to https://github.com/llvm/llvm-project/issues/120615. Looks like the fix wasn't a complete one. Here is an example:

```llvm
target triple = "x86_64-unknown-linux-gnu"

define ptr @f(i32 %0) {
  switch i32 0, label %bb4 [
    i32 1, label %bb4
    i32 2, label %bb4
    i32 3, label %bb4
    i32 4, label %bb1
    i32 5, label %bb4
    i32 6, label %bb4
  ]

bb:                                               ; No predecessors!
  switch i32 0, label %bb4 [
    i32 0, label %bb4
    i32 1, label %bb1
  ]

bb1:                                              ; preds = %bb2, %bb, %1
  %2 = phi i32 [ %3, %bb2 ], [ 0, %bb ], [ 0, %1 ]
  switch i32 %0, label %bb3 [
    i32 0, label %bb2
    i32 1, label %bb2
    i32 2, label %bb2
  ]

bb2:                                              ; preds = %bb1, %bb1, %bb1
  %3 = add i32 %2, 1
  %4 = icmp ult i32 %0, 0
  br i1 %4, label %bb1, label %bb4

bb3:                                              ; preds = %bb1
  unreachable

bb4:                                              ; preds = %bb2, %bb, %bb, %1, %1, %1, %1, %1, %1
  ret ptr null
}
```
Crashes with the same command line `opt -passes=nary-reassociate --scalar-evolution-use-expensive-range-sharpening`
godbolt: https://godbolt.org/z/4d3jo8jTz

Thanks, checking!

@juliannagele Thanks for looking into it! Do you need any additional info?