-
Notifications
You must be signed in to change notification settings - Fork 14.5k
[VPlan] Convert EVL loops to variable-length stepping after dissolution #147222
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
0234453
c969cf8
5008301
c82b31a
b1ec544
4bd4bf3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -2357,6 +2357,71 @@ bool VPlanTransforms::tryAddExplicitVectorLength( | |||||
return true; | ||||||
} | ||||||
|
||||||
void VPlanTransforms::simplifyEVLIVs(VPlan &Plan) { | ||||||
using namespace llvm::VPlanPatternMatch; | ||||||
// Find EVL loop entries by locating VPEVLBasedIVPHIRecipe | ||||||
// There should be only one EVL PHI in the entire plan | ||||||
VPEVLBasedIVPHIRecipe *EVLPhi = 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; | ||||||
} | ||||||
|
||||||
// Early return if no EVL PHI is found | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
if (!EVLPhi) | ||||||
return; | ||||||
|
||||||
VPBasicBlock *Entry = EVLPhi->getParent(); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
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(); | ||||||
|
||||||
// Replace CanonicalIVInc with EVL-PHI increment | ||||||
VPRecipeBase *CanonicalIV = &*Entry->begin(); | ||||||
assert(dyn_cast<VPPhi>(CanonicalIV) && "Unexpected canoincal iv"); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we can use an isa to check
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should probably at least also check if the backedge value is |
||||||
VPValue *Backedge = CanonicalIV->getOperand(1); | ||||||
Backedge->replaceAllUsesWith(EVLIncrement); | ||||||
|
||||||
// Remove unused phi | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit
Suggested change
|
||||||
VPRecipeBase *CanonicalIVIncrement = Backedge->getDefiningRecipe(); | ||||||
CanonicalIVIncrement->eraseFromParent(); | ||||||
CanonicalIV->eraseFromParent(); | ||||||
|
||||||
// Find the latch-exiting block and replace use of VectorTripCount | ||||||
// Before: (branch-on-count EVLIVInc, VectorTripCount) | ||||||
// After: (branch-on-count EVLIVInc, TripCount) | ||||||
auto Range = | ||||||
VPBlockUtils::blocksOnly<VPBasicBlock>(vp_depth_first_shallow(Entry)); | ||||||
auto It = find_if(Range, [&Entry](VPBasicBlock *VPBB) { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. looking for the latch could be done by just getting the second predecessor of the header? |
||||||
return any_of(VPBB->successors(), | ||||||
[&Entry](VPBlockBase *Succ) { return Succ == Entry; }); | ||||||
}); | ||||||
assert((It != Range.end()) && "LatchExiting is not found"); | ||||||
|
||||||
VPBasicBlock *LatchExiting = *It; | ||||||
|
||||||
auto *LatchExitingBr = cast<VPInstruction>(LatchExiting->getTerminator()); | ||||||
|
||||||
// Skip single-iteration loop region | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
if (match(LatchExitingBr, m_BranchOnCond(m_True()))) | ||||||
return; | ||||||
assert(LatchExitingBr && | ||||||
match(LatchExitingBr, | ||||||
m_BranchOnCount(m_VPValue(EVLIncrement), | ||||||
m_Specific(&Plan.getVectorTripCount()))) && | ||||||
"Unexpected terminator in EVL loop"); | ||||||
LatchExitingBr->setOperand(1, Plan.getTripCount()); | ||||||
} | ||||||
|
||||||
void VPlanTransforms::dropPoisonGeneratingRecipes( | ||||||
VPlan &Plan, | ||||||
const std::function<bool(BasicBlock *)> &BlockNeedsPredication) { | ||||||
|
@@ -2688,15 +2753,6 @@ void VPlanTransforms::convertToConcreteRecipes(VPlan &Plan, | |||||
for (VPBasicBlock *VPBB : VPBlockUtils::blocksOnly<VPBasicBlock>( | ||||||
vp_depth_first_deep(Plan.getEntry()))) { | ||||||
for (VPRecipeBase &R : make_early_inc_range(*VPBB)) { | ||||||
if (auto *PhiR = dyn_cast<VPEVLBasedIVPHIRecipe>(&R)) { | ||||||
auto *ScalarR = VPBuilder(PhiR).createScalarPhi( | ||||||
{PhiR->getStartValue(), PhiR->getBackedgeValue()}, | ||||||
PhiR->getDebugLoc(), "evl.based.iv"); | ||||||
PhiR->replaceAllUsesWith(ScalarR); | ||||||
ToRemove.push_back(PhiR); | ||||||
continue; | ||||||
} | ||||||
|
||||||
if (auto *WidenIVR = dyn_cast<VPWidenIntOrFpInductionRecipe>(&R)) { | ||||||
expandVPWidenIntOrFpInduction(WidenIVR, TypeInfo); | ||||||
ToRemove.push_back(WidenIVR); | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -193,6 +193,17 @@ struct VPlanTransforms { | |
/// Replace loop regions with explicit CFG. | ||
static void dissolveLoopRegions(VPlan &Plan); | ||
|
||
/// Transform EVL loops to use variable-length stepping after region | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This does more, it also converts EVL based phi recipe to plain scalar phi |
||
/// dissolution. | ||
/// | ||
/// Once loop regions are replaced with explicit CFG, EVL loops can step with | ||
/// variable vector lengths instead of fixed lengths. This transformation: | ||
/// * EVL-Phi concretization (makes them concrete) | ||
/// * Replaces fixed-length stepping (branch-on-cond CanonicalIVInc, | ||
/// VectorTripCount) with variable-length stepping (branch-on-cond | ||
/// EVLIVInc, TripCount). | ||
static void simplifyEVLIVs(VPlan &Plan); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure if the name is accurate, EVLIVs aren't really simplified, but the canonical IV is replaced by EVL-based phi? |
||
|
||
/// Lower abstract recipes to concrete ones, that can be codegen'd. Use \p | ||
/// CanonicalIVTy as type for all un-typed live-ins in VPTypeAnalysis. | ||
static void convertToConcreteRecipes(VPlan &Plan, Type &CanonicalIVTy); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -192,7 +192,9 @@ bool VPlanVerifier::verifyEVLRecipe(const VPInstruction &EVL) const { | |
errs() << "EVL used by unexpected VPInstruction\n"; | ||
return false; | ||
} | ||
if (I->getNumUsers() != 1) { | ||
// EVLIVIncrement is only used by EVLIV & BranchOnCount. | ||
// More than two is unexpected. | ||
if (I->getNumUsers() > 2) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This needs to verify that the other user is BranchOnCount? |
||
errs() << "EVL is used in VPInstruction with multiple users\n"; | ||
return false; | ||
} | ||
|
Uh oh!
There was an error while loading. Please reload this page.