Bug type: crash
Component: LoopVectorize
Bug location: llvm/lib/Transforms/Vectorize/LoopVectorize.cpp: LoopVectorizationPlanner::precomputeCosts
Issue title: [VPlan] Assertion "VPlan cost model and legacy cost model disagreed"' failed.
Labels: release:backport
vectorizers
crash
Reported by: patrick-rivos

C program:
```c
signed char a;
short b;
int c, g;
long d, e, f;
void h(long i[][2], long j[][2][2], short k[][2]) {
  for (unsigned l = g; l; l += 4) {
    a *= (signed char)((f ? 0 : k[l][l]) ?: (_Bool)(d << j[8][l][e]) ? i[l][l] : c);
    b = ~i[e][l];
  }
}
```
`/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/clang -march=rv64gcv -O3 red.c -o rv64gcv.bc -w -emit-llvm -c`

LLVM IR:
```llvm ir
; ModuleID = 'reduced.bc'
target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"
target triple = "riscv64-unknown-linux-gnu"

define void @h(ptr %i, ptr %k, i64 %idxprom.us) #0 {
entry:
  br label %for.body.us

for.body.us:                                      ; preds = %cond.end23.us, %entry
  %l.046.us = phi i32 [ %add.us, %cond.end23.us ], [ 0, %entry ]
  %conv284345.us = phi i8 [ %conv28.us, %cond.end23.us ], [ 0, %entry ]
  %idxprom.us1 = zext i32 %l.046.us to i64
  %arrayidx3.us = getelementptr [2 x i16], ptr %k, i64 %idxprom.us1, i64 %idxprom.us
  %0 = load i16, ptr %arrayidx3.us, align 2
  %tobool4.not.us = icmp eq i16 %0, 0
  br i1 %tobool4.not.us, label %cond.false7.us, label %cond.end23.us

cond.false7.us:                                   ; preds = %for.body.us
  %1 = load i64, ptr %i, align 8
  %shl.us = shl i64 0, %1
  %tobool12.not.us = icmp eq i64 %shl.us, 0
  br i1 %tobool12.not.us, label %cond.end23.us, label %cond.true14.us

cond.true14.us:                                   ; preds = %cond.false7.us
  %2 = load i64, ptr %i, align 8
  %3 = trunc i64 %2 to i32
  br label %cond.end23.us

cond.end23.us:                                    ; preds = %cond.true14.us, %cond.false7.us, %for.body.us
  %cond24.us = phi i32 [ %3, %cond.true14.us ], [ 0, %for.body.us ], [ 0, %cond.false7.us ]
  %4 = trunc i32 %cond24.us to i8
  %conv28.us = mul i8 0, %4
  %arrayidx31.us = getelementptr [2 x i64], ptr %i, i64 0, i64 %idxprom.us1
  %5 = load i64, ptr %arrayidx31.us, align 8
  %6 = trunc i64 %5 to i16
  %conv32.us = xor i16 %6, 0
  store i16 %conv32.us, ptr null, align 2
  %add.us = add i32 %l.046.us, 4
  %tobool.not.us = icmp eq i32 %add.us, 0
  br i1 %tobool.not.us, label %for.cond.for.cond.cleanup_crit_edge, label %for.body.us

for.cond.for.cond.cleanup_crit_edge:              ; preds = %cond.end23.us
  store i8 %4, ptr null, align 1
  ret void
}

attributes #0 = { "target-features"="+64bit,+a,+c,+d,+f,+m,+relax,+v,+zicsr,+zifencei,+zmmul,+zve32f,+zve32x,+zve64d,+zve64f,+zve64x,+zvl128b,+zvl32b,+zvl64b,-b,-e,-experimental-smctr,-experimental-ssctr,-experimental-zalasr,-experimental-zicfilp,-experimental-zicfiss,-experimental-zvbc32e,-experimental-zvkgs,-h,-sha,-shcounterenw,-shgatpa,-shtvala,-shvsatpa,-shvstvala,-shvstvecd,-smaia,-smcdeleg,-smcsrind,-smdbltrp,-smepmp,-smmpm,-smnpm,-smrnmi,-smstateen,-ssaia,-ssccfg,-ssccptr,-sscofpmf,-sscounterenw,-sscsrind,-ssdbltrp,-ssnpm,-sspm,-ssqosid,-ssstateen,-ssstrict,-sstc,-sstvala,-sstvecd,-ssu64xl,-supm,-svade,-svadu,-svbare,-svinval,-svnapot,-svpbmt,-svvptc,-xcvalu,-xcvbi,-xcvbitmanip,-xcvelw,-xcvmac,-xcvmem,-xcvsimd,-xsfcease,-xsfvcp,-xsfvfnrclipxfqf,-xsfvfwmaccqqq,-xsfvqmaccdod,-xsfvqmaccqoq,-xsifivecdiscarddlone,-xsifivecflushdlone,-xtheadba,-xtheadbb,-xtheadbs,-xtheadcmo,-xtheadcondmov,-xtheadfmemidx,-xtheadmac,-xtheadmemidx,-xtheadmempair,-xtheadsync,-xtheadvdot,-xventanacondops,-xwchc,-za128rs,-za64rs,-zaamo,-zabha,-zacas,-zalrsc,-zama16b,-zawrs,-zba,-zbb,-zbc,-zbkb,-zbkc,-zbkx,-zbs,-zca,-zcb,-zcd,-zce,-zcf,-zcmop,-zcmp,-zcmt,-zdinx,-zfa,-zfbfmin,-zfh,-zfhmin,-zfinx,-zhinx,-zhinxmin,-zic64b,-zicbom,-zicbop,-zicboz,-ziccamoa,-ziccif,-zicclsm,-ziccrse,-zicntr,-zicond,-zihintntl,-zihintpause,-zihpm,-zimop,-zk,-zkn,-zknd,-zkne,-zknh,-zkr,-zks,-zksed,-zksh,-zkt,-ztso,-zvbb,-zvbc,-zvfbfmin,-zvfbfwma,-zvfh,-zvfhmin,-zvkb,-zvkg,-zvkn,-zvknc,-zvkned,-zvkng,-zvknha,-zvknhb,-zvks,-zvksc,-zvksed,-zvksg,-zvksh,-zvkt,-zvl1024b,-zvl16384b,-zvl2048b,-zvl256b,-zvl32768b,-zvl4096b,-zvl512b,-zvl65536b,-zvl8192b" }
```

