[llvm] [VPlan] Add transform to replace VPWidenCanonicalIV with wide IV. (PR #194267)

Florian Hahn via llvm-commits llvm-commits at lists.llvm.org
Tue Apr 28 01:53:48 PDT 2026


================
@@ -691,6 +691,73 @@ static void removeRedundantCanonicalIVs(VPlan &Plan) {
   }
 }
 
+void VPlanTransforms::replaceWidenCanonicalIVWithWidenIV(
+    VPlan &Plan, ScalarEvolution &SE, const TargetTransformInfo &TTI,
+    TargetTransformInfo::TargetCostKind CostKind, ElementCount VF,
+    unsigned UF) {
+  VPRegionBlock *LoopRegion = Plan.getVectorLoopRegion();
+  if (!LoopRegion || Plan.hasScalarVFOnly())
+    return;
+
+  VPValue *CanonicalIV = LoopRegion->getCanonicalIV();
+  auto *WideCanIV = vputils::findUserOf<VPWidenCanonicalIVRecipe>(CanonicalIV);
+  if (!WideCanIV)
+    return;
+
+  // If a canonical VPWidenIntOrFpInductionRecipe already exists, reuse it.
+  VPBasicBlock *Header = LoopRegion->getEntryBasicBlock();
+  for (VPRecipeBase &Phi : Header->phis()) {
+    auto *WideIV = dyn_cast<VPWidenIntOrFpInductionRecipe>(&Phi);
+    if (!WideIV || !WideIV->isCanonical())
+      continue;
+    // The canonical wide IV is used to compute the header mask, hence all
+    // lanes will be used. Drop poison-generating flags.
+    WideIV->dropPoisonGeneratingFlags();
+    WideCanIV->replaceAllUsesWith(WideIV);
+    WideCanIV->eraseFromParent();
+    return;
+  }
+
+  // Otherwise, introduce a new VPWidenIntOrFpInductionRecipe if profitable.
+  if (vputils::onlyFirstLaneUsed(WideCanIV) ||
+      vputils::onlyScalarValuesUsed(WideCanIV))
+    return;
+
+  Type *CanIVTy = LoopRegion->getCanonicalIVType();
+  auto *VecTy = VectorType::get(CanIVTy, VF);
+  InstructionCost BroadcastCost = TTI.getShuffleCost(
+      TargetTransformInfo::SK_Broadcast, VecTy, VecTy, {}, CostKind);
+  InstructionCost PHICost = TTI.getCFInstrCost(Instruction::PHI, CostKind);
+  if (PHICost > BroadcastCost)
+    return;
+
+  // Bail out if the wide induction phis increase the expected spill cost.
+  SmallPtrSet<const Value *, 1> ValuesToIgnore;
+  VPRegisterUsage UnrolledBase =
+      calculateRegisterUsageForPlan(Plan, {VF}, TTI, ValuesToIgnore)[0];
+  for (auto &Pair : UnrolledBase.MaxLocalUsers)
+    Pair.second *= UF;
+  unsigned RegClass = TTI.getRegisterClassForType(/*Vector=*/true, VecTy);
+  VPRegisterUsage Projected = UnrolledBase;
+  Projected.MaxLocalUsers[RegClass] += UF;
+  if (Projected.spillCost(TTI, CostKind) >
+      UnrolledBase.spillCost(TTI, CostKind))
+    return;
----------------
fhahn wrote:

not sure, we only need to do the check if we have a VPWidenCanonialIVRecipe, and cannot re-use an existing wide IV. We could pass a lambda, but not sure that's worth it?

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


More information about the llvm-commits mailing list