Skip to content

Commit

Permalink
[VPlan] Manage created blocks directly in VPlan. (NFC)
Browse files Browse the repository at this point in the history
This patch changes the way blocks are managed by VPlan. Previously all
blocks reachable from entry would be cleaned up when a VPlan is
destroyed. With this patch, each VPlan keeps track of blocks created for
it in a list and this list is then used to delete all blocks in the list
when the VPlan is destroyed. To do so, block creation is funneled
through helpers in directly in VPlan.

The main advantage of doing so is it simplifies CFG transformations, as
those do not have to take care of deleting any blocks, just adjusting
the CFG. This helps to simplify
llvm#108378 and
llvm#106748.

This also simplifies handling of 'immutable' blocks a VPlan holds
references to, which at the moment only include the scalar
header block.

Note that the original constructors taking VPBlockBase are retained at
the moment for unit tests.
  • Loading branch information
fhahn committed Dec 22, 2024
1 parent c5492e3 commit 83f4c78
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 71 deletions.
7 changes: 3 additions & 4 deletions llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2477,7 +2477,7 @@ static void introduceCheckBlockInVPlan(VPlan &Plan, BasicBlock *CheckIRBB) {
assert(PreVectorPH->getNumSuccessors() == 2 && "Expected 2 successors");
assert(PreVectorPH->getSuccessors()[0] == ScalarPH &&
"Unexpected successor");
VPIRBasicBlock *CheckVPIRBB = VPIRBasicBlock::fromBasicBlock(CheckIRBB);
VPIRBasicBlock *CheckVPIRBB = Plan.createVPIRBasicBlock(CheckIRBB);
VPBlockUtils::insertOnEdge(PreVectorPH, VectorPH, CheckVPIRBB);
PreVectorPH = CheckVPIRBB;
}
Expand Down Expand Up @@ -8185,11 +8185,10 @@ EpilogueVectorizerEpilogueLoop::emitMinimumVectorEpilogueIterCountCheck(

// A new entry block has been created for the epilogue VPlan. Hook it in, as
// otherwise we would try to modify the entry to the main vector loop.
VPIRBasicBlock *NewEntry = VPIRBasicBlock::fromBasicBlock(Insert);
VPIRBasicBlock *NewEntry = Plan.createVPIRBasicBlock(Insert);
VPBasicBlock *OldEntry = Plan.getEntry();
VPBlockUtils::reassociateBlocks(OldEntry, NewEntry);
Plan.setEntry(NewEntry);
delete OldEntry;

introduceCheckBlockInVPlan(Plan, Insert);
return Insert;
Expand Down Expand Up @@ -9335,7 +9334,7 @@ LoopVectorizationPlanner::tryToBuildVPlanWithVPRecipes(VFRange &Range) {
VPBB->appendRecipe(Recipe);
}

VPBlockUtils::insertBlockAfter(new VPBasicBlock(), VPBB);
VPBlockUtils::insertBlockAfter(Plan->createVPBasicBlock(""), VPBB);
VPBB = cast<VPBasicBlock>(VPBB->getSingleSuccessor());
}

Expand Down
84 changes: 52 additions & 32 deletions llvm/lib/Transforms/Vectorize/VPlan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -205,11 +205,6 @@ VPBlockBase *VPBlockBase::getEnclosingBlockWithPredecessors() {
return Parent->getEnclosingBlockWithPredecessors();
}

void VPBlockBase::deleteCFG(VPBlockBase *Entry) {
for (VPBlockBase *Block : to_vector(vp_depth_first_shallow(Entry)))
delete Block;
}