Command/backtrace:
```
> /scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt --passes "loop-vectorize" reduced.ll -f
opt: /scratch/tc-testing/tc-compiler-fuzz-trunk/llvm/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp:7522: llvm::VectorizationFactor llvm::LoopVectorizationPlanner::computeBestVF(): Assertion `(BestFactor.Width == LegacyVF.Width || 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.
Stack dump:
0.      Program arguments: /scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt --passes loop-vectorize reduced.ll -f
1.      Running pass "function(loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>)" on module "reduced.ll"
2.      Running pass "loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>" on function "h"
 #0 0x000062cc6ec1de70 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x319de70)
 #1 0x000062cc6ec1b27f llvm::sys::RunSignalHandlers() (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x319b27f)
 #2 0x000062cc6ec1b3d5 SignalHandler(int) Signals.cpp:0:0
 #3 0x000074efe9a42520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #4 0x000074efe9a969fc __pthread_kill_implementation ./nptl/pthread_kill.c:44:76
 #5 0x000074efe9a969fc __pthread_kill_internal ./nptl/pthread_kill.c:78:10
 #6 0x000074efe9a969fc pthread_kill ./nptl/pthread_kill.c:89:10
 #7 0x000074efe9a42476 gsignal ./signal/../sysdeps/posix/raise.c:27:6
 #8 0x000074efe9a287f3 abort ./stdlib/abort.c:81:7
 #9 0x000074efe9a2871b _nl_load_domain ./intl/loadmsgcat.c:1177:9
#10 0x000074efe9a39e96 (/lib/x86_64-linux-gnu/libc.so.6+0x39e96)
#11 0x000062cc6db65039 llvm::LoopVectorizationPlanner::computeBestVF() (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x20e5039)
#12 0x000062cc6db7c50c llvm::LoopVectorizePass::processLoop(llvm::Loop*) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x20fc50c)
#13 0x000062cc6db7f1e1 llvm::LoopVectorizePass::runImpl(llvm::Function&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x20ff1e1)
#14 0x000062cc6db7f857 llvm::LoopVectorizePass::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x20ff857)
#15 0x000062cc6c963a06 llvm::detail::PassModel<llvm::Function, llvm::LoopVectorizePass, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0xee3a06)
#16 0x000062cc6ea24b0f llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x2fa4b0f)
#17 0x000062cc6c966b96 llvm::detail::PassModel<llvm::Function, llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0xee6b96)
#18 0x000062cc6ea22e9b llvm::ModuleToFunctionPassAdaptor::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x2fa2e9b)
#19 0x000062cc6c962ac6 llvm::detail::PassModel<llvm::Module, llvm::ModuleToFunctionPassAdaptor, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0xee2ac6)
#20 0x000062cc6ea239fd llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x2fa39fd)
#21 0x000062cc6c15c33d 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) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x6dc33d)
#22 0x000062cc6c14e1c1 optMain (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x6ce1c1)
#23 0x000074efe9a29d90 __libc_start_call_main ./csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#24 0x000074efe9a29e40 call_init ./csu/../csu/libc-start.c:128:20
#25 0x000074efe9a29e40 __libc_start_main ./csu/../csu/libc-start.c:379:5
#26 0x000062cc6c144725 _start (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x6c4725)
zsh: IOT instruction (core dumped)  /scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt
```

Godbolt: https://godbolt.org/z/v5K5Wbxcn

Found via fuzzer

cc @fhahn 

Comments: author: patrick-rivos
body: Bisected to b3edc764f70f4e56807af60abdcfbef4dbdc5d95
cc @ElvisWang123 
author: ElvisWang123
body: > Bisected to [b3edc76](https://github.com/llvm/llvm-project/commit/b3edc764f70f4e56807af60abdcfbef4dbdc5d95) cc @ElvisWang123

I will take a look.
author: ElvisWang123
body: The main difference of this case is that 
`LV: Found an estimated cost of 3 for VF vscale x 2 For instruction:   %3 = trunc i64 %2 to i32` from legacy cost model and `Cost of 1 for VF vscale x 2: WIDEN-CAST ir<%3> = trunc  ir<%2> to i32` from VPlan-based cost model.

Legacy cost model will consider the new type after MinBW by `canTruncateToMinimalBitwidth()`. And finds that `i32` can further truncate to `i8`. So the legacy cost model will calculate the cost from `i64` to `i8`.
 But in the VPTransforms,  the result type of this  recipe cannot be shrunk from `i32` to `i8`. So the final recipes will only calculate the cost from `i64` to `i32`.

I think this might be the MinBW transformation issue which cannot further truncate the type.

BTW, the cost from the VPlan-based cost model is closer to the generated vector loop.

Some cost model information:
Legacy cost
```
LV: Found an estimated cost of 0 for VF vscale x 2 For instruction:   %l.046.us = phi i32 [ %add.us, %cond.end23.us ], [ 0, %entry ]
LV: Found an estimated cost of 2 for VF vscale x 2 For instruction:   %conv284345.us = phi i8 [ %conv28.us, %cond.end23.us ], [ 0, %entr
y ]
LV: Found an estimated cost of 2 for VF vscale x 2 For instruction:   %idxprom.us1 = zext i32 %l.046.us to i64
LV: Found an estimated cost of 0 for VF vscale x 2 For instruction:   %arrayidx3.us = getelementptr [2 x i16], ptr %k, i64 %idxprom.us1,
 i64 %idxprom.us
LV: Found an estimated cost of 4 for VF vscale x 2 For instruction:   %0 = load i16, ptr %arrayidx3.us, align 2
LV: Found an estimated cost of 1 for VF vscale x 2 For instruction:   %tobool4.not.us = icmp eq i16 %0, 0
LV: Found an estimated cost of 0 for VF vscale x 2 For instruction:   br i1 %tobool4.not.us, label %cond.false7.us, label %cond.end23.us
LV: Found an estimated cost of 4 for VF vscale x 2 For instruction:   %1 = load i64, ptr %i, align 8
LV: Found an estimated cost of 2 for VF vscale x 2 For instruction:   %shl.us = shl i64 0, %1
LV: Found an estimated cost of 2 for VF vscale x 2 For instruction:   %tobool12.not.us = icmp eq i64 %shl.us, 0
LV: Found an estimated cost of 0 for VF vscale x 2 For instruction:   br i1 %tobool12.not.us, label %cond.end23.us, label %cond.true14.u
s
LV: Found an estimated cost of 4 for VF vscale x 2 For instruction:   %2 = load i64, ptr %i, align 8
====> LV: Found an estimated cost of 3 for VF vscale x 2 For instruction:   %3 = trunc i64 %2 to i32 <=====
LV: Found an estimated cost of 0 for VF vscale x 2 For instruction:   br label %cond.end23.us
LV: Found an estimated cost of 2 for VF vscale x 2 For instruction:   %cond24.us = phi i32 [ %3, %cond.true14.us ], [ 0, %for.body.us ],
 [ 0, %cond.false7.us ]
LV: Found an estimated cost of 2 for VF vscale x 2 For instruction:   %4 = trunc i32 %cond24.us to i8
LV: Found an estimated cost of 1 for VF vscale x 2 For instruction:   %conv28.us = mul i8 0, %4
LV: Found an estimated cost of 0 for VF vscale x 2 For instruction:   %arrayidx31.us = getelementptr [2 x i64], ptr %i, i64 0, i64 %idxp
rom.us1
LV: Found an estimated cost of 4 for VF vscale x 2 For instruction:   %5 = load i64, ptr %arrayidx31.us, align 8
LV: Found an estimated cost of 2 for VF vscale x 2 For instruction:   %6 = trunc i64 %5 to i16
LV: Found an estimated cost of 1 for VF vscale x 2 For instruction:   %conv32.us = xor i16 %6, 0
LV: Found an estimated cost of 3 for VF vscale x 2 For instruction:   store i16 %conv32.us, ptr null, align 2
LV: Found an estimated cost of 1 for VF vscale x 2 For instruction:   %add.us = add i32 %l.046.us, 4
LV: Found an estimated cost of 1 for VF vscale x 2 For instruction:   %tobool.not.us = icmp eq i32 %add.us, 0
LV: Found an estimated cost of 0 for VF vscale x 2 For instruction:   br i1 %tobool.not.us, label %for.cond.for.cond.cleanup_crit_edge, 
label %for.body.us
LV: Vector loop of width vscale x 2 costs: 10 (assuming a minimum vscale of 2).
```

VPlan-based
```
Cost of 1 for VF vscale x 2: induction instruction   %add.us = add i32 %l.046.us, 4
Cost of 0 for VF vscale x 2: induction instruction   %l.046.us = phi i32 [ %add.us, %cond.end23.us ], [ 0, %entry ]
Cost of 1 for VF vscale x 2: exit condition instruction   %tobool.not.us = icmp eq i32 %add.us, 0
Cost of 0 for VF vscale x 2: EMIT vp<%3> = CANONICAL-INDUCTION ir<0>, vp<%index.next>
Cost of 0 for VF vscale x 2: WIDEN-INDUCTION %l.046.us = phi %add.us, 0, ir<4>, vp<%0>
Cost of 2 for VF vscale x 2: FIRST-ORDER-RECURRENCE-PHI ir<%conv284345.us> = phi ir<0>, ir<%conv28.us>
Cost of 2 for VF vscale x 2: WIDEN-CAST ir<%idxprom.us1> = zext  ir<%l.046.us> to i64
Cost of 0 for VF vscale x 2: WIDEN-GEP Inv[Var][Inv] ir<%arrayidx3.us> = getelementptr ir<%k>, ir<%idxprom.us1>, ir<%idxprom.us>
Cost of 4 for VF vscale x 2: WIDEN ir<%0> = load ir<%arrayidx3.us>
Cost of 1 for VF vscale x 2: WIDEN ir<%tobool4.not.us> = icmp eq ir<%0>, ir<0>
Cost of 4 for VF vscale x 2: WIDEN ir<%1> = load ir<%i>, ir<%tobool4.not.us>
Cost of 2 for VF vscale x 2: WIDEN ir<%shl.us> = shl ir<0>, ir<%1>
Cost of 2 for VF vscale x 2: WIDEN ir<%tobool12.not.us> = icmp eq ir<%shl.us>, ir<0>
Cost of 0 for VF vscale x 2: EMIT vp<%4> = not ir<%tobool12.not.us>
Cost of 0 for VF vscale x 2: EMIT vp<%5> = logical-and ir<%tobool4.not.us>, vp<%4>
Cost of 4 for VF vscale x 2: WIDEN ir<%2> = load ir<%i>, vp<%5>
====> Cost of 1 for VF vscale x 2: WIDEN-CAST ir<%3> = trunc  ir<%2> to i32 <=======
Cost of 0 for VF vscale x 2: EMIT vp<%6> = not ir<%tobool4.not.us>
Cost of 2 for VF vscale x 2: BLEND ir<%cond24.us> = ir<0> ir<%3>/vp<%5> ir<0>/vp<%6>
Cost of 2 for VF vscale x 2: WIDEN-CAST ir<%4> = trunc  ir<%cond24.us> to i8
Cost of 1 for VF vscale x 2: WIDEN ir<%conv28.us> = mul ir<0>, ir<%4>
Cost of 0 for VF vscale x 2: WIDEN-GEP Inv[Inv][Var] ir<%arrayidx31.us> = getelementptr ir<%i>, ir<0>, ir<%idxprom.us1>
Cost of 4 for VF vscale x 2: WIDEN ir<%5> = load ir<%arrayidx31.us>
Cost of 2 for VF vscale x 2: WIDEN-CAST ir<%6> = trunc  ir<%5> to i16
Cost of 1 for VF vscale x 2: WIDEN ir<%conv32.us> = xor ir<%6>, ir<0>
Cost of 3 for VF vscale x 2: REPLICATE store ir<%conv32.us>, ir<null>
Cost of 0 for VF vscale x 2: EMIT vp<%index.next> = add nuw vp<%3>, vp<%1>
Cost of 0 for VF vscale x 2: EMIT branch-on-count vp<%index.next>, vp<%2>
Cost of 0 for VF vscale x 2: vector loop backedge
Cost for VF vscale x 2: 39
```
Generated vector.body
``` 
vector.body:                                      ; preds = %vector.body, %vector.ph
  %index = phi i32 [ 0, %vector.ph ]
  %vec.ind = phi <vscale x 2 x i32> [ %induction, %vector.ph ], [ %vec.ind.next, %vector.ph ]
  %vector.recur = phi <vscale x 2 x i8> [ %vector.recur.init, %vector.ph ]
  %vec.ind.next = add <vscale x 2 x i32> %vec.ind, %.splat
  %15 = zext <vscale x 2 x i32> %vec.ind to <vscale x 2 x i64>
  %16 = getelementptr [2 x i16], ptr %k, <vscale x 2 x i64> %15, i64 %idxprom.us
  %wide.masked.gather = call <vscale x 2 x i16> @llvm.masked.gather.nxv2i16.nxv2p0(<vscale x 2 x ptr> %16, i32 2, <vscale x 2 x i1> shufflevector (<vscale x 2 x i1> insertelement (<vscale x 2 x i1> poison, i1 true, i64 0), <vscale x 2 x i1> poison, <vscale x 2 x i32> zeroinitializer), <vscale x 2 x i16> poison)
  %17 = icmp eq <vscale x 2 x i16> %wide.masked.gather, zeroinitializer
  %wide.masked.gather1 = call <vscale x 2 x i64> @llvm.masked.gather.nxv2i64.nxv2p0(<vscale x 2 x ptr> %broadcast.splat, i32 8, <vscale x 2 x i1> %17, <vscale x 2 x i64> poison)
  %18 = shl <vscale x 2 x i64> zeroinitializer, %wide.masked.gather1
  %19 = icmp eq <vscale x 2 x i64> %18, zeroinitializer
  %20 = xor <vscale x 2 x i1> %19, shufflevector (<vscale x 2 x i1> insertelement (<vscale x 2 x i1> poison, i1 true, i64 0), <vscale x 2 x i1> poison, <vscale x 2 x i32> zeroinitializer)
  %21 = select <vscale x 2 x i1> %17, <vscale x 2 x i1> %20, <vscale x 2 x i1> zeroinitializer
  %wide.masked.gather2 = call <vscale x 2 x i64> @llvm.masked.gather.nxv2i64.nxv2p0(<vscale x 2 x ptr> %broadcast.splat, i32 8, <vscale x 2 x i1> %21, <vscale x 2 x i64> poison)
  %22 = trunc <vscale x 2 x i64> %wide.masked.gather2 to <vscale x 2 x i32>   <================
  %23 = xor <vscale x 2 x i1> %17, shufflevector (<vscale x 2 x i1> insertelement (<vscale x 2 x i1> poison, i1 true, i64 0), <vscale x 2 x i1> poison, <vscale x 2 x i32> zeroinitializer)
  %predphi = select <vscale x 2 x i1> %21, <vscale x 2 x i32> %22, <vscale x 2 x i32> zeroinitializer
  %predphi3 = select <vscale x 2 x i1> %23, <vscale x 2 x i32> zeroinitializer, <vscale x 2 x i32> %predphi
  %24 = trunc <vscale x 2 x i32> %predphi3 to <vscale x 2 x i8>
  %25 = mul <vscale x 2 x i8> zeroinitializer, %24
  %26 = getelementptr [2 x i64], ptr %i, i64 0, <vscale x 2 x i64> %15
  %wide.masked.gather4 = call <vscale x 2 x i64> @llvm.masked.gather.nxv2i64.nxv2p0(<vscale x 2 x ptr> %26, i32 8, <vscale x 2 x i1> shufflevector (<vscale x 2 x i1> insertelement (<vscale x 2 x i1> poison, i1 true, i64 0), <vscale x 2 x i1> poison, <vscale x 2 x i32> zeroinitializer), <vscale x 2 x i64> poison)
  %27 = trunc <vscale x 2 x i64> %wide.masked.gather4 to <vscale x 2 x i16>
  %28 = xor <vscale x 2 x i16> %27, zeroinitializer
  %29 = call i32 @llvm.vscale.i32()
%30 = mul i32 %29, 2
  %31 = sub i32 %30, 1
  %32 = extractelement <vscale x 2 x i16> %28, i32 %31
  store i16 %32, ptr null, align 2
  %index.next = add nuw i32 %index, %7
  %33 = icmp eq i32 %index.next, %n.vec
  br i1 %33, <null operand!>, label %vector.body
...
author: ElvisWang123
body: In this case, we can find that all the following recipes can be shrinkage to `i8`.
```
====> Cost of 1 for VF vscale x 2: WIDEN-CAST ir<%3> = trunc  ir<%2> to i32 <=======
Cost of 0 for VF vscale x 2: EMIT vp<%6> = not ir<%tobool4.not.us>
Cost of 2 for VF vscale x 2: BLEND ir<%cond24.us> = ir<0> ir<%3>/vp<%5> ir<0>/vp<%6>
Cost of 2 for VF vscale x 2: WIDEN-CAST ir<%4> = trunc  ir<%cond24.us> to i8
Cost of 1 for VF vscale x 2: WIDEN ir<%conv28.us> = mul ir<0>, ir<%4>
```
But in current minimal-bit-width analysis, there are some checks prevent this type shrinkage.
1. If any of  instructions in the EC (equivalent class) is PHI node, minimal-bit-width wont narrow the type.

To support type shrinkage for this case. We need to change the MinBW which is the analysis based on the scalar instructions.

Modify current minimal-bit-width architecture (Analysis scalar instructions). This implementation may not be accurate since the VPlan may contains some of the recipe without underlying instructions.
1. Support Phi node in the EC. Although  induction phi should not be modified and the recurrence descriptor will handle the type shrinkage.  We still need the information from MinBW to shrinkage the non-header phis.
2. Add the support of `VPBlendRecipe` in `truncateToMinimalBitWidth()` in VPTransform.

Or rewrite a new minimal-bit-width analysis based on Vplan. This implementation will be more accurate than the current analysis but will be more works.

1. To support Vplan-based MinBW, we may need to rewrite a new VPlan-based DemandedBits analysis.


@fhahn What do you think about the these two implementations, modify current MinBW or rewrite a new vplan-based MinBW. Or do you have a better implementation to make MinBW more accurate on Vplan?

@patrick-rivos BTW, the C program in this issue is a little bit weird.  Without initializing  `a`, loop vectorizer cannot recognize the reduction pattern of the `a *= (signed char)((f ? 0 : k[l][l]) ?: (_Bool)(d << j[8][l][e]) ? i[l][l] : c);`.  However, we still have some issue on the minimal-bit-width analysis.
author: cardigan1008
body: Hi, there's another case that triggers this crash:

```c
int a;
int b(int c) {
  int d = 0;
  for (; d < c; d++) {
    a++;
    if (d != c - 1)
      a++;
  }
}
int *e;
int f;
void g() {
  for (; e[f]; f++)
    e[b(f + 9)];
}
```

Compiler Explorer: https://godbolt.org/z/16Tr15KGx

Hope this helps :)
author: ElvisWang123
body: @cardigan1008 Thanks for your test case. I will take a look.

