Bug type: crash
Component: LoopVectorize
Bug location: llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp: VPReplicateRecipe::computeCost
Issue title: New case of "VPlan cost model and legacy cost model disagreed"
Labels: vectorizers
crash-on-valid
Reported by: gregbedwell

Our testing encountered a new regression which bisects to 91d4c0dfdf226665c17d4a44e2fab466e6103d18 (tag @fhahn ).

Let me know if you need any more info!


https://godbolt.org/z/r4qo3e9fs

```
target triple = "x86_64-unknown-unknown"

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

define i64 @baz(i32 %arg, i1 %arg1) #1 {
bb:
  br label %bb3

bb2:                                              ; preds = %bb5
  ret i64 %phi6

bb3:                                              ; preds = %bb5, %bb
  %phi = phi i32 [ 0, %bb ], [ %add, %bb5 ]
  br i1 %arg1, label %bb5, label %bb4

bb4:                                              ; preds = %bb3
  %call = tail call i32 @llvm.usub.sat.i32(i32 %phi, i32 1)
  %udiv = udiv i32 %call, %arg
  %zext = zext i32 %udiv to i64
  br label %bb5

bb5:                                              ; preds = %bb4, %bb3
  %phi6 = phi i64 [ %zext, %bb4 ], [ 0, %bb3 ]
  %add = add i32 %phi, 1
  %icmp = icmp eq i32 %phi, %arg
  br i1 %icmp, label %bb2, label %bb3
}

attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
attributes #1 = { "target-cpu"="znver2" }
```

```
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 --passes=loop-vectorize <source>
1.	Running pass "function(loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>)" on module "<source>"
2.	Running pass "loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>" on function "baz"
 #0 0x00000000058a7268 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x58a7268)
 #1 0x00000000058a4114 SignalHandler(int, siginfo_t*, void*) Signals.cpp:0:0
 #2 0x0000710df7042520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #3 0x0000710df70969fc pthread_kill (/lib/x86_64-linux-gnu/libc.so.6+0x969fc)
 #4 0x0000710df7042476 gsignal (/lib/x86_64-linux-gnu/libc.so.6+0x42476)
 #5 0x0000710df70287f3 abort (/lib/x86_64-linux-gnu/libc.so.6+0x287f3)
 #6 0x0000710df702871b (/lib/x86_64-linux-gnu/libc.so.6+0x2871b)
 #7 0x0000710df7039e96 (/lib/x86_64-linux-gnu/libc.so.6+0x39e96)
 #8 0x000000000362ead6 llvm::LoopVectorizationPlanner::computeBestVF() (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x362ead6)
 #9 0x000000000363c224 llvm::LoopVectorizePass::processLoop(llvm::Loop*) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x363c224)
#10 0x000000000363f420 llvm::LoopVectorizePass::runImpl(llvm::Function&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x363f420)
#11 0x000000000363fb05 llvm::LoopVectorizePass::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x363fb05)
#12 0x0000000002f3816e 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+0x2f3816e)
#13 0x00000000056905d1 llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x56905d1)
#14 0x0000000000eec31e 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+0xeec31e)
#15 0x000000000568eb3a llvm::ModuleToFunctionPassAdaptor::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x568eb3a)
#16 0x000000000096f54e 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+0x96f54e)
#17 0x000000000568e4f1 llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x568e4f1)
#18 0x0000000000979848 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+0x979848)
#19 0x000000000096d8c9 optMain (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x96d8c9)
#20 0x0000710df7029d90 (/lib/x86_64-linux-gnu/libc.so.6+0x29d90)
#21 0x0000710df7029e40 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e40)
#22 0x0000000000964a15 _start (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x964a15)
Program terminated with signal: SIGSEGV
Compiler returned: 139
```


Fix patch:
commit 1858532c48cf5d93aa82966110fe1cada6ab6ba8
Author: Florian Hahn <flo@fhahn.com>
Date:   Mon Sep 15 21:46:49 2025 +0100

    [VPlan] Handle predicated UDiv in VPReplicateRecipe::computeCost.
    
    Account for predicated UDiv,SDiv,URem,SRem in
    VPReplicateRecipe::computeCost: compute costs of extra phis and apply
    getPredBlockCostDivisor.
    
    Fixes https://github.com/llvm/llvm-project/issues/158660

diff --git a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
index 723363fba572..2844b8348027 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
@@ -3163,9 +3163,22 @@ InstructionCost VPReplicateRecipe::computeCost(ElementCount VF,
     if (isSingleScalar())
       return ScalarCost;
 
-    return ScalarCost * VF.getFixedValue() +
-           Ctx.getScalarizationOverhead(Ctx.Types.inferScalarType(this),
-                                        to_vector(operands()), VF);
+    ScalarCost = ScalarCost * VF.getFixedValue() +
+                 Ctx.getScalarizationOverhead(Ctx.Types.inferScalarType(this),
+                                              to_vector(operands()), VF);
+    // If the recipe is not predicated (i.e. not in a replicate region), return
+    // the scalar cost. Otherwise handle predicated cost.
+    if (!getParent()->getParent()->isReplicator())
+      return ScalarCost;
+
+    // Account for the phi nodes that we will create.
+    ScalarCost += VF.getFixedValue() *
+                  Ctx.TTI.getCFInstrCost(Instruction::PHI, Ctx.CostKind);
+    // Scale the cost by the probability of executing the predicated blocks.
+    // This assumes the predicated block for each vector lane is equally
+    // likely.
+    ScalarCost /= getPredBlockCostDivisor(Ctx.CostKind);
+    return ScalarCost;
   }
   case Instruction::Load:
   case Instruction::Store: {


Regression tests:
file: llvm/test/Transforms/LoopVectorize/X86/cost-conditional-branches.ll
commands: opt < %s -passes=loop-vectorize -mtriple=x86_64-apple-macosx10.8.0 -mcpu=corei7-avx -S
tests: test_name: test_predicated_udiv
test_body: target triple = "x86_64-apple-macosx10.8.0"

define i64 @test_predicated_udiv(i32 %d, i1 %c) #0 {
entry:
  br label %loop.header

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

then:                                             ; preds = %loop.header
  %call = tail call i32 @llvm.usub.sat.i32(i32 %iv, i32 1)
  %udiv = udiv i32 %call, %d
  %zext = zext i32 %udiv to i64
  br label %loop.latch

loop.latch:                                       ; preds = %then, %loop.header
  %merge = phi i64 [ %zext, %then ], [ 0, %loop.header ]
  %iv.next = add i32 %iv, 1
  %ec = icmp eq i32 %iv, 1000
  br i1 %ec, label %exit, label %loop.header

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

; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i32 @llvm.usub.sat.i32(i32, i32) #1

attributes #0 = { "target-cpu"="znver3" }
attributes #1 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }