[llvm] [SLPVectorizer] Widen constant strided loads. (PR #162324)
Mikhail Gudim via llvm-commits
llvm-commits at lists.llvm.org
Mon Nov 17 00:15:57 PST 2025
================
@@ -6942,32 +6941,101 @@ bool BoUpSLP::analyzeConstantStrideCandidate(
const SmallVectorImpl<unsigned> &SortedIndices, const int64_t Diff,
Value *Ptr0, Value *PtrN, StridedPtrInfo &SPtrInfo) const {
const size_t Sz = PointerOps.size();
- if (!isStridedLoad(PointerOps, ScalarTy, Alignment, Diff, Sz))
+ SmallVector<int64_t> SortedOffsetsFromBase(Sz);
+ // Go through `PointerOps` in sorted order and record offsets from `Ptr0`.
+ for (unsigned I : seq<unsigned>(Sz)) {
+ Value *Ptr =
+ SortedIndices.empty() ? PointerOps[I] : PointerOps[SortedIndices[I]];
+ SortedOffsetsFromBase[I] =
+ *getPointersDiff(ScalarTy, Ptr0, ScalarTy, Ptr, *DL, *SE);
+ }
+
+ // The code below checks that `SortedOffsetsFromBase` looks as follows:
+ // ```
+ // [
+ // (e_{0, 0}, e_{0, 1}, ..., e_{0, GroupSize - 1}), // first group
+ // (e_{1, 0}, e_{1, 1}, ..., e_{1, GroupSize - 1}), // secon group
+ // ...
+ // (e_{NumGroups - 1, 0}, e_{NumGroups - 1, 1}, ..., e_{NumGroups - 1,
+ // GroupSize - 1}), // last group
+ // ]
+ // ```
+ // The distance between consecutive elements within each group should all be
+ // the same `StrideWithinGroup`. The distance between the first elements of
+ // consecutive groups should all be the same `StrideBetweenGroups`.
+
+ int64_t StrideWithinGroup =
+ SortedOffsetsFromBase[1] - SortedOffsetsFromBase[0];
+ // Determine size of the first group. Later we will check that all other
+ // groups have the same size.
+ auto IsEndOfGroupIndex = [=, &SortedOffsetsFromBase](unsigned Idx) {
+ return SortedOffsetsFromBase[Idx] - SortedOffsetsFromBase[Idx - 1] !=
+ StrideWithinGroup;
+ };
+ auto Indices = seq<unsigned>(1, Sz);
+ auto FoundIt = llvm::find_if(Indices, IsEndOfGroupIndex);
+ unsigned GroupSize = FoundIt != Indices.end() ? *FoundIt : Sz;
+
+ unsigned VecSz = Sz;
+ Type *NewScalarTy = ScalarTy;
+ FixedVectorType *StridedLoadTy = getWidenedType(NewScalarTy, VecSz);
+
+ // Quick detour: at this point we can say what the type of strided load would
+ // be if all the checks pass. Check if this type is legal for the target.
+ bool NeedsWidening = Sz != GroupSize;
+ if (NeedsWidening) {
+ if (Sz % GroupSize != 0)
+ return false;
+ VecSz = Sz / GroupSize;
+
+ if (StrideWithinGroup != 1)
+ return false;
+ unsigned VecSz = Sz / GroupSize;
+ NewScalarTy = Type::getIntNTy(
+ SE->getContext(),
+ DL->getTypeSizeInBits(ScalarTy).getFixedValue() * GroupSize);
+ StridedLoadTy = getWidenedType(NewScalarTy, VecSz);
+ }
+
+ if (!isStridedLoad(PointerOps, NewScalarTy, Alignment, Diff, VecSz))
return false;
- int64_t Stride = Diff / static_cast<int64_t>(Sz - 1);
+ int64_t StrideIntVal = StrideWithinGroup;
+ if (NeedsWidening) {
+ // Continue with checking the "shape" of `SortedOffsetsFromBase`.
+ // Check that the strides between groups are all the same.
+ unsigned CurrentGroupStartIdx = GroupSize;
+ int64_t StrideBetweenGroups =
+ SortedOffsetsFromBase[GroupSize] - SortedOffsetsFromBase[0];
+ StrideIntVal = StrideBetweenGroups;
+ for (; CurrentGroupStartIdx < Sz; CurrentGroupStartIdx += GroupSize) {
+ if (SortedOffsetsFromBase[CurrentGroupStartIdx] -
+ SortedOffsetsFromBase[CurrentGroupStartIdx - GroupSize] !=
+ StrideBetweenGroups)
+ return false;
+ }
- // Iterate through all pointers and check if all distances are
- // unique multiple of Dist.
- SmallSet<int64_t, 4> Dists;
- for (Value *Ptr : PointerOps) {
- int64_t Dist = 0;
- if (Ptr == PtrN)
- Dist = Diff;
- else if (Ptr != Ptr0)
- Dist = *getPointersDiff(ScalarTy, Ptr0, ScalarTy, Ptr, *DL, *SE);
- // If the strides are not the same or repeated, we can't
- // vectorize.
- if (((Dist / Stride) * Stride) != Dist || !Dists.insert(Dist).second)
- break;
- }
- if (Dists.size() == Sz) {
- Type *StrideTy = DL->getIndexType(Ptr0->getType());
- SPtrInfo.StrideVal = ConstantInt::get(StrideTy, Stride);
- SPtrInfo.Ty = getWidenedType(ScalarTy, Sz);
- return true;
+ auto CheckGroup = [&](const unsigned StartIdx, const unsigned GroupSize0,
+ const int64_t StrideWithinGroup) -> bool {
+ unsigned GroupEndIdx = StartIdx + 1;
+ for (; GroupEndIdx != Sz; ++GroupEndIdx) {
+ if (SortedOffsetsFromBase[GroupEndIdx] -
+ SortedOffsetsFromBase[GroupEndIdx - 1] !=
+ StrideWithinGroup)
+ break;
----------------
mgudim wrote:
done
https://github.com/llvm/llvm-project/pull/162324
More information about the llvm-commits
mailing list