Bug type: crash
Component: SLPVectorizer
Bug location: llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp: BoUpSLP::getReorderingData
Issue title: [SLP]  llvm::BitVector::set(unsigned int): Assertion `Idx < Size && "access in bound"' failed.
Labels: llvm:SLPVectorizer
crash
Reported by: JonPsson1

[crash41.tar.gz](https://github.com/user-attachments/files/18712696/crash41.tar.gz)

clang -O3 -march=z15 crash41.i -o a.out -w -mllvm -inline-threshold=450

llvm/include/llvm/ADT/BitVector.h:358: llvm::BitVector& llvm::BitVector::set(unsigned int): Assertion `Idx < Size && "access in bound"' failed.

#11 0x000002aa03b45768 llvm::SLPVectorizerPass::vectorizeHorReduction

@alexey-bataev 



Fix patch:
commit 10844fb9b0b78695243391e091e17ec29295872a
Author: Alexey Bataev <a.bataev@outlook.com>
Date:   Tue Feb 11 13:23:55 2025 -0800

    [SLP]Fix attempt to build the reorder mask for non-adjusted reuse mask
    
    When building the reorder for non-single use reuse mask, need to check
    if the size of the mask is multiple of the number of unique scalars.
      Otherwise, the compiler may crash when trying to reorder nodes.
    
    Fixes #126304

diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index e1c08077126d..fb1054ee30aa 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -5596,6 +5596,8 @@ BoUpSLP::getReorderingData(const TreeEntry &TE, bool TopToBottom) {
         ::getNumberOfParts(*TTI, getWidenedType(TE.Scalars.front()->getType(),
                                                 2 * TE.getVectorFactor())) == 1)
       return std::nullopt;
