[llvm] [SLP] Create SLP trees starting from constant stride stores (PR #175126)

Ryan Buchner via llvm-commits llvm-commits at lists.llvm.org
Tue Jan 13 14:50:55 PST 2026


================
@@ -23884,32 +23920,98 @@ bool SLPVectorizerPass::vectorizeStores(
   bool Changed = false;
 
   auto TryToVectorize = [&](const RelatedStoreInsts::DistToInstMap &StoreSeq) {
-    int64_t PrevDist = -1;
-    BoUpSLP::ValueList Operands;
-    // Collect the chain into a list.
+    struct OperandsT {
+      BoUpSLP::ValueList Ops;
+      unsigned Stride;
+      OperandsT(std::initializer_list<Value *> Ops, unsigned Stride)
+          : Ops(Ops), Stride(Stride) {};
+
+      bool operator>(const OperandsT &Other) const {
+        auto GetScore = [](const OperandsT &Ops) -> unsigned {
+          return Ops.Ops.size() / ((Ops.Stride == 1) ? 1 : 2);
+        };
+        return GetScore(*this) > GetScore(Other);
+      }
+    };
+    SmallVector<OperandsT> AllOperands;
+    // All chains that we're still building
+    // - bool: Has been added to AllOperands, if just single operand, don't add
+    // yet
+    // - unsigned: Idx into either AllOperands or Stores depending on if added
+    // already
+    // - unsigned: Stride size
+    SmallVector<SmallVector<std::tuple<bool, unsigned, unsigned>, 1>> Chains(
+        MaxProfitableStride + 2);
+    auto GetChainsKey = [&](int64_t Query) -> unsigned {
+      // Just modulo function, get the index into Chains for a given query
+      int64_t Rem = (Query % (int64_t)Chains.size());
+      if (Rem < 0)
+        Rem += (int64_t)Chains.size();
+      return (unsigned)Rem;
+    };
+    int64_t LastDist;
     for (auto [Idx, Data] : enumerate(StoreSeq)) {
       auto &[Dist, InstIdx] = Data;
-      if (Operands.empty() || Dist - PrevDist == 1) {
-        Operands.push_back(Stores[InstIdx]);
-        PrevDist = Dist;
-        if (Idx != StoreSeq.size() - 1)
+      // Clean up chains that can't be continued
+      if (Idx > 0)
+        for (int64_t D = LastDist; D < Dist; ++D) {
+          Chains[GetChainsKey(D)].clear();
+        }
+      LastDist = Dist;
+
+      // Track which stride lengths we found existing chains for
+      // Don't have to add new entries for these
+      SmallVector<bool> FoundStrides(MaxProfitableStride + 1, false);
+      for (auto [IsAllOpsIdx, OpIdx, Stride] : Chains[GetChainsKey(Dist)]) {
+        if (IsAllOpsIdx) {
+          // Chain already in AllOperands()
+          AllOperands[OpIdx].Ops.push_back(Stores[InstIdx]);
+        } else {
+          // Chain just a single element, not yet in AllOperands()
+          AllOperands.emplace_back(
+              std::initializer_list<Value *>{Stores[OpIdx], Stores[InstIdx]},
+              Stride);
+          OpIdx = AllOperands.size() - 1;
+        }
+        unsigned Key = GetChainsKey(Stride + Dist);
+        Chains[Key].push_back({true, OpIdx, Stride});
+        FoundStrides[Stride] = true;
+      }
+
+      // For any stride lengths that we didn't append to a chain for,
+      // instead start a new chain
+      for (auto Stride : seq<unsigned>(
+               1, (EnableStridedStores ? MaxProfitableStride : 1) + 1)) {
+        if (FoundStrides[Stride])
           continue;
+        unsigned Key = GetChainsKey(Dist + Stride);
+        Chains[Key].push_back({false, InstIdx, Stride});
       }
-      llvm::scope_exit E([&, &Dist = Dist, &InstIdx = InstIdx]() {
-        Operands.clear();
-        Operands.push_back(Stores[InstIdx]);
-        PrevDist = Dist;
-      });
+    }
 
+    // Try longer chains first
+    std::sort(AllOperands.begin(), AllOperands.end(),
+              std::greater<OperandsT>());
+    for (auto &[RawOperands, Stride] : AllOperands) {
+      bool Strided = Stride != 1;
+
+      unsigned FirstAlive = RawOperands.size();
+      for (unsigned Idx : seq<unsigned>(RawOperands.size()))
+        if (!R.isDeleted(cast<Instruction>(RawOperands[Idx]))) {
----------------
bababuck wrote:

Use `VectorizedStores` instead.

https://github.com/llvm/llvm-project/pull/175126


More information about the llvm-commits mailing list