Bug type: crash
Component: LoopVectorize
Bug location: llvm/lib/Transforms/Vectorize/LoopVectorize.cpp: LoopVectorizationCostModel::getInstructionCost
Issue title: Crash in LV: "VPlan cost model and legacy cost model disagreed"
Labels: vectorizers
crash
Reported by: alexey-bataev

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.



Fix patch:
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);
   }


Regression tests:
file: llvm/test/Transforms/LoopVectorize/RISCV/blend-any-of-reduction-cost.ll
commands: opt -p loop-vectorize -S %s
tests: test_name: any_of_reduction_used_in_blend
test_body: 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" }

test_name: any_of_reduction_used_in_blend_with_mutliple_phis
test_body: 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" }