Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
6391ca9
[VPlan] Don't reset canonical IV start value.
fhahn Aug 29, 2025
9361797
[VPlan] Make canonical IV part of the region
fhahn Jun 5, 2025
c709ab9
!fixup address latest comments, thanks
fhahn Oct 5, 2025
84bd5ef
[VPlan] Don't reset canonical IV start value.
fhahn Aug 29, 2025
bb0c0ac
Merge remote-tracking branch 'origin/main' into vplan-can-iv-dont-reset
fhahn Oct 11, 2025
5cb548e
!fixup address latest comments, thanks
fhahn Oct 11, 2025
93b05f2
Merge branch 'vplan-can-iv-dont-reset' into vplan-caniv-defined-by-re…
fhahn Oct 11, 2025
959d673
!fixup update remaining tests.
fhahn Oct 12, 2025
00fa5fb
Merge remote-tracking branch 'origin/main' into vplan-caniv-defined-b…
fhahn Oct 16, 2025
2c423d3
!fixup address latest comments, thansk
fhahn Oct 16, 2025
1503c71
[VPlan] Add getCanonicalIVType (NFC).
fhahn Oct 18, 2025
8bc50a6
Merge branch 'vplan-region-getcanonicalivtype' into vplan-caniv-defin…
fhahn Oct 18, 2025
96f41f5
Merge remote-tracking branch 'origin/main' into vplan-caniv-defined-b…
fhahn Oct 19, 2025
14f70e4
Merge remote-tracking branch 'origin/main' into vplan-caniv-defined-b…
fhahn Oct 21, 2025
580865a
!fixup address latest comments, thanks
fhahn Oct 21, 2025
d103bef
Merge remote-tracking branch 'origin/main' into vplan-caniv-defined-b…
fhahn Oct 21, 2025
cf165c5
Merge remote-tracking branch 'origin/main' into vplan-caniv-defined-b…
fhahn Oct 21, 2025
1832282
!fixup fix after merge.
fhahn Oct 21, 2025
05643fd
Merge remote-tracking branch 'origin/main' into vplan-caniv-defined-b…
fhahn Nov 1, 2025
6c35c36
!fixup store defining region.
fhahn Nov 1, 2025
005b24c
Merge remote-tracking branch 'origin/main' into vplan-caniv-defined-b…
fhahn Nov 10, 2025
102396a
!fixup address comments, thanks
fhahn Nov 10, 2025
320164a
Merge remote-tracking branch 'origin/main' into vplan-caniv-defined-b…
fhahn Nov 10, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 10 additions & 16 deletions llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4060,7 +4060,6 @@ static bool willGenerateVectors(VPlan &Plan, ElementCount VF,
case VPDef::VPScalarIVStepsSC:
case VPDef::VPReplicateSC:
case VPDef::VPInstructionSC:
case VPDef::VPCanonicalIVPHISC:
case VPDef::VPVectorPointerSC:
case VPDef::VPVectorEndPointerSC:
case VPDef::VPExpandSCEVSC:
Expand Down Expand Up @@ -8328,6 +8327,7 @@ VPlanPtr LoopVectorizationPlanner::tryToBuildVPlanWithVPRecipes(
m_Specific(LoopRegion->getCanonicalIV()), m_VPValue())) &&
"Did not find the canonical IV increment");
cast<VPRecipeWithIRFlags>(IVInc)->dropPoisonGeneratingFlags();
LoopRegion->clearCanonicalIVNUW();
}

