Bug type: crash
Component: LoopVectorize
Bug location: llvm/lib/Transforms/Vectorize/LoopVectorize.cpp: LoopVectorizationCostModel::collectValuesToIgnore
Issue title: [VPlan] Assertion " VPlan cost model and legacy cost model disagreed"' failed.
Labels: vectorizers
crash
Reported by: patrick-rivos

Tested using ef7b18a53c0d186dcda1e322be6035407fdedb55

Testcase:
```c
unsigned short a;
extern int b;
void c(_Bool d, int e, long long f[], unsigned short g[][16],
       unsigned short h[][16], unsigned short i[][13], short j[][13],
       int k[][21], unsigned char l[][21][21], signed char m[][24]) {
  for (short n = 0; n < 5; n += -5532)
    for (char o = 0; o < 3; o += d)
      for (int p = 0; p < -({ g[d][1] > 0115 ? g[d][1] : 0115; }) + 770; p++)
        for (_Bool q = 0; q < (_Bool)e; q = 5)
          for (_Bool r = 2048749519 ? 8 ? f[d] : 0 : 0; r < 1; r = h)
            b = a = 0;
}
void hash();
unsigned short a = 6;
long long f[6];
unsigned short g[6][16];
unsigned short h[1][16];
unsigned short i[1][13];
short j[1][13];
int k[1][21];
unsigned char l[1][21][21];
signed char m[1][24];
int main() {
  for (long s = 0; s < 6; ++s)
    f[s] = 6;
  for (long s = 0; s < 16; ++s)
    for (long n = 0; n < 16; ++n)
      g[s][n] = 7;
  c(1, 407418382874, f, g, h, i, j, k, l, m);
  hash(a);
}
```
c command:
```
/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/clang -fno-strict-aliasing -march=rv64gcv -flto -O3 -fuse-ld=lld red.c -o rv64gcv.out -w
```

