Skip to content

Commit 5785048

Browse files
authored
[VPlan] Add VPIRBasicBlock, use to model pre-preheader. (#93398)
This patch adds a new special type of VPBasicBlock that wraps an existing IR basic block. Recipes of the block get added before the terminator of the wrapped IR basic block. Making it a subclass of VPBasicBlock avoids duplicating various APIs to manage recipes in a block, as well as makes sure the traversals filtering VPBasicBlocks automatically apply as well. Initially VPIRBasicBlock are only used for the pre-preheader (wrapping the original preheader of the scalar loop). As follow-up, this will be used to move more parts of the skeleton inside VPlan, starting with the branch and condition in the middle block. Separated out of #92651 PR: #93398
1 parent 8fa66c6 commit 5785048

File tree

5 files changed

+99
-26
lines changed

5 files changed

+99
-26
lines changed

llvm/lib/Transforms/Vectorize/LoopVectorize.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8608,7 +8608,7 @@ LoopVectorizationPlanner::tryToBuildVPlanWithVPRecipes(VFRange &Range) {
86088608
// loop region contains a header and latch basic blocks.
86098609
VPlanPtr Plan = VPlan::createInitialVPlan(
86108610
createTripCountSCEV(Legal->getWidestInductionType(), PSE, OrigLoop),
8611-
*PSE.getSE());
8611+
*PSE.getSE(), OrigLoop->getLoopPreheader());
86128612
VPBasicBlock *HeaderVPBB = new VPBasicBlock("vector.body");
86138613
VPBasicBlock *LatchVPBB = new VPBasicBlock("vector.latch");
86148614
VPBlockUtils::insertBlockAfter(LatchVPBB, HeaderVPBB);
@@ -8856,7 +8856,7 @@ VPlanPtr LoopVectorizationPlanner::buildVPlan(VFRange &Range) {
88568856
// Create new empty VPlan
88578857
auto Plan = VPlan::createInitialVPlan(
88588858
createTripCountSCEV(Legal->getWidestInductionType(), PSE, OrigLoop),
8859-
*PSE.getSE());
8859+
*PSE.getSE(), OrigLoop->getLoopPreheader());
88608860

88618861
// Build hierarchical CFG
88628862
VPlanHCFGBuilder HCFGBuilder(OrigLoop, LI, *Plan);

llvm/lib/Transforms/Vectorize/VPlan.cpp

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,16 @@ VPBasicBlock::createEmptyBasicBlock(VPTransformState::CFGState &CFG) {
442442
return NewBB;
443443
}
444444

445+
void VPIRBasicBlock::execute(VPTransformState *State) {
446+
assert(getHierarchicalPredecessors().empty() &&
447+
"VPIRBasicBlock cannot have predecessors at the moment");
448+
assert(getHierarchicalSuccessors().empty() &&
449+
"VPIRBasicBlock cannot have successors at the moment");
450+
451+
State->Builder.SetInsertPoint(getIRBasicBlock()->getTerminator());
452+
executeRecipes(State, getIRBasicBlock());
453+
}
454+
445455
void VPBasicBlock::execute(VPTransformState *State) {
446456
bool Replica = State->Instance && !State->Instance->isFirstIteration();
447457
VPBasicBlock *PrevVPBB = State->CFG.PrevVPBB;
@@ -499,16 +509,7 @@ void VPBasicBlock::execute(VPTransformState *State) {
499509
}
500510

501511
// 2. Fill the IR basic block with IR instructions.
502-
LLVM_DEBUG(dbgs() << "LV: vectorizing VPBB:" << getName()
503-
<< " in BB:" << NewBB->getName() << '\n');
504-
505-
State->CFG.VPBB2IRBB[this] = NewBB;
506-
State->CFG.PrevVPBB = this;
507-
508-
for (VPRecipeBase &Recipe : Recipes)
509-
Recipe.execute(*State);
510-
511-
LLVM_DEBUG(dbgs() << "LV: filled BB:" << *NewBB);
512+
executeRecipes(State, NewBB);
512513
}
513514

514515
void VPBasicBlock::dropAllReferences(VPValue *NewValue) {
@@ -521,6 +522,19 @@ void VPBasicBlock::dropAllReferences(VPValue *NewValue) {
521522
}
522523
}
523524

525+
void VPBasicBlock::executeRecipes(VPTransformState *State, BasicBlock *BB) {
526+
LLVM_DEBUG(dbgs() << "LV: vectorizing VPBB:" << getName()
527+
<< " in BB:" << BB->getName() << '\n');
528+
529+
State->CFG.VPBB2IRBB[this] = BB;
530+
State->CFG.PrevVPBB = this;
531+
532+
for (VPRecipeBase &Recipe : Recipes)
533+
Recipe.execute(*State);
534+
535+
LLVM_DEBUG(dbgs() << "LV: filled BB:" << *BB);
536+
}
537+
524538
VPBasicBlock *VPBasicBlock::splitAt(iterator SplitAt) {
525539
assert((SplitAt == end() || SplitAt->getParent() == this) &&
526540
"can only split at a position in the same block");
@@ -769,8 +783,9 @@ VPlan::~VPlan() {
769783
delete BackedgeTakenCount;
770784
}
771785

772-
VPlanPtr VPlan::createInitialVPlan(const SCEV *TripCount, ScalarEvolution &SE) {
773-
VPBasicBlock *Preheader = new VPBasicBlock("ph");
786+
VPlanPtr VPlan::createInitialVPlan(const SCEV *TripCount, ScalarEvolution &SE,
787+
BasicBlock *PH) {
788+
VPIRBasicBlock *Preheader = new VPIRBasicBlock(PH);
774789
VPBasicBlock *VecPreheader = new VPBasicBlock("vector.ph");
775790
auto Plan = std::make_unique<VPlan>(Preheader, VecPreheader);
776791
Plan->TripCount =

llvm/lib/Transforms/Vectorize/VPlan.h

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,7 @@ class VPBlockBase {
473473
/// that are actually instantiated. Values of this enumeration are kept in the
474474
/// SubclassID field of the VPBlockBase objects. They are used for concrete
475475
/// type identification.
476-
using VPBlockTy = enum { VPBasicBlockSC, VPRegionBlockSC };
476+
using VPBlockTy = enum { VPRegionBlockSC, VPBasicBlockSC, VPIRBasicBlockSC };
477477

478478
using VPBlocksTy = SmallVectorImpl<VPBlockBase *>;
479479

@@ -2833,10 +2833,13 @@ class VPBasicBlock : public VPBlockBase {
28332833
public:
28342834
using RecipeListTy = iplist<VPRecipeBase>;
28352835

2836-
private:
2836+
protected:
28372837
/// The VPRecipes held in the order of output instructions to generate.
28382838
RecipeListTy Recipes;
28392839

2840+
VPBasicBlock(const unsigned char BlockSC, const Twine &Name = "")
2841+
: VPBlockBase(BlockSC, Name.str()) {}
2842+
28402843
public:
28412844
VPBasicBlock(const Twine &Name = "", VPRecipeBase *Recipe = nullptr)
28422845
: VPBlockBase(VPBasicBlockSC, Name.str()) {
@@ -2885,7 +2888,8 @@ class VPBasicBlock : public VPBlockBase {
28852888

28862889
/// Method to support type inquiry through isa, cast, and dyn_cast.
28872890
static inline bool classof(const VPBlockBase *V) {
2888-
return V->getVPBlockID() == VPBlockBase::VPBasicBlockSC;
2891+
return V->getVPBlockID() == VPBlockBase::VPBasicBlockSC ||
2892+
V->getVPBlockID() == VPBlockBase::VPIRBasicBlockSC;
28892893
}
28902894

28912895
void insert(VPRecipeBase *Recipe, iterator InsertPt) {
@@ -2948,12 +2952,48 @@ class VPBasicBlock : public VPBlockBase {
29482952
return NewBlock;
29492953
}
29502954

2955+
protected:
2956+
/// Execute the recipes in the IR basic block \p BB.
2957+
void executeRecipes(VPTransformState *State, BasicBlock *BB);
2958+
29512959
private:
29522960
/// Create an IR BasicBlock to hold the output instructions generated by this
29532961
/// VPBasicBlock, and return it. Update the CFGState accordingly.
29542962
BasicBlock *createEmptyBasicBlock(VPTransformState::CFGState &CFG);
29552963
};
29562964

2965+
/// A special type of VPBasicBlock that wraps an existing IR basic block.
2966+
/// Recipes of the block get added before the first non-phi instruction in the
2967+
/// wrapped block.
2968+
/// Note: At the moment, VPIRBasicBlock can only be used to wrap VPlan's
2969+
/// preheader block.
2970+
class VPIRBasicBlock : public VPBasicBlock {
2971+
BasicBlock *IRBB;
2972+
2973+
public:
2974+
VPIRBasicBlock(BasicBlock *IRBB)
2975+
: VPBasicBlock(VPIRBasicBlockSC, "ph"), IRBB(IRBB) {}
2976+
2977+
~VPIRBasicBlock() override {}
2978+
2979+
static inline bool classof(const VPBlockBase *V) {
2980+
return V->getVPBlockID() == VPBlockBase::VPIRBasicBlockSC;
2981+
}
2982+
2983+
/// The method which generates the output IR instructions that correspond to
2984+
/// this VPBasicBlock, thereby "executing" the VPlan.
2985+
void execute(VPTransformState *State) override;
2986+
2987+
VPIRBasicBlock *clone() override {
2988+
auto *NewBlock = new VPIRBasicBlock(IRBB);
2989+
for (VPRecipeBase &R : Recipes)
2990+
NewBlock->appendRecipe(R.clone());
2991+
return NewBlock;
2992+
}
2993+
2994+
BasicBlock *getIRBasicBlock() const { return IRBB; }
2995+
};
2996+
29572997
/// VPRegionBlock represents a collection of VPBasicBlocks and VPRegionBlocks
29582998
/// which form a Single-Entry-Single-Exiting subgraph of the output IR CFG.
29592999
/// A VPRegionBlock may indicate that its contents are to be replicated several
@@ -3142,12 +3182,12 @@ class VPlan {
31423182
~VPlan();
31433183

31443184
/// Create initial VPlan skeleton, having an "entry" VPBasicBlock (wrapping
3145-
/// original scalar pre-header) which contains SCEV expansions that need to
3146-
/// happen before the CFG is modified; a VPBasicBlock for the vector
3185+
/// original scalar pre-header \p PH) which contains SCEV expansions that need
3186+
/// to happen before the CFG is modified; a VPBasicBlock for the vector
31473187
/// pre-header, followed by a region for the vector loop, followed by the
31483188
/// middle VPBasicBlock.
31493189
static VPlanPtr createInitialVPlan(const SCEV *TripCount,
3150-
ScalarEvolution &PSE);
3190+
ScalarEvolution &PSE, BasicBlock *PH);
31513191

31523192
/// Prepare the plan for execution, setting up the required live-in values.
31533193
void prepareToExecute(Value *TripCount, Value *VectorTripCount,

llvm/lib/Transforms/Vectorize/VPlanVerifier.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "VPlanCFG.h"
1818
#include "VPlanDominatorTree.h"
1919
#include "llvm/ADT/DepthFirstIterator.h"
20+
#include "llvm/ADT/SmallPtrSet.h"
2021
#include "llvm/Support/CommandLine.h"
2122

2223
#define DEBUG_TYPE "loop-vectorize"
@@ -27,6 +28,8 @@ namespace {
2728
class VPlanVerifier {
2829
const VPDominatorTree &VPDT;
2930

31+
SmallPtrSet<BasicBlock *, 8> WrappedIRBBs;
32+
3033
// Verify that phi-like recipes are at the beginning of \p VPBB, with no
3134
// other recipes in between. Also check that only header blocks contain
3235
// VPHeaderPHIRecipes.
@@ -148,6 +151,19 @@ bool VPlanVerifier::verifyVPBasicBlock(const VPBasicBlock *VPBB) {
148151
}
149152
}
150153
}
154+
155+
auto *IRBB = dyn_cast<VPIRBasicBlock>(VPBB);
156+
if (!IRBB)
157+
return true;
158+
159+
if (!WrappedIRBBs.insert(IRBB->getIRBasicBlock()).second) {
160+
errs() << "Same IR basic block used by multiple wrapper blocks!\n";
161+
return false;
162+
}
163+
if (IRBB != IRBB->getPlan()->getPreheader()) {
164+
errs() << "VPIRBasicBlock can only be used as pre-header at the moment!\n";
165+
return false;
166+
}
151167
return true;
152168
}
153169

llvm/unittests/Transforms/Vectorize/VPlanTestBase.h

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,10 @@ class VPlanTestBase : public testing::Test {
6767
assert(!verifyFunction(F) && "input function must be valid");
6868
doAnalysis(F);
6969

70-
auto Plan = VPlan::createInitialVPlan(
71-
SE->getBackedgeTakenCount(LI->getLoopFor(LoopHeader)), *SE);
72-
VPlanHCFGBuilder HCFGBuilder(LI->getLoopFor(LoopHeader), LI.get(), *Plan);
70+
Loop *L = LI->getLoopFor(LoopHeader);
71+
auto Plan = VPlan::createInitialVPlan(SE->getBackedgeTakenCount(L), *SE,
72+
L->getLoopPreheader());
73+
VPlanHCFGBuilder HCFGBuilder(L, LI.get(), *Plan);
7374
HCFGBuilder.buildHierarchicalCFG();
7475
return Plan;
7576
}
@@ -80,9 +81,10 @@ class VPlanTestBase : public testing::Test {
8081
assert(!verifyFunction(F) && "input function must be valid");
8182
doAnalysis(F);
8283

83-
auto Plan = VPlan::createInitialVPlan(
84-
SE->getBackedgeTakenCount(LI->getLoopFor(LoopHeader)), *SE);
85-
VPlanHCFGBuilder HCFGBuilder(LI->getLoopFor(LoopHeader), LI.get(), *Plan);
84+
Loop *L = LI->getLoopFor(LoopHeader);
85+
auto Plan = VPlan::createInitialVPlan(SE->getBackedgeTakenCount(L), *SE,
86+
L->getLoopPreheader());
87+
VPlanHCFGBuilder HCFGBuilder(L, LI.get(), *Plan);
8688
HCFGBuilder.buildPlainCFG();
8789
return Plan;
8890
}

0 commit comments

Comments
 (0)