Bug type: crash
Component: LoopVectorize
Bug location: llvm/lib/Transforms/Vectorize/LoopVectorize.cpp: VPRecipeBuilder::tryToWiden
llvm/lib/Transforms/Vectorize/VPRecipeBuilder.h: getVPValueOrAddLiveIn
Issue title: [clang] Crash with assertion failed in Vectorize
Labels: vectorizers
crash
Reported by: cardigan1008

The compiler crashed with -O2 in this code:

```c
#include<stdint.h>
static uint8_t b[][1] = {127};
long a(int c, int e) {
  long d;
  for (; c <= e; c++)
    if (c % 2 == 0)
      ;
    else
      d *= c;
  return d;
}
int64_t f();
int16_t g() {
  int32_t h = 1653000360;
  f(a(h - 1653000360, b[0][0] - 126));
  uint8_t *i[] = {b, b};
}
```

The crash is:
```
clang: /root/llvm-project/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp:7369: 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, preprocessed source, and associated run script.
```

The details can be found here: https://godbolt.org/z/eeWW6raPb


Fix patch:
commit 954ed05c1001489802ae43d4bea403181570a799
Author: Florian Hahn <flo@fhahn.com>
Date:   Mon Sep 2 21:25:30 2024 +0100

    [VPlan] Simplify MUL operands at recipe construction.
    
    This moves the logic to create simplified operands using SCEV to MUL
    recipe creation. This is needed to match the behavior of the legacy's cost
    model. TODOs are to extend to other opcodes and move to a transform.
    
    Note that this also restricts the number of SCEV simplifications we
    apply to more precisely match the cases handled by the legacy cost
    model.
    
    Fixes https://github.com/llvm/llvm-project/issues/107015.

diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index a8722db654f5..a64848c1fdce 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -8393,6 +8393,20 @@ VPWidenRecipe *VPRecipeBuilder::tryToWiden(Instruction *I,
   case Instruction::Sub:
   case Instruction::Xor:
   case Instruction::Freeze:
+    if (I->getOpcode() == Instruction::Mul) {
+      // Simplify operands of multiplications using SCEV. This is needed at the
+      // moment to match the behavior of the legacy cost-model.
+      // TODO: Generalize to any opcode and move to VPlan transformation.
+      SmallVector<VPValue *> NewOps(Operands);
+      ScalarEvolution &SE = *PSE.getSE();
+      for (unsigned I = 0; I < Operands.size(); ++I) {
+        Value *V = NewOps[I]->getUnderlyingValue();
+        if (!isa<Constant>(V) && SE.isSCEVable(V->getType()))
+          if (auto *C = dyn_cast<SCEVConstant>(PSE.getSE()->getSCEV(V)))
+            NewOps[I] = Plan.getOrAddLiveIn(C->getValue());
+      }
+      return new VPWidenRecipe(*I, make_range(NewOps.begin(), NewOps.end()));
+    }
     return new VPWidenRecipe(*I, make_range(Operands.begin(), Operands.end()));
   };
 }
diff --git a/llvm/lib/Transforms/Vectorize/VPRecipeBuilder.h b/llvm/lib/Transforms/Vectorize/VPRecipeBuilder.h
index 0fbdeeddaf4a..25b8bf3e089e 100644
--- a/llvm/lib/Transforms/Vectorize/VPRecipeBuilder.h
+++ b/llvm/lib/Transforms/Vectorize/VPRecipeBuilder.h
@@ -174,11 +174,6 @@ public:
       if (auto *R = Ingredient2Recipe.lookup(I))
         return R->getVPSingleValue();
     }
-    ScalarEvolution &SE = *PSE.getSE();
-    if (!isa<Constant>(V) && SE.isSCEVable(V->getType()))
-      if (auto *C = dyn_cast<SCEVConstant>(PSE.getSE()->getSCEV(V)))
-        return Plan.getOrAddLiveIn(C->getValue());
-
     return Plan.getOrAddLiveIn(V);
   }
 };


Regression tests:
file: llvm/test/Transforms/LoopVectorize/AArch64/mul-simplification.ll
commands: opt -p loop-vectorize -S %s
tests: test_name: mul_select_operand_known_1_via_scev
test_body: target triple = "arm64-apple-macosx"

define i64 @mul_select_operand_known_1_via_scev() {
entry:
  br label %loop

loop:                                             ; preds = %loop, %entry
  %red = phi i64 [ 12, %entry ], [ %red.next, %loop ]
  %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
  %0 = and i32 %iv, 1
  %cmp1.i = icmp eq i32 %0, 0
  %narrow.i = select i1 %cmp1.i, i32 1, i32 %iv
  %mul = zext nneg i32 %narrow.i to i64
  %red.next = mul nsw i64 %red, %mul
  %iv.next = add nuw nsw i32 %iv, 1
  %ec = icmp eq i32 %iv, 1
  br i1 %ec, label %exit, label %loop

exit:                                             ; preds = %loop
  %res = phi i64 [ %red.next, %loop ]
  ret i64 %res
}