[llvm] [SLP] Support ordered fadd reduction via reduction intrinsics (PR #189451)
Ryan Buchner via llvm-commits
llvm-commits at lists.llvm.org
Sun May 10 11:46:36 PDT 2026
================
@@ -29185,6 +29277,239 @@ class HorizontalReduction {
return VectorizedTree;
}
+ /// Attempt to vectorize an ordered (linearized) reduction chain.
+ /// Reduced values from matchOrderedReduction() are in accumulation order.
+ /// Vectorized subsets are immediately reduced via ordered reduction
+ /// intrinsics; non-vectorized values are folded linearly.
+ Value *tryToReduceOrdered(BoUpSLP &V, const DataLayout &DL,
+ TargetTransformInfo *TTI,
+ const TargetLibraryInfo &TLI, AssumptionCache *AC,
+ DominatorTree &DT) {
+ constexpr unsigned RegMaxNumber = 4;
+ constexpr unsigned RedValsMaxNumber = 128;
+
+ assert(RK == ReductionOrdering::Ordered && "Expected ordered reduction");
+ assert(ReducedVals.size() == 1 &&
+ "Expected single group from matchOrderedReduction");
+
+ IRBuilder<TargetFolder> Builder(ReductionRoot->getContext(),
+ TargetFolder(DL));
+ Instruction *RdxRootInst = cast<Instruction>(ReductionRoot);
+ Builder.SetInsertPoint(RdxRootInst);
+
+ SmallVector<Value *> Candidates(ReducedVals.back());
+
+ // Intersect the fast-math-flags from all reduction operations.
+ FastMathFlags RdxFMF;
+ RdxFMF.set();
+ for (Value *RdxVal : Candidates)
+ for (Instruction *Op : ReducedValsToOps.at(RdxVal))
+ if (auto *FPMO = dyn_cast<FPMathOperator>(Op))
+ RdxFMF &= FPMO->getFastMathFlags();
+
+ unsigned MaxVecRegSize = V.getMaxVecRegSize();
+ unsigned EltSize = V.getVectorElementSize(Candidates[0]);
+ const unsigned MaxElts =
+ std::clamp<unsigned>(llvm::bit_floor(MaxVecRegSize / EltSize),
+ RedValsMaxNumber, RegMaxNumber * RedValsMaxNumber);
+
+ unsigned ReduxWidth = 0;
+ auto GetVectorFactor = [&, &TTI = *TTI](unsigned ReduxWidth) {
+ Type *ScalarTy = Candidates.front()->getType();
+ ReduxWidth =
+ getFloorFullVectorNumberOfElements(TTI, ScalarTy, ReduxWidth);
+ VectorType *Tp = getWidenedType(ScalarTy, ReduxWidth);
+ unsigned NumParts = ::getNumberOfParts(TTI, Tp, ScalarTy);
+ unsigned NumRegs =
+ TTI.getNumberOfRegisters(TTI.getRegisterClassForType(true, Tp));
+ while (NumParts > NumRegs) {
+ assert(ReduxWidth > 0 && "ReduxWidth is unexpectedly 0.");
+ ReduxWidth = bit_floor(ReduxWidth - 1);
+ VectorType *Tp = getWidenedType(ScalarTy, ReduxWidth);
+ NumParts = ::getNumberOfParts(TTI, Tp, ScalarTy);
+ NumRegs =
+ TTI.getNumberOfRegisters(TTI.getRegisterClassForType(true, Tp));
+ }
+ if (NumParts > NumRegs / 2)
+ ReduxWidth = bit_floor(ReduxWidth);
+ return ReduxWidth;
+ };
+ auto ShrinkReduxWidth = [&]() {
+ --ReduxWidth;
+ if (ReduxWidth > 1)
+ ReduxWidth = GetVectorFactor(ReduxWidth);
+ };
+
+ // Try to build, cost-check, and vectorize a window [Start, Start+Width).
+ unsigned SuccessStart = 0, SuccessWidth = 0;
+ Value *SuccessRoot = nullptr;
+ SmallMapVector<Value *, unsigned, 16> EmptySameValuesCounter;
+ auto TryWindow = [&](unsigned Start, unsigned Width) -> bool {
+ ArrayRef<Value *> VL = ArrayRef(Candidates).slice(Start, Width);
+ if (V.areAnalyzedReductionVals(VL))
+ return false;
+ if (any_of(VL, [&V](Value *RedVal) {
+ auto *RedValI = dyn_cast<Instruction>(RedVal);
+ return RedValI && V.isDeleted(RedValI);
+ }))
+ return false;
+
+ SmallDenseSet<Value *> IgnoreList;
+ for (Value *RdxVal : VL)
+ for (Instruction *Op : ReducedValsToOps.at(RdxVal))
+ IgnoreList.insert(Op);
+
+ V.buildTree(VL, IgnoreList);
+ if (V.isTreeTinyAndNotFullyVectorizable(false)) {
+ V.analyzedReductionVals(VL);
+ return false;
+ }
+ V.reorderTopToBottom();
+ V.reorderBottomToTop();
+
+ BoUpSLP::ExtraValueToDebugLocsMap LocalExternallyUsedValues;
+ LocalExternallyUsedValues.insert(ReductionRoot);
+ for (unsigned Cnt : seq<unsigned>(Candidates.size())) {
+ if (Cnt >= Start && Cnt < Start + Width)
+ continue;
+ if (isa<Instruction>(Candidates[Cnt]))
+ LocalExternallyUsedValues.insert(Candidates[Cnt]);
+ }
+
+ V.transformNodes();
+ V.computeMinimumValueSizes();
+ InstructionCost TreeCost = V.calculateTreeCostAndTrimNonProfitable(VL);
+ V.buildExternalUses(LocalExternallyUsedValues);
+
+ InstructionCost ReductionCost =
+ getReductionCost(TTI, VL, EmptySameValuesCounter,
+ /*IsCmpSelMinMax=*/false, RdxFMF, V, DT, DL, TLI);
+ InstructionCost Cost =
+ V.getTreeCost(TreeCost, VL, ReductionCost, RdxRootInst);
+ LLVM_DEBUG(dbgs() << "SLP: Found cost = " << Cost
+ << " for ordered reduction\n");
+ if (Cost > -SLPCostThreshold ||
+ (Cost == -SLPCostThreshold && V.getTreeSize() > 1)) {
----------------
bababuck wrote:
What's special about this case?
https://github.com/llvm/llvm-project/pull/189451
More information about the llvm-commits
mailing list