VPBasicBlock::iterator VPBasicBlock::getFirstNonPhi() {
iterator It = begin();
while (It != end() && It->isPhi())
Expand Down Expand Up @@ -474,6 +469,16 @@ void VPIRBasicBlock::execute(VPTransformState *State) {
connectToPredecessors(State->CFG);
}

VPIRBasicBlock *VPIRBasicBlock::clone() {
auto *NewBlock = getPlan()->createVPIRBasicBlock(IRBB);
for (VPRecipeBase &R : make_early_inc_range(*NewBlock))
R.eraseFromParent();

for (VPRecipeBase &R : Recipes)
NewBlock->appendRecipe(R.clone());
return NewBlock;
}

void VPBasicBlock::execute(VPTransformState *State) {
bool Replica = bool(State->Lane);
BasicBlock *NewBB = State->CFG.PrevBB; // Reuse it if possible.
Expand Down Expand Up @@ -523,6 +528,13 @@ void VPBasicBlock::dropAllReferences(VPValue *NewValue) {
}
}

VPBasicBlock *VPBasicBlock::clone() {
auto *NewBlock = getPlan()->createVPBasicBlock(getName());
for (VPRecipeBase &R : *this)
NewBlock->appendRecipe(R.clone());
return NewBlock;
}

void VPBasicBlock::executeRecipes(VPTransformState *State, BasicBlock *BB) {
LLVM_DEBUG(dbgs() << "LV: vectorizing VPBB:" << getName()
<< " in BB:" << BB->getName() << '\n');
Expand All @@ -541,7 +553,7 @@ VPBasicBlock *VPBasicBlock::splitAt(iterator SplitAt) {

SmallVector<VPBlockBase *, 2> Succs(successors());
// Create new empty block after the block to split.
auto *SplitBlock = new VPBasicBlock(getName() + ".split");
auto *SplitBlock = getPlan()->createVPBasicBlock(getName() + ".split");
VPBlockUtils::insertBlockAfter(SplitBlock, this);

// Finally, move the recipes starting at SplitAt to new block.
Expand Down Expand Up @@ -701,8 +713,8 @@ static std::pair<VPBlockBase *, VPBlockBase *> cloneFrom(VPBlockBase *Entry) {

VPRegionBlock *VPRegionBlock::clone() {
const auto &[NewEntry, NewExiting] = cloneFrom(getEntry());
auto *NewRegion =
new VPRegionBlock(NewEntry, NewExiting, getName(), isReplicator());
auto *NewRegion = getPlan()->createVPRegionBlock(NewEntry, NewExiting,
getName(), isReplicator());
for (VPBlockBase *Block : vp_depth_first_shallow(NewEntry))
Block->setParent(NewRegion);
return NewRegion;
Expand Down Expand Up @@ -822,32 +834,27 @@ void VPRegionBlock::print(raw_ostream &O, const Twine &Indent,
#endif

VPlan::VPlan(Loop *L) {
setEntry(VPIRBasicBlock::fromBasicBlock(L->getLoopPreheader()));
ScalarHeader = VPIRBasicBlock::fromBasicBlock(L->getHeader());
setEntry(createVPIRBasicBlock(L->getLoopPreheader()));
ScalarHeader = createVPIRBasicBlock(L->getHeader());
}

VPlan::~VPlan() {
if (Entry) {
VPValue DummyValue;
for (VPBlockBase *Block : vp_depth_first_shallow(Entry))
Block->dropAllReferences(&DummyValue);

VPBlockBase::deleteCFG(Entry);
for (auto *VPB : reverse(CreatedBlocks))
VPB->dropAllReferences(&DummyValue);

for (auto *VPB : reverse(CreatedBlocks)) {
delete VPB;
}
}
for (VPValue *VPV : VPLiveInsToFree)
delete VPV;
if (BackedgeTakenCount)
delete BackedgeTakenCount;
}

VPIRBasicBlock *VPIRBasicBlock::fromBasicBlock(BasicBlock *IRBB) {
auto *VPIRBB = new VPIRBasicBlock(IRBB);
for (Instruction &I :
make_range(IRBB->begin(), IRBB->getTerminator()->getIterator()))
VPIRBB->appendRecipe(new VPIRInstruction(I));
return VPIRBB;
}

VPlanPtr VPlan::createInitialVPlan(Type *InductionTy,
PredicatedScalarEvolution &PSE,
bool RequiresScalarEpilogueCheck,
Expand All @@ -861,7 +868,7 @@ VPlanPtr VPlan::createInitialVPlan(Type *InductionTy,
// an epilogue vector loop, the original entry block here will be replaced by
// a new VPIRBasicBlock wrapping the entry to the epilogue vector loop after
// generating code for the main vector loop.
VPBasicBlock *VecPreheader = new VPBasicBlock("vector.ph");
VPBasicBlock *VecPreheader = Plan->createVPBasicBlock("vector.ph");
VPBlockUtils::connectBlocks(Plan->getEntry(), VecPreheader);

// Create SCEV and VPValue for the trip count.
Expand All @@ -878,17 +885,17 @@ VPlanPtr VPlan::createInitialVPlan(Type *InductionTy,

// Create VPRegionBlock, with empty header and latch blocks, to be filled
// during processing later.
VPBasicBlock *HeaderVPBB = new VPBasicBlock("vector.body");
VPBasicBlock *LatchVPBB = new VPBasicBlock("vector.latch");
VPBasicBlock *HeaderVPBB = Plan->createVPBasicBlock("vector.body");
VPBasicBlock *LatchVPBB = Plan->createVPBasicBlock("vector.latch");
VPBlockUtils::insertBlockAfter(LatchVPBB, HeaderVPBB);
auto *TopRegion = new VPRegionBlock(HeaderVPBB, LatchVPBB, "vector loop",
false /*isReplicator*/);
auto *TopRegion = Plan->createVPRegionBlock(
HeaderVPBB, LatchVPBB, "vector loop", false /*isReplicator*/);

VPBlockUtils::insertBlockAfter(TopRegion, VecPreheader);
VPBasicBlock *MiddleVPBB = new VPBasicBlock("middle.block");
VPBasicBlock *MiddleVPBB = Plan->createVPBasicBlock("middle.block");
VPBlockUtils::insertBlockAfter(MiddleVPBB, TopRegion);

VPBasicBlock *ScalarPH = new VPBasicBlock("scalar.ph");
VPBasicBlock *ScalarPH = Plan->createVPBasicBlock("scalar.ph");
VPBlockUtils::connectBlocks(ScalarPH, ScalarHeader);
if (!RequiresScalarEpilogueCheck) {
VPBlockUtils::connectBlocks(MiddleVPBB, ScalarPH);
Expand All @@ -904,7 +911,7 @@ VPlanPtr VPlan::createInitialVPlan(Type *InductionTy,
// we unconditionally branch to the scalar preheader. Do nothing.
// 3) Otherwise, construct a runtime check.
BasicBlock *IRExitBlock = TheLoop->getUniqueLatchExitBlock();
auto *VPExitBlock = VPIRBasicBlock::fromBasicBlock(IRExitBlock);
auto *VPExitBlock = Plan->createVPIRBasicBlock(IRExitBlock);
// The connection order corresponds to the operands of the conditional branch.
VPBlockUtils::insertBlockAfter(VPExitBlock, MiddleVPBB);
VPBlockUtils::connectBlocks(MiddleVPBB, ScalarPH);
Expand Down Expand Up @@ -960,15 +967,13 @@ void VPlan::prepareToExecute(Value *TripCountV, Value *VectorTripCountV,
/// have a single predecessor, which is rewired to the new VPIRBasicBlock. All
/// successors of VPBB, if any, are rewired to the new VPIRBasicBlock.
static void replaceVPBBWithIRVPBB(VPBasicBlock *VPBB, BasicBlock *IRBB) {
VPIRBasicBlock *IRVPBB = VPIRBasicBlock::fromBasicBlock(IRBB);
VPIRBasicBlock *IRVPBB = VPBB->getPlan()->createVPIRBasicBlock(IRBB);
for (auto &R : make_early_inc_range(*VPBB)) {
assert(!R.isPhi() && "Tried to move phi recipe to end of block");
R.moveBefore(*IRVPBB, IRVPBB->end());
}

VPBlockUtils::reassociateBlocks(VPBB, IRVPBB);

delete VPBB;
}

/// Generate the code inside the preheader and body of the vectorized loop.
Expand Down Expand Up @@ -1222,6 +1227,7 @@ static void remapOperands(VPBlockBase *Entry, VPBlockBase *NewEntry,
}

VPlan *VPlan::duplicate() {
unsigned CreatedBlockSize = CreatedBlocks.size();
// Clone blocks.
const auto &[NewEntry, __] = cloneFrom(Entry);

Expand Down Expand Up @@ -1262,9 +1268,23 @@ VPlan *VPlan::duplicate() {
assert(Old2NewVPValues.contains(TripCount) &&
"TripCount must have been added to Old2NewVPValues");
NewPlan->TripCount = Old2NewVPValues[TripCount];

for (unsigned I = CreatedBlockSize; I != CreatedBlocks.size(); ++I)
NewPlan->CreatedBlocks.push_back(CreatedBlocks[I]);
CreatedBlocks.truncate(CreatedBlockSize);

return NewPlan;
}

VPIRBasicBlock *VPlan::createVPIRBasicBlock(BasicBlock *IRBB) {
auto *VPIRBB = new VPIRBasicBlock(IRBB);
for (Instruction &I :
make_range(IRBB->begin(), IRBB->getTerminator()->getIterator()))
VPIRBB->appendRecipe(new VPIRInstruction(I));
CreatedBlocks.push_back(VPIRBB);
return VPIRBB;
}

#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)

Twine VPlanPrinter::getUID(const VPBlockBase *Block) {
Expand Down
54 changes: 30 additions & 24 deletions llvm/lib/Transforms/Vectorize/VPlan.h
Original file line number Diff line number Diff line change
Expand Up @@ -636,9 +636,6 @@ class VPBlockBase {
/// Return the cost of the block.
virtual InstructionCost cost(ElementCount VF, VPCostContext &Ctx) = 0;

/// Delete all blocks reachable from a given VPBlockBase, inclusive.
static void deleteCFG(VPBlockBase *Entry);

/// Return true if it is legal to hoist instructions into this block.
bool isLegalToHoistInto() {
// There are currently no constraints that prevent an instruction to be
Expand Down Expand Up @@ -3585,12 +3582,7 @@ class VPBasicBlock : public VPBlockBase {

/// Clone the current block and it's recipes, without updating the operands of
/// the cloned recipes.
VPBasicBlock *clone() override {
auto *NewBlock = new VPBasicBlock(getName());
for (VPRecipeBase &R : *this)
NewBlock->appendRecipe(R.clone());
return NewBlock;
}
VPBasicBlock *clone() override;

protected:
/// Execute the recipes in the IR basic block \p BB.
Expand Down Expand Up @@ -3626,20 +3618,11 @@ class VPIRBasicBlock : public VPBasicBlock {
return V->getVPBlockID() == VPBlockBase::VPIRBasicBlockSC;
}

/// Create a VPIRBasicBlock from \p IRBB containing VPIRInstructions for all
/// instructions in \p IRBB, except its terminator which is managed in VPlan.
static VPIRBasicBlock *fromBasicBlock(BasicBlock *IRBB);

/// The method which generates the output IR instructions that correspond to
/// this VPBasicBlock, thereby "executing" the VPlan.
void execute(VPTransformState *State) override;

VPIRBasicBlock *clone() override {
auto *NewBlock = new VPIRBasicBlock(IRBB);
for (VPRecipeBase &R : Recipes)
NewBlock->appendRecipe(R.clone());
return NewBlock;
}
VPIRBasicBlock *clone() override;

BasicBlock *getIRBasicBlock() const { return IRBB; }
};
Expand Down Expand Up @@ -3679,11 +3662,6 @@ class VPRegionBlock : public VPBlockBase {
IsReplicator(IsReplicator) {}

~VPRegionBlock() override {
if (Entry) {
VPValue DummyValue;
Entry->dropAllReferences(&DummyValue);
deleteCFG(Entry);
}
}

/// Method to support type inquiry through isa, cast, and dyn_cast.
Expand Down Expand Up @@ -3810,6 +3788,8 @@ class VPlan {
/// been modeled in VPlan directly.
DenseMap<const SCEV *, VPValue *> SCEVToExpansion;

SmallVector<VPBlockBase *> CreatedBlocks;

public:
/// Construct a VPlan with \p Entry to the plan and with \p ScalarHeader
/// wrapping the original header of the scalar loop.
Expand Down Expand Up @@ -4026,6 +4006,32 @@ class VPlan {
/// Clone the current VPlan, update all VPValues of the new VPlan and cloned
/// recipes to refer to the clones, and return it.
VPlan *duplicate();

VPBasicBlock *createVPBasicBlock(const Twine &Name,
VPRecipeBase *Recipe = nullptr) {
auto *VPB = new VPBasicBlock(Name, Recipe);
CreatedBlocks.push_back(VPB);
return VPB;
}

VPRegionBlock *createVPRegionBlock(VPBlockBase *Entry, VPBlockBase *Exiting,
const std::string &Name = "",
bool IsReplicator = false) {
auto *VPB = new VPRegionBlock(Entry, Exiting, Name, IsReplicator);
CreatedBlocks.push_back(VPB);
return VPB;
}

VPRegionBlock *createVPRegionBlock(const std::string &Name = "",
bool IsReplicator = false) {
auto *VPB = new VPRegionBlock(Name, IsReplicator);
CreatedBlocks.push_back(VPB);
return VPB;
}

/// Create a VPIRBasicBlock from \p IRBB containing VPIRInstructions for all
/// instructions in \p IRBB, except its terminator which is managed in VPlan.
VPIRBasicBlock *createVPIRBasicBlock(BasicBlock *IRBB);
};

#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
Expand Down
4 changes: 2 additions & 2 deletions llvm/lib/Transforms/Vectorize/VPlanHCFGBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ VPBasicBlock *PlainCFGBuilder::getOrCreateVPBB(BasicBlock *BB) {
// Create new VPBB.
StringRef Name = isHeaderBB(BB, TheLoop) ? "vector.body" : BB->getName();
LLVM_DEBUG(dbgs() << "Creating VPBasicBlock for " << Name << "\n");
VPBasicBlock *VPBB = new VPBasicBlock(Name);
VPBasicBlock *VPBB = Plan.createVPBasicBlock(Name);
BB2VPBB[BB] = VPBB;

// Get or create a region for the loop containing BB.
Expand All @@ -204,7 +204,7 @@ VPBasicBlock *PlainCFGBuilder::getOrCreateVPBB(BasicBlock *BB) {
if (LoopOfBB == TheLoop) {
RegionOfVPBB = Plan.getVectorLoopRegion();
} else {
RegionOfVPBB = new VPRegionBlock(Name.str(), false /*isReplicator*/);
RegionOfVPBB = Plan.createVPRegionBlock(Name.str(), false /*isReplicator*/);
RegionOfVPBB->setParent(Loop2Region[LoopOfBB->getParentLoop()]);
}
RegionOfVPBB->setEntry(VPBB);
Expand Down
Loading

0 comments on commit 83f4c78

Please sign in to comment.