commit 54a9f0007cb4f19d2e9df30405c5027229f5def0
Author: annamthomas <anna@azul.com>
Date:   Wed Apr 10 09:02:23 2024 -0400

    [SCEV] Fix BinomialCoefficient Iteration to fit in W bits (#88010)

    BinomialCoefficient computes the value of W-bit IV at iteration It of a loop. When W is 1, we can call multiplicative inverse on 0 which triggers an assert since 1b76120.

    Since the arithmetic is supposed to wrap if It or K does not fit in W bits, do the truncation into W bits after we do the shift.

     Fixes #87798

diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index e030b9fc7dac..9fcce797f559 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -928,11 +928,9 @@ static const SCEV *BinomialCoefficient(const SCEV *It, unsigned K,
   APInt OddFactorial(W, 1);
   unsigned T = 1;
   for (unsigned i = 3; i <= K; ++i) {
-    APInt Mult(W, i);
-    unsigned TwoFactors = Mult.countr_zero();
+    unsigned TwoFactors = countr_zero(i);
     T += TwoFactors;
-    Mult.lshrInPlace(TwoFactors);
-    OddFactorial *= Mult;
+    OddFactorial *= (i >> TwoFactors);
   }

   // We need at least W + T bits for the multiplication step

opt -disable-output -passes='print<scalar-evolution>' -verify-scev < %s 2>&1

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

define i32 @pr87798() {
bb:
  br label %bb1

bb1:                                              ; preds = %bb1, %bb
  %phi = phi i32 [ 0, %bb ], [ %add4, %bb1 ]
  %phi2 = phi i32 [ 0, %bb ], [ %add, %bb1 ]
  %phi3 = phi i32 [ 0, %bb ], [ %add5, %bb1 ]
  %add = add i32 %phi2, %phi3
  %mul = mul i32 %phi2, %phi3
  %add4 = add i32 %mul, %phi
  %and = and i32 %phi, 1
  %add5 = add i32 %phi3, 1
  br i1 true, label %preheader, label %bb1

preheader:                                        ; preds = %bb1
  %phi9 = phi i32 [ %and, %bb1 ]
  br label %loop

loop:                                             ; preds = %loop, %preheader
  br label %loop

bb7:                                              ; No predecessors!
  %zext = zext i32 %phi9 to i64
  ret i32 0
}

Assertion failure: "multiplicative inverse is only defined for odd numbers" exposed through usage in SCEV

With this change [1b76120](https://github.com/llvm/llvm-project/commit/1b761205f2686516cebadbcbc37f798197d9c482) landed in https://github.com/llvm/llvm-project/pull/87610, we started seeing an assertion failure on the introduced API.

This change caused an assertion failure in usage of multiplicativeInverse in SCEV's BinomialCoefficient algorithm (which was also updated by the change to use this overloaded API). The `oddFactorial` in this algorithm becomes  0 and the assertion in newly introduced API gets triggered. Note that the old API for multiplicativeInverse (which passed in the explicit modulo) returned 0 when the input was also 0, and probably hid this bug in SCEV.

Here's a minimal reproducer for trunk:
```
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128-ni:1-p2:32:8:8:32-ni:2"
target triple = "x86_64-unknown-linux-gnu"

define i32 @"static jint Test.iMeth(jlong, jint, jint)2272037699586"() {
bci_0:
  br label %bci_71.preheader

bci_71.preheader:                                 ; preds = %bci_71.preheader, %bci_0
  %local_9_242 = phi i32 [ 0, %bci_0 ], [ %1, %bci_71.preheader ]
  %local_7_241 = phi i32 [ 0, %bci_0 ], [ %0, %bci_71.preheader ]
  %local_4_239 = phi i32 [ 0, %bci_0 ], [ %3, %bci_71.preheader ]
  %0 = add i32 %local_7_241, %local_4_239
  %.neg14 = mul i32 %local_7_241, %local_4_239
  %1 = add i32 %.neg14, %local_9_242
  %2 = and i32 %local_9_242, 1
  %3 = add i32 %local_4_239, 1
  br i1 true, label %bci_10.i38.preheader, label %bci_71.preheader

bci_10.i38:                                       ; preds = %bci_10.i38.preheader, %bci_10.i38
  br label %bci_10.i38

"static jlong FuzzerUtils.checkSum(jobject)2306397437964.exit": ; No predecessors!
  %4 = zext i32 %.lcssa596 to i64
  ret i32 0

bci_10.i38.preheader:                             ; preds = %bci_71.preheader
  %.lcssa596 = phi i32 [ %2, %bci_71.preheader ]
  br label %bci_10.i38
}
```

opt -passes=indvars reduced.ll produces:
```
opt: /root/llvm-project/llvm/lib/Support/APInt.cpp:1245: llvm::APInt llvm::APInt::multiplicativeInverse() const: Assertion `(*this)[0] && "multiplicative inverse is only defined for odd numbers!"' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:
0.	Program arguments: /opt/compiler-explorer/clang-assertions-trunk/bin/opt -o /app/output.s -S -passes=indvars <source>
 #0 0x0000000004cfc568 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4cfc568)
 #1 0x0000000004cf9cbc SignalHandler(int) Signals.cpp:0:0
 #2 0x00007f7209e42520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #3 0x00007f7209e969fc pthread_kill (/lib/x86_64-linux-gnu/libc.so.6+0x969fc)
 #4 0x00007f7209e42476 gsignal (/lib/x86_64-linux-gnu/libc.so.6+0x42476)
 #5 0x00007f7209e287f3 abort (/lib/x86_64-linux-gnu/libc.so.6+0x287f3)
 #6 0x00007f7209e2871b (/lib/x86_64-linux-gnu/libc.so.6+0x2871b)
 #7 0x00007f7209e39e96 (/lib/x86_64-linux-gnu/libc.so.6+0x39e96)
 #8 0x0000000004bf9eff llvm::APInt::multiplicativeInverse() const (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4bf9eff)
 #9 0x000000000443a4b5 llvm::SCEVAddRecExpr::evaluateAtIteration(llvm::ArrayRef<llvm::SCEV const*>, llvm::SCEV const*, llvm::ScalarEvolution&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x443a4b5)
#10 0x000000000443cb4f llvm::ScalarEvolution::computeSCEVAtScope(llvm::SCEV const*, llvm::Loop const*) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x443cb4f)
#11 0x000000000443cfee llvm::ScalarEvolution::getSCEVAtScope(llvm::SCEV const*, llvm::Loop const*) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x443cfee)
#12 0x000000000443c525 llvm::ScalarEvolution::computeSCEVAtScope(llvm::SCEV const*, llvm::Loop const*) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x443c525)
#13 0x000000000443cfee llvm::ScalarEvolution::getSCEVAtScope(llvm::SCEV const*, llvm::Loop const*) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x443cfee)
#14 0x000000000404eca0 llvm::rewriteLoopExitValues(llvm::Loop*, llvm::LoopInfo*, llvm::TargetLibraryInfo*, llvm::ScalarEvolution*, llvm::TargetTransformInfo const*, llvm::SCEVExpander&, llvm::DominatorTree*, llvm::ReplaceExitVal, llvm::SmallVector<llvm::WeakTrackingVH, 16u>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x404eca0)
#15 0x0000000003a10fd8 (anonymous namespace)::IndVarSimplify::run(llvm::Loop*) IndVarSimplify.cpp:0:0
#16 0x0000000003a11c1a llvm::IndVarSimplifyPass::run(llvm::Loop&, llvm::AnalysisManager<llvm::Loop, llvm::LoopStandardAnalysisResults&>&, llvm::LoopStandardAnalysisResults&, llvm::LPMUpdater&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x3a11c1a)
#17 0x00000000029ffd4e llvm::detail::PassModel<llvm::Loop, llvm::IndVarSimplifyPass, llvm::AnalysisManager<llvm::Loop, llvm::LoopStandardAnalysisResults&>, llvm::LoopStandardAnalysisResults&, llvm::LPMUpdater&>::run(llvm::Loop&, llvm::AnalysisManager<llvm::Loop, llvm::LoopStandardAnalysisResults&>&, llvm::LoopStandardAnalysisResults&, llvm::LPMUpdater&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x29ffd4e)
#18 0x0000000003aaef56 std::optional<llvm::PreservedAnalyses> llvm::PassManager<llvm::Loop, llvm::AnalysisManager<llvm::Loop, llvm::LoopStandardAnalysisResults&>, llvm::LoopStandardAnalysisResults&, llvm::LPMUpdater&>::runSinglePass<llvm::Loop, std::unique_ptr<llvm::detail::PassConcept<llvm::Loop, llvm::AnalysisManager<llvm::Loop, llvm::LoopStandardAnalysisResults&>, llvm::LoopStandardAnalysisResults&, llvm::LPMUpdater&>, std::default_delete<llvm::detail::PassConcept<llvm::Loop, llvm::AnalysisManager<llvm::Loop, llvm::LoopStandardAnalysisResults&>, llvm::LoopStandardAnalysisResults&, llvm::LPMUpdater&>>>>(llvm::Loop&, std::unique_ptr<llvm::detail::PassConcept<llvm::Loop, llvm::AnalysisManager<llvm::Loop, llvm::LoopStandardAnalysisResults&>, llvm::LoopStandardAnalysisResults&, llvm::LPMUpdater&>, std::default_delete<llvm::detail::PassConcept<llvm::Loop, llvm::AnalysisManager<llvm::Loop, llvm::LoopStandardAnalysisResults&>, llvm::LoopStandardAnalysisResults&, llvm::LPMUpdater&>>>&, llvm::AnalysisManager<llvm::Loop, llvm::LoopStandardAnalysisResults&>&, llvm::LoopStandardAnalysisResults&, llvm::LPMUpdater&, llvm::PassInstrumentation&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x3aaef56)
#19 0x0000000003aaf1ee llvm::PassManager<llvm::Loop, llvm::AnalysisManager<llvm::Loop, llvm::LoopStandardAnalysisResults&>, llvm::LoopStandardAnalysisResults&, llvm::LPMUpdater&>::runWithoutLoopNestPasses(llvm::Loop&, llvm::AnalysisManager<llvm::Loop, llvm::LoopStandardAnalysisResults&>&, llvm::LoopStandardAnalysisResults&, llvm::LPMUpdater&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x3aaf1ee)
#20 0x0000000003ab05d9 llvm::PassManager<llvm::Loop, llvm::AnalysisManager<llvm::Loop, llvm::LoopStandardAnalysisResults&>, llvm::LoopStandardAnalysisResults&, llvm::LPMUpdater&>::run(llvm::Loop&, llvm::AnalysisManager<llvm::Loop, llvm::LoopStandardAnalysisResults&>&, llvm::LoopStandardAnalysisResults&, llvm::LPMUpdater&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x3ab05d9)
...
```

CC @jayfoad

I think the old API (multiplicativeInverse when modulo provided) was hiding this bug since multiplicative inverse shouldn't be asked for 0.
Also, the reason the `oddFactorial` becomes 0 here is because of this:
```
// Calculate K! / 2^T and T; we divide out the factors of two before
    // multiplying for calculating K! / 2^T to avoid overflow.
    // Other overflow doesn't matter because we only care about the bottom
    // W bits of the result.
    APInt OddFactorial(W, 1);
    unsigned T = 1;
    for (unsigned i = 3; i <= K; ++i) {
      APInt Mult(W, i);
      unsigned TwoFactors = Mult.countr_zero();
      T += TwoFactors;
      Mult.lshrInPlace(TwoFactors);
      OddFactorial *= Mult;
    }
  ```

Here, W is one (bit width = 1 and I believe this is the bug) and we are trying to represent Mult=4  in one bit. That makes `Mult` 0 and hence `OddFactorial` 0.

One thing we can obviously do is in the newly introduced API, explicitly check if the APInt is 0 and return 0 (this makes behaviour same as the old API).
But I think this is hiding the bug.

Suggestion:
```diff
diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index e030b9fc7dac..3f8c390614ff 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -928,11 +928,9 @@ static const SCEV *BinomialCoefficient(const SCEV *It, unsigned K,
   APInt OddFactorial(W, 1);
   unsigned T = 1;
   for (unsigned i = 3; i <= K; ++i) {
-    APInt Mult(W, i);
-    unsigned TwoFactors = Mult.countr_zero();
+    unsigned TwoFactors = countr_zero(i);
     T += TwoFactors;
-    Mult.lshrInPlace(TwoFactors);
-    OddFactorial *= Mult;
+    OddFactorial *= i >> TwoFactors;
   }

   // We need at least W + T bits for the multiplication step
```

> yes, that would probably work as well (since we avoid representing Mult in W bit width), but how can the bitWidth of the SCEV result`W` be 1 in the first place?

No idea! I have only looked at `BinomialCoefficient` itself, not at its callers. I assume it is supposed to work for any W > 0 and K > 0. At least I don't see it mentioned that K has to be representable in W bits, or anything like that.

The function is supposed to compute `BC(It, K) mod 2^W`, i.e. the binomial coefficient truncated to fit into a W-bit integer.  This is  useful for computing the value of a W-bit induction variable at iteration "It" of a loop.  There isn't any expectation that "It" or "K" fit losslessly into "W": the arithmetic is supposed to wrap.

Given the way the function works, truncating "i" after the shift looks like the right solution.


commit 2d31a12dbe2339d20844ede70cbb54dbaf4ceea9
Author: Nikita Popov <npopov@redhat.com>
Date:   Mon Feb 10 10:34:03 2025 +0100

    [DSE] Don't use initializes on byval argument (#126259)

    There are two ways we can fix this problem, depending on how the
    semantics of byval and initializes should interact:

    * Don't infer initializes on byval arguments. initializes on byval
    refers to the original caller memory (or having both attributes is made
    a verifier error).
    * Infer initializes on byval, but don't use it in DSE. initializes on
    byval refers to the callee copy. This matches the semantics of readonly
    on byval. This is slightly more powerful, for example, we could do a
    backend optimization where byval + initializes will allocate the full
    size of byval on the stack but not copy over the parts covered by
    initializes.

    I went with the second variant here, skipping byval + initializes in DSE
    (FunctionAttrs already doesn't propagate initializes past byval). I'm
    open to going in the other direction though.

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

diff --git a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
index 05b4f176bfc3..38454053b039 100644
--- a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
@@ -2283,7 +2283,9 @@ DSEState::getInitializesArgMemLoc(const Instruction *I) {
   for (unsigned Idx = 0, Count = CB->arg_size(); Idx < Count; ++Idx) {
     ConstantRangeList Inits;
     Attribute InitializesAttr = CB->getParamAttr(Idx, Attribute::Initializes);
-    if (InitializesAttr.isValid())
+    // initializes on byval arguments refers to the callee copy, not the
+    // original memory the caller passed in.
+    if (InitializesAttr.isValid() && !CB->isByValArgument(Idx))
       Inits = InitializesAttr.getValueAsConstantRangeList();

     Value *CurArg = CB->getArgOperand(Idx);

opt < %s -passes=dse -enable-dse-initializes-attr-improvement -S

%struct.a = type { i32, i64, i32, i32 }

@e = dso_local global { i32, [4 x i8], i64, i32, i32 } { i32 5, [4 x i8] zeroinitializer, i64 0, i32 1, i32 90986701 }, align 8

define i8 @ad(ptr byval(%struct.a) %ah) {
entry:
  store i32 0, ptr %ah, align 8
  %call = call i64 @af(ptr %ah)
  %0 = load i8, ptr %ah, align 1
  ret i8 %0
}

define i64 @af(ptr byval(%struct.a) initializes((0, 24)) %am) {
entry:
  call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 8 dereferenceable(24) %am, ptr noundef nonnull align 8 dereferenceable(24) @e, i64 24, i1 false)
  ret i64 0
}

define i32 @main() {
  %res = call i8 @ad(ptr @e)
  %val = sext i8 %res to i32
  ret i32 %val
}

[FuncAttrs] `initializes` is incorrectly set on parameters with `byval`

Reproducer: https://godbolt.org/z/Mcx1nY4E7
```
; bin/opt -passes=function-attrs reduced.ll -S
%struct.a = type { i32, i64, i32, i32 }

@e = dso_local global { i32, [4 x i8], i64, i32, i32 } { i32 5, [4 x i8] zeroinitializer, i64 0, i32 1, i32 90986701 }, align 8

define i8 @ad(ptr byval(%struct.a) %ah) {
entry:
  store i32 0, ptr %ah, align 8
  %call = call i64 @af(ptr %ah)
  %0 = load i8, ptr %ah, align 1
  ret i8 %0
}

define i64 @af(ptr byval(%struct.a) %am) {
entry:
  call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 8 dereferenceable(24) %am, ptr noundef nonnull align 8 dereferenceable(24) @e, i64 24, i1 false)
  ret i64 0
}

```
```
define i8 @ad(ptr byval(%struct.a) captures(none) initializes((0, 4)) %ah) #0 {
  store i32 0, ptr %ah, align 8
  %call = call i64 @af(ptr %ah)
  %0 = load i8, ptr %ah, align 1
  ret i8 %0
}

define noundef i64 @af(ptr writeonly byval(%struct.a) captures(none) initializes((0, 24)) %am) #0 {
  call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 8 dereferenceable(24) %am, ptr noundef nonnull align 8 dereferenceable(24) @e, i64 24, i1 false)
  ret i64 0
}
```
After DSE:
```
define i8 @ad(ptr byval(%struct.a) captures(none) initializes((0, 4)) %ah) #0 {
  %call = call i64 @af(ptr %ah)
  %0 = load i8, ptr %ah, align 1
  ret i8 %0
}