// ---------------------------------------------------------------------------
Expand Down Expand Up @@ -8385,13 +8385,12 @@ VPlanPtr LoopVectorizationPlanner::tryToBuildVPlanWithVPRecipes(
for (VPRecipeBase &R : make_early_inc_range(*VPBB)) {
auto *SingleDef = cast<VPSingleDefRecipe>(&R);
auto *UnderlyingValue = SingleDef->getUnderlyingValue();
// Skip recipes that do not need transforming, including canonical IV,
// wide canonical IV and VPInstructions without underlying values. The
// Skip recipes that do not need transforming, including blends,
// widened canonical IV and VPInstructions without underlying values. The
// latter are added above for masking.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replace "including canonical IV," above with "including blends,"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done thanks

// FIXME: Migrate code relying on the underlying instruction from VPlan0
// to construct recipes below to not use the underlying instruction.
if (isa<VPCanonicalIVPHIRecipe, VPWidenCanonicalIVRecipe, VPBlendRecipe>(
&R) ||
if (isa<VPWidenCanonicalIVRecipe, VPBlendRecipe>(&R) ||
(isa<VPInstruction>(&R) && !UnderlyingValue))
continue;
assert(isa<VPInstruction>(&R) && UnderlyingValue && "unsupported recipe");
Expand Down Expand Up @@ -8578,8 +8577,6 @@ VPlanPtr LoopVectorizationPlanner::tryToBuildVPlan(VFRange &Range) {
VPRecipeBuilder RecipeBuilder(*Plan, OrigLoop, TLI, &TTI, Legal, CM, PSE,
Builder, BlockMaskCache, nullptr /*LVer*/);
for (auto &R : Plan->getVectorLoopRegion()->getEntryBasicBlock()->phis()) {
if (isa<VPCanonicalIVPHIRecipe>(&R))
continue;
auto *HeaderR = cast<VPHeaderPHIRecipe>(&R);
RecipeBuilder.setRecipe(HeaderR->getUnderlyingInstr(), HeaderR);
}
Expand Down Expand Up @@ -9334,8 +9331,6 @@ static void preparePlanForMainVectorLoop(VPlan &MainPlan, VPlan &EpiPlan) {
SmallPtrSet<PHINode *, 2> EpiWidenedPhis;
for (VPRecipeBase &R :
EpiPlan.getVectorLoopRegion()->getEntryBasicBlock()->phis()) {
if (isa<VPCanonicalIVPHIRecipe>(&R))
continue;
EpiWidenedPhis.insert(
cast<PHINode>(R.getVPSingleValue()->getUnderlyingValue()));
}
Expand Down Expand Up @@ -9396,10 +9391,10 @@ static void preparePlanForMainVectorLoop(VPlan &MainPlan, VPlan &EpiPlan) {
VPPhi *ResumePhi = nullptr;
if (ResumePhiIter == MainScalarPH->phis().end()) {
VPBuilder ScalarPHBuilder(MainScalarPH, MainScalarPH->begin());
Type *Ty = VPTypeAnalysis(MainPlan).inferScalarType(VectorTC);
ResumePhi = ScalarPHBuilder.createScalarPhi(
{VectorTC,
MainPlan.getVectorLoopRegion()->getCanonicalIV()->getStartValue()},
{}, "vec.epilog.resume.val");
{VectorTC, MainPlan.getConstantInt(Ty, 0)}, {},
"vec.epilog.resume.val");
} else {
ResumePhi = cast<VPPhi>(&*ResumePhiIter);
if (MainScalarPH->begin() == MainScalarPH->end())
Expand All @@ -9426,7 +9421,6 @@ static SmallVector<Instruction *> preparePlanForEpilogueVectorLoop(
VPBasicBlock *Header = VectorLoop->getEntryBasicBlock();
Header->setName("vec.epilog.vector.body");

VPCanonicalIVPHIRecipe *IV = VectorLoop->getCanonicalIV();
// When vectorizing the epilogue loop, the canonical induction needs to be
// adjusted by the value after the main vector loop. Find the resume value
// created during execution of the main VPlan. It must be the first phi in the
Expand Down Expand Up @@ -9456,6 +9450,7 @@ static SmallVector<Instruction *> preparePlanForEpilogueVectorLoop(
EPI.VectorTripCount = EPResumeVal->getOperand(0);
}
VPValue *VPV = Plan.getOrAddLiveIn(EPResumeVal);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Independent: better rename VPV

VPValue *IV = VectorLoop->getCanonicalIV();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This replaces an if (auto *IV = dyn_cast...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep originally part of the loop

assert(all_of(IV->users(),
[](const VPUser *U) {
return isa<VPScalarIVStepsRecipe>(U) ||
Expand All @@ -9474,9 +9469,8 @@ static SmallVector<Instruction *> preparePlanForEpilogueVectorLoop(
DenseMap<Value *, Value *> ToFrozen;
SmallVector<Instruction *> InstsToMove;
// Ensure that the start values for all header phi recipes are updated before
// vectorizing the epilogue loop. Skip the canonical IV, which has been
// handled above.
for (VPRecipeBase &R : drop_begin(Header->phis())) {
// vectorizing the epilogue loop.
for (VPRecipeBase &R : Header->phis()) {
Value *ResumeV = nullptr;
// TODO: Move setting of resume values to prepareToExecute.
if (auto *ReductionPhi = dyn_cast<VPReductionPHIRecipe>(&R)) {
Expand Down
83 changes: 71 additions & 12 deletions llvm/lib/Transforms/Vectorize/VPlan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,14 @@ void VPDef::dump() const {
#endif

VPRecipeBase *VPValue::getDefiningRecipe() {
if (SubclassID == VPRegionValueSC)
return nullptr;
return cast_or_null<VPRecipeBase>(Def);
}

const VPRecipeBase *VPValue::getDefiningRecipe() const {
if (SubclassID == VPRegionValueSC)
return nullptr;
return cast_or_null<VPRecipeBase>(Def);
}

Expand Down Expand Up @@ -731,10 +735,13 @@ VPRegionBlock *VPRegionBlock::clone() {
VPRegionBlock *NewRegion =
isReplicator()
? Plan.createReplicateRegion(NewEntry, NewExiting, getName())
: Plan.createLoopRegion(getName(), NewEntry, NewExiting);
: Plan.createLoopRegion(CanIVInfo->getType(),
CanIVInfo->getDebugLoc(), getName(), NewEntry,
NewExiting);

for (VPBlockBase *Block : vp_depth_first_shallow(NewEntry))
Block->setParent(NewRegion);

return NewRegion;
}

Expand Down Expand Up @@ -819,6 +826,11 @@ void VPRegionBlock::print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const {
O << Indent << (isReplicator() ? "<xVFxUF> " : "<x1> ") << getName() << ": {";
auto NewIndent = Indent + " ";
if (!isReplicator()) {
O << '\n';
getCanonicalIV()->print(O, SlotTracker);
O << " = CANONICAL-IV\n";
}
for (auto *BlockBase : vp_depth_first_shallow(Entry)) {
O << '\n';
BlockBase->print(O, NewIndent, SlotTracker);
Expand All @@ -831,18 +843,29 @@ void VPRegionBlock::print(raw_ostream &O, const Twine &Indent,

void VPRegionBlock::dissolveToCFGLoop() {
auto *Header = cast<VPBasicBlock>(getEntry());
if (auto *CanIV = dyn_cast<VPCanonicalIVPHIRecipe>(&Header->front())) {
assert(this == getPlan()->getVectorLoopRegion() &&
"Canonical IV must be in the entry of the top-level loop region");
auto *ScalarR = VPBuilder(CanIV).createScalarPhi(
{CanIV->getStartValue(), CanIV->getBackedgeValue()},
CanIV->getDebugLoc(), "index");
auto *ExitingLatch = cast<VPBasicBlock>(getExiting());
VPValue *CanIV = getCanonicalIV();
if (CanIV && CanIV->getNumUsers() > 0) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth documenting somewhere that CanIV should continue to exist (until loop region dissolves) even w/o users, i.e., avoid dce, as its existence indicates region loopness, and provides other information such as type; plus users might conceptually be introduced late(?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, added to CanIVInfo, thanks

VPlan &Plan = *getPlan();
VPInstruction *CanIVInc = getCanonicalIVIncrement();
// If the increment doesn't exist yet, create it.
if (!CanIVInc) {
auto *ExitingTerm = ExitingLatch->getTerminator();
CanIVInc =
VPBuilder(ExitingTerm)
.createOverflowingOp(Instruction::Add, {CanIV, &Plan.getVFxUF()},
{CanIVInfo->hasNUW(), /* HasNSW */ false},
CanIVInfo->getDebugLoc(), "index.next");
}
auto *ScalarR =
VPBuilder(Header, Header->begin())
.createScalarPhi(
{Plan.getConstantInt(CanIVInfo->getType(), 0), CanIVInc},
CanIVInfo->getDebugLoc(), "index");
CanIV->replaceAllUsesWith(ScalarR);
CanIV->eraseFromParent();
}

VPBlockBase *Preheader = getSinglePredecessor();
auto *ExitingLatch = cast<VPBasicBlock>(getExiting());
VPBlockBase *Middle = getSingleSuccessor();
VPBlockUtils::disconnectBlocks(Preheader, this);
VPBlockUtils::disconnectBlocks(this, Middle);
Expand All @@ -855,6 +878,25 @@ void VPRegionBlock::dissolveToCFGLoop() {
VPBlockUtils::connectBlocks(ExitingLatch, Header);
}

VPInstruction *VPRegionBlock::getCanonicalIVIncrement() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Follow-up: represent CanIVInc as a region VPValue too?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, added a TODO

// TODO: Represent the increment as VPRegionValue as well.
auto *ExitingLatch = cast<VPBasicBlock>(getExiting());
VPValue *CanIV = getCanonicalIV();
assert(CanIV && "Expected a canonical IV");

auto *ExitingTerm = ExitingLatch->getTerminator();
VPInstruction *CanIVInc = nullptr;
if (match(ExitingTerm,
m_BranchOnCount(m_VPInstruction(CanIVInc), m_VPValue()))) {
assert(match(CanIVInc,
m_c_Add(m_CombineOr(m_Specific(CanIV),
m_c_Add(m_Specific(CanIV), m_LiveIn())),
m_VPValue())) &&
"invalid existing IV increment");
}
Comment on lines +889 to +896
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok to only have an assert under an if?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep I think it should be fine, alternative is capturing the result of the match in a variable, marking it as maybe unusued and use that in the assert

return CanIVInc;
}

VPlan::VPlan(Loop *L) {
setEntry(createVPIRBasicBlock(L->getLoopPreheader()));
ScalarHeader = createVPIRBasicBlock(L->getHeader());
Expand All @@ -879,7 +921,11 @@ VPlan::~VPlan() {
for (unsigned I = 0, E = R.getNumOperands(); I != E; I++)
R.setOperand(I, &DummyValue);
}
} else if (!cast<VPRegionBlock>(VPB)->isReplicator()) {
cast<VPRegionBlock>(VPB)->getCanonicalIV()->replaceAllUsesWith(
&DummyValue);
}

delete VPB;
}
for (VPValue *VPV : getLiveIns())
Expand Down Expand Up @@ -1187,6 +1233,14 @@ VPlan *VPlan::duplicate() {
// else NewTripCount will be created and inserted into Old2NewVPValues when
// TripCount is cloned. In any case NewPlan->TripCount is updated below.

if (auto *LoopRegion = getVectorLoopRegion()) {
assert(LoopRegion->getCanonicalIV() &&
NewPlan->getVectorLoopRegion()->getCanonicalIV() &&
"Loop regions of both plans must have canonical IVs.");
Old2NewVPValues[LoopRegion->getCanonicalIV()] =
NewPlan->getVectorLoopRegion()->getCanonicalIV();
}

remapOperands(Entry, NewEntry, Old2NewVPValues);

// Initialize remaining fields of cloned VPlan.
Expand Down Expand Up @@ -1367,6 +1421,8 @@ void VPlanPrinter::dumpRegion(const VPRegionBlock *Region) {
/// Returns true if there is a vector loop region and \p VPV is defined in a
/// loop region.
static bool isDefinedInsideLoopRegions(const VPValue *VPV) {
if (isa<VPRegionValue>(VPV))
return true;
const VPRecipeBase *DefR = VPV->getDefiningRecipe();
return DefR && (!DefR->getParent()->getPlan()->getVectorLoopRegion() ||
DefR->getParent()->getEnclosingLoopRegion());
Expand Down Expand Up @@ -1476,9 +1532,12 @@ void VPSlotTracker::assignNames(const VPlan &Plan) {

ReversePostOrderTraversal<VPBlockDeepTraversalWrapper<const VPBlockBase *>>
RPOT(VPBlockDeepTraversalWrapper<const VPBlockBase *>(Plan.getEntry()));
for (const VPBasicBlock *VPBB :
VPBlockUtils::blocksOnly<const VPBasicBlock>(RPOT))
assignNames(VPBB);
for (const VPBlockBase *VPB : RPOT) {
if (auto *VPBB = dyn_cast<VPBasicBlock>(VPB))
assignNames(VPBB);
else if (!cast<VPRegionBlock>(VPB)->isReplicator())
assignName(cast<VPRegionBlock>(VPB)->getCanonicalIV());
Comment on lines +1538 to +1539
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can also introduce assignName(VPRegionBlock) which will take care of assigning a name to its canonical IV if it's a loop region.

}
}

void VPSlotTracker::assignNames(const VPBasicBlock *VPBB) {
Expand Down
Loading
Loading