[llvm] [LV] Vectorize histogram operations (PR #99851)
Florian Hahn via llvm-commits
llvm-commits at lists.llvm.org
Mon Aug 12 00:28:31 PDT 2024
================
@@ -1046,6 +1050,114 @@ bool LoopVectorizationLegality::canVectorizeInstrs() {
return true;
}
+/// Find histogram operations that match high-level code in loops:
+/// \code
+/// buckets[indices[i]]+=step;
+/// \endcode
+///
+/// It matches a pattern starting from \p HSt, which Stores to the 'buckets'
+/// array the computed histogram. It uses a BinOp to sum all counts, storing
+/// them using a loop-variant index Load from the 'indices' input array.
+///
+/// On successful matches it updates the STATISTIC 'HistogramsDetected',
+/// regardless of hardware support. When there is support, it additionally
+/// stores the BinOp/Load pairs in \p HistogramCounts, as well the pointers
+/// used to update histogram in \p HistogramPtrs.
+static bool findHistogram(LoadInst *LI, StoreInst *HSt, Loop *TheLoop,
+ const PredicatedScalarEvolution &PSE,
+ SmallVectorImpl<HistogramInfo> &Histograms) {
+
+ // Store value must come from a Binary Operation.
+ Instruction *HPtrInstr = nullptr;
+ BinaryOperator *HBinOp = nullptr;
+ if (!match(HSt, m_Store(m_BinOp(HBinOp), m_Instruction(HPtrInstr))))
+ return false;
+
+ // BinOp must be an Add or a Sub modifying the bucket value by a
+ // loop invariant amount.
+ // FIXME: We assume the loop invariant term is on the RHS.
+ // Fine for an immediate/constant, but maybe not a generic value?
+ Value *HIncVal = nullptr;
+ if (!match(HBinOp, m_Add(m_Load(m_Specific(HPtrInstr)), m_Value(HIncVal))) &&
+ !match(HBinOp, m_Sub(m_Load(m_Specific(HPtrInstr)), m_Value(HIncVal))))
+ return false;
+
+ // Make sure the increment value is loop invariant.
+ if (!TheLoop->isLoopInvariant(HIncVal))
+ return false;
+
+ // The address to store is calculated through a GEP Instruction.
+ GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(HPtrInstr);
+ if (!GEP)
+ return false;
+
+ // Restrict address calculation to constant indices except for the last term.
+ Value *HIdx = nullptr;
+ for (Value *Index : GEP->indices()) {
+ if (HIdx)
+ return false;
+ if (!isa<ConstantInt>(Index))
+ HIdx = Index;
+ }
+
+ if (!HIdx)
+ return false;
+
+ // Check that the index is calculated by loading from another array. Ignore
+ // any extensions.
+ // FIXME: Support indices from other sources that a linear load from memory?
+ Value *VPtrVal;
+ if (!match(HIdx, m_ZExtOrSExtOrSelf(m_Load(m_Value(VPtrVal)))))
+ return false;
+
+ if (!isa<SCEVAddRecExpr>(PSE.getSE()->getSCEV(VPtrVal)))
+ return false;
+
+ // Ensure we'll have the same mask by checking that all parts of the histogram
+ // (gather load, update, scatter store) are in the same block.
+ LoadInst *IndexedLoad = cast<LoadInst>(HBinOp->getOperand(0));
+ BasicBlock *LdBB = IndexedLoad->getParent();
+ if (LdBB != HBinOp->getParent() || LdBB != HSt->getParent())
+ return false;
+
+ LLVM_DEBUG(dbgs() << "LV: Found histogram for: " << *HSt << "\n");
+
+ // Store the operations that make up the histogram.
+ Histograms.emplace_back(IndexedLoad, HBinOp, HSt);
+ return true;
+}
+
+bool LoopVectorizationLegality::canVectorizeUncheckedDependences() {
+ // For now, we only support an unknown dependency that calculates a histogram
----------------
fhahn wrote:
unknown-> IndirectUnsafe?
https://github.com/llvm/llvm-project/pull/99851
More information about the llvm-commits
mailing list