-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[VPlan] Implement cloning of VPlans. #73158
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
Changes from all commits
13a26e8
bbbe8ae
de00ebd
945e4fe
5a84586
b08c11b
9b1f6b3
6068940
0033a40
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 |
---|---|---|
|
@@ -615,6 +615,54 @@ void VPBasicBlock::print(raw_ostream &O, const Twine &Indent, | |
} | ||
#endif | ||
|
||
static std::pair<VPBlockBase *, VPBlockBase *> cloneSESE(VPBlockBase *Entry); | ||
|
||
// Clone the CFG for all nodes in the single-entry-single-exit region reachable | ||
// from \p Entry, this includes cloning the blocks and their recipes. Operands | ||
// of cloned recipes will NOT be updated. Remapping of operands must be done | ||
// separately. Returns a pair with the the new entry and exiting blocks of the | ||
// cloned region. | ||
static std::pair<VPBlockBase *, VPBlockBase *> cloneSESE(VPBlockBase *Entry) { | ||
DenseMap<VPBlockBase *, VPBlockBase *> Old2NewVPBlocks; | ||
ReversePostOrderTraversal<VPBlockShallowTraversalWrapper<VPBlockBase *>> RPOT( | ||
Entry); | ||
for (VPBlockBase *BB : RPOT) { | ||
VPBlockBase *NewBB = BB->clone(); | ||
for (VPBlockBase *Pred : BB->getPredecessors()) | ||
VPBlockUtils::connectBlocks(Old2NewVPBlocks[Pred], NewBB); | ||
|
||
Old2NewVPBlocks[BB] = NewBB; | ||
} | ||
|
||
#if !defined(NDEBUG) | ||
// Verify that the order of predecessors and successors matches in the cloned | ||
// version. | ||
ReversePostOrderTraversal<VPBlockShallowTraversalWrapper<VPBlockBase *>> | ||
NewRPOT(Old2NewVPBlocks[Entry]); | ||
for (const auto &[OldBB, NewBB] : zip(RPOT, NewRPOT)) { | ||
for (const auto &[OldPred, NewPred] : | ||
zip(OldBB->getPredecessors(), NewBB->getPredecessors())) | ||
assert(NewPred == Old2NewVPBlocks[OldPred] && "Different predecessors"); | ||
|
||
for (const auto &[OldSucc, NewSucc] : | ||
zip(OldBB->successors(), NewBB->successors())) | ||
assert(NewSucc == Old2NewVPBlocks[OldSucc] && "Different successors"); | ||
} | ||
#endif | ||
|
||
return std::make_pair(Old2NewVPBlocks[Entry], | ||
Old2NewVPBlocks[*reverse(RPOT).begin()]); | ||
} | ||
|
||
VPRegionBlock *VPRegionBlock::clone() { | ||
const auto &[NewEntry, NewExiting] = cloneSESE(getEntry()); | ||
auto *NewRegion = | ||
new VPRegionBlock(NewEntry, NewExiting, getName(), isReplicator()); | ||
for (VPBlockBase *Block : vp_depth_first_shallow(NewEntry)) | ||
Block->setParent(NewRegion); | ||
return NewRegion; | ||
} | ||
|
||
void VPRegionBlock::dropAllReferences(VPValue *NewValue) { | ||
for (VPBlockBase *Block : vp_depth_first_shallow(Entry)) | ||
// Drop all references in VPBasicBlocks and replace all uses with | ||
|
@@ -983,6 +1031,87 @@ void VPlan::updateDominatorTree(DominatorTree *DT, BasicBlock *LoopHeaderBB, | |
assert(DT->verify(DominatorTree::VerificationLevel::Fast)); | ||
} | ||
|
||
static void remapOperands(VPBlockBase *Entry, VPBlockBase *NewEntry, | ||
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. Should 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 left it as is, as keeping it is quite long and having it separate makes it a bit easier to read IMO (also reduces one level of indent), but happy to move it preferred. |
||
DenseMap<VPValue *, VPValue *> &Old2NewVPValues) { | ||
// Update the operands of all cloned recipes starting at NewEntry. This | ||
// traverses all reachable blocks. This is done in two steps, to handle cycles | ||
// in PHI recipes. | ||
ReversePostOrderTraversal<VPBlockDeepTraversalWrapper<VPBlockBase *>> | ||
OldDeepRPOT(Entry); | ||
ReversePostOrderTraversal<VPBlockDeepTraversalWrapper<VPBlockBase *>> | ||
NewDeepRPOT(NewEntry); | ||
// First, collect all mappings from old to new VPValues defined by cloned | ||
// recipes. | ||
for (const auto &[OldBB, NewBB] : | ||
zip(VPBlockUtils::blocksOnly<VPBasicBlock>(OldDeepRPOT), | ||
VPBlockUtils::blocksOnly<VPBasicBlock>(NewDeepRPOT))) { | ||
assert(OldBB->getRecipeList().size() == NewBB->getRecipeList().size() && | ||
"blocks must have the same number of recipes"); | ||
for (const auto &[OldR, NewR] : zip(*OldBB, *NewBB)) { | ||
assert(OldR.getNumOperands() == NewR.getNumOperands() && | ||
"recipes must have the same number of operands"); | ||
assert(OldR.getNumDefinedValues() == NewR.getNumDefinedValues() && | ||
"recipes must define the same number of operands"); | ||
for (const auto &[OldV, NewV] : | ||
zip(OldR.definedValues(), NewR.definedValues())) | ||
Old2NewVPValues[OldV] = NewV; | ||
} | ||
} | ||
|
||
// Update all operands to use cloned VPValues. | ||
for (VPBasicBlock *NewBB : | ||
VPBlockUtils::blocksOnly<VPBasicBlock>(NewDeepRPOT)) { | ||
for (VPRecipeBase &NewR : *NewBB) | ||
for (unsigned I = 0, E = NewR.getNumOperands(); I != E; ++I) { | ||
VPValue *NewOp = Old2NewVPValues.lookup(NewR.getOperand(I)); | ||
NewR.setOperand(I, NewOp); | ||
} | ||
} | ||
} | ||
|
||
VPlan *VPlan::duplicate() { | ||
// Clone blocks. | ||
VPBasicBlock *NewPreheader = Preheader->clone(); | ||
const auto &[NewEntry, __] = cloneSESE(Entry); | ||
|
||
// Create VPlan, clone live-ins and remap operands in the cloned blocks. | ||
auto *NewPlan = new VPlan(NewPreheader, cast<VPBasicBlock>(NewEntry)); | ||
DenseMap<VPValue *, VPValue *> Old2NewVPValues; | ||
for (VPValue *OldLiveIn : VPLiveInsToFree) { | ||
VPValue *NewLiveIn = new VPValue(OldLiveIn->getLiveInIRValue()); | ||
NewPlan->VPLiveInsToFree.push_back(NewLiveIn); | ||
Old2NewVPValues[OldLiveIn] = NewLiveIn; | ||
} | ||
Old2NewVPValues[&VectorTripCount] = &NewPlan->VectorTripCount; | ||
Old2NewVPValues[&VFxUF] = &NewPlan->VFxUF; | ||
if (BackedgeTakenCount) { | ||
NewPlan->BackedgeTakenCount = new VPValue(); | ||
Old2NewVPValues[BackedgeTakenCount] = NewPlan->BackedgeTakenCount; | ||
} | ||
assert(TripCount && "trip count must be set"); | ||
if (TripCount->isLiveIn()) | ||
Old2NewVPValues[TripCount] = new VPValue(TripCount->getLiveInIRValue()); | ||
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. // else NewTripCount will be created and inserted into 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. Added, thanks! |
||
// else NewTripCount will be created and inserted into Old2NewVPValues when | ||
// TripCount is cloned. In any case NewPlan->TripCount is updated below. | ||
|
||
remapOperands(Preheader, NewPreheader, Old2NewVPValues); | ||
remapOperands(Entry, NewEntry, Old2NewVPValues); | ||
|
||
// Clone live-outs. | ||
for (const auto &[_, LO] : LiveOuts) | ||
NewPlan->addLiveOut(LO->getPhi(), Old2NewVPValues[LO->getOperand(0)]); | ||
|
||
// Initialize remaining fields of cloned VPlan. | ||
NewPlan->VFs = VFs; | ||
NewPlan->UFs = UFs; | ||
// TODO: Adjust names. | ||
NewPlan->Name = Name; | ||
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. Some attention should be given to renaming, of all clones. Would be good to leave behind a note to resolve later, if not now. 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. Added a TODO to adjust names, thanks! |
||
assert(Old2NewVPValues.contains(TripCount) && | ||
"TripCount must have been added to Old2NewVPValues"); | ||
NewPlan->TripCount = Old2NewVPValues[TripCount]; | ||
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: can assert that Old2NewVPValues contains TripCount. 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. Added, thanks! |
||
return NewPlan; | ||
} | ||
|
||
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) | ||
|
||
Twine VPlanPrinter::getUID(const VPBlockBase *Block) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Return
Old2NewVPBlocks[Entry]
along with (the last)NewBB
, or along withOld2NewVPBlocks[Exit]
where Exit = *RPOT->end()?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated, thanks!