LLVM IR testcase:
```llvm ir
; ModuleID = 'reduced.bc'
target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"
target triple = "riscv64-unknown-linux-gnu"

; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i16 @llvm.umax.i16(i16, i16) #0

define i32 @main(ptr %a) #1 {
entry:
  br label %for.cond22.preheader.us.us76.us.us.us.us.i.1

for.cond22.preheader.us.us76.us.us.us.us.i.1:     ; preds = %for.cond22.preheader.us.us76.us.us.us.usthread-pre-split.i.1, %entry
  %p.072.us.us77.us.us.us.us.i.1 = phi i32 [ %inc.us.us80.us.us.us.us.i.1, %for.cond22.preheader.us.us76.us.us.us.usthread-pre-split.i.1 ], [ 0, %entry ]
  br i1 false, label %for.body41.lr.ph.us.us.us.us.us.us.us.i.1, label %for.cond22.for.cond.cleanup28_crit_edge.us.us.us.us.us.us.i.1

for.body41.lr.ph.us.us.us.us.us.us.us.i.1:        ; preds = %for.cond22.preheader.us.us76.us.us.us.us.i.1
  store i1 false, ptr %a, align 1
  store i32 0, ptr null, align 4
  br label %for.cond22.for.cond.cleanup28_crit_edge.us.us.us.us.us.us.i.1

for.cond22.for.cond.cleanup28_crit_edge.us.us.us.us.us.us.i.1: ; preds = %for.body41.lr.ph.us.us.us.us.us.us.us.i.1, %for.cond22.preheader.us.us76.us.us.us.us.i.1
  %inc.us.us80.us.us.us.us.i.1 = add i32 %p.072.us.us77.us.us.us.us.i.1, 1
  %narrow.us.us81.us.us.us.us.i.1 = tail call i16 @llvm.umax.i16(i16 0, i16 0)
  %spec.select.us.us82.us.us.us.us.i.1 = zext i16 %narrow.us.us81.us.us.us.us.i.1 to i32
  %add.us.us83.us.us.us.us.i.1 = sub i32 770, %spec.select.us.us82.us.us.us.us.i.1
  %cmp18.us.us84.us.us.us.us.i.1 = icmp slt i32 %p.072.us.us77.us.us.us.us.i.1, %add.us.us83.us.us.us.us.i.1
  br i1 %cmp18.us.us84.us.us.us.us.i.1, label %for.cond22.preheader.us.us76.us.us.us.usthread-pre-split.i.1, label %for.cond22.for.cond.cleanup28_crit_edge.us.us.us.us.us.us.i.1.for.cond.cleanup20.us.us.us.us.i.1_crit_edge

for.cond22.for.cond.cleanup28_crit_edge.us.us.us.us.us.us.i.1.for.cond.cleanup20.us.us.us.us.i.1_crit_edge: ; preds = %for.cond22.for.cond.cleanup28_crit_edge.us.us.us.us.us.us.i.1
  br label %for.cond.cleanup20.us.us.us.us.i.1

for.cond.cleanup20.us.us.us.us.i.1:               ; preds = %for.cond22.for.cond.cleanup28_crit_edge.us.us.us.us.us.us.i.1.for.cond.cleanup20.us.us.us.us.i.1_crit_edge
  ret i32 0

for.cond22.preheader.us.us76.us.us.us.usthread-pre-split.i.1: ; preds = %for.cond22.for.cond.cleanup28_crit_edge.us.us.us.us.us.us.i.1
  br label %for.cond22.preheader.us.us76.us.us.us.us.i.1
}

attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
attributes #1 = { "target-features"="+64bit,+a,+c,+d,+f,+m,+relax,+v,+zicsr,+zifencei,+zmmul,+zve32f,+zve32x,+zve64d,+zve64f,+zve64x,+zvl128b,+zvl32b,+zvl64b,-b,-e,-experimental-smctr,-experimental-smmpm,-experimental-smnpm,-experimental-ssctr,-experimental-ssnpm,-experimental-sspm,-experimental-supm,-experimental-zacas,-experimental-zalasr,-experimental-zicfilp,-experimental-zicfiss,-experimental-zvbc32e,-experimental-zvkgs,-h,-shcounterenw,-shgatpa,-shtvala,-shvsatpa,-shvstvala,-shvstvecd,-smaia,-smcdeleg,-smcsrind,-smepmp,-smstateen,-ssaia,-ssccfg,-ssccptr,-sscofpmf,-sscounterenw,-sscsrind,-ssqosid,-ssstateen,-ssstrict,-sstc,-sstvala,-sstvecd,-ssu64xl,-svade,-svadu,-svbare,-svinval,-svnapot,-svpbmt,-xcvalu,-xcvbi,-xcvbitmanip,-xcvelw,-xcvmac,-xcvmem,-xcvsimd,-xsfcease,-xsfvcp,-xsfvfnrclipxfqf,-xsfvfwmaccqqq,-xsfvqmaccdod,-xsfvqmaccqoq,-xsifivecdiscarddlone,-xsifivecflushdlone,-xtheadba,-xtheadbb,-xtheadbs,-xtheadcmo,-xtheadcondmov,-xtheadfmemidx,-xtheadmac,-xtheadmemidx,-xtheadmempair,-xtheadsync,-xtheadvdot,-xventanacondops,-xwchc,-za128rs,-za64rs,-zaamo,-zabha,-zalrsc,-zama16b,-zawrs,-zba,-zbb,-zbc,-zbkb,-zbkc,-zbkx,-zbs,-zca,-zcb,-zcd,-zce,-zcf,-zcmop,-zcmp,-zcmt,-zdinx,-zfa,-zfbfmin,-zfh,-zfhmin,-zfinx,-zhinx,-zhinxmin,-zic64b,-zicbom,-zicbop,-zicboz,-ziccamoa,-ziccif,-zicclsm,-ziccrse,-zicntr,-zicond,-zihintntl,-zihintpause,-zihpm,-zimop,-zk,-zkn,-zknd,-zkne,-zknh,-zkr,-zks,-zksed,-zksh,-zkt,-ztso,-zvbb,-zvbc,-zvfbfmin,-zvfbfwma,-zvfh,-zvfhmin,-zvkb,-zvkg,-zvkn,-zvknc,-zvkned,-zvkng,-zvknha,-zvknhb,-zvks,-zvksc,-zvksed,-zvksg,-zvksh,-zvkt,-zvl1024b,-zvl16384b,-zvl2048b,-zvl256b,-zvl32768b,-zvl4096b,-zvl512b,-zvl65536b,-zvl8192b" }
```

Command/backtrace:
```
> /scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt -passes=loop-vectorize reduced.ll -S
opt: /scratch/tc-testing/tc-compiler-fuzz-trunk/llvm/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp:7366: llvm::VectorizationFactor llvm::LoopVectorizationPlanner::computeBestVF(): Assertion `(BestFactor.Width == LegacyVF.Width || planContainsAdditionalSimplifications(getPlanFor(BestFactor.Width), CostCtx, OrigLoop)) && " VPlan cost model and legacy cost model disagreed"' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:
0.      Program arguments: /scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt -passes=loop-vectorize reduced.ll -S
1.      Running pass "function(loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>)" on module "reduced.ll"
2.      Running pass "loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>" on function "main"
 #0 0x00005e8221f7d690 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x301e690)
 #1 0x00005e8221f7aa9f llvm::sys::RunSignalHandlers() (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x301ba9f)
 #2 0x00005e8221f7abf5 SignalHandler(int) Signals.cpp:0:0
 #3 0x0000772c88c42520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #4 0x0000772c88c969fc __pthread_kill_implementation ./nptl/pthread_kill.c:44:76
 #5 0x0000772c88c969fc __pthread_kill_internal ./nptl/pthread_kill.c:78:10
 #6 0x0000772c88c969fc pthread_kill ./nptl/pthread_kill.c:89:10
 #7 0x0000772c88c42476 gsignal ./signal/../sysdeps/posix/raise.c:27:6
 #8 0x0000772c88c287f3 abort ./stdlib/abort.c:81:7
 #9 0x0000772c88c2871b _nl_load_domain ./intl/loadmsgcat.c:1177:9