Fix patch:
commit 8009c1fd81ad0b6ac65724d2b134a92db48f8fbf
Author: Elvis Wang <elvis.wang@sifive.com>
Date:   Tue Feb 25 11:09:09 2025 +0800

    [LV][VPlan] Prevent calculate cost for skiped instructions in precomputeCosts(). (#127966)
    
    Skip calculating instruction costs for exit conditions in
    precomputeCosts() when it should be skipped.
    
    Reported from:
    https://github.com/llvm/llvm-project/issues/115744#issuecomment-2670479463
    Godbolt for reduced test cases: https://godbolt.org/z/fr4YMeqcv

diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index 4d2df9179aa3..0bf2d71a63ef 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -7291,7 +7291,7 @@ LoopVectorizationPlanner::precomputeCosts(VPlan &Plan, ElementCount VF,
   // Collect all exit conditions.
   for (BasicBlock *EB : Exiting) {
     auto *Term = dyn_cast<BranchInst>(EB->getTerminator());
-    if (!Term)
+    if (!Term || CostCtx.skipCostComputation(Term, VF.isVector()))
       continue;
     if (auto *CondI = dyn_cast<Instruction>(Term->getOperand(0))) {
       ExitInstrs.insert(CondI);
@@ -7311,7 +7311,8 @@ LoopVectorizationPlanner::precomputeCosts(VPlan &Plan, ElementCount VF,
     Cost += CondICost;
     for (Value *Op : CondI->operands()) {
       auto *OpI = dyn_cast<Instruction>(Op);
-      if (!OpI || any_of(OpI->users(), [&ExitInstrs, this](User *U) {
+      if (!OpI || CostCtx.skipCostComputation(OpI, VF.isVector()) ||
+          any_of(OpI->users(), [&ExitInstrs, this](User *U) {
             return OrigLoop->contains(cast<Instruction>(U)->getParent()) &&
                    !ExitInstrs.contains(cast<Instruction>(U));
           }))


Regression tests:
file: llvm/test/Transforms/LoopVectorize/X86/cost-model.ll
commands: opt < %s -passes=loop-vectorize -mtriple=x86_64-apple-macosx10.8.0 -mcpu=corei7-avx -S
tests: test_name: g
test_body: target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.8.0"

define i32 @g(i64 %n) {
entry:
  br label %loop

loop:                                             ; preds = %loop, %entry
  %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
  %select = phi i32 [ 0, %entry ], [ %select.next, %loop ]
  %iv.widen = zext i32 %iv to i64
  %exitcond = icmp eq i64 %n, %iv.widen
  %select.i = select i1 %exitcond, i32 0, i32 2
  %select.next = or i32 %select.i, %select
  %iv.next = add i32 %iv, 1
  br i1 %exitcond, label %exit, label %loop

exit:                                             ; preds = %loop
  ret i32 %select.next
}