[llvm] [SLP] Bail out on store-to-load forwarding hazards (PR #199606)

Alexey Bataev via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 12 13:07:42 PDT 2026


================
@@ -28257,6 +28285,110 @@ bool SLPVectorizerPass::runImpl(Function &F, ScalarEvolution *SE_,
   return Changed;
 }
 
+bool BoUpSLP::findStoreLoadForwardingConflict(StoreInst *BaseStore,
+                                              unsigned VF) {
+  if (!BaseStore)
+    return false;
+
+  StoreInst *FirstStore = BaseStore;
+
+  // Memoize per (store, VF); the entry is re-costed repeatedly.
+  auto Key = std::make_pair(FirstStore, VF);
+  auto CacheIt = StlfConflictCache.find(Key);
+  if (CacheIt != StlfConflictCache.end())
+    return CacheIt->second;
+
+  auto CacheAndReturn = [&](bool Result) -> bool {
+    StlfConflictCache[Key] = Result;
+    // No conflict at VF implies none at any smaller VF that divides VF, so seed
+    // those entries too. The recency window is VF-independent (so it stays
+    // satisfied for any smaller width), and the distance remains a multiple of
+    // V * ElementSize only for divisors of VF. This covers the power-of-2
+    // ladder (each smaller power of 2 divides the larger) and any
+    // non-power-of-2 VF the caller may probe. Conflicts do not propagate
+    // downward.
+    if (!Result)
+      for (unsigned V = 2; V < VF; ++V)
+        if (VF % V == 0)
+          StlfConflictCache.try_emplace(std::make_pair(FirstStore, V), false);
+    return Result;
+  };
+
+  Type *ValueTy = FirstStore->getValueOperand()->getType();
+  TypeSize StoreSize = DL->getTypeStoreSize(ValueTy);
+  if (StoreSize.isScalable())
+    return CacheAndReturn(false);
+  uint64_t ElementSize = StoreSize.getFixedValue();
+  if (ElementSize == 0)
+    return CacheAndReturn(false);
+
+  // Store-to-load forwarding hazards are a loop-carried concern.
+  if (!LI->getLoopFor(FirstStore->getParent()))
+    return CacheAndReturn(false);
+
+  uint64_t VectorStoreBytes = VF * ElementSize;
+  LLVM_DEBUG(dbgs() << "SLP: STLF check: VF=" << VF
+                    << " ElementSize=" << ElementSize
+                    << " VectorStoreBytes=" << VectorStoreBytes << "\n");
+
+  // Enumerate candidate loads directly from the tree's load and gather nodes: a
+  // conflicting load is either widened (a load node) or packed into a gather
+  // leaf (e.g. a splat), so scanning those node kinds is sufficient.
+  Value *StoreBase = getUnderlyingObject(FirstStore->getPointerOperand());
+  SmallPtrSet<LoadInst *, 8> CandidateLoads;
+  for (const std::unique_ptr<TreeEntry> &TEPtr : VectorizableTree) {
+    const TreeEntry *TE = TEPtr.get();
+    if (DeletedNodes.contains(TE))
+      continue;
----------------
alexey-bataev wrote:

Also, need to check for TransformedToGathers

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


More information about the llvm-commits mailing list