define noundef i64 @af(ptr writeonly byval(%struct.a) captures(none) initializes((0, 24)) %am) #0 {
  ret i64 0
}
```

llvm version: d21fc58aeeaa7f0369a24dbe70a0360e0edbf76f

> We should also emit the padding for %struct.a.

Without commenting on whether we should or shouldn't, why is not having the padding a miscompile? As this is not a packed struct, for a i64:64 target, LLVM will implicitly insert the padding and it should have the correct size.

>  As this is not a packed struct, for a i64:64 target, LLVM will implicitly insert the padding and it should have the correct size.

Sorry. It is a DSE bug.

cc @haopliu

@dtcxzyw I think your new IR is over-reduced. You have `initializes((0, 24)` on `@af`, so I think eliminating the store is correct.

> [@dtcxzyw](https://github.com/dtcxzyw) I think your new IR is over-reduced. You have `initializes((0, 24)` on `@af`, so I think eliminating the store is correct.

Fixed.

There are two ways we can fix this, depending on what we want the semantics to do:

 1. Don't infer initializes on byval arguments. initializes on byval refers to the original caller memory (or having both attributes is made a verifier error).
 2. Infer initializes on byval, but don't use it in DSE. initializes on byval refers to the callee copy. This matches the semantics of readonly on byval.

I think variant 2 is marginally more powerful. For example, we could do a backend optimization where byval + initializes will allocate the full size of byval on the stack but not copy over the parts covered by initializes.


commit b210cbbd0eb8ef7cd2735e99570474e6e53ee00b
Author: Nikita Popov <npopov@redhat.com>
Date:   Wed Jan 31 11:01:03 2024 +0100

    [BDCE] Fix clearing of poison-generating flags

    If the demanded bits of an instruction are full, we don't have to
    recurse to its users, but we may still have to clear flags on the
    instruction itself.

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

diff --git a/llvm/lib/Transforms/Scalar/BDCE.cpp b/llvm/lib/Transforms/Scalar/BDCE.cpp
index e99210ce2f22..6e6fa6c8ffc4 100644
--- a/llvm/lib/Transforms/Scalar/BDCE.cpp
+++ b/llvm/lib/Transforms/Scalar/BDCE.cpp
@@ -45,15 +45,17 @@ static void clearAssumptionsOfUsers(Instruction *I, DemandedBits &DB) {
   assert(I->getType()->isIntOrIntVectorTy() &&
          "Trivializing a non-integer value?");

+  // If all bits of a user are demanded, then we know that nothing below that
+  // in the def-use chain needs to be changed.
+  if (DB.getDemandedBits(I).isAllOnes())
+    return;
+
   // Initialize the worklist with eligible direct users.
   SmallPtrSet<Instruction *, 16> Visited;
   SmallVector<Instruction *, 16> WorkList;
   for (User *JU : I->users()) {
-    // If all bits of a user are demanded, then we know that nothing below that
-    // in the def-use chain needs to be changed.
-    auto *J = dyn_cast<Instruction>(JU);
-    if (J && J->getType()->isIntOrIntVectorTy() &&
-        !DB.getDemandedBits(J).isAllOnes()) {
+    auto *J = cast<Instruction>(JU);
+    if (J->getType()->isIntOrIntVectorTy()) {
       Visited.insert(J);
       WorkList.push_back(J);
     }
@@ -79,12 +81,14 @@ static void clearAssumptionsOfUsers(Instruction *I, DemandedBits &DB) {
     // 1. llvm.assume demands its operand, so trivializing can't change it.
     // 2. range metadata only applies to memory accesses which demand all bits.

+    // If all bits of a user are demanded, then we know that nothing below
+    // that in the def-use chain needs to be changed.
+    if (DB.getDemandedBits(J).isAllOnes())
+      continue;
+
     for (User *KU : J->users()) {
-      // If all bits of a user are demanded, then we know that nothing below
-      // that in the def-use chain needs to be changed.
-      auto *K = dyn_cast<Instruction>(KU);
-      if (K && Visited.insert(K).second && K->getType()->isIntOrIntVectorTy() &&
-          !DB.getDemandedBits(K).isAllOnes())
+      auto *K = cast<Instruction>(KU);
+      if (Visited.insert(K).second && K->getType()->isIntOrIntVectorTy())
         WorkList.push_back(K);
     }
   }

define i32 @disjoint_indirect(i64 %x) {
  %and = and i64 %x, 1
  %trunc = trunc i64 %and to i32
  %or = or disjoint i32 %trunc, -2
  ret i32 %or
}

define i64 @disjoint(i64 %x) {
  %and = and i64 %x, 1
  %or = or disjoint i64 %and, -2
  ret i64 %or
}

Wrong code at -O2/3 on x86-64_linux-gnu (recent regression)

clang at -O2/3 produced the wrong code. This is a recent regression.

Bisected to 20737825c9122b6e0a8912731cfa7e0558fe025d, which was committed by @antoniofrighetto

Compiler explorer: https://godbolt.org/z/55z1WT3MM

```console
% cat reduced.c
int printf(const char *, ...);
short a, f = 6;
int b, e, g;
int c[7][1];
static int *d = &b;
long h;
int *const *i;
static unsigned char j(long k, short *n) {
  int *l = &c[5][0];
  int *const **m = &i;
  i = &l;
  *d = 0;
  for (; e < 60; e++)
    ***m = ((h = *d == (1 ^ k)) & *n + f) - 2;
  return 0;
}
int main() {
  j(1, &a);
  printf("%d\n", c[5][0]);
}
%
% clang -O0 reduced.c &&./a.out
-2
% clang -O2 reduced.c &&./a.out
4
%
```

Looks like poison flags don't get cleared as expected.

Minimized:
```llvm
define i32 @test(i64 %x) {
  %and = and i64 %x, 1
  %trunc = trunc i64 %and to i32
  %or = or disjoint i32 %trunc, -2
  ret i32 %or
}
```
The `%and` gets dropped but `disjoint` is kept.

@nikic, could you kindly elaborate this? I'm having a hard time getting this, the transformation looks correct with simple `or` (https://alive2.llvm.org/ce/z/ui3yFf). Semantics for `disjoint`:
> If the disjoint flag is set, and the or has a one and the same bit in both arguments, the result is poison.

However, here:
```llvm
  %add = add nuw nsw i64 %conv5, %conv4
  %and = and i64 %add, 1
  %2 = trunc i64 %and to i32
  %conv7 = or disjoint i32 %2, -2
```
The two or operands do not seem to have any same bit in both arguments.

OK, I got it now, the `disjoint` should not be there at all after the transformation. Makes sense, thank you.

Fixed another issue I noticed in this code in https://github.com/llvm/llvm-project/commit/cb6240d247b3419dea29eb99261171ea239b1c5c.


commit 45b526afa26e76e0c351e947ac8f0e4b55aa760b
Author: Florian Hahn <flo@fhahn.com>
Date:   Sun Oct 6 10:34:37 2024 +0100

    [LV] Honor uniform-after-vectorization in setVectorizedCallDecision.

    The legacy cost model always computes the cost for uniforms as cost of
    VF = 1, but VPWidenCallRecipes would be created, as
    setVectorizedCallDecisions would not consider uniform calls.

    Fix setVectorizedCallDecision to set to Scalarize, if the call is
    uniform-after-vectorization.

    This fixes a bug in VPlan construction uncovered by the VPlan-based
    cost model.

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

diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index 6e082b1c134d..35c042b3ab7f 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -6196,11 +6196,12 @@ void LoopVectorizationCostModel::setVectorizedCallDecision(ElementCount VF) {
           getScalarizationOverhead(CI, VF, CostKind);

       ScalarCost = ScalarCallCost * VF.getKnownMinValue() + ScalarizationCost;
-      // Honor ForcedScalars decision.
+      // Honor ForcedScalars and UniformAfterVectorization decisions.
       // TODO: For calls, it might still be more profitable to widen. Use
       // VPlan-based cost model to compare different options.
-      if (VF.isVector() && ForcedScalar != ForcedScalars.end() &&
-          ForcedScalar->second.contains(CI)) {
+      if (VF.isVector() && ((ForcedScalar != ForcedScalars.end() &&
+                             ForcedScalar->second.contains(CI)) ||
+                            isUniformAfterVectorization(CI, VF))) {
         setCallWideningDecision(CI, VF, CM_Scalarize, nullptr,
                                 Intrinsic::not_intrinsic, std::nullopt,
                                 ScalarCost);

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 @smax_call_uniform(ptr %dst, i64 %x) {
entry:
  %c = icmp ult i8 -68, -69
  %mul = mul nuw nsw i64 %x, 0
  br label %loop.header

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

else:                                             ; preds = %loop.header
  %rem = urem i64 %mul, %x
  %smax = tail call i64 @llvm.smax.i64(i64 %rem, i64 0)
  br label %loop.latch

loop.latch:                                       ; preds = %else, %loop.header
  %p = phi i64 [ 1, %loop.header ], [ %smax, %else ]
  %add = add i64 %p, 1
  %gep = getelementptr i64, ptr %dst, i64 %add
  store i64 0, ptr %gep, align 8
  %iv.next = add i64 %iv, 1
  %ec = icmp eq i64 %iv.next, 0
  br i1 %ec, label %exit, label %loop.header

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

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

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

[clang] Assertion failed in LoopVectorize.cpp:7401

When I compiled the code with -O2 flag, it crashed:

```c
#include <stdint.h>
static uint8_t b = 188;
void c();
long d(int e, int p2, short j) {
  long f = 0, a = 1;
  unsigned long g;
  int h;
  if (e < 0 || j < 0)
    return 1;
  h = 0;
  for (; h < p2; h++) {
    a *= j + 1;
    g = e * a;
    f += g % (j + 1);
  }
  if (f < 0)
    return 0;
  return f;
}
void i();
int64_t k() {
  uint32_t l[][8][10] = {0, 4, 7, 1, 4, 3446557846};
  int64_t m[10];
  int h;
  for (h = 0; c + h < 10; h++)
    m[(int)d(5, l[0][0][5] - 3446557842, b - 187) + h] = 1;
  i(m);
  uint8_t *n = &b;
  uint8_t **o;
  o[0] = &n;
}
```

The crash is:
```
clang: /root/llvm-project/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp:7401: 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.
```

Details can be found here: https://godbolt.org/z/hqP8vMG7b

This is a regression in trunk: https://godbolt.org/z/a53x7oxhq


commit c9a5e1b665dbba898e9981fd7d48881947e6560e
Author: Nikita Popov <npopov@redhat.com>
Date:   Wed Aug 28 12:54:14 2024 +0200

    [IndVars] Check if WideInc available before trying to use it

    WideInc/WideIncExpr can be null. Previously this worked out
    because the comparison with WideIncExpr would fail. Now we have
    accesses to WideInc prior to that. Avoid the issue with an
    explicit check.

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

diff --git a/llvm/lib/Transforms/Utils/SimplifyIndVar.cpp b/llvm/lib/Transforms/Utils/SimplifyIndVar.cpp
index 8e3a14bb4f6d..a950a4f57ef4 100644
--- a/llvm/lib/Transforms/Utils/SimplifyIndVar.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyIndVar.cpp
@@ -1928,18 +1928,24 @@ Instruction *WidenIV::widenIVUse(WidenIV::NarrowIVDefUse DU,
     if (!WideAddRec.first)
       return nullptr;

-    // Reuse the IV increment that SCEVExpander created. Recompute flags, unless
-    // the flags for both increments agree and it is safe to use the ones from
-    // the original inc. In that case, the new use of the wide increment won't
-    // be more poisonous.
-    bool NeedToRecomputeFlags =
-        !SCEVExpander::canReuseFlagsFromOriginalIVInc(OrigPhi, WidePhi,
-                                                      DU.NarrowUse, WideInc) ||
-        DU.NarrowUse->hasNoUnsignedWrap() != WideInc->hasNoUnsignedWrap() ||
-        DU.NarrowUse->hasNoSignedWrap() != WideInc->hasNoSignedWrap();
+    auto CanUseWideInc = [&]() {
+      if (!WideInc)
+        return false;
+      // Reuse the IV increment that SCEVExpander created. Recompute flags,
+      // unless the flags for both increments agree and it is safe to use the
+      // ones from the original inc. In that case, the new use of the wide
+      // increment won't be more poisonous.
+      bool NeedToRecomputeFlags =
+          !SCEVExpander::canReuseFlagsFromOriginalIVInc(
+              OrigPhi, WidePhi, DU.NarrowUse, WideInc) ||
+          DU.NarrowUse->hasNoUnsignedWrap() != WideInc->hasNoUnsignedWrap() ||
+          DU.NarrowUse->hasNoSignedWrap() != WideInc->hasNoSignedWrap();
+      return WideAddRec.first == WideIncExpr &&
+             Rewriter.hoistIVInc(WideInc, DU.NarrowUse, NeedToRecomputeFlags);
+    };
+
     Instruction *WideUse = nullptr;
-    if (WideAddRec.first == WideIncExpr &&
-        Rewriter.hoistIVInc(WideInc, DU.NarrowUse, NeedToRecomputeFlags))
+    if (CanUseWideInc())
       WideUse = WideInc;
     else {
       WideUse = cloneIVUser(DU, WideAddRec.first);

target datalayout = "n8:16:32:64"

define i32 @m() {
entry:
  %div.i4 = sdiv i32 1, 0
  br label %for.body.i6

for.body.i6:                                      ; preds = %if.end.i, %entry
  %add57.i = phi i32 [ %add.i7, %if.end.i ], [ 0, %entry ]
  br i1 true, label %i.exit, label %if.end.i

if.end.i:                                         ; preds = %for.body.i6
  %add.i7 = add i32 %add57.i, %div.i4
  %conv.i = zext i32 %add57.i to i64
  store i64 %conv.i, ptr null, align 8
  br label %for.body.i6

i.exit:                                           ; preds = %for.body.i6
  ret i32 0
}

[clang] Crash with O2 optimization flag

I compiled this code with -O2 flag and it crashed. The code is:

```c
#include <stdint.h>
long a, c;
unsigned d;
int32_t g;
uint8_t h[];
long b(long p1, long k) {
  long e = k;
  int b = 0;
  while (e) {
    e /= 10;
    b++;
  }
  for (int f = 0; f < b; f++)
    p1 *= 10;
  a = p1 + k;
  return a;
}
long i(int p1, int, int l) {
  int j = l / p1;
  for (int f = 0; f < p1; f++) {
    if (d > l)
      break;
    c = d += j;
  }
}
uint32_t m() {
  for (g = 8; b(35, 46) - 3546 + g >= 0; g--)
    ;
  h[i(g + 1, 0, -4294967221)];
}
```

The crash is: clang: /root/llvm-project/llvm/include/llvm/Support/Casting.h:662: decltype(auto) llvm::dyn_cast(From*) [with To = llvm::BinaryOperator; From = llvm::Instruction]: Assertion `detail::isPresent(Val) && "dyn_cast on a non-existent value"' failed.

The details can be found here: https://godbolt.org/z/37WsGxMcv

regression release:backport confirmed crash llvm:transforms

Looks like a regression, does not crash in clang-18: https://godbolt.org/z/1zYqs3sbz

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

```
; bin/opt -passes=indvars reduced.ll -S
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"

define i32 @m() {
entry:
  %div.i4 = sdiv i32 1, 0
  br label %for.body.i6

for.body.i6:                                      ; preds = %if.end.i, %entry
  %add57.i = phi i32 [ %add.i7, %if.end.i ], [ 0, %entry ]
  br i1 true, label %i.exit, label %if.end.i

if.end.i:                                         ; preds = %for.body.i6
  %add.i7 = add i32 %add57.i, %div.i4
  %conv.i = zext i32 %add57.i to i64
  store i64 %conv.i, ptr null, align 8
  br label %for.body.i6

i.exit:                                           ; preds = %for.body.i6
  ret i32 0
}
```
cc @nikic

This regressed with `llvmorg-19-init-02822-g`4db93e5d564 ("[IndVars] Recompute flags if needed in widenIVUse of IV increment. (#82352)") by @fhahn.


commit 4db93e5d56440be44d8ad2036e2579208c82ad37
Author: Florian Hahn <flo@fhahn.com>
Date:   Tue Feb 20 14:03:25 2024 +0000

    [IndVars] Recompute flags if needed in widenIVUse of IV increment. (#82352)

    widenIVUse may hoist a wide induction increment and introduce new uses,
    but does not recompute the wrap flags. In some cases this can make the
    new uses of the wide IV inc more poisonous.

    Update the code to recompute flags if needed when hoisting an IV. If
    both the narrow and wide IV increment's flags match and we can re-use
    the flags from the increments, there's no need to recompute the flags,
    as the replacement won't make the new uses of the wide IV's increment
    more poisonous.

    Note that this also updates a stale comment which claimed that the widen
    increment is only used if it dominates the new use.

    The helper should also be used to guard the code added in da437330be,
    which I am planning on doing separately once the helper lands.

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

diff --git a/llvm/include/llvm/Transforms/Utils/ScalarEvolutionExpander.h b/llvm/include/llvm/Transforms/Utils/ScalarEvolutionExpander.h
index 035705b7f4b7..fa10443f14bb 100644
--- a/llvm/include/llvm/Transforms/Utils/ScalarEvolutionExpander.h
+++ b/llvm/include/llvm/Transforms/Utils/ScalarEvolutionExpander.h
@@ -258,6 +258,14 @@ public:
   bool hoistIVInc(Instruction *IncV, Instruction *InsertPos,
                   bool RecomputePoisonFlags = false);

+  /// Return true if both increments directly increment the corresponding IV PHI
+  /// nodes and have the same opcode. It is not safe to re-use the flags from
+  /// the original increment, if it is more complex and SCEV expansion may have
+  /// yielded a more simplified wider increment.
+  static bool canReuseFlagsFromOriginalIVInc(PHINode *OrigPhi, PHINode *WidePhi,
+                                             Instruction *OrigInc,
+                                             Instruction *WideInc);
+
   /// replace congruent phis with their most canonical representative. Return
   /// the number of phis eliminated.
   unsigned replaceCongruentIVs(Loop *L, const DominatorTree *DT,
diff --git a/llvm/lib/Transforms/Utils/ScalarEvolutionExpander.cpp b/llvm/lib/Transforms/Utils/ScalarEvolutionExpander.cpp
index 3a28909473d9..fbe1dba5b8d4 100644
--- a/llvm/lib/Transforms/Utils/ScalarEvolutionExpander.cpp
+++ b/llvm/lib/Transforms/Utils/ScalarEvolutionExpander.cpp
@@ -771,6 +771,15 @@ bool SCEVExpander::hoistIVInc(Instruction *IncV, Instruction *InsertPos,
   return true;
 }

+bool SCEVExpander::canReuseFlagsFromOriginalIVInc(PHINode *OrigPhi,
+                                                  PHINode *WidePhi,
+                                                  Instruction *OrigInc,
+                                                  Instruction *WideInc) {
+  return match(OrigInc, m_c_BinOp(m_Specific(OrigPhi), m_Value())) &&
+         match(WideInc, m_c_BinOp(m_Specific(WidePhi), m_Value())) &&
+         OrigInc->getOpcode() == WideInc->getOpcode();
+}
+
 /// Determine if this cyclic phi is in a form that would have been generated by
 /// LSR. We don't care if the phi was actually expanded in this pass, as long
 /// as it is in a low-cost form, for example, no implied multiplication. This
diff --git a/llvm/lib/Transforms/Utils/SimplifyIndVar.cpp b/llvm/lib/Transforms/Utils/SimplifyIndVar.cpp
index 5aa6df49e7f6..66bba1ca2f1d 100644
--- a/llvm/lib/Transforms/Utils/SimplifyIndVar.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyIndVar.cpp
@@ -1131,7 +1131,8 @@ protected:
   const SCEV *getSCEVByOpCode(const SCEV *LHS, const SCEV *RHS,
                               unsigned OpCode) const;

-  Instruction *widenIVUse(NarrowIVDefUse DU, SCEVExpander &Rewriter);
+  Instruction *widenIVUse(NarrowIVDefUse DU, SCEVExpander &Rewriter,
+                          PHINode *OrigPhi, PHINode *WidePhi);

   bool widenLoopCompare(NarrowIVDefUse DU);
   bool widenWithVariantUse(NarrowIVDefUse DU);
@@ -1731,7 +1732,9 @@ bool WidenIV::widenWithVariantUse(WidenIV::NarrowIVDefUse DU) {

 /// Determine whether an individual user of the narrow IV can be widened. If so,
 /// return the wide clone of the user.
-Instruction *WidenIV::widenIVUse(WidenIV::NarrowIVDefUse DU, SCEVExpander &Rewriter) {
+Instruction *WidenIV::widenIVUse(WidenIV::NarrowIVDefUse DU,
+                                 SCEVExpander &Rewriter, PHINode *OrigPhi,
+                                 PHINode *WidePhi) {
   assert(ExtendKindMap.count(DU.NarrowDef) &&
          "Should already know the kind of extension used to widen NarrowDef");

@@ -1825,11 +1828,18 @@ Instruction *WidenIV::widenIVUse(WidenIV::NarrowIVDefUse DU, SCEVExpander &Rewri
     if (!WideAddRec.first)
       return nullptr;

-    // Reuse the IV increment that SCEVExpander created as long as it dominates
-    // NarrowUse.
+    // Reuse the IV increment that SCEVExpander created. Recompute flags, unless
+    // the flags for both increments agree and it is safe to use the ones from
+    // the original inc. In that case, the new use of the wide increment won't
+    // be more poisonous.
+    bool NeedToRecomputeFlags =
+        !SCEVExpander::canReuseFlagsFromOriginalIVInc(OrigPhi, WidePhi,
+                                                      DU.NarrowUse, WideInc) ||
+        DU.NarrowUse->hasNoUnsignedWrap() != WideInc->hasNoUnsignedWrap() ||
+        DU.NarrowUse->hasNoSignedWrap() != WideInc->hasNoSignedWrap();
     Instruction *WideUse = nullptr;
     if (WideAddRec.first == WideIncExpr &&
-        Rewriter.hoistIVInc(WideInc, DU.NarrowUse))
+        Rewriter.hoistIVInc(WideInc, DU.NarrowUse, NeedToRecomputeFlags))
       WideUse = WideInc;
     else {
       WideUse = cloneIVUser(DU, WideAddRec.first);
@@ -1996,11 +2006,9 @@ PHINode *WidenIV::createWideIV(SCEVExpander &Rewriter) {
       // the same opcode. It is not safe to re-use the flags from the original
       // increment, if it is more complex and SCEV expansion may have yielded a
       // more simplified wider increment.
-      bool MatchingOps =
-          match(OrigInc, m_c_BinOp(m_Specific(OrigPhi), m_Value())) &&
-          match(WideInc, m_c_BinOp(m_Specific(WidePhi), m_Value())) &&
-          OrigInc->getOpcode() == WideInc->getOpcode();
-      if (MatchingOps && isa<OverflowingBinaryOperator>(OrigInc) &&
+      if (SCEVExpander::canReuseFlagsFromOriginalIVInc(OrigPhi, WidePhi,
+                                                       OrigInc, WideInc) &&
+          isa<OverflowingBinaryOperator>(OrigInc) &&
           isa<OverflowingBinaryOperator>(WideInc)) {
         WideInc->setHasNoUnsignedWrap(WideInc->hasNoUnsignedWrap() ||
                                       OrigInc->hasNoUnsignedWrap());
@@ -2024,7 +2032,7 @@ PHINode *WidenIV::createWideIV(SCEVExpander &Rewriter) {

     // Process a def-use edge. This may replace the use, so don't hold a
     // use_iterator across it.
-    Instruction *WideUse = widenIVUse(DU, Rewriter);
+    Instruction *WideUse = widenIVUse(DU, Rewriter, OrigPhi, WidePhi);

     // Follow all def-use edges from the previous narrow use.
     if (WideUse)

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

define void @test_pr82243(ptr %f) {
entry:
  br label %outer.header

outer.header:                                     ; preds = %outer.latch, %entry
  %iv = phi i32 [ 1, %entry ], [ %iv.next, %outer.latch ]
  %iv.sext = sext i32 %iv to i64
  %gep.iv.ext = getelementptr i32, ptr %f, i64 %iv.sext
  store i32 1, ptr %gep.iv.ext, align 4
  %sub = add i32 %iv, -1
  %shl = shl i32 123, %sub
  %gep.shl = getelementptr i32, ptr %f, i32 %shl
  br label %inner.header

inner.header:                                     ; preds = %inner.latch, %outer.header
  store i32 0, ptr %gep.shl, align 4
  br i1 false, label %inner.latch, label %exit

inner.latch:                                      ; preds = %inner.header
  br i1 false, label %inner.header, label %outer.latch

outer.latch:                                      ; preds = %inner.latch
  %iv.next = add i32 %iv, -1
  br label %outer.header

exit:                                             ; preds = %inner.header
  ret void
}

Wrong code at -Os on x86-64_gnu-linux (recent regression)

Clang at -Os produced the wrong code.

Bisected to dce77a357948709e335910ddc07f9c3f2eb2ac4b, which was committed by @fhahn

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

```console
% cat reduced.c
int printf(const char *, ...);
int a, b, c, d, e;
int f[9];
int g(int i) {
  c = 1 << i;
  if (b & c)
    return 4;
  return 0;
}
int j(int i) {
  int h = g(i);
  return h;
}
int k() {
  d = 6;
  for (; d; d--) {
    e = 0;
    for (; e <= 6; e++) {
      f[j(d - 1)] = f[d];
      for (; e + d;)
        return 0;
    }
  }
  return 0;
}
int main() {
  k();
  printf("%d\n", a);
}
%
% clang -O3 reduced.c && ./a.out
0
% clang -Os reduced.c && ./a.out

%
```

The issue is that IndVars doesn't drop poison-generating flags when hoisting the IV to introduce a new use of the widened IV. working on a fix

Should be fixed, thanks again as always @shao-hua-li

You're welcome @fhahn


commit 65da32c634a8345fcbe021f69fc6a609d074c08c
Author: Florian Hahn <flo@fhahn.com>
Date:   Fri Oct 11 11:26:57 2024 +0100

    [LV] Account for any-of reduction when computing costs of blend phis.

    Any-of reductions are narrowed to i1. Update the legacy cost model to
    use the correct type when computing the cost of a phi that gets lowered
    to selects (BLEND).

    This fixes a divergence between legacy and VPlan-based cost models after
    36fc291b6ec6d.

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

diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index 05dc58a42249..54f57fb0b6b5 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -6480,12 +6480,32 @@ LoopVectorizationCostModel::getInstructionCost(Instruction *I,
     // Phi nodes in non-header blocks (not inductions, reductions, etc.) are
     // converted into select instructions. We require N - 1 selects per phi
     // node, where N is the number of incoming values.
-    if (VF.isVector() && Phi->getParent() != TheLoop->getHeader())
+    if (VF.isVector() && Phi->getParent() != TheLoop->getHeader()) {
+      Type *ResultTy = Phi->getType();
+
+      // All instructions in an Any-of reduction chain are narrowed to bool.
+      // Check if that is the case for this phi node.
+      auto *HeaderUser = cast_if_present<PHINode>(
+          find_singleton<User>(Phi->users(), [this](User *U, bool) -> User * {
+            auto *Phi = dyn_cast<PHINode>(U);
+            if (Phi && Phi->getParent() == TheLoop->getHeader())
+              return Phi;
+            return nullptr;
+          }));
+      if (HeaderUser) {
+        auto &ReductionVars = Legal->getReductionVars();
+        auto Iter = ReductionVars.find(HeaderUser);
+        if (Iter != ReductionVars.end() &&
+            RecurrenceDescriptor::isAnyOfRecurrenceKind(
+                Iter->second.getRecurrenceKind()))
+          ResultTy = Type::getInt1Ty(Phi->getContext());
+      }
       return (Phi->getNumIncomingValues() - 1) *
              TTI.getCmpSelInstrCost(
-                 Instruction::Select, ToVectorTy(Phi->getType(), VF),
+                 Instruction::Select, ToVectorTy(ResultTy, VF),
                  ToVectorTy(Type::getInt1Ty(Phi->getContext()), VF),
                  CmpInst::BAD_ICMP_PREDICATE, CostKind);
+    }

     return TTI.getCFInstrCost(Instruction::PHI, CostKind);
   }

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

define i32 @any_of_reduction_used_in_blend(ptr %src, i64 %N, i1 %c.0, i1 %c.1) #0 {
entry:
  br label %loop.header

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

else.1:                                           ; preds = %loop.header
  br i1 %c.1, label %loop.latch, label %else.2

else.2:                                           ; preds = %else.1
  %l = load ptr, ptr %src, align 8
  %c.2 = icmp eq ptr %l, null
  %sel = select i1 %c.2, i32 0, i32 %any.of.red
  br label %loop.latch

loop.latch:                                       ; preds = %else.2, %else.1, %loop.header
  %any.of.red.next = phi i32 [ %any.of.red, %loop.header ], [ %any.of.red, %else.1 ], [ %sel, %else.2 ]
  %iv.next = add i64 %iv, 1
  %ec = icmp eq i64 %iv.next, %N
  br i1 %ec, label %exit, label %loop.header

exit:                                             ; preds = %loop.latch
  %res = phi i32 [ %any.of.red.next, %loop.latch ]
  ret i32 %res
}

attributes #0 = { "target-cpu"="sifive-p670" }

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

define i32 @any_of_reduction_used_in_blend_with_mutliple_phis(ptr %src, i64 %N, i1 %c.0, i1 %c.1) #0 {
entry:
  br label %loop.header

loop.header:                                      ; preds = %loop.latch, %entry
  %any.of.red = phi i32 [ 0, %entry ], [ %any.of.red.next, %loop.latch ]
  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ]
  br i1 %c.0, label %x.1, label %else.1

else.1:                                           ; preds = %loop.header
  br i1 %c.1, label %x.1, label %else.2

else.2:                                           ; preds = %else.1
  %l = load ptr, ptr %src, align 8
  %c.2 = icmp eq ptr %l, null
  %sel = select i1 %c.2, i32 0, i32 %any.of.red
  br label %loop.latch

x.1:                                              ; preds = %else.1, %loop.header
  %p = phi i32 [ %any.of.red, %loop.header ], [ %any.of.red, %else.1 ]
  br label %loop.latch

loop.latch:                                       ; preds = %x.1, %else.2
  %any.of.red.next = phi i32 [ %p, %x.1 ], [ %sel, %else.2 ]
  %iv.next = add i64 %iv, 1
  %ec = icmp eq i64 %iv.next, %N
  br i1 %ec, label %exit, label %loop.header

exit:                                             ; preds = %loop.latch
  %res = phi i32 [ %any.of.red.next, %loop.latch ]
  ret i32 %res
}

attributes #0 = { "target-cpu"="sifive-p670" }

Crash in LV: "VPlan cost model and legacy cost model disagreed"

Loop vectorizer crash for the following reproducer:
```
target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"
target triple = "riscv64-unknown-linux-gnu"

define void @init_dependence_analysis(ptr %iiv_used.i.i.i.sroa.0, i64 %indvars.iv71.i.i.i, i1 %cmp104.not.i.i.i, i1 %tobool108.not.i.i.i) #0 {
entry:
  br label %for.cond101.preheader.i.i.i

for.cond101.preheader.i.i.i:                      ; preds = %for.inc121.i.i.i, %entry
  %separability.0.i.i = phi i32 [ 0, %entry ], [ %separability.2.i.i, %for.inc121.i.i.i ]
  br label %for.body103.i.i.i

for.body103.i.i.i:                                ; preds = %for.inc121.i.i.i, %for.cond101.preheader.i.i.i
  %separability.1.i.i = phi i32 [ %separability.0.i.i, %for.cond101.preheader.i.i.i ], [ %separability.2.i.i, %for.inc121.i.i.i ]
  %indvars.iv71.i.i.i5 = phi i64 [ 0, %for.cond101.preheader.i.i.i ], [ %indvars.iv.next72.i.i.i, %for.inc121.i.i.i ]
  br i1 %cmp104.not.i.i.i, label %for.inc121.i.i.i, label %land.lhs.true105.i.i.i

land.lhs.true105.i.i.i:                           ; preds = %for.body103.i.i.i
  br i1 %tobool108.not.i.i.i, label %for.inc121.i.i.i, label %land.lhs.true109.i.i.i

land.lhs.true109.i.i.i:                           ; preds = %land.lhs.true105.i.i.i
  %0 = load ptr, ptr %iiv_used.i.i.i.sroa.0, align 8
  %cmp118.i.i.i = icmp eq ptr %0, null
  %spec.select209.i.i = select i1 %cmp118.i.i.i, i32 0, i32 %separability.1.i.i
  br label %for.inc121.i.i.i

for.inc121.i.i.i:                                 ; preds = %land.lhs.true109.i.i.i, %land.lhs.true105.i.i.i, %for.body103.i.i.i
  %separability.2.i.i = phi i32 [ %separability.1.i.i, %for.body103.i.i.i ], [ %separability.1.i.i, %land.lhs.true105.i.i.i ], [ %spec.select209.i.i, %land.lhs.true109.i.i.i ]
  %indvars.iv.next72.i.i.i = add i64 %indvars.iv71.i.i.i5, 1
  %exitcond74.not.i.i.i = icmp eq i64 %indvars.iv71.i.i.i5, %indvars.iv71.i.i.i
  br i1 %exitcond74.not.i.i.i, label %for.cond101.preheader.i.i.i, label %for.body103.i.i.i

; uselistorder directives
  uselistorder i32 %separability.2.i.i, { 1, 0 }
}

attributes #0 = { "target-cpu"="sifive-p670" }
```

opt -S --passes=loop-vectorize ./reduced.ll
LoopVectorize.cpp:7430: VectorizationFactor llvm::LoopVectorizationPlanner::computeBestVF(): Assertion `(BestFactor.Width == LegacyVF.Width || planContainsAdditionalSimplifications(getPlanFor(BestFactor.Width), CostCtx, OrigLoop)) && " VPlan cost model and legacy cost model disagreed"' failed.


commit a77dedcacb4c5eb221395b69877981dd6ad98989
Author: Yingwei Zheng <dtcxzyw2333@gmail.com>
Date:   Fri Nov 1 22:56:22 2024 +0800

    [InstSimplify][InstCombine][ConstantFold] Move vector div/rem by zero fold to InstCombine (#114280)

    Previously we fold `div/rem X, C` into `poison` if any element of the
    constant divisor `C` is zero or undef. However, it is incorrect when
    threading udiv over an vector select:
    https://alive2.llvm.org/ce/z/3Ninx5
    ```
    define <2 x i32> @vec_select_udiv_poison(<2 x i1> %x) {
      %sel = select <2 x i1> %x, <2 x i32> <i32 -1, i32 -1>, <2 x i32> <i32 0, i32 1>
      %div = udiv <2 x i32> <i32 42, i32 -7>, %sel
      ret <2 x i32> %div
    }
    ```
    In this case, `threadBinOpOverSelect` folds `udiv <i32 42, i32 -7>, <i32
    -1, i32 -1>` and `udiv <i32 42, i32 -7>, <i32 0, i32 1>` into
    `zeroinitializer` and `poison`, respectively. One solution is to
    introduce a new flag indicating that we are threading over a vector
    select. But it requires to modify both `InstSimplify` and
    `ConstantFold`.

    However, this optimization doesn't provide benefits to real-world
    programs:

    https://dtcxzyw.github.io/llvm-opt-benchmark/coverage/data/zyw/opt-ci/actions-runner/_work/llvm-opt-benchmark/llvm-opt-benchmark/llvm/llvm-project/llvm/lib/IR/ConstantFold.cpp.html#L908

    https://dtcxzyw.github.io/llvm-opt-benchmark/coverage/data/zyw/opt-ci/actions-runner/_work/llvm-opt-benchmark/llvm-opt-benchmark/llvm/llvm-project/llvm/lib/Analysis/InstructionSimplify.cpp.html#L1107

    This patch moves the fold into InstCombine to avoid breaking numerous
    existing tests.

    Fixes #114191 and #113866 (only poison-safety issue).

diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index d08be1e55c85..2cb2612bf611 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -1095,19 +1095,6 @@ static Value *simplifyDivRem(Instruction::BinaryOps Opcode, Value *Op0,
   if (match(Op1, m_Zero()))
     return PoisonValue::get(Ty);

-  // If any element of a constant divisor fixed width vector is zero or undef
-  // the behavior is undefined and we can fold the whole op to poison.
-  auto *Op1C = dyn_cast<Constant>(Op1);
-  auto *VTy = dyn_cast<FixedVectorType>(Ty);
-  if (Op1C && VTy) {
-    unsigned NumElts = VTy->getNumElements();
-    for (unsigned i = 0; i != NumElts; ++i) {
-      Constant *Elt = Op1C->getAggregateElement(i);
-      if (Elt && (Elt->isNullValue() || Q.isUndefValue(Elt)))
-        return PoisonValue::get(Ty);
-    }
-  }
-
   // poison / X -> poison
   // poison % X -> poison
   if (isa<PoisonValue>(Op0))
diff --git a/llvm/lib/IR/ConstantFold.cpp b/llvm/lib/IR/ConstantFold.cpp
index 07dfbc41e79b..c2780faee403 100644
--- a/llvm/lib/IR/ConstantFold.cpp
+++ b/llvm/lib/IR/ConstantFold.cpp
@@ -902,11 +902,6 @@ Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode, Constant *C1,
         Constant *ExtractIdx = ConstantInt::get(Ty, i);
         Constant *LHS = ConstantExpr::getExtractElement(C1, ExtractIdx);
         Constant *RHS = ConstantExpr::getExtractElement(C2, ExtractIdx);
-
-        // If any element of a divisor vector is zero, the whole op is poison.
-        if (Instruction::isIntDivRem(Opcode) && RHS->isNullValue())
-          return PoisonValue::get(VTy);
-
         Constant *Res = ConstantExpr::isDesirableBinOp(Opcode)
                             ? ConstantExpr::get(Opcode, LHS, RHS)
                             : ConstantFoldBinaryInstruction(Opcode, LHS, RHS);
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
index 7a060cdab2d3..adbd9186c59c 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
+++ b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
@@ -102,6 +102,7 @@ public:
   Instruction *visitSRem(BinaryOperator &I);
   Instruction *visitFRem(BinaryOperator &I);
   bool simplifyDivRemOfSelectWithZeroOp(BinaryOperator &I);
+  Instruction *commonIDivRemTransforms(BinaryOperator &I);
   Instruction *commonIRemTransforms(BinaryOperator &I);
   Instruction *commonIDivTransforms(BinaryOperator &I);
   Instruction *visitUDiv(BinaryOperator &I);
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index b9c165da906d..f85a3c936513 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -1158,29 +1158,39 @@ static Value *foldIDivShl(BinaryOperator &I, InstCombiner::BuilderTy &Builder) {
   return nullptr;
 }

-/// This function implements the transforms common to both integer division
-/// instructions (udiv and sdiv). It is called by the visitors to those integer
-/// division instructions.
-/// Common integer divide transforms
-Instruction *InstCombinerImpl::commonIDivTransforms(BinaryOperator &I) {
-  if (Instruction *Phi = foldBinopWithPhiOperands(I))
-    return Phi;
-
+/// Common integer divide/remainder transforms
+Instruction *InstCombinerImpl::commonIDivRemTransforms(BinaryOperator &I) {
+  assert(I.isIntDivRem() && "Unexpected instruction");
   Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
-  bool IsSigned = I.getOpcode() == Instruction::SDiv;
+
+  // If any element of a constant divisor fixed width vector is zero or undef
+  // the behavior is undefined and we can fold the whole op to poison.
+  auto *Op1C = dyn_cast<Constant>(Op1);
   Type *Ty = I.getType();
+  auto *VTy = dyn_cast<FixedVectorType>(Ty);
+  if (Op1C && VTy) {
+    unsigned NumElts = VTy->getNumElements();
+    for (unsigned i = 0; i != NumElts; ++i) {
+      Constant *Elt = Op1C->getAggregateElement(i);
+      if (Elt && (Elt->isNullValue() || isa<UndefValue>(Elt)))
+        return replaceInstUsesWith(I, PoisonValue::get(Ty));
+    }
+  }
+
+  if (Instruction *Phi = foldBinopWithPhiOperands(I))
+    return Phi;

   // The RHS is known non-zero.
   if (Value *V = simplifyValueKnownNonZero(I.getOperand(1), *this, I))
     return replaceOperand(I, 1, V);

-  // Handle cases involving: [su]div X, (select Cond, Y, Z)
-  // This does not apply for fdiv.
+  // Handle cases involving: div/rem X, (select Cond, Y, Z)
   if (simplifyDivRemOfSelectWithZeroOp(I))
     return &I;

   // If the divisor is a select-of-constants, try to constant fold all div ops:
-  // C / (select Cond, TrueC, FalseC) --> select Cond, (C / TrueC), (C / FalseC)
+  // C div/rem (select Cond, TrueC, FalseC) --> select Cond, (C div/rem TrueC),
+  // (C div/rem FalseC)
   // TODO: Adapt simplifyDivRemOfSelectWithZeroOp to allow this and other folds.
   if (match(Op0, m_ImmConstant()) &&
       match(Op1, m_Select(m_Value(), m_ImmConstant(), m_ImmConstant()))) {
@@ -1189,6 +1199,21 @@ Instruction *InstCombinerImpl::commonIDivTransforms(BinaryOperator &I) {
       return R;
   }

+  return nullptr;
+}
+
+/// This function implements the transforms common to both integer division
+/// instructions (udiv and sdiv). It is called by the visitors to those integer
+/// division instructions.
+/// Common integer divide transforms
+Instruction *InstCombinerImpl::commonIDivTransforms(BinaryOperator &I) {
+  if (Instruction *Res = commonIDivRemTransforms(I))
+    return Res;
+
+  Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
+  bool IsSigned = I.getOpcode() == Instruction::SDiv;
+  Type *Ty = I.getType();
+
   const APInt *C2;
   if (match(Op1, m_APInt(C2))) {
     Value *X;
@@ -2138,29 +2163,11 @@ static Instruction *simplifyIRemMulShl(BinaryOperator &I,
 /// remainder instructions.
 /// Common integer remainder transforms
 Instruction *InstCombinerImpl::commonIRemTransforms(BinaryOperator &I) {
-  if (Instruction *Phi = foldBinopWithPhiOperands(I))
-    return Phi;
+  if (Instruction *Res = commonIDivRemTransforms(I))
+    return Res;

   Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);

-  // The RHS is known non-zero.
-  if (Value *V = simplifyValueKnownNonZero(I.getOperand(1), *this, I))
-    return replaceOperand(I, 1, V);
-
-  // Handle cases involving: rem X, (select Cond, Y, Z)
-  if (simplifyDivRemOfSelectWithZeroOp(I))
-    return &I;
-
-  // If the divisor is a select-of-constants, try to constant fold all rem ops:
-  // C % (select Cond, TrueC, FalseC) --> select Cond, (C % TrueC), (C % FalseC)
-  // TODO: Adapt simplifyDivRemOfSelectWithZeroOp to allow this and other folds.
-  if (match(Op0, m_ImmConstant()) &&
-      match(Op1, m_Select(m_Value(), m_ImmConstant(), m_ImmConstant()))) {
-    if (Instruction *R = FoldOpIntoSelect(I, cast<SelectInst>(Op1),
-                                          /*FoldWithMultiUse*/ true))
-      return R;
-  }
-
   if (isa<Constant>(Op1)) {
     if (Instruction *Op0I = dyn_cast<Instruction>(Op0)) {
       if (SelectInst *SI = dyn_cast<SelectInst>(Op0I)) {

define <2 x i8> @sdiv_constant_dividend_select_of_constants_divisor_vec(i1 %b) {
  %s = select i1 %b, <2 x i8> <i8 12, i8 -5>, <2 x i8> <i8 -4, i8 4>
  %r = sdiv <2 x i8> <i8 42, i8 -42>, %s
  ret <2 x i8> %r
}

define <2 x i8> @udiv_constant_dividend_select_of_constants_divisor_vec(i1 %b) {
  %s = select i1 %b, <2 x i8> <i8 12, i8 -5>, <2 x i8> <i8 -4, i8 4>
  %r = udiv <2 x i8> <i8 42, i8 -42>, %s
  ret <2 x i8> %r
}

define <2 x i8> @sdiv_constant_dividend_select_of_constants_divisor_vec_ub1(i1 %b) {
  %s = select i1 %b, <2 x i8> <i8 0, i8 -5>, <2 x i8> <i8 -4, i8 4>
  %r = sdiv <2 x i8> <i8 42, i8 -42>, %s
  ret <2 x i8> %r
}

define <2 x i8> @udiv_constant_dividend_select_of_constants_divisor_vec_ub1(i1 %b) {
  %s = select i1 %b, <2 x i8> <i8 0, i8 -5>, <2 x i8> <i8 -4, i8 4>
  %r = udiv <2 x i8> <i8 42, i8 -42>, %s
  ret <2 x i8> %r
}

define <2 x i8> @urem_constant_dividend_select_of_constants_divisor_vec_ub1(i1 %b) {
  %s = select i1 %b, <2 x i8> <i8 0, i8 -5>, <2 x i8> <i8 -4, i8 4>
  %r = urem <2 x i8> <i8 42, i8 -42>, %s
  ret <2 x i8> %r
}

define <2 x i8> @urem_constant_dividend_select_of_constants_divisor_vec(i1 %b) {
  %s = select i1 %b, <2 x i8> <i8 12, i8 -5>, <2 x i8> <i8 -4, i8 4>
  %r = urem <2 x i8> <i8 42, i8 -42>, %s
  ret <2 x i8> %r
}

define <2 x i8> @udiv_zero_elt_vec(<2 x i8> %x) {
  %div = udiv <2 x i8> %x, <i8 0, i8 42>
  ret <2 x i8> %div
}

define <2 x i8> @sdiv_zero_elt_vec(<2 x i8> %x) {
  %div = sdiv <2 x i8> %x, <i8 -42, i8 0>
  ret <2 x i8> %div
}

define <2 x i8> @udiv_poison_elt_vec(<2 x i8> %x) {
  %div = udiv <2 x i8> %x, <i8 poison, i8 42>
  ret <2 x i8> %div
}

define <2 x i8> @sdiv_zero_elt_vec_constfold(<2 x i8> %x) {
  %div = sdiv <2 x i8> <i8 1, i8 2>, <i8 0, i8 -42>
  ret <2 x i8> %div
}

define <2 x i8> @sdiv_poison_elt_vec(<2 x i8> %x) {
  %div = sdiv <2 x i8> %x, <i8 -42, i8 poison>
  ret <2 x i8> %div
}

define <2 x i8> @udiv_zero_elt_vec_constfold(<2 x i8> %x) {
  %div = udiv <2 x i8> <i8 1, i8 2>, <i8 42, i8 0>
  ret <2 x i8> %div
}

define <2 x i32> @zero_dividend_vector_poison_elt(<2 x i32> %A) {
  %B = sdiv <2 x i32> <i32 0, i32 poison>, %A
  ret <2 x i32> %B
}

define <2 x i8> @srem_zero_elt_vec_constfold(<2 x i8> %x) {
  %rem = srem <2 x i8> <i8 1, i8 2>, <i8 0, i8 -42>
  ret <2 x i8> %rem
}

define <2 x i8> @urem_zero_elt_vec(<2 x i8> %x) {
  %rem = urem <2 x i8> %x, <i8 0, i8 42>
  ret <2 x i8> %rem
}

define <2 x i8> @urem_zero_elt_vec_constfold(<2 x i8> %x) {
  %rem = urem <2 x i8> <i8 1, i8 2>, <i8 42, i8 0>
  ret <2 x i8> %rem
}

define <2 x i8> @srem_undef_elt_vec(<2 x i8> %x) {
  %rem = srem <2 x i8> %x, <i8 -42, i8 undef>
  ret <2 x i8> %rem
}

define <2 x i8> @urem_undef_elt_vec(<2 x i8> %x) {
  %rem = urem <2 x i8> %x, <i8 undef, i8 42>
  ret <2 x i8> %rem
}

define <2 x i32> @zero_dividend_vector_poison_elt(<2 x i32> %A) {
  %B = urem <2 x i32> <i32 poison, i32 0>, %A
  ret <2 x i32> %B
}

define <2 x i8> @srem_zero_elt_vec(<2 x i8> %x) {
  %rem = srem <2 x i8> %x, <i8 -42, i8 0>
  ret <2 x i8> %rem
}

[InstCombine] miscompilation of `or` of vectors

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

```llvm
----------------------------------------
define <2 x i32> @or_sext_to_sel_constant_vec.3(<2 x i1> %y) {
#0:
  %sext = sext <2 x i1> %y to <2 x i32>
  %#1 = or <2 x i32> %sext, { 0, 1 }
  %#2 = udiv <2 x i32> { 42, 4294967289 }, %#1
  ret <2 x i32> %#2
}
=>
define <2 x i32> @or_sext_to_sel_constant_vec.3(<2 x i1> %y) {
#0:
  ret <2 x i32> { 0, 0 }
}
Transformation doesn't verify!

ERROR: Value mismatch

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

Source:
<2 x i32> %sext = < #xffffffff (4294967295, -1), #x00000000 (0) >
<2 x i32> %#1 = < #xffffffff (4294967295, -1), #x00000001 (1) >
<2 x i32> %#2 = < #x00000000 (0), #xfffffff9 (4294967289, -7) >

Target:
Source value: < #x00000000 (0), #xfffffff9 (4294967289, -7) >
Target value: < #x00000000 (0), #x00000000 (0) >

----------------------------------------
define <2 x i32> @or_sext_to_sel_constant_vec.2(<2 x i1> %y) {
#0:
  %sext = sext <2 x i1> %y to <2 x i32>
  %#1 = or <2 x i32> %sext, { 0, 1 }
  %#2 = sdiv <2 x i32> { 42, 4294967289 }, %#1
  %#3 = udiv exact <2 x i32> %#2, %#2
  %#4 = or <2 x i32> %#2, %#2
  ret <2 x i32> %#4
}
=>
define <2 x i32> @or_sext_to_sel_constant_vec.2(<2 x i1> %y) {
#0:
  ret <2 x i32> { 4294967254, 7 }
}
Transformation doesn't verify!

ERROR: Value mismatch

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

Source:
<2 x i32> %sext = < #xffffffff (4294967295, -1), #x00000000 (0) >
<2 x i32> %#1 = < #xffffffff (4294967295, -1), #x00000001 (1) >
<2 x i32> %#2 = < #xffffffd6 (4294967254, -42), #xfffffff9 (4294967289, -7) >
<2 x i32> %#3 = < #x00000001 (1), #x00000001 (1) >
<2 x i32> %#4 = < #xffffffd6 (4294967254, -42), #xfffffff9 (4294967289, -7) >

Target:
Source value: < #xffffffd6 (4294967254, -42), #xfffffff9 (4294967289, -7) >
Target value: < #xffffffd6 (4294967254, -42), #x00000007 (7) >

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

@bongjunj Feel free to ping me if you find new InstCombine miscompilation bugs without involving undef values/NaN payloads.

https://github.com/llvm/llvm-project/blob/eac2c182c6f852fc187af9952250a43d6fb17b28/llvm/lib/Analysis/InstructionSimplify.cpp#L1098-L1109

We cannot do this simplification when threading udiv over selects.


commit 929cbe7f596733f85cd274485acc19442dd34a80
Author: Antonio Frighetto <me@antoniofrighetto.com>
Date:   Tue Nov 12 19:02:04 2024 +0100

    [InstCombine] Intersect nowrap flags between geps while folding into phi

    A miscompilation issue has been addressed with refined checking.

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

diff --git a/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp b/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp
index cb5c44730512..1fcf1c570add 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp
@@ -545,7 +545,8 @@ Instruction *InstCombinerImpl::foldPHIArgGEPIntoPHI(PHINode &PN) {
   // especially bad when the PHIs are in the header of a loop.
   bool NeededPhi = false;

-  GEPNoWrapFlags NW = GEPNoWrapFlags::all();
+  // Remember flags of the first phi-operand getelementptr.
+  GEPNoWrapFlags NW = FirstInst->getNoWrapFlags();

   // Scan to see if all operands are the same opcode, and all have one user.
   for (Value *V : drop_begin(PN.incoming_values())) {

define ptr @phi_of_gep_flags_1(i1 %c, ptr %p) {
  br i1 %c, label %if, label %else

if:                                               ; preds = %0
  %gep1 = getelementptr inbounds i32, ptr %p, i64 1
  br label %join

else:                                             ; preds = %0
  %gep2 = getelementptr nusw nuw i32, ptr %p, i64 1
  br label %join

join:                                             ; preds = %else, %if
  %phi = phi ptr [ %gep1, %if ], [ %gep2, %else ]
  ret ptr %phi
}

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 i64 @wrong_gep_arg_into_phi(ptr noundef %ptr) {
entry:
  %add.ptr = getelementptr i8, ptr %ptr, i64 1
  br label %for.cond

for.cond:                                         ; preds = %for.cond, %entry
  %.pn = phi ptr [ %add.ptr, %entry ], [ %incdec.ptr, %for.cond ]
  %val = load i8, ptr %.pn, align 1
  %cond = icmp ne i8 %val, 0
  %incdec.ptr = getelementptr inbounds nuw i8, ptr %.pn, i64 1
  br i1 %cond, label %for.cond, label %exit

exit:                                             ; preds = %for.cond
  ret i64 0
}

[clang] Miscompile with -O3 and -O0/1/2 since 18.1.0

When I compiled this code with -O0/1/2, its output is 0. However, with -O3, it returned 143:

```c
int printf(const char *, ...);
char a, b;
int c;
char *e = &b;
int f(char *g, int *k) {
  char *d = g + *k;
  for (; *d && *d <= ' '; d++)
    ;
  if (*d)
    return 0;
  return 1;
}
int l(int g) {
  char h[] = {a, a, a};
  int i[] = {g};
  int j = f(h, i);
  return j;
}
long m() {
  *e = 255;
  for (; l(b + 1);)
    return 0;
  for (;;)
    ;
}
int main() {
  m();
  printf("%d\n", c);
}
```

Details can be found here: https://godbolt.org/z/dnvvTPror

This looks like a nasty one. Getting the optimized IR via -O3 and setting noinline/optnone to main, we get: https://llvm.godbolt.org/z/vaPvs6d16.

This is the initial assembly output with -O1 (which leads to the infinite loop):

```asm
main:                                   # @main
        push    rax
        mov     rax, qword ptr [e]
        mov     byte ptr [rax], -1
        movsx   rax, byte ptr [b]
        mov     cl, byte ptr [a]
        mov     byte ptr [rsp + 6], cl
        mov     byte ptr [rsp + 7], cl
        lea     rdx, [rsp + 5]
        add     rdx, rax
        mov     rax, rdx
.LBB0_1:                                # %for.cond.i.i.i
        add     rax, 1
        mov     cl, byte ptr [rdx + 1]
        ...
```
Whereas this is with -O0 (returns 0):
```asm
main:                                   # @main
        sub     rsp, 24
        mov     rax, qword ptr [e]
        mov     byte ptr [rax], -1
        movsx   rcx, byte ptr [b]
        mov     al, byte ptr [a]
        mov     byte ptr [rsp + 22], al
        mov     byte ptr [rsp + 23], al
        lea     rax, [rsp + 21]
        add     rax, rcx
        mov     qword ptr [rsp + 8], rax        # 8-byte Spill
.LBB0_1:                                # %for.cond.i.i.i
        mov     rcx, qword ptr [rsp + 8]        # 8-byte Reload
        mov     rax, rcx
        add     rax, 1
        mov     dl, byte ptr [rcx + 1]
```
In the optimized one, $rdx is set to point to $rsp+0x5, part of the stack slot containing $rax (undef), later dereferenced to set the condition leading to the loop. Initially I thought some bug in regalloc, but to me it seems more something in prologepiloginserter. Function prologue / epilogue seems set up correctly with triple arm64-apple-macosx.

Looking at the IR better, it seems like InstCombine performs a wrong optimization immediately after inlining `l` into `m`, probably related with default argument conversion done by operator + (which should include integer promotion on types smaller than integer). Alive2 seems to confirm it: https://alive2.llvm.org/ce/z/XAzrip.

Reduced to:
```llvm
@a = global i8 0, align 1

define i64 @src(i8 noundef %arg) {
entry:
  %h.i = alloca [3 x i8], align 1
  %conv = sext i8 %arg to i32
  %add = add nsw i32 %conv, 1
  %2 = load i8, ptr @a, align 1
  store i8 %2, ptr %h.i, align 1
  %idx.ext.i.i = sext i32 %add to i64
  %add.ptr.i.i = getelementptr inbounds i8, ptr %h.i, i64 %idx.ext.i.i
  br label %for.cond.i.i

for.cond.i.i:                                     ; preds = %for.cond.i.i, %entry
  %d.0.i.i = phi ptr [ %add.ptr.i.i, %entry ], [ %incdec.ptr.i.i, %for.cond.i.i ]
  %3 = load i8, ptr %d.0.i.i, align 1
  %tobool.not.i.i = icmp ne i8 %3, 0
  %incdec.ptr.i.i = getelementptr inbounds nuw i8, ptr %d.0.i.i, i64 1
  br i1 %tobool.not.i.i, label %for.cond.i.i, label %l.exit

l.exit:                                           ; preds = %for.cond.i.i
  ret i64 0
}
```
Wrong sext of add of sext simplified to sext leads to wrong gep offset: https://alive2.llvm.org/ce/z/JaR4j9.

Can we backport this to 19.x?

Should be fixed in 929cbe7f596733f85cd274485acc19442dd34a80, thanks for reporting!

@antoniofrighetto can we please backport this


commit acfd26a93be3fb70013560f3fb894eb9086e7e32
Author: Julian Nagele <j.nagele@apple.com>
Date:   Fri Dec 20 15:44:15 2024 +0100

    [SCEV] Fix exit condition for recursive loop guard collection (#120442)

    When assumptions are present `Terms.size()` does not actually count the
    number of conditions collected from dominating branches; introduce a
    separate counter.

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

diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index d55d09020fc1..1e4bb1d606cd 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -15753,6 +15753,7 @@ void ScalarEvolution::LoopGuards::collectFromBlock(
   // predecessors that can be found that have unique successors leading to the
   // original header.
   // TODO: share this logic with isLoopEntryGuardedByCond.
+  unsigned NumCollectedConditions = 0;
   std::pair<const BasicBlock *, const BasicBlock *> Pair(Pred, Block);
   for (; Pair.first;
        Pair = SE.getPredecessorWithUniqueSuccessorForBB(Pair.first)) {
@@ -15764,10 +15765,11 @@ void ScalarEvolution::LoopGuards::collectFromBlock(

     Terms.emplace_back(LoopEntryPredicate->getCondition(),
                        LoopEntryPredicate->getSuccessor(0) == Pair.second);
+    NumCollectedConditions++;

     // If we are recursively collecting guards stop after 2
-    // predecessors to limit compile-time impact for now.
-    if (Depth > 0 && Terms.size() == 2)
+    // conditions to limit compile-time impact for now.
+    if (Depth > 0 && NumCollectedConditions == 2)
       break;
   }
   // Finally, if we stopped climbing the predecessor chain because

opt < %s -disable-output "-passes=print<scalar-evolution>" -scalar-evolution-max-iterations=0  -scalar-evolution-classify-expressions=0  2>&1

; Function Attrs: nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: write)
declare void @llvm.assume(i1 noundef) #0

define void @pr120442(i1 %c.1, i1 %c.2) {
entry:
  call void @llvm.assume(i1 %c.1)
  call void @llvm.assume(i1 %c.2)
  br label %outer.header

outer.header:                                     ; preds = %bb, %entry
  %phi7 = phi i32 [ 0, %bb ], [ 0, %entry ]
  br label %inner.header

bb:                                               ; preds = %bb
  br i1 false, label %outer.header, label %bb

inner.header:                                     ; preds = %inner.header, %outer.header
  %phi = phi i32 [ %add, %inner.header ], [ 0, %outer.header ]
  %add = add i32 %phi, 1
  %icmp = icmp ugt i32 %add, 0
  br i1 %icmp, label %exit, label %inner.header

exit:                                             ; preds = %inner.header
  ret void
}

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

Program terminated with signal: SIGKILL Compiler returned: 137

To reproduce run the following test with -passes=loop-vectorize on opt:
```
; 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:
  call void @llvm.assume(i1 false)
  call void @llvm.assume(i1 false)
  br label %bb6

bb1:                                              ; preds = %bb2, %bb6
  br label %bb2

bb2:                                              ; preds = %bb2, %bb1
  %phi = phi i32 [ %add4, %bb2 ], [ 0, %bb1 ]
  %phi3 = phi i32 [ 0, %bb2 ], [ 0, %bb1 ]
  %add = add i32 0, 0
  %add4 = add i32 %phi, 1
  %icmp = icmp ugt i32 %phi, 0
  br i1 %icmp, label %bb1, label %bb2

bb5:                                              ; preds = %bb5
  br i1 false, label %bb6, label %bb5

bb6:                                              ; preds = %bb5, %bb
  %phi7 = phi i32 [ 0, %bb5 ], [ 0, %bb ]
  br label %bb1
}

; Function Attrs: nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: write)
declare void @llvm.assume(i1 noundef) #1

attributes #0 = { "target-features"="+prfchw,-cldemote,+avx,+aes,+sahf,+pclmul,-xop,+crc32,-amx-fp8,+xsaves,-avx512fp16,-usermsr,-sm4,-egpr,+sse4.1,-avx512ifma,+xsave,+sse4.2,-tsxldtrk,-sm3,-ptwrite,-widekl,-movrs,+invpcid,+64bit,+xsavec,-avx10.1-512,-avx512vpopcntdq,+cmov,-avx512vp2intersect,+avx512cd,+movbe,-avxvnniint8,-ccmp,-amx-int8,-kl,-avx10.1-256,+evex512,-avxvnni,+rtm,+adx,+avx2,-hreset,-movdiri,-serialize,-sha512,-vpclmulqdq,+avx512vl,-uintr,-cf,+clflushopt,-raoint,-cmpccxadd,+bmi,-amx-tile,+sse,-avx10.2-256,-gfni,-avxvnniint16,-amx-fp16,-zu,-ndd,+xsaveopt,+rdrnd,+avx512f,-amx-bf16,-avx512bf16,-avx512vnni,-push2pop2,+cx8,+avx512bw,+sse3,+pku,-nf,-amx-tf32,-amx-avx512,+fsgsbase,-clzero,-mwaitx,-lwp,+lzcnt,-sha,-movdir64b,-ppx,-wbnoinvd,-enqcmd,-amx-transpose,-avx10.2-512,-avxneconvert,-tbm,-pconfig,-amx-complex,+ssse3,+cx16,+bmi2,+fma,+popcnt,-avxifma,+f16c,-avx512bitalg,-rdpru,+clwb,+mmx,+sse2,+rdseed,-avx512vbmi2,-prefetchi,-amx-movrs,-rdpid,-fma4,-avx512vbmi,-shstk,-vaes,-waitpkg,-sgx,+fxsr,+avx512dq,-sse4a,-avx512f" }
attributes #1 = { nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: write) "target-features"="+prfchw,-cldemote,+avx,+aes,+sahf,+pclmul,-xop,+crc32,-amx-fp8,+xsaves,-avx512fp16,-usermsr,-sm4,-egpr,+sse4.1,-avx512ifma,+xsave,+sse4.2,-tsxldtrk,-sm3,-ptwrite,-widekl,-movrs,+invpcid,+64bit,+xsavec,-avx10.1-512,-avx512vpopcntdq,+cmov,-avx512vp2intersect,+avx512cd,+movbe,-avxvnniint8,-ccmp,-amx-int8,-kl,-avx10.1-256,+evex512,-avxvnni,+rtm,+adx,+avx2,-hreset,-movdiri,-serialize,-sha512,-vpclmulqdq,+avx512vl,-uintr,-cf,+clflushopt,-raoint,-cmpccxadd,+bmi,-amx-tile,+sse,-avx10.2-256,-gfni,-avxvnniint16,-amx-fp16,-zu,-ndd,+xsaveopt,+rdrnd,+avx512f,-amx-bf16,-avx512bf16,-avx512vnni,-push2pop2,+cx8,+avx512bw,+sse3,+pku,-nf,-amx-tf32,-amx-avx512,+fsgsbase,-clzero,-mwaitx,-lwp,+lzcnt,-sha,-movdir64b,-ppx,-wbnoinvd,-enqcmd,-amx-transpose,-avx10.2-512,-avxneconvert,-tbm,-pconfig,-amx-complex,+ssse3,+cx16,+bmi2,+fma,+popcnt,-avxifma,+f16c,-avx512bitalg,-rdpru,+clwb,+mmx,+sse2,+rdseed,-avx512vbmi2,-prefetchi,-amx-movrs,-rdpid,-fma4,-avx512vbmi,-shstk,-vaes,-waitpkg,-sgx,+fxsr,+avx512dq,-sse4a,-avx512f" }
```

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

The godbolt is not informative. But locally I see the following stack dump:
```
bin/opt -S -passes=loop-vectorize reduced-stripped.ll
LLVM ERROR: SmallVector unable to grow. Requested capacity (4294967296) is larger than maximum value for size type (4294967295)
0.      Program arguments: bin/opt -S -passes=loop-vectorize reduced-stripped.ll
1.      Running pass "function(loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>)" on module "reduced-stripped.ll"
2.      Running pass "loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>" on function "wombat"
 #0 0x00007f945d6be47b llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) llvm/lib/Support/Unix/Signals.inc:727:3
 #1 0x00007f945d6bbfbb llvm::sys::RunSignalHandlers() llvm/lib/Support/Signals.cpp:105:20
 #2 0x00007f945d6bc2fe SignalHandler(int) llvm/lib/Support/Unix/Signals.inc:413:1
 #3 0x00007f9462a89980 __restore_rt (/lib/x86_64-linux-gnu/libpthread.so.0+0x12980)
 #4 0x00007f945c0fbe87 raise (/lib/x86_64-linux-gnu/libc.so.6+0x3ee87)
 #5 0x00007f945c0fd7f1 abort (/lib/x86_64-linux-gnu/libc.so.6+0x407f1)
 #6 0x00007f945d435674 std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>::_M_replace(unsigned long, unsigned long, char const*, unsigned long) gcc-13.3.0-rhel6/include/c++/13.3.0/bits/basic_string.tcc:545:21
 #7 0x00007f945d435674 std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>::assign(char const*) (.isra.0.cold) gcc-13.3.0-rhel6/include/c++/13.3.0/bits
/basic_string.h:1684:19
 #8 0x00007f945d63c540 std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>::replace(unsigned long, unsigned long, char const*, unsigned long) gcc-13.3.0-rhel6/include/c++/13.3.0/bits/basic_string.h:2208:19
 #9 0x00007f945d63c540 std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>::insert(unsigned long, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const
&) gcc-13.3.0-rhel6/include/c++/13.3.0/bits/basic_string.h:1895:29
#10 0x00007f945d63c540 std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> std::operator+<char, std::char_traits<char>, std::allocator<char>>(std::__cxx11::basic_string<char, std::ch
ar_traits<char>, std::allocator<char>>&&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&&) gcc-13.3.0-rhel6/include/c++/13.3.0/bits/basic_string.
h:3666:35
#11 0x00007f945d63c540 report_size_overflow(unsigned long, unsigned long) (.constprop.0) llvm/lib/Support/SmallVector.cpp:65:73
#12 0x00007f945d63c79e ......
#13 0x00007f945f6b3c9c llvm::PointerIntPairInfo<llvm::Value*, 1u, llvm::PointerLikeTypeTraits<llvm::Value*>>::updateInt(long, long)
llvm/include/llvm/ADT/PointerIntPair.h:213:55
#14 0x00007f945f6b3c9c llvm::PointerIntPair<llvm::Value*, 1u, bool, llvm::PointerLikeTypeTraits<llvm::Value*>, llvm::PointerIntPairInfo<llvm::Value*, 1u, llvm::PointerLikeTypeTraits<llvm::Value*>>>::setPointer
AndInt(llvm::Value*, bool) & llvm/include/llvm/ADT/PointerIntPair.h:111:11
#15 0x00007f945f6b3c9c llvm::PointerIntPair<llvm::Value*, 1u, bool, llvm::PointerLikeTypeTraits<llvm::Value*>, llvm::PointerIntPairInfo<llvm::Value*, 1u, llvm::PointerLikeTypeTraits<llvm::Value*>>>::PointerInt
Pair(llvm::Value*, bool) llvm/include/llvm/ADT/PointerIntPair.h:89:21
#16 0x00007f945f6b3c9c llvm::PointerIntPair<llvm::Value*, 1u, bool, llvm::PointerLikeTypeTraits<llvm::Value*>, llvm::PointerIntPairInfo<llvm::Value*, 1u, llvm::PointerLikeTypeTraits<llvm::Value*>>>& llvm::Smal
lVectorTemplateBase<llvm::PointerIntPair<llvm::Value*, 1u, bool, llvm::PointerLikeTypeTraits<llvm::Value*>, llvm::PointerIntPairInfo<llvm::Value*, 1u, llvm::PointerLikeTypeTraits<llvm::Value*>>>, true>::growAn
dEmplaceBack<llvm::Value*, bool>(llvm::Value*&&, bool&&) llvm/include/llvm/ADT/SmallVector.h:559:14
#17 0x00007f945f6b3c9c llvm::PointerIntPair<llvm::Value*, 1u, bool, llvm::PointerLikeTypeTraits<llvm::Value*>, llvm::PointerIntPairInfo<llvm::Value*, 1u, llvm::PointerLikeTypeTraits<llvm::Value*>>>& llvm::Smal
lVectorImpl<llvm::PointerIntPair<llvm::Value*, 1u, bool, llvm::PointerLikeTypeTraits<llvm::Value*>, llvm::PointerIntPairInfo<llvm::Value*, 1u, llvm::PointerLikeTypeTraits<llvm::Value*>>>>::emplace_back<llvm::V
alue*, bool>(llvm::Value*&&, bool&&) llvm/include/llvm/ADT/SmallVector.h:946:38
#18 0x00007f945f6b3c9c llvm::ScalarEvolution::LoopGuards::collectFromBlock(llvm::ScalarEvolution&, llvm::ScalarEvolution::LoopGuards&, llvm::BasicBlock const*, llvm::BasicBlock const*, llvm::SmallPtrSetImpl<llvm::BasicBlock const*>&, unsigned int) llvm/lib/Analysis/ScalarEvolution.cpp:15708:23
#19 0x00007f945f6b51fa llvm::DenseMapIterator<llvm::BasicBlock const*, llvm::ScalarEvolution::LoopGuards, llvm::DenseMapInfo<llvm::BasicBlock const*, void>, llvm::detail::DenseMapPair<llvm::BasicBlock const*, llvm::ScalarEvolution::LoopGuards>, false>::operator->() const llvm/include/llvm/ADT/DenseMap.h:1238:5
#20 0x00007f945f6b51fa llvm::ScalarEvolution::LoopGuards::collectFromPHI(llvm::ScalarEvolution&, llvm::ScalarEvolution::LoopGuards&, llvm::PHINode const&, llvm::SmallPtrSetImpl<llvm::BasicBlock const*>&, llvm::SmallDenseMap<llvm::BasicBlock const*, llvm::ScalarEvolution::LoopGuards, 4u, llvm::DenseMapInfo<llvm::BasicBlock const*, void>, llvm::detail::DenseMapPair<llvm::BasicBlock const*, llvm::ScalarEvolution::LoopGuards>>&, unsigned int)::'lambda'(unsigned int)::operator()(unsigned int) const llvm/lib/Analysis/ScalarEvolution.cpp:15285:25
#21 0x00007f945f6b200c llvm::ScalarEvolution::LoopGuards::collectFromPHI(llvm::ScalarEvolution&, llvm::ScalarEvolution::LoopGuards&, llvm::PHINode const&, llvm::SmallPtrSetImpl<llvm::BasicBlock const*>&, llvm::SmallDenseMap<llvm::BasicBlock const*, llvm::ScalarEvolution::LoopGuards, 4u, llvm::DenseMapInfo<llvm::BasicBlock const*, void>, llvm::detail::DenseMapPair<llvm::BasicBlock const*, llvm::ScalarEvolution::LoopGuards>>&, unsigned int) llvm/lib/Analysis/ScalarEvolution.cpp:15317:26
#22 0x00007f945f6b40af llvm::BasicBlock::phi_iterator_impl<llvm::PHINode const, llvm::ilist_iterator_w_bits<llvm::ilist_detail::node_options<llvm::Instruction, true, false, void, true, llvm::BasicBlock>, false, true>>::operator++() llvm/include/llvm/IR/BasicBlock.h:505:7
#23 0x00007f945f6b40af llvm::ScalarEvolution::LoopGuards::collectFromBlock(llvm::ScalarEvolution&, llvm::ScalarEvolution::LoopGuards&, llvm::BasicBlock const*, llvm::BasicBlock const*, llvm::SmallPtrSetImpl<llvm::BasicBlock const*>&, unsigned int) llvm/lib/Analysis/ScalarEvolution.cpp:15724:40
#24 0x00007f945f6b534b llvm::SmallPtrSetImplBase::~SmallPtrSetImplBase() llvm/include/llvm/ADT/SmallPtrSet.h:87:5
#25 0x00007f945f6b534b llvm::SmallPtrSetImpl<llvm::BasicBlock const*>::~SmallPtrSetImpl() llvm/include/llvm/ADT/SmallPtrSet.h:368:7
#26 0x00007f945f6b534b llvm::SmallPtrSet<llvm::BasicBlock const*, 8u>::~SmallPtrSet() llvm/include/llvm/ADT/SmallPtrSet.h:524:7
#27 0x00007f945f6b534b llvm::ScalarEvolution::LoopGuards::collect(llvm::Loop const*, llvm::ScalarEvolution&) llvm/lib/Analysis/ScalarEvolution.cpp:15266:1
#28 0x00007f945f6b539a llvm::ScalarEvolution::LoopGuards::rewrite(llvm::SCEV const*) const llvm/lib/Analysis/ScalarEvolution.cpp:15892:3
#29 0x00007f945f6b539a llvm::ScalarEvolution::applyLoopGuards(llvm::SCEV const*, llvm::ScalarEvolution::LoopGuards const&) llvm/lib/Analysis/ScalarEvolution.cpp:15905:24
#30 0x00007f945f6b539a llvm::ScalarEvolution::applyLoopGuards(llvm::SCEV const*, llvm::Loop const*) llvm/lib/Analysis/ScalarEvolution.cpp:15900:25
#31 0x00007f945f1e1c35 llvm::LoopVectorizationCostModel::computeMaxVF(llvm::ElementCount, unsigned int) llvm/lib/Transforms/Vectorize/LoopVectorize.cpp:4119:38
#32 0x00007f945f1e5bfb llvm::LoopVectorizationPlanner::plan(llvm::ElementCount, unsigned int) llvm/lib/Transforms/Vectorize/LoopVectorize.cpp:7150:51
#33 0x00007f945f1e7b71 llvm::LoopVectorizePass::processLoop(llvm::Loop*) llvm/lib/Transforms/Vectorize/LoopVectorize.cpp:10095:45
#34 0x00007f945f1eb181 llvm::LoopVectorizePass::runImpl(llvm::Function&) llvm/lib/Transforms/Vectorize/LoopVectorize.cpp:10441:27
#35 0x00007f945f1eb777 llvm::LoopVectorizePass::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) llvm/lib/Transforms/Vectorize/LoopVectorize.cpp:10478:39
#36 0x00007f94606acedd llvm::detail::PassModel<llvm::Function, llvm::LoopVectorizePass, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) llvm/include/llvm/IR/PassManagerInternal.h:91:3
#37 0x00007f945d8d889f llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) llvm/include/llvm/IR/PassManagerImpl.h:85:18
#38 0x00007f94601642ed llvm::detail::PassModel<llvm::Function, llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) llvm/include/llvm/IR/PassManagerInternal.h:91:3
#39 0x00007f945d8d8dea llvm::ModuleToFunctionPassAdaptor::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) llvm/lib/IR/PassManager.cpp:129:41
#40 0x00007f94601646dd llvm::detail::PassModel<llvm::Module, llvm::ModuleToFunctionPassAdaptor, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) llvm/include/llvm/IR/PassManagerInternal.h:91:3
#41 0x00007f945d8da12f llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) llvm/include/llvm/IR/PassManagerImpl.h:85:18
#42 0x000000000042ccba llvm::SmallPtrSetImplBase::~SmallPtrSetImplBase() llvm/include/llvm/ADT/SmallPtrSet.h:87:5
#43 0x000000000042ccba llvm::SmallPtrSetImpl<llvm::AnalysisKey*>::~SmallPtrSetImpl() llvm/include/llvm/ADT/SmallPtrSet.h:368:7
#44 0x000000000042ccba llvm::SmallPtrSet<llvm::AnalysisKey*, 2u>::~SmallPtrSet() llvm/include/llvm/ADT/SmallPtrSet.h:524:7
#45 0x000000000042ccba llvm::PreservedAnalyses::~PreservedAnalyses() llvm/include/llvm/IR/Analysis.h:111:7
#46 0x000000000042ccba 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) llvm/tools/opt/NewPMDriver.cpp:553:10
#47 0x00000000004207e3 std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>::~basic_string() gcc-13.3.0-rhel6/include/c++/13.3.0/bits/basic_string.h:804:19
#48 0x00000000004207e3 optMain llvm/tools/opt/optdriver.cpp:765:3
#49 0x00007f945c0dec87 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c87)
......
```

@juliannagele could you take a look? Seems like a crash in `collectFromPHI` you recently added

> [@juliannagele](https://github.com/juliannagele) could you take a look? Seems like a crash in `collectFromPHI` you recently added

Sure, checking!

Thanks for the report, should be fixed here: https://github.com/llvm/llvm-project/pull/120442