Bug type: crash
Component: LoopVectorize
Bug location: llvm/lib/Transforms/Vectorize/LoopVectorize.cpp: planContainsAdditionalSimplifications
Issue title: clang crashes at -Os on x86_64-linux-gnu: Assertion `... " VPlan cost model and legacy cost model disagreed"' failed
Labels: vectorizers
crash
regression:20
Reported by: zhendongsu

It appears to be a regression from 19.1.0 and affects 20.1.0 and later. 

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

```
[515] % clangtk -v
clang version 21.0.0git (https://github.com/llvm/llvm-project.git da3ee9763266f9adedaac1b1b3162d14f951fc55)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /local/suz-local/software/local/clang-trunk/bin
Build config: +assertions
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/10
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/11
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/9
Selected GCC installation: /usr/lib/gcc/x86_64-linux-gnu/11
Candidate multilib: .;@m64
Selected multilib: .;@m64
[516] % 
[516] % clangtk -Os small.c
clang-21: /local/suz-local/software/clangbuild/llvm-project/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp:7574: llvm::VectorizationFactor llvm::LoopVectorizationPlanner::computeBestVF(): Assertion `(BestFactor.Width == LegacyVF.Width || PlanForEarlyExitLoop || planContainsAdditionalSimplifications(getPlanFor(BestFactor.Width), CostCtx, OrigLoop) || planContainsAdditionalSimplifications(getPlanFor(LegacyVF.Width), CostCtx, OrigLoop)) && " VPlan cost model and legacy cost model disagreed"' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace, preprocessed source, and associated run script.
Stack dump:
0.	Program arguments: /local/suz-local/software/local/clang-trunk/bin/clang-21 -cc1 -triple x86_64-unknown-linux-gnu -emit-obj -dumpdir a- -disable-free -clear-ast-before-backend -main-file-name small.c -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/local/suz-local/software/emitesting/bugs/20250313-clangtk-m64-Os-build-082148/delta -fcoverage-compilation-dir=/local/suz-local/software/emitesting/bugs/20250313-clangtk-m64-Os-build-082148/delta -resource-dir /local/suz-local/software/local/clang-trunk/lib/clang/21 -I /usr/local/include -I /local/suz-local/software/local/include -internal-isystem /local/suz-local/software/local/clang-trunk/lib/clang/21/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/11/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Os -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fcolor-diagnostics -vectorize-loops -vectorize-slp -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/small-d02bf4.o -x c small.c
1.	<eof> parser at end of file
2.	Optimizer
3.	Running pass "function<eager-inv>(float2int,lower-constant-intrinsics,loop(loop-rotate<header-duplication;no-prepare-for-lto>,loop-deletion),loop-distribute,inject-tli-mappings,loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>,infer-alignment,loop-load-elim,instcombine<max-iterations=1;no-verify-fixpoint>,simplifycfg<bonus-inst-threshold=1;forward-switch-cond;switch-range-to-icmp;switch-to-lookup;no-keep-loops;hoist-common-insts;no-hoist-loads-stores-with-cond-faulting;sink-common-insts;speculate-blocks;simplify-cond-branch;no-speculate-unpredictables>,slp-vectorizer,vector-combine,instcombine<max-iterations=1;no-verify-fixpoint>,loop-unroll<O2>,transform-warning,sroa<preserve-cfg>,infer-alignment,instcombine<max-iterations=1;no-verify-fixpoint>,loop-mssa(licm<allowspeculation>),alignment-from-assumptions,loop-sink,instsimplify,div-rem-pairs,tailcallelim,simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;hoist-loads-stores-with-cond-faulting;no-sink-common-insts;speculate-blocks;simplify-cond-branch;speculate-unpredictables>)" on module "small.c"
4.	Running pass "loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>" on function "main"
 #0 0x0000563ced471fcf llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/local/suz-local/software/local/clang-trunk/bin/clang-21+0x4577fcf)
 #1 0x0000563ced46f7a4 SignalHandler(int, siginfo_t*, void*) Signals.cpp:0:0
 #2 0x00007f1c5b61c420 __restore_rt (/lib/x86_64-linux-gnu/libpthread.so.0+0x14420)
 #3 0x00007f1c5b05300b raise /build/glibc-LcI20x/glibc-2.31/signal/../sysdeps/unix/sysv/linux/raise.c:51:1
 #4 0x00007f1c5b032859 abort /build/glibc-LcI20x/glibc-2.31/stdlib/abort.c:81:7
 #5 0x00007f1c5b032729 get_sysdep_segment_value /build/glibc-LcI20x/glibc-2.31/intl/loadmsgcat.c:509:8
 #6 0x00007f1c5b032729 _nl_load_domain /build/glibc-LcI20x/glibc-2.31/intl/loadmsgcat.c:970:34
 #7 0x00007f1c5b043fd6 (/lib/x86_64-linux-gnu/libc.so.6+0x33fd6)
 #8 0x0000563ceeecce93 llvm::LoopVectorizationPlanner::computeBestVF() (/local/suz-local/software/local/clang-trunk/bin/clang-21+0x5fd2e93)
 #9 0x0000563ceeee48a6 llvm::LoopVectorizePass::processLoop(llvm::Loop*) (/local/suz-local/software/local/clang-trunk/bin/clang-21+0x5fea8a6)
#10 0x0000563ceeee72a1 llvm::LoopVectorizePass::runImpl(llvm::Function&) (/local/suz-local/software/local/clang-trunk/bin/clang-21+0x5fed2a1)
#11 0x0000563ceeee7943 llvm::LoopVectorizePass::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/local/suz-local/software/local/clang-trunk/bin/clang-21+0x5fed943)
#12 0x0000563ceea5a6d6 llvm::detail::PassModel<llvm::Function, llvm::LoopVectorizePass, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/local/suz-local/software/local/clang-trunk/bin/clang-21+0x5b606d6)
#13 0x0000563cecde27c9 llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/local/suz-local/software/local/clang-trunk/bin/clang-21+0x3ee87c9)
#14 0x0000563cea6cc7a6 llvm::detail::PassModel<llvm::Function, llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/local/suz-local/software/local/clang-trunk/bin/clang-21+0x17d27a6)
#15 0x0000563cecde1032 llvm::ModuleToFunctionPassAdaptor::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/local/suz-local/software/local/clang-trunk/bin/clang-21+0x3ee7032)
#16 0x0000563cea6ca3b6 llvm::detail::PassModel<llvm::Module, llvm::ModuleToFunctionPassAdaptor, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/local/suz-local/software/local/clang-trunk/bin/clang-21+0x17d03b6)
#17 0x0000563cecde0a51 llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/local/suz-local/software/local/clang-trunk/bin/clang-21+0x3ee6a51)
#18 0x0000563ced72fe4a (anonymous namespace)::EmitAssemblyHelper::RunOptimizationPipeline(clang::BackendAction, std::unique_ptr<llvm::raw_pwrite_stream, std::default_delete<llvm::raw_pwrite_stream>>&, std::unique_ptr<llvm::ToolOutputFile, std::default_delete<llvm::ToolOutputFile>>&, clang::BackendConsumer*) BackendUtil.cpp:0:0
#19 0x0000563ced7338a1 clang::emitBackendOutput(clang::CompilerInstance&, clang::CodeGenOptions&, llvm::StringRef, llvm::Module*, clang::BackendAction, llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>, std::unique_ptr<llvm::raw_pwrite_stream, std::default_delete<llvm::raw_pwrite_stream>>, clang::BackendConsumer*) (/local/suz-local/software/local/clang-trunk/bin/clang-21+0x48398a1)
#20 0x0000563cede73d91 clang::BackendConsumer::HandleTranslationUnit(clang::ASTContext&) (/local/suz-local/software/local/clang-trunk/bin/clang-21+0x4f79d91)
#21 0x0000563cef8016dc clang::ParseAST(clang::Sema&, bool, bool) (/local/suz-local/software/local/clang-trunk/bin/clang-21+0x69076dc)
#22 0x0000563cede741b8 clang::CodeGenAction::ExecuteAction() (/local/suz-local/software/local/clang-trunk/bin/clang-21+0x4f7a1b8)
#23 0x0000563cee14abc9 clang::FrontendAction::Execute() (/local/suz-local/software/local/clang-trunk/bin/clang-21+0x5250bc9)
#24 0x0000563cee0cbece clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) (/local/suz-local/software/local/clang-trunk/bin/clang-21+0x51d1ece)
#25 0x0000563cee23f996 clang::ExecuteCompilerInvocation(clang::CompilerInstance*) (/local/suz-local/software/local/clang-trunk/bin/clang-21+0x5345996)
#26 0x0000563cea25f9ed cc1_main(llvm::ArrayRef<char const*>, char const*, void*) (/local/suz-local/software/local/clang-trunk/bin/clang-21+0x13659ed)
#27 0x0000563cea25715a ExecuteCC1Tool(llvm::SmallVectorImpl<char const*>&, llvm::ToolContext const&) driver.cpp:0:0
#28 0x0000563cea25b3c7 clang_main(int, char**, llvm::ToolContext const&) (/local/suz-local/software/local/clang-trunk/bin/clang-21+0x13613c7)
#29 0x0000563cea1400db main (/local/suz-local/software/local/clang-trunk/bin/clang-21+0x12460db)
#30 0x00007f1c5b034083 __libc_start_main /build/glibc-LcI20x/glibc-2.31/csu/../csu/libc-start.c:342:3
#31 0x0000563cea256bee _start (/local/suz-local/software/local/clang-trunk/bin/clang-21+0x135cbee)
clangtk: error: unable to execute command: Aborted
clangtk: error: clang frontend command failed due to signal (use -v to see invocation)
clang version 21.0.0git (https://github.com/llvm/llvm-project.git da3ee9763266f9adedaac1b1b3162d14f951fc55)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /local/suz-local/software/local/clang-trunk/bin
Build config: +assertions
clangtk: note: diagnostic msg: 
********************

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

********************
[517] % 
[517] % cat small.c
int printf(const char *, ...);
int a, c, d, e;
static int b = 2;
static void f() {
  printf("0\n");
  for (c = 0; c < 3; c++)
    if (d && c >= b && e)
      a = 0;
}
int main() {
  b = 0;
  f();
  return 0;
}
```



Comments: author: cardigan1008
body: Here is another case that triggers the same crash at `-O2`:

```c
int a, b;
char c;
void f(int g) {
  int d;
  for (int e = 0; e < g; e++)
    d = e;
  a = d;
}
void h() {
  if (c)
    b = 0;
  else
    b = 1;
  f(b + 42);
}
void main() {}
```

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

Bisected to https://github.com/llvm/llvm-project/commit/26324bc1bf397453ce966f56a88245263f7beec5, which was committed by @lukel97 
author: lukel97
body: Hi @zhendongsu @cardigan1008, thanks for reporting/reducing/bisecting this. Can you confirm that this is fixed now after [eef5ea0](https://github.com/llvm/llvm-project/commit/eef5ea0c42fc07ef2c948be59b57d0df8ec801ca)?
author: cardigan1008
body: Hi @lukel97 my case has been fixed. But the first case seems to still trigger the same crash at `-Os`.

My clang version: clang version 21.0.0git (https://github.com/llvm/llvm-project.git b3c5031b07396959c5d4e7f62d516d63de015358)
author: lukel97
body: @cardigan1008 Looks like that's a separate vplan-legacy cost model mismatch, it seems to be reproducible before 26324bc1bf397453ce966f56a88245263f7beec5. I'll leave this issue open

Fix patch:
commit eef5ea0c42fc07ef2c948be59b57d0df8ec801ca
Author: Luke Lau <luke@igalia.com>
Date:   Tue Mar 18 01:00:54 2025 +0900

    [VPlan] Account for dead FOR splice simplification in cost model (#131486)
    
    Fixes #131359
    
    After #129645, a first-order recurrence will no longer have it's splice
    costed if the VPInstruction::FirstOrderRecurrenceSplice has no users and
    is dead.
    
    The legacy cost model didn't account for this, so this accounts for it
    in planContainsAdditionalSimplifications to avoid the "VPlan cost model
    and legacy cost model disagreed" assertion.

diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index b26b36f91a39..0e38ccc565ea 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -7467,6 +7467,16 @@ static bool planContainsAdditionalSimplifications(VPlan &Plan,
         }
         continue;
       }
+      // Unused FOR splices are removed by VPlan transforms, so the VPlan-based
+      // cost model won't cost it whilst the legacy will.
+      if (auto *FOR = dyn_cast<VPFirstOrderRecurrencePHIRecipe>(&R)) {
+        if (none_of(FOR->users(), [](VPUser *U) {
+              auto *VPI = dyn_cast<VPInstruction>(U);
+              return VPI && VPI->getOpcode() ==
+                                VPInstruction::FirstOrderRecurrenceSplice;
+            }))
+          return true;
+      }
       // The VPlan-based cost model is more accurate for partial reduction and
       // comparing against the legacy cost isn't desirable.
       if (isa<VPPartialReductionRecipe>(&R))


Regression tests:
file: llvm/test/Transforms/LoopVectorize/X86/pr131359-dead-for-splice.ll
commands: opt -p loop-vectorize -S %s
tests: test_name: <module>
test_body: 
; If a FOR isn't used the VPInstruction::FirstOrderRecurrenceSplice will be dead
; and won't be costed in the VPlan cost model. Make sure we account for this
; simplifcation in comparison to the legacy cost model.

target triple = "x86_64"

define void @no_use() {
;
entry:
  br label %loop

loop:
  %for = phi i32 [ 0, %entry ], [ %iv, %loop ]
  %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
  %iv.next = add i32 %iv, 1
  %exitcond.not.i = icmp eq i32 %iv, 43
  br i1 %exitcond.not.i, label %exit, label %loop

exit:
  ret void
}

define void @dead_use() {
;
entry:
  br label %loop

loop:
  %for = phi i32 [ 0, %entry ], [ %iv, %loop ]
  %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
  %dead = add i32 %for, 1
  %iv.next = add i32 %iv, 1
  %exitcond.not.i = icmp eq i32 %iv, 43
  br i1 %exitcond.not.i, label %exit, label %loop

exit:
  ret void
}