Bug type: crash
Component: LoopVectorize
Bug location: llvm/lib/Transforms/Vectorize/LoopVectorize.cpp: LoopVectorizationCostModel::setVectorizedCallDecision
Issue title: [clang] Assertion failed in LoopVectorize.cpp:7401
Labels: regression
vectorizers
crash
Reported by: cardigan1008

When I compiled the code with -O2 flag, it crashed:

```c
#include <stdint.h>
static uint8_t b = 188;
void c();
long d(int e, int p2, short j) {
  long f = 0, a = 1;
  unsigned long g;
  int h;
  if (e < 0 || j < 0)
    return 1;
  h = 0;
  for (; h < p2; h++) {
    a *= j + 1;
    g = e * a;
    f += g % (j + 1);
  }
  if (f < 0)
    return 0;
  return f;
}
void i();
int64_t k() {
  uint32_t l[][8][10] = {0, 4, 7, 1, 4, 3446557846};
  int64_t m[10];
  int h;
  for (h = 0; c + h < 10; h++)
    m[(int)d(5, l[0][0][5] - 3446557842, b - 187) + h] = 1;
  i(m);
  uint8_t *n = &b;
  uint8_t **o;
  o[0] = &n;
}
```

The crash is:
```
clang: /root/llvm-project/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp:7401: 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.
```

Details can be found here: https://godbolt.org/z/hqP8vMG7b


Comments: author: shafik
body: This is a regression in trunk: https://godbolt.org/z/a53x7oxhq

Fix patch:
commit 45b526afa26e76e0c351e947ac8f0e4b55aa760b
Author: Florian Hahn <flo@fhahn.com>
Date:   Sun Oct 6 10:34:37 2024 +0100

    [LV] Honor uniform-after-vectorization in setVectorizedCallDecision.
    
    The legacy cost model always computes the cost for uniforms as cost of
    VF = 1, but VPWidenCallRecipes would be created, as
    setVectorizedCallDecisions would not consider uniform calls.
    
    Fix setVectorizedCallDecision to set to Scalarize, if the call is
    uniform-after-vectorization.
    
    This fixes a bug in VPlan construction uncovered by the VPlan-based
    cost model.
    
    Fixes https://github.com/llvm/llvm-project/issues/111040.

diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index 6e082b1c134d..35c042b3ab7f 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -6196,11 +6196,12 @@ void LoopVectorizationCostModel::setVectorizedCallDecision(ElementCount VF) {
           getScalarizationOverhead(CI, VF, CostKind);
 
       ScalarCost = ScalarCallCost * VF.getKnownMinValue() + ScalarizationCost;
-      // Honor ForcedScalars decision.
+      // Honor ForcedScalars and UniformAfterVectorization decisions.
       // TODO: For calls, it might still be more profitable to widen. Use
       // VPlan-based cost model to compare different options.
-      if (VF.isVector() && ForcedScalar != ForcedScalars.end() &&
-          ForcedScalar->second.contains(CI)) {
+      if (VF.isVector() && ((ForcedScalar != ForcedScalars.end() &&
+                             ForcedScalar->second.contains(CI)) ||
+                            isUniformAfterVectorization(CI, VF))) {
         setCallWideningDecision(CI, VF, CM_Scalarize, nullptr,
                                 Intrinsic::not_intrinsic, std::nullopt,
                                 ScalarCost);


Regression tests:
file: llvm/test/Transforms/LoopVectorize/X86/replicate-uniform-call.ll
commands: opt -p loop-vectorize -S %s
tests: test_name: smax_call_uniform
test_body: target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

define void @smax_call_uniform(ptr %dst, i64 %x) {
entry:
  %c = icmp ult i8 -68, -69
  %mul = mul nuw nsw i64 %x, 0
  br label %loop.header

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

else:                                             ; preds = %loop.header
  %rem = urem i64 %mul, %x
  %smax = tail call i64 @llvm.smax.i64(i64 %rem, i64 0)
  br label %loop.latch

loop.latch:                                       ; preds = %else, %loop.header
  %p = phi i64 [ 1, %loop.header ], [ %smax, %else ]
  %add = add i64 %p, 1
  %gep = getelementptr i64, ptr %dst, i64 %add
  store i64 0, ptr %gep, align 8
  %iv.next = add i64 %iv, 1
  %ec = icmp eq i64 %iv.next, 0
  br i1 %ec, label %exit, label %loop.header

exit:                                             ; preds = %loop.latch
  ret void
}

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

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