[llvm] [LV] Vectorize selecting last IV of min/max element. (PR #141431)

Mel Chen via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 1 04:40:56 PDT 2025


================
@@ -815,3 +815,148 @@ bool VPlanTransforms::handleMaxMinNumReductions(VPlan &Plan) {
   MiddleTerm->setOperand(0, NewCond);
   return true;
 }
+
+bool VPlanTransforms::legalizeUnclassifiedPhis(VPlan &Plan) {
+  using namespace VPlanPatternMatch;
+  for (auto &PhiR : make_early_inc_range(
+           Plan.getVectorLoopRegion()->getEntryBasicBlock()->phis())) {
+    if (!isa<VPWidenPHIRecipe>(&PhiR))
+      continue;
+
+    // Check if PhiR is a min/max reduction that has a user inside the loop
+    // outside the min/max reduction chain. The other user must be the compare
+    // of a FindLastIV reduction chain.
+    auto *MinMaxPhiR = cast<VPWidenPHIRecipe>(&PhiR);
+    auto *MinMaxOp = dyn_cast_or_null<VPSingleDefRecipe>(
+        MinMaxPhiR->getOperand(1)->getDefiningRecipe());
+    if (!MinMaxOp)
+      return false;
+
+    // The incoming value must be a min/max instrinsic.
+    // TODO: Also handle the select variant.
+    Intrinsic::ID ID = Intrinsic::not_intrinsic;
+    if (auto *WideInt = dyn_cast<VPWidenIntrinsicRecipe>(MinMaxOp)) {
+      ID = WideInt->getVectorIntrinsicID();
+    } else {
+      auto *RepR = dyn_cast<VPReplicateRecipe>(MinMaxOp);
+      if (!RepR || !isa<IntrinsicInst>(RepR->getUnderlyingInstr()))
+        return false;
+      ID = cast<IntrinsicInst>(RepR->getUnderlyingInstr())->getIntrinsicID();
+    }
+    RecurKind RdxKind = RecurKind::None;
+    switch (ID) {
+    case Intrinsic::umax:
+      RdxKind = RecurKind::UMax;
+      break;
+    case Intrinsic::umin:
+      RdxKind = RecurKind::UMin;
+      break;
+    case Intrinsic::smax:
+      RdxKind = RecurKind::SMax;
+      break;
+    case Intrinsic::smin:
+      RdxKind = RecurKind::SMin;
+      break;
+    default:
+      return false;
+    }
+
+    // The min/max intrinsic must use the phi and itself must only be used by
+    // the phi and a resume-phi in the scalar preheader.
+    if (MinMaxOp->getOperand(0) != MinMaxPhiR &&
+        MinMaxOp->getOperand(1) != MinMaxPhiR)
+      return false;
+    if (MinMaxPhiR->getNumUsers() != 2 ||
+        any_of(MinMaxOp->users(), [MinMaxPhiR, &Plan](VPUser *U) {
+          auto *Phi = dyn_cast<VPPhi>(U);
+          return MinMaxPhiR != U &&
+                 (!Phi || Phi->getParent() != Plan.getScalarPreheader());
+        }))
+      return false;
+
+    // One user of MinMaxPhiR is MinMaxOp, the other users must be a compare
+    // that's part of a FindLastIV chain.
+    auto MinMaxUsers = to_vector(MinMaxPhiR->users());
+    auto *Cmp = dyn_cast<VPRecipeWithIRFlags>(
+        MinMaxUsers[0] == MinMaxOp ? MinMaxUsers[1] : MinMaxUsers[0]);
----------------
Mel-Chen wrote:

Should check the number of phi's users, like #141467 did:
```
  // TODO: support min/max with 2-D indexes.
  if (!Phi->hasNUses(2))
    return false;
```

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


More information about the llvm-commits mailing list