[llvm] [VPlan] Optimize FindLast of (binop %IV, live-in) by sinking. (PR #183911)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Mar 31 05:22:41 PDT 2026
================
@@ -5695,25 +5695,64 @@ void VPlanTransforms::addExitUsersForFirstOrderRecurrences(VPlan &Plan,
}
}
+/// Check if \p V is a binary expression of a widened IV and a loop-invariant
+/// value. Returns the widened IV if found, nullptr otherwise.
+static VPWidenIntOrFpInductionRecipe *getExpressionIV(VPValue *V) {
+ auto *BinOp = dyn_cast<VPWidenRecipe>(V);
+ if (!BinOp || !Instruction::isBinaryOp(BinOp->getOpcode()))
+ return nullptr;
+
+ VPValue *WidenIVCandidate = BinOp->getOperand(0);
+ VPValue *InvariantCandidate = BinOp->getOperand(1);
+ if (!isa<VPWidenIntOrFpInductionRecipe>(WidenIVCandidate))
+ std::swap(WidenIVCandidate, InvariantCandidate);
+
+ if (!InvariantCandidate->isDefinedOutsideLoopRegions())
+ return nullptr;
+
+ return dyn_cast<VPWidenIntOrFpInductionRecipe>(WidenIVCandidate);
+}
+
+/// Create a scalar version of \p BinOp and place it after \p ScalarIV's
+/// defining recipe, replacing \p WidenIV with \p ScalarIV.
+static VPValue *cloneBinOpForScalarIV(VPWidenRecipe *BinOp, VPValue *ScalarIV,
+ VPWidenIntOrFpInductionRecipe *WidenIV) {
+ assert(Instruction::isBinaryOp(BinOp->getOpcode()) &&
+ BinOp->getNumOperands() == 2 && "BinOp must have 2 operands");
+ auto *ClonedOp = BinOp->clone();
+ if (ClonedOp->getOperand(0) == WidenIV) {
+ ClonedOp->setOperand(0, ScalarIV);
+ } else {
+ assert(ClonedOp->getOperand(1) == WidenIV && "one operand must be WideIV");
+ ClonedOp->setOperand(1, ScalarIV);
+ }
+ ClonedOp->insertAfter(ScalarIV->getDefiningRecipe());
+ return ClonedOp;
+}
+
void VPlanTransforms::optimizeFindIVReductions(VPlan &Plan,
PredicatedScalarEvolution &PSE,
Loop &L) {
ScalarEvolution &SE = *PSE.getSE();
VPRegionBlock *VectorLoopRegion = Plan.getVectorLoopRegion();
- // Helper lambda to check if the IV range excludes the sentinel value.
- auto CheckSentinel = [&SE](const SCEV *IVSCEV, bool UseMax,
- bool Signed) -> std::optional<APInt> {
+ // Helper lambda to check if the IV range excludes the sentinel value. Try
+ // signed first, then unsigned.
+ auto CheckSentinel =
+ [&SE](const SCEV *IVSCEV,
+ bool UseMax) -> std::optional<std::pair<APInt, bool>> {
unsigned BW = IVSCEV->getType()->getScalarSizeInBits();
- APInt Sentinel =
- UseMax
- ? (Signed ? APInt::getSignedMinValue(BW) : APInt::getMinValue(BW))
- : (Signed ? APInt::getSignedMaxValue(BW) : APInt::getMaxValue(BW));
-
- ConstantRange IVRange =
- Signed ? SE.getSignedRange(IVSCEV) : SE.getUnsignedRange(IVSCEV);
- if (!IVRange.contains(Sentinel))
- return Sentinel;
+ for (bool Signed : {true, false}) {
+ APInt Sentinel = UseMax ? (Signed ? APInt::getSignedMinValue(BW)
+ : APInt::getMinValue(BW))
+ : (Signed ? APInt::getSignedMaxValue(BW)
+ : APInt::getMaxValue(BW));
+
+ ConstantRange IVRange =
----------------
ayalz wrote:
Ah, this use of min/max is in the final reduction of partial LastIV's, one per lane, after the loop.
For this min/max to work, the IV recorded inside the loop must not wrap.
If largest/smallest value works as sentinel, then this IV doesn't wrap.
If the IV wraps yet its IVRange isn't full, one could use a "canonical" IV instead which starts at 1, which will not wrap (unsigned). As if a binary expression "IV + offset" is used which turns a non-wrapping IV into a wrapping one. I.e., a case where a sentinel can be found for the original IV, but not for the expression. It is also possible that such an expression turns a wrapping IV into a non-wrapping one. Perhaps such cases should best be canonicalized/normalized to use a "canonical" IV (rather than derivatives thereof) which starts at 1 (rather than 0) and bumps by 1 (rather than VFxUF) - which never wraps, even if the original/vector IV may, because VFxUF > 1, sinking derivative expressions out of the loop; potentially hoisting back "shriking" expressions that may use IV of smaller bitwidth if possible and profitable.
https://github.com/llvm/llvm-project/pull/183911
More information about the llvm-commits
mailing list