+    if (TE.ReuseShuffleIndices.size() % Sz != 0)
+      return std::nullopt;
     if (!ShuffleVectorInst::isOneUseSingleSourceMask(TE.ReuseShuffleIndices,
                                                      Sz)) {
       SmallVector<int> ReorderMask(Sz, PoisonMaskElem);
@@ -5626,7 +5628,7 @@ BoUpSLP::getReorderingData(const TreeEntry &TE, bool TopToBottom) {
         UsedVals.set(Val);
         for (unsigned K = 0; K < NumParts; ++K) {
           unsigned Idx = Val + Sz * K;
-          if (Idx < VF)
+          if (Idx < VF && I + K < VF)
             ResOrder[Idx] = I + K;
         }
       }


Regression tests:
file: llvm/test/Transforms/SLPVectorizer/SystemZ/reuse-non-power-of-2-reorder.ll
commands: opt -S --passes=slp-vectorizer -mtriple=systemz -mcpu=z15 < %s -slp-threshold=-100
tests: test_name: <module>
test_body: 
define void @test(i32 %0, i64 %1, i32 %2, i32 %3, ptr %4) {
;
  %6 = trunc i64 %1 to i32
  %7 = xor i32 %6, 1
  %8 = xor i32 %6, 1
  %9 = or i32 %7, %8
  %10 = xor i32 %6, 1
  %11 = or i32 %9, %10
  %12 = xor i32 %6, 1
  %13 = or i32 %11, %12
  %14 = xor i32 %6, 1
  %15 = or i32 %13, %14
  %16 = xor i32 %6, 1
  %17 = or i32 %15, %16
  %18 = xor i32 %6, 1
  %19 = or i32 %17, %18
  %20 = xor i32 %6, 1
  %21 = or i32 %19, %20
  %22 = trunc i64 %1 to i32
  %23 = xor i32 %22, 1
  %24 = or i32 %23, %21
  %25 = xor i32 %22, 1
  %26 = or i32 %24, %25
  %27 = xor i32 %22, 1
  %28 = or i32 %26, %27
  %29 = xor i32 %22, 1
  %30 = or i32 %28, %29
  %31 = xor i32 %22, 1
  %32 = or i32 %30, %31
  %33 = xor i32 %22, 1
  %34 = or i32 %32, %33
  %35 = xor i32 %22, 1
  %36 = or i32 %34, %35
  %37 = xor i32 %22, 1
  %38 = or i32 %36, %37
  %39 = trunc i64 %1 to i32
  %40 = xor i32 %39, 1
  %41 = or i32 %40, %38
  %42 = xor i32 %39, 1
  %43 = or i32 %41, %42
  %44 = xor i32 %39, 1
  %45 = or i32 %43, %44
  %46 = xor i32 %39, 1
  %47 = or i32 %45, %46
  %48 = xor i32 %39, 1
  %49 = or i32 %47, %48
  %50 = xor i32 %39, 1
  %51 = or i32 %49, %50
  %52 = xor i32 %39, 1
  %53 = or i32 %51, %52
  %54 = xor i32 %39, 1
  %55 = or i32 %53, %54
  %56 = trunc i64 %1 to i32
  %57 = xor i32 %56, 1
  %58 = or i32 %57, %55
  %59 = xor i32 %56, 1
  %60 = or i32 %58, %59
  %61 = xor i32 %56, 1
  %62 = or i32 %60, %61
  %63 = xor i32 %56, 1
  %64 = or i32 %62, %63
  %65 = xor i32 %56, 1
  %66 = or i32 %64, %65
  %67 = xor i32 %56, 1
  %68 = or i32 %66, %67
  %69 = xor i32 %56, 1
  %70 = or i32 %68, %69
  %71 = xor i32 %56, 1
  %72 = or i32 %70, %71
  %73 = trunc i64 %1 to i32
  %74 = xor i32 %73, 1
  %75 = or i32 %74, %72
  %76 = xor i32 %73, 1
  %77 = or i32 %75, %76
  %78 = xor i32 %73, 1
  %79 = or i32 %77, %78
  %80 = xor i32 %73, 1
  %81 = or i32 %79, %80
  %82 = xor i32 %73, 1
  %83 = or i32 %81, %82
  %84 = xor i32 %73, 1
  %85 = or i32 %83, %84
  %86 = xor i32 %73, 1
  %87 = or i32 %85, %86
  %88 = xor i32 %0, %73
  %89 = or i32 %87, %88
  %90 = xor i32 %0, %2
  %91 = or i32 %90, %89
  %92 = xor i32 %0, %2
  %93 = or i32 %91, %92
  %94 = xor i32 %0, %2
  %95 = or i32 %93, %94
  %96 = xor i32 %0, %2
  %97 = or i32 %95, %96
  %98 = trunc i64 %1 to i32
  %99 = xor i32 %98, 1
  %100 = xor i32 %98, 1
  %101 = or i32 %99, %100
  %102 = xor i32 %98, 1
  %103 = or i32 %101, %102
  %104 = xor i32 %98, 1
  %105 = or i32 %103, %104
  %106 = xor i32 %98, 1
  %107 = or i32 %105, %106
  %108 = xor i32 %98, 1
  %109 = or i32 %107, %108
  %110 = xor i32 %98, 1
  %111 = or i32 %109, %110
  %112 = xor i32 %0, %98
  %113 = or i32 %111, %112
  %114 = xor i32 %0, %3
  %115 = or i32 %113, %114
  %116 = xor i32 %0, %3
  %117 = or i32 %115, %116
  %118 = xor i32 %0, %3
  %119 = or i32 %117, %118
  %120 = xor i32 %0, %3
  %121 = or i32 %119, %120
  %122 = xor i32 %0, %3
  %123 = or i32 %121, %122
  %124 = xor i32 %0, %3
  %125 = or i32 %123, %124
  %126 = xor i32 %0, %3
  %127 = or i32 %125, %126
  %128 = xor i32 %0, %3
  %129 = or i32 %127, %128
  %130 = or i32 %129, %97
  store i32 %130, ptr %4, align 4
  ret void
}