#10 0x0000772c88c39e96 (/lib/x86_64-linux-gnu/libc.so.6+0x39e96)
#11 0x00005e8220f4a3e0 llvm::LoopVectorizationPlanner::computeBestVF() (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x1feb3e0)
#12 0x00005e8220f60ffb llvm::LoopVectorizePass::processLoop(llvm::Loop*) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x2001ffb)
#13 0x00005e8220f64011 llvm::LoopVectorizePass::runImpl(llvm::Function&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x2005011)
#14 0x00005e8220f64687 llvm::LoopVectorizePass::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x2005687)
#15 0x00005e821fdc0fb6 llvm::detail::PassModel<llvm::Function, llvm::LoopVectorizePass, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0xe61fb6)
#16 0x00005e8221d8858f llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x2e2958f)
#17 0x00005e821fdc4146 llvm::detail::PassModel<llvm::Function, llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0xe65146)
#18 0x00005e8221d8730b llvm::ModuleToFunctionPassAdaptor::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x2e2830b)
#19 0x00005e821fdc03e6 llvm::detail::PassModel<llvm::Module, llvm::ModuleToFunctionPassAdaptor, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0xe613e6)
#20 0x00005e8221d8534d llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x2e2634d)
#21 0x00005e821f5e6ee6 llvm::runPassPipeline(llvm::StringRef, llvm::Module&, llvm::TargetMachine*, llvm::TargetLibraryInfoImpl*, llvm::ToolOutputFile*, llvm::ToolOutputFile*, llvm::ToolOutputFile*, llvm::StringRef, llvm::ArrayRef<llvm::PassPlugin>, llvm::ArrayRef<std::function<void (llvm::PassBuilder&)>>, llvm::opt_tool::OutputKind, llvm::opt_tool::VerifierKind, bool, bool, bool, bool, bool, bool, bool) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x687ee6)
#22 0x00005e821f5d8c71 optMain (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x679c71)
#23 0x0000772c88c29d90 __libc_start_call_main ./csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#24 0x0000772c88c29e40 call_init ./csu/../csu/libc-start.c:128:20
#25 0x0000772c88c29e40 __libc_start_main ./csu/../csu/libc-start.c:379:5
#26 0x00005e821f5cf025 _start (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x670025)
zsh: IOT instruction (core dumped)  /scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt
```
https://godbolt.org/z/ej1Gax953

Found via fuzzer

Related/prior issue: https://github.com/llvm/llvm-project/issues/106641

cc @fhahn


Fix patch:
commit 654bb4e9f287f9ccb5142d1c62a9ab17c16e29d7
Author: Florian Hahn <flo@fhahn.com>
Date:   Sun Sep 1 20:35:28 2024 +0100

    [LV] Don't consider branches leaving loop in collectValuesToIgnore.
    
    Branches exiting the loop will remain regardless, so don't consider them
    in collectValuesToIgnore.
    
    This fixes another divergence between legacy and VPlan-based cost model.
    
    Fixes https://github.com/llvm/llvm-project/issues/106780.

diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index fa05b8dd2242..a8722db654f5 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -6817,6 +6817,9 @@ void LoopVectorizationCostModel::collectValuesToIgnore() {
     if (auto *Br = dyn_cast_or_null<BranchInst>(Op)) {
       BasicBlock *ThenBB = Br->getSuccessor(0);
       BasicBlock *ElseBB = Br->getSuccessor(1);
+      // Don't considers branches leaving the loop for simplification.
+      if (!TheLoop->contains(ThenBB) || !TheLoop->contains(ElseBB))
+        continue;
       bool ThenEmpty = IsEmptyBlock(ThenBB);
       bool ElseEmpty = IsEmptyBlock(ElseBB);
       if ((ThenEmpty && ElseEmpty) ||


Regression tests:
file: llvm/test/Transforms/LoopVectorize/RISCV/dead-ops-cost.ll
commands: opt -p loop-vectorize -mtriple riscv64-linux-gnu -mattr=+v,+f -S %s
tests: test_name: dead_load
test_body: target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"

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

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

exit:                                             ; preds = %loop
  ret void
}

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

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

define i32 @cost_of_exit_branch_and_cond_insts(ptr %a, ptr %b, i1 %c, i16 %x) {
entry:
  br label %loop.header

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

then:                                             ; preds = %loop.header
  %gep = getelementptr inbounds i32, ptr %b, i32 %iv
  store i1 false, ptr %a, align 1
  store i32 0, ptr %gep, align 4
  br label %loop.exiting

loop.exiting:                                     ; preds = %then, %loop.header
  %iv.next = add i32 %iv, 1
  %umax = tail call i16 @llvm.umax.i16(i16 %x, i16 111)
  %umax.ext = zext i16 %umax to i32
  %sub = sub i32 770, %umax.ext
  %ec = icmp slt i32 %iv, %sub
  br i1 %ec, label %loop.latch, label %exit

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

exit:                                             ; preds = %loop.exiting
  br label %return

return:                                           ; preds = %exit
  ret i32 0
}

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

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

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

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

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