[llvm] [VPlan] Convert EVL loops to variable-length stepping after dissolution (PR #147222)

Luke Lau via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 17 09:16:25 PDT 2025


================
@@ -2357,6 +2357,64 @@ bool VPlanTransforms::tryAddExplicitVectorLength(
   return true;
 }
 
+void VPlanTransforms::simplifyEVLIVs(VPlan &Plan) {
+  auto ConvertEVLPhi = [](VPlan &Plan, VPBasicBlock *Entry,
+                          VPEVLBasedIVPHIRecipe *EVLPhi) {
+    using namespace llvm::VPlanPatternMatch;
+    VPValue *EVLIncrement = EVLPhi->getBackedgeValue();
+
+    // Convert EVLPhi to concrete recipe.
+    auto *ScalarR = VPBuilder(EVLPhi).createScalarPhi(
+        {EVLPhi->getStartValue(), EVLIncrement}, EVLPhi->getDebugLoc(),
+        "evl.based.iv");
+    EVLPhi->replaceAllUsesWith(ScalarR);
+    EVLPhi->eraseFromParent();
+
+    // Find the latch-exiting block and convert to variable-length stepping.
+    // Before: (branch-on-count CanonicalIVInc, VectorTripCount)
+    // After: (branch-on-count EVLIVInc, TripCount)
+    auto Range =
+        VPBlockUtils::blocksOnly<VPBasicBlock>(vp_depth_first_shallow(Entry));
+    auto It = find_if(Range, [&](VPBasicBlock *VPBB) {
+      return any_of(VPBB->successors(),
+                    [&](VPBlockBase *Succ) { return Succ == Entry; });
+    });
+    assert((It != Range.end()) && "LatchExiting is not found");
+    VPBasicBlock *LatchExiting = *It;
+    auto *LatchExitingBr = cast<VPInstruction>(LatchExiting->getTerminator());
+    VPValue *ScalarIVInc;
+    assert(LatchExitingBr &&
+           match(LatchExitingBr,
+                 m_BranchOnCount(m_VPValue(ScalarIVInc),
+                                 m_Specific(&Plan.getVectorTripCount()))) &&
+           "Unexpected terminator in EVL loop");
+    LatchExitingBr->setOperand(1, Plan.getTripCount());
+    ScalarIVInc->replaceAllUsesWith(EVLIncrement);
+    VPRecipeBase *IVIncR = ScalarIVInc->getDefiningRecipe();
+    VPRecipeBase *ScalarIV = IVIncR->getOperand(0)->getDefiningRecipe();
+    IVIncR->eraseFromParent();
+    ScalarIV->eraseFromParent();
+  };
+
+  // Find EVL loop entries by locating VPEVLBasedIVPHIRecipe
+  // There should be only one EVL PHI in the entire plan
+  VPEVLBasedIVPHIRecipe *EVLPhi = nullptr;
+  VPBasicBlock *EVLPhiBlock = nullptr;
+
+  for (VPBasicBlock *VPBB : VPBlockUtils::blocksOnly<VPBasicBlock>(
+           vp_depth_first_shallow(Plan.getEntry())))
+    for (VPRecipeBase &R : VPBB->phis())
+      if (auto *PhiR = dyn_cast<VPEVLBasedIVPHIRecipe>(&R)) {
+        assert(!EVLPhi && "Found multiple EVL PHIs - only one expected");
+        EVLPhi = PhiR;
+        EVLPhiBlock = VPBB;
+      }
+
+  // Process the single EVL PHI if found
+  if (EVLPhi)
+    ConvertEVLPhi(Plan, EVLPhiBlock, EVLPhi);
----------------
lukel97 wrote:

If we just early return then I think we can remove the ConvertEVLPhi lambda too?

```suggestion
  if (!EVLPhi)
    return;
  
  // ... inline ConvertEVLPhi here
```

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


More information about the llvm-commits mailing list