[llvm] [VPlan] Explicitly unroll replicate-regions without live-outs by VF. (PR #170212)
Andrei Elovikov via llvm-commits
llvm-commits at lists.llvm.org
Mon Mar 9 10:34:47 PDT 2026
================
@@ -729,3 +733,150 @@ void VPlanTransforms::replicateByVF(VPlan &Plan, ElementCount VF) {
for (auto *R : reverse(ToRemove))
R->eraseFromParent();
}
+
+/// Convert recipes in region blocks to operate on a single lane 0. Lane 0
+/// uses the original blocks, and the recipes are adjusted:
+/// VPReplicateRecipes are converted to single-scalar ones, branch-on-mask is
+/// converted into BranchOnCond and extracts are created as needed.
+static void convertRecipesInRegionBlocksToSingleScalar(
+ VPlan &Plan, Type *IdxTy, ElementCount VF,
+ ArrayRef<VPBlockBase *> RegionBlocks) {
+ for (VPBlockBase *VPB : RegionBlocks) {
+ for (VPRecipeBase &NewR : make_early_inc_range(*cast<VPBasicBlock>(VPB))) {
+ VPBuilder Builder(&NewR);
+ for (const auto &[I, Op] : enumerate(NewR.operands())) {
+ // Skip operands that don't need extraction: scalar VF (no vectors),
+ // values defined in the same block (already scalar), or values that
+ // are already single scalars.
+ auto *DefR = Op->getDefiningRecipe();
+ if (VF.isScalar() || (DefR && DefR->getParent() == VPB) ||
+ vputils::isSingleScalar(Op))
+ continue;
+
+ // Extract the lane from values defined outside the region.
+ VPValue *Idx = Plan.getConstantInt(IdxTy, 0);
+ VPValue *Extract = Builder.createNaryOp(Instruction::ExtractElement,
+ {Op, Idx}, NewR.getDebugLoc());
+ NewR.setOperand(I, Extract);
+ }
+
+ if (auto *RepR = dyn_cast<VPReplicateRecipe>(&NewR)) {
+ auto *New =
+ new VPReplicateRecipe(RepR->getUnderlyingInstr(), RepR->operands(),
+ /* IsSingleScalar=*/true, /*Mask=*/nullptr,
+ *RepR, *RepR, RepR->getDebugLoc());
+ New->insertBefore(RepR);
+ RepR->replaceAllUsesWith(New);
+ RepR->eraseFromParent();
+ } else if (auto *BranchOnMask = dyn_cast<VPBranchOnMaskRecipe>(&NewR)) {
+ Builder.createNaryOp(VPInstruction::BranchOnCond,
+ {BranchOnMask->getOperand(0)},
+ BranchOnMask->getDebugLoc());
+ BranchOnMask->eraseFromParent();
+ }
+ }
+ }
+}
+
+/// Process recipes in a single lane's blocks, updating them for lane-specific
+/// operations.
+static void processLaneForReplicateRegion(
+ VPlan &Plan, Type *IdxTy, unsigned Lane,
+ ArrayRef<VPBlockBase *> RegionBlocks,
+ DenseMap<VPBlockBase *, VPBlockBase *> &Old2NewBlocks) {
+ DenseMap<VPValue *, VPValue *> Old2NewVPValues;
+ for (VPBlockBase *OldVPB : RegionBlocks) {
+ auto *OldBB = cast<VPBasicBlock>(OldVPB);
+ auto *NewBB = cast<VPBasicBlock>(Old2NewBlocks.lookup(OldVPB));
+ for (const auto &[OldR, NewR] : zip(*OldBB, *NewBB)) {
+ for (const auto &[OldV, NewV] :
+ zip(OldR.definedValues(), NewR.definedValues()))
+ Old2NewVPValues[OldV] = NewV;
+ }
+
+ // Update lane operands and remap operands to use copies for current lane.
+ for (VPRecipeBase &NewR : make_early_inc_range(*NewBB)) {
+ if (auto *Steps = dyn_cast<VPScalarIVStepsRecipe>(&NewR)) {
+ VPBuilder Builder(Steps);
+ addStartIndexForLane(Steps, Lane, Plan, Builder);
+ } else if (match(&NewR, m_ExtractElement(m_VPValue(), m_ZeroInt()))) {
+ NewR.setOperand(1, Plan.getConstantInt(IdxTy, Lane));
----------------
eas wrote:
How do we know this `extractelement` requires updates? Isn't it possible it was uniform but sinked into the region for some reason?
https://github.com/llvm/llvm-project/pull/170212
More information about the llvm-commits
mailing list