Bug type: crash
Component: LoopVectorize
Bug location: llvm/lib/Transforms/Vectorize/LoopVectorize.cpp: LoopVectorizationCostModel::getDivRemSpeculationCost
Issue title: [LoopVectorizer] Trigger assertion " VPlan cost model and legacy cost model disagreed"
Labels: vectorizers
crash-on-valid
Reported by: XChy

Reproducer: https://godbolt.org/z/ef9TWaKrj
The testcase is generated by Csmith.
Output:
```
opt: /root/llvm-project/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp:7074: llvm::VectorizationFactor llvm::LoopVectorizationPlanner::computeBestVF(): Assertion `(BestFactor.Width == LegacyVF.Width || BestPlan.hasEarlyExit() || planContainsAdditionalSimplifications(getPlanFor(BestFactor.Width), CostCtx, OrigLoop, BestFactor.Width) || planContainsAdditionalSimplifications( getPlanFor(LegacyVF.Width), CostCtx, OrigLoop, LegacyVF.Width)) && " 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 and instructions to reproduce the bug.
Stack dump:
0.	Program arguments: /opt/compiler-explorer/clang-assertions-trunk/bin/opt -o /app/output.s -S -O2 <source>
1.	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 "<source>"
2.	Running pass "loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>" on function "func_1"
 #0 0x00000000058b6c38 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x58b6c38)
 #1 0x00000000058b3ae4 SignalHandler(int, siginfo_t*, void*) Signals.cpp:0:0
 #2 0x00007134e2e42520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #3 0x00007134e2e969fc pthread_kill (/lib/x86_64-linux-gnu/libc.so.6+0x969fc)
 #4 0x00007134e2e42476 gsignal (/lib/x86_64-linux-gnu/libc.so.6+0x42476)
 #5 0x00007134e2e287f3 abort (/lib/x86_64-linux-gnu/libc.so.6+0x287f3)
 #6 0x00007134e2e2871b (/lib/x86_64-linux-gnu/libc.so.6+0x2871b)
 #7 0x00007134e2e39e96 (/lib/x86_64-linux-gnu/libc.so.6+0x39e96)
 #8 0x000000000363aad6 llvm::LoopVectorizationPlanner::computeBestVF() (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x363aad6)
 #9 0x0000000003648204 llvm::LoopVectorizePass::processLoop(llvm::Loop*) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x3648204)
#10 0x000000000364b400 llvm::LoopVectorizePass::runImpl(llvm::Function&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x364b400)
#11 0x000000000364bae5 llvm::LoopVectorizePass::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x364bae5)
#12 0x0000000002f44ece llvm::detail::PassModel<llvm::Function, llvm::LoopVectorizePass, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x2f44ece)
#13 0x000000000569e1f1 llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x569e1f1)
#14 0x0000000000eeadbe llvm::detail::PassModel<llvm::Function, llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0xeeadbe)
#15 0x000000000569c75a llvm::ModuleToFunctionPassAdaptor::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x569c75a)
#16 0x000000000096fb6e llvm::detail::PassModel<llvm::Module, llvm::ModuleToFunctionPassAdaptor, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x96fb6e)
#17 0x000000000569c111 llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x569c111)
#18 0x0000000000979d28 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, bool) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x979d28)
#19 0x000000000096dee9 optMain (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x96dee9)
#20 0x00007134e2e29d90 (/lib/x86_64-linux-gnu/libc.so.6+0x29d90)
#21 0x00007134e2e29e40 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e40)
#22 0x0000000000965035 _start (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x965035)
Program terminated with signal: SIGSEGV
```


Fix patch:
commit addfdb5273170901ed4fec5dac421e0559466ffb
Author: Florian Hahn <flo@fhahn.com>
Date:   Sun Sep 21 15:08:50 2025 +0100

    [LV] Skip select cost for invariant divisors in legacy cost model.
    
    For UDiv/SDiv with invariant divisors, the created selects will be
    hoisted out. Don't compute their cost for each iteration, to match the
    more accurate VPlan-based cost modeling.
    
    Fixes https://github.com/llvm/llvm-project/issues/159402.

diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index f71369e7f021..3ec187c6b41e 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -2904,16 +2904,18 @@ LoopVectorizationCostModel::getDivRemSpeculationCost(Instruction *I,
     // likely.
     ScalarizationCost = ScalarizationCost / getPredBlockCostDivisor(CostKind);
   }
-  InstructionCost SafeDivisorCost = 0;
 
+  InstructionCost SafeDivisorCost = 0;
   auto *VecTy = toVectorTy(I->getType(), VF);
-
-  // The cost of the select guard to ensure all lanes are well defined
-  // after we speculate above any internal control flow.
-  SafeDivisorCost +=
-      TTI.getCmpSelInstrCost(Instruction::Select, VecTy,
-                             toVectorTy(Type::getInt1Ty(I->getContext()), VF),
-                             CmpInst::BAD_ICMP_PREDICATE, CostKind);
+  auto *DivisorI = dyn_cast<Instruction>(I->getOperand(1));
+  if (DivisorI && !Legal->isInvariant(DivisorI)) {
+    // The cost of the select guard to ensure all lanes are well defined
+    // after we speculate above any internal control flow.
+    SafeDivisorCost +=
+        TTI.getCmpSelInstrCost(Instruction::Select, VecTy,
+                               toVectorTy(Type::getInt1Ty(I->getContext()), VF),
+                               CmpInst::BAD_ICMP_PREDICATE, CostKind);
+  }
 
   SmallVector<const Value *, 4> Operands(I->operand_values());
   SafeDivisorCost += TTI.getArithmeticInstrCost(


Regression tests:
file: llvm/test/Transforms/LoopVectorize/RISCV/divrem.ll
commands: opt < %s -passes=loop-vectorize -scalable-vectorization=on -mtriple riscv64-linux-gnu -mattr=+v,+f -S
opt < %s -passes=loop-vectorize -scalable-vectorization=off -mtriple riscv64-linux-gnu -mattr=+v,+f -S
tests: test_name: udiv_sdiv_with_invariant_divisors
test_body: target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n64-S128"
target triple = "riscv64"

define i32 @udiv_sdiv_with_invariant_divisors(i8 %x, i16 %y, i1 %c) {
entry:
  br label %loop.header

loop.header:                                      ; preds = %loop.latch, %entry
  %iv = phi i16 [ -12, %entry ], [ %iv.next, %loop.latch ]
  %narrow.iv = phi i8 [ -12, %entry ], [ %iv.next.trunc, %loop.latch ]
  br i1 %c, label %loop.latch, label %then

then:                                             ; preds = %loop.header
  %ud = udiv i8 %narrow.iv, %x
  %ud.ext = zext i8 %ud to i16
  %sd = sdiv i16 %ud.ext, %y
  %sd.ext = sext i16 %sd to i32
  br label %loop.latch

loop.latch:                                       ; preds = %then, %loop.header
  %merge = phi i32 [ 0, %loop.header ], [ %sd.ext, %then ]
  %iv.next = add nsw i16 %iv, 1
  %ec = icmp eq i16 %iv.next, 0
  %iv.next.trunc = trunc i16 %iv.next to i8
  br i1 %ec, label %exit, label %loop.header

exit:                                             ; preds = %loop.latch
  ret i32 %merge
}