Bug type: crash
Component: SLPVectorizer
Bug location: llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp: BoUpSLP::tryToGatherExtractElements
Issue title: [SLP][REVEC] Assertion `N + M <= this->size() && "Invalid specifier"' failed with -slp-revec -slp-vectorize-non-power-of-2
Labels: llvm:SLPVectorizer
crash
Reported by: Andarwinux

https://rust.godbolt.org/z/qxf3r78Y4

```
opt: /root/llvm-project/llvm/include/llvm/ADT/ArrayRef.h:378: llvm::MutableArrayRef<T> llvm::MutableArrayRef<T>::slice(size_t, size_t) const [with T = llvm::Value*; size_t = long unsigned int]: Assertion `N + M <= this->size() && "Invalid specifier"' 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 -slp-revec -slp-vectorize-non-power-of-2 -O3 <source>
1.	Running pass "function<eager-inv>(drop-unnecessary-assumes,float2int,lower-constant-intrinsics,chr,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;>,drop-unnecessary-assumes,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-arithmetic;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<O3>,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;switch-to-arithmetic;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 "slp-vectorizer" on function "av1_finalize_encoded_frame"
 #0 0x0000000005b8a888 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x5b8a888)
 #1 0x0000000005b87764 SignalHandler(int, siginfo_t*, void*) Signals.cpp:0:0
 #2 0x00007833c0042520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #3 0x00007833c00969fc pthread_kill (/lib/x86_64-linux-gnu/libc.so.6+0x969fc)
 #4 0x00007833c0042476 gsignal (/lib/x86_64-linux-gnu/libc.so.6+0x42476)
 #5 0x00007833c00287f3 abort (/lib/x86_64-linux-gnu/libc.so.6+0x287f3)
 #6 0x00007833c002871b (/lib/x86_64-linux-gnu/libc.so.6+0x2871b)
 #7 0x00007833c0039e96 (/lib/x86_64-linux-gnu/libc.so.6+0x39e96)
 #8 0x00000000038a0ce8 llvm::slpvectorizer::BoUpSLP::tryToGatherExtractElements(llvm::SmallVectorImpl<llvm::Value*>&, llvm::SmallVectorImpl<int>&, unsigned int) const (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x38a0ce8)
 #9 0x00000000038cd7da llvm::slpvectorizer::BoUpSLP::findReusedOrderedScalars(llvm::slpvectorizer::BoUpSLP::TreeEntry const&, bool, bool) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x38cd7da)
#10 0x000000000390a0fb llvm::slpvectorizer::BoUpSLP::getReorderingData(llvm::slpvectorizer::BoUpSLP::TreeEntry const&, bool, bool) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x390a0fb)
#11 0x000000000390ef52 llvm::slpvectorizer::BoUpSLP::reorderTopToBottom() (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x390ef52)
#12 0x000000000391d03c (anonymous namespace)::HorizontalReduction::tryToReduce(llvm::slpvectorizer::BoUpSLP&, llvm::DataLayout const&, llvm::TargetTransformInfo*, llvm::TargetLibraryInfo const&, llvm::AssumptionCache*, llvm::DominatorTree&) SLPVectorizer.cpp:0:0
#13 0x0000000003921808 llvm::SLPVectorizerPass::vectorizeHorReduction(llvm::PHINode*, llvm::Instruction*, llvm::BasicBlock*, llvm::slpvectorizer::BoUpSLP&, llvm::SmallVectorImpl<llvm::WeakTrackingVH>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x3921808)
#14 0x0000000003926753 bool llvm::SLPVectorizerPass::vectorizeCmpInsts<std::reverse_iterator<llvm::CmpInst* const*>>(llvm::iterator_range<std::reverse_iterator<llvm::CmpInst* const*>>, llvm::BasicBlock*, llvm::slpvectorizer::BoUpSLP&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x3926753)
#15 0x0000000003929fc0 llvm::SLPVectorizerPass::vectorizeChainsInBlock(llvm::BasicBlock*, llvm::slpvectorizer::BoUpSLP&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x3929fc0)
#16 0x0000000003930c16 llvm::SLPVectorizerPass::runImpl(llvm::Function&, llvm::ScalarEvolution*, llvm::TargetTransformInfo*, llvm::TargetLibraryInfo*, llvm::AAResults*, llvm::LoopInfo*, llvm::DominatorTree*, llvm::AssumptionCache*, llvm::DemandedBits*, llvm::OptimizationRemarkEmitter*) (.part.0) SLPVectorizer.cpp:0:0
#17 0x0000000003931a9b llvm::SLPVectorizerPass::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x3931a9b)
#18 0x00000000030ca01e llvm::detail::PassModel<llvm::Function, llvm::SLPVectorizerPass, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x30ca01e)
#19 0x00000000058f5961 llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x58f5961)
#20 0x0000000000f1420e 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+0xf1420e)
#21 0x00000000058f3f1a llvm::ModuleToFunctionPassAdaptor::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x58f3f1a)
#22 0x000000000096bdfe 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+0x96bdfe)
#23 0x00000000058f38d1 llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x58f38d1)
#24 0x0000000000975fba 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+0x975fba)
#25 0x000000000096a068 optMain (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x96a068)
#26 0x00007833c0029d90 (/lib/x86_64-linux-gnu/libc.so.6+0x29d90)
#27 0x00007833c0029e40 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e40)
#28 0x0000000000960ce5 _start (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x960ce5)
```


