[llvm] [VPlan] Expand VPWidenIntOrFpInductionRecipe into separate recipes (PR #118638)
Luke Lau via llvm-commits
llvm-commits at lists.llvm.org
Thu May 8 09:21:29 PDT 2025
================
@@ -2390,6 +2380,129 @@ void VPlanTransforms::createInterleaveGroups(
}
}
+/// Expand a VPWidenIntOrFpInduction into executable recipes. for the initial
+/// value, phi and backedge value. In the followng example:
+///
+/// vector.ph:
+/// Successor(s): vector loop
+///
+/// <x1> vector loop: {
+/// vector.body:
+/// WIDEN-INDUCTION %i = phi %start, %step, %vf
+/// ...
+/// EMIT branch-on-count ...
+/// No successors
+/// }
+///
+/// WIDEN-INDUCTION will get expanded to:
+///
+/// vector.ph:
+/// ...
+/// vp<%induction> = ...
+/// vp<%inc> = ...
+///
+/// Successor(s): vector loop
+///
+/// <x1> vector loop: {
+/// vector.body:
+/// ir<%i> = WIDEN-PHI vp<%induction>, vp<%vec.ind.next>
+/// ...
+/// vp<%vec.ind.next> = add ir<%i>, vp<%inc>
+/// EMIT branch-on-count ...
+/// No successors
+/// }
+static void
+expandVPWidenIntOrFpInduction(VPWidenIntOrFpInductionRecipe *WidenIVR,
+ VPTypeAnalysis &TypeInfo) {
+ VPlan *Plan = WidenIVR->getParent()->getPlan();
+ VPValue *Start = WidenIVR->getStartValue();
+ VPValue *Step = WidenIVR->getStepValue();
+ VPValue *VF = WidenIVR->getVFValue();
+ TruncInst *Trunc = WidenIVR->getTruncInst();
+ DebugLoc DL = WidenIVR->getDebugLoc();
+
+ // The value from the original loop to which we are mapping the new induction
+ // variable.
+ Instruction *IV = Trunc ? cast<Instruction>(Trunc) : WidenIVR->getPHINode();
+ Type *Ty = IV->getType();
+
+ const InductionDescriptor &ID = WidenIVR->getInductionDescriptor();
+ Instruction::BinaryOps AddOp;
+ Instruction::BinaryOps MulOp;
+ std::optional<FastMathFlags> FMFs;
+ if (ID.getKind() == InductionDescriptor::IK_IntInduction) {
+ AddOp = Instruction::Add;
+ MulOp = Instruction::Mul;
+ } else {
+ AddOp = ID.getInductionOpcode();
+ MulOp = Instruction::FMul;
+ FMFs = ID.getInductionBinOp()->getFastMathFlags();
+ }
+
+ // If the phi is truncated, truncate the start and step values.
+ VPBuilder Builder(Plan->getVectorPreheader());
+ if (isa<TruncInst>(IV)) {
+ assert(Start->getUnderlyingValue()->getType()->isIntegerTy() &&
+ "Truncation requires an integer type");
+ Step = Builder.createScalarCast(Instruction::Trunc, Step, Ty, DL);
+ Start = Builder.createScalarCast(Instruction::Trunc, Start, Ty, DL);
+ }
+
+ // Construct the initial value of the vector IV in the vector loop preheader.
+ Type *StepTy = TypeInfo.inferScalarType(Step);
+ Type *IVIntTy =
+ IntegerType::get(IV->getContext(), StepTy->getScalarSizeInBits());
+ VPValue *Init = Builder.createNaryOp(VPInstruction::StepVector, {}, IVIntTy);
+ if (StepTy->isFloatingPointTy())
+ Init = Builder.createWidenCast(Instruction::UIToFP, Init, StepTy);
+
+ VPValue *SplatStart = Builder.createNaryOp(VPInstruction::Broadcast, Start);
+ VPValue *SplatStep = Builder.createNaryOp(VPInstruction::Broadcast, Step);
+
+ // FIXME: The newly created binary instructions should contain nsw/nuw
+ // flags, which can be found from the original scalar operations.
+ Init = Builder.createNaryOp(MulOp, {Init, SplatStep}, FMFs);
+ Init = Builder.createNaryOp(AddOp, {SplatStart, Init}, FMFs, {}, "induction");
+
+ // Create the widened phi of the vector IV.
+ auto *WidePHI =
+ new VPWidenPHIRecipe(IV, nullptr, WidenIVR->getDebugLoc(), "vec.ind");
+ WidePHI->addOperand(Init);
+ WidePHI->insertBefore(WidenIVR);
+
+ // Create the backedge value for the vector IV.
+ VPValue *Inc;
+ VPValue *Prev;
+ // If unrolled, use the increment and prev value from the operands.
+ if (auto *SplatVF = WidenIVR->getSplatVFValue()) {
+ Inc = SplatVF;
+ Prev = WidenIVR->getLastUnrolledPartOperand();
+ } else {
+ // Multiply the vectorization factor by the step using integer or
+ // floating-point arithmetic as appropriate.
+ if (StepTy->isFloatingPointTy())
+ VF = Builder.createScalarCast(Instruction::CastOps::UIToFP, VF, StepTy,
+ DL);
+ else
+ VF =
+ Builder.createScalarCast(Instruction::CastOps::Trunc, VF, StepTy, DL);
+
+ Inc = Builder.createNaryOp(MulOp, {Step, VF}, FMFs);
+ Inc = Builder.createNaryOp(VPInstruction::Broadcast, Inc);
----------------
lukel97 wrote:
I'm reusing VPInstruction::Broadcast here to splat the vectors, hope that's ok. I also experimented with moving `materializeBroadcasts` to after `convertToConcreteRecipes` to see if we could avoid the need for the explicit broadcasts here, but it looks like it only handles live-ins and not arbitrary VPValues at the moment.
https://github.com/llvm/llvm-project/pull/118638
More information about the llvm-commits
mailing list