Fix patch:
commit 26f944bb50b0f585ba1be805368a987ad5543a07
Author: Alexey Bataev <a.bataev@outlook.com>
Date:   Tue Feb 17 09:39:12 2026 -0800

    [SLP]Fix an ArrayRef out-of-bounds access in slice
    
    If the revec is enabled, may have the number of parts (registers) for
    the combined node, not a single element node, so need to check for
    potential out-of-bounds access
    
    Fixes #181798

diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index d97faa59a483..afc2ffb71e1c 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -17846,8 +17846,13 @@ BoUpSLP::tryToGatherExtractElements(SmallVectorImpl<Value *> &VL,
   for (unsigned Part : seq<unsigned>(NumParts)) {
     // Scan list of gathered scalars for extractelements that can be represented
     // as shuffles.
-    MutableArrayRef<Value *> SubVL = MutableArrayRef(VL).slice(
-        Part * SliceSize, getNumElems(VL.size(), SliceSize, Part));
+    const unsigned PartOffset = Part * SliceSize;
+    const unsigned PartSize = getNumElems(VL.size(), SliceSize, Part);
+    // It may happen in case of revec, need to check no access out of bounds.
+    if (PartOffset + PartSize > VL.size())
+      break;
+    MutableArrayRef<Value *> SubVL =
+        MutableArrayRef(VL).slice(PartOffset, PartSize);
     SmallVector<int> SubMask;
     std::optional<TTI::ShuffleKind> Res =
         tryToGatherSingleRegisterExtractElements(SubVL, SubMask);


Regression tests:
file: llvm/test/Transforms/SLPVectorizer/AArch64/revec-non-pow2.ll
commands: opt -slp-revec -slp-vectorize-non-power-of-2 --passes=slp-vectorizer -S -mtriple=aarch64-pc-windows-gnu < %s
tests: test_name: <module>
test_body: 
define i32 @test(ptr %0) {
;
.split:
  %1 = load ptr, ptr %0, align 8
  %2 = getelementptr i8, ptr %1, i64 96
  %3 = load i32, ptr %2, align 4
  %4 = add i32 %3, 1
  %5 = getelementptr i8, ptr %1, i64 108
  %6 = load i32, ptr %5, align 4
  %7 = add i32 %4, %6
  %8 = getelementptr i8, ptr %1, i64 120
  %9 = load i32, ptr %8, align 4
  %10 = add i32 %7, %9
  %11 = getelementptr i8, ptr %1, i64 132
  %12 = load i32, ptr %11, align 4
  %13 = add i32 %10, %12
  %14 = getelementptr i8, ptr %1, i64 144
  %15 = load i32, ptr %14, align 4
  %16 = add i32 %13, %15
  %17 = getelementptr i8, ptr %1, i64 156
  %18 = load i32, ptr %17, align 4
  %19 = add i32 %16, %18
  %20 = getelementptr i8, ptr %1, i64 168
  %21 = load i32, ptr %20, align 4
  %22 = add i32 %19, %21
  %23 = getelementptr i8, ptr %1, i64 180
  %24 = load i32, ptr %23, align 4
  %25 = add i32 %22, %24
  %26 = getelementptr i8, ptr %1, i64 100
  %27 = load i32, ptr %26, align 4
  %28 = add i32 %27, 1
  %29 = getelementptr i8, ptr %1, i64 112
  %30 = load i32, ptr %29, align 4
  %31 = add i32 %28, %30
  %32 = getelementptr i8, ptr %1, i64 124
  %33 = load i32, ptr %32, align 4
  %34 = add i32 %31, %33
  %35 = getelementptr i8, ptr %1, i64 136
  %36 = load i32, ptr %35, align 4
  %37 = add i32 %34, %36
  %38 = getelementptr i8, ptr %1, i64 148
  %39 = load i32, ptr %38, align 4
  %40 = add i32 %37, %39
  %41 = getelementptr i8, ptr %1, i64 160
  %42 = load i32, ptr %41, align 4
  %43 = getelementptr i8, ptr %1, i64 172
  %44 = getelementptr i8, ptr %1, i64 116
  %45 = load i32, ptr %44, align 4
  %46 = getelementptr i8, ptr %1, i64 104
  %47 = load i32, ptr %46, align 4
  %48 = add i32 %45, %47
  %49 = getelementptr i8, ptr %1, i64 128
  %50 = load i32, ptr %49, align 4
  %51 = add i32 %48, %50
  %52 = getelementptr i8, ptr %1, i64 140
  %53 = load i32, ptr %52, align 4
  %54 = add i32 %51, %53
  %55 = getelementptr i8, ptr %1, i64 152
  %56 = load i32, ptr %55, align 4
  %57 = add i32 %54, %56
  %58 = getelementptr i8, ptr %1, i64 164
  %59 = load i32, ptr %58, align 4
  %60 = add i32 %57, %59
  %61 = getelementptr i8, ptr %1, i64 176
  %62 = load i32, ptr %61, align 4
  %63 = add i32 %60, %62
  %64 = getelementptr i8, ptr %1, i64 188
  %65 = load i32, ptr %64, align 4
  %66 = add i32 %63, %65
  %67 = add i32 %40, %42
  %68 = load i32, ptr %43, align 4
  %69 = add i32 %67, %68
  %70 = getelementptr i8, ptr %1, i64 184
  %71 = load i32, ptr %70, align 4
  %72 = add i32 %69, %71
  %73 = icmp sgt i32 %72, 0
  %74 = zext i1 %73 to i32
  %75 = icmp sgt i32 %25, 0
  %76 = zext i1 %75 to i32
  %77 = add i32 %74, %76
  %78 = icmp sgt i32 %66, 0
  %79 = zext i1 %78 to i32
  %80 = add i32 %77, %79
  ret i32 %80
}