From 522b05afb636229acd1f2a50eff14a29c79b4a1a Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Tue, 25 Feb 2025 14:23:27 +0000 Subject: [PATCH] [VPlan] Construct immutable VPIRBBs for exit blocks at construction(NFC) (#128374) Constract immutable VPIRBasicBlocks for all exit blocks up front and keep a list of them. Same as the scalar header, they are leaf nodes of the VPlan and won't change. Some exit blocks may be unreachable, e.g. if the scalar epilogue always executes or depending on optimizations. This simplifies both the way we retrieve the exit blocks as well as hooking up the exit blocks. PR: https://github.com/llvm/llvm-project/pull/128374 --- llvm/lib/Transforms/Vectorize/LoopVectorize.cpp | 4 ++++ llvm/lib/Transforms/Vectorize/VPlan.cpp | 15 ++++++++++++++- llvm/lib/Transforms/Vectorize/VPlan.h | 17 ++++++++++++----- llvm/lib/Transforms/Vectorize/VPlanCFG.h | 9 --------- .../Transforms/Vectorize/VPlanTransforms.cpp | 15 +++------------ 5 files changed, 33 insertions(+), 27 deletions(-) diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp index 0bf2d71a63ef..226fc23888f0 100644 --- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp +++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp @@ -9132,6 +9132,10 @@ collectUsersInExitBlocks(Loop *OrigLoop, VPRecipeBuilder &Builder, VPlan &Plan) { SetVector ExitUsersToFix; for (VPIRBasicBlock *ExitVPBB : Plan.getExitBlocks()) { + // Nothing to do for unreachable exit blocks. + if (ExitVPBB->getNumPredecessors() == 0) + continue; + for (VPRecipeBase &R : *ExitVPBB) { auto *ExitIRI = dyn_cast(&R); if (!ExitIRI) diff --git a/llvm/lib/Transforms/Vectorize/VPlan.cpp b/llvm/lib/Transforms/Vectorize/VPlan.cpp index 121678b52a9f..d3c195d4a70e 100644 --- a/llvm/lib/Transforms/Vectorize/VPlan.cpp +++ b/llvm/lib/Transforms/Vectorize/VPlan.cpp @@ -850,6 +850,11 @@ void VPRegionBlock::print(raw_ostream &O, const Twine &Indent, VPlan::VPlan(Loop *L) { setEntry(createVPIRBasicBlock(L->getLoopPreheader())); ScalarHeader = createVPIRBasicBlock(L->getHeader()); + + SmallVector IRExitBlocks; + L->getExitBlocks(IRExitBlocks); + for (BasicBlock *EB : IRExitBlocks) + ExitBlocks.push_back(createVPIRBasicBlock(EB)); } VPlan::~VPlan() { @@ -931,7 +936,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 = Plan->createVPIRBasicBlock(IRExitBlock); + VPIRBasicBlock *VPExitBlock = Plan->getExitBlock(IRExitBlock); // The connection order corresponds to the operands of the conditional branch. VPBlockUtils::insertBlockAfter(VPExitBlock, MiddleVPBB); VPBlockUtils::connectBlocks(MiddleVPBB, ScalarPH); @@ -983,6 +988,14 @@ void VPlan::prepareToExecute(Value *TripCountV, Value *VectorTripCountV, } } +VPIRBasicBlock *VPlan::getExitBlock(BasicBlock *IRBB) const { + auto Iter = find_if(getExitBlocks(), [IRBB](const VPIRBasicBlock *VPIRBB) { + return VPIRBB->getIRBasicBlock() == IRBB; + }); + assert(Iter != getExitBlocks().end() && "no exit block found"); + return *Iter; +} + bool VPlan::isExitBlock(VPBlockBase *VPBB) { return isa(VPBB) && VPBB->getNumSuccessors() == 0; } diff --git a/llvm/lib/Transforms/Vectorize/VPlan.h b/llvm/lib/Transforms/Vectorize/VPlan.h index d86914f0fb02..1f1af7f87e55 100644 --- a/llvm/lib/Transforms/Vectorize/VPlan.h +++ b/llvm/lib/Transforms/Vectorize/VPlan.h @@ -3426,6 +3426,11 @@ class VPlan { /// VPIRBasicBlock wrapping the header of the original scalar loop. VPIRBasicBlock *ScalarHeader; + /// Immutable list of VPIRBasicBlocks wrapping the exit blocks of the original + /// scalar loop. Note that some exit blocks may be unreachable at the moment, + /// e.g. if the scalar epilogue always executes. + SmallVector ExitBlocks; + /// Holds the VFs applicable to this VPlan. SmallSetVector VFs; @@ -3559,11 +3564,13 @@ public: /// Return the VPIRBasicBlock wrapping the header of the scalar loop. VPIRBasicBlock *getScalarHeader() const { return ScalarHeader; } - /// Return an iterator range over the VPIRBasicBlock wrapping the exit blocks - /// of the VPlan, that is leaf nodes except the scalar header. Defined in - /// VPlanHCFG, as the definition of the type needs access to the definitions - /// of VPBlockShallowTraversalWrapper. - auto getExitBlocks(); + /// Return an ArrayRef containing VPIRBasicBlocks wrapping the exit blocks of + /// the original scalar loop. + ArrayRef getExitBlocks() const { return ExitBlocks; } + + /// Return the VPIRBasicBlock corresponding to \p IRBB. \p IRBB must be an + /// exit block. + VPIRBasicBlock *getExitBlock(BasicBlock *IRBB) const; /// Returns true if \p VPBB is an exit block. bool isExitBlock(VPBlockBase *VPBB); diff --git a/llvm/lib/Transforms/Vectorize/VPlanCFG.h b/llvm/lib/Transforms/Vectorize/VPlanCFG.h index 8fbdacd1ea77..a1014c398789 100644 --- a/llvm/lib/Transforms/Vectorize/VPlanCFG.h +++ b/llvm/lib/Transforms/Vectorize/VPlanCFG.h @@ -307,15 +307,6 @@ template <> struct GraphTraits { } }; -inline auto VPlan::getExitBlocks() { - VPBlockBase *ScalarHeader = getScalarHeader(); - return make_filter_range( - VPBlockUtils::blocksOnly( - vp_depth_first_shallow(getVectorLoopRegion()->getSingleSuccessor())), - [ScalarHeader](VPIRBasicBlock *VPIRBB) { - return VPIRBB != ScalarHeader && VPIRBB->getNumSuccessors() == 0; - }); -} } // namespace llvm #endif // LLVM_TRANSFORMS_VECTORIZE_VPLANCFG_H diff --git a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp index 8e773272300b..13ef3029023f 100644 --- a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp +++ b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp @@ -2049,18 +2049,9 @@ void VPlanTransforms::handleUncountableEarlyExit( cast(UncountableExitingBlock->getTerminator()); BasicBlock *TrueSucc = EarlyExitingBranch->getSuccessor(0); BasicBlock *FalseSucc = EarlyExitingBranch->getSuccessor(1); - - // The early exit block may or may not be the same as the "countable" exit - // block. Creates a new VPIRBB for the early exit block in case it is distinct - // from the countable exit block. - // TODO: Introduce both exit blocks during VPlan skeleton construction. - VPIRBasicBlock *VPEarlyExitBlock; - if (OrigLoop->getUniqueExitBlock()) { - VPEarlyExitBlock = cast(MiddleVPBB->getSuccessors()[0]); - } else { - VPEarlyExitBlock = Plan.createVPIRBasicBlock( - !OrigLoop->contains(TrueSucc) ? TrueSucc : FalseSucc); - } + BasicBlock *EarlyExitIRBB = + !OrigLoop->contains(TrueSucc) ? TrueSucc : FalseSucc; + VPIRBasicBlock *VPEarlyExitBlock = Plan.getExitBlock(EarlyExitIRBB); VPValue *EarlyExitNotTakenCond = RecipeBuilder.getBlockInMask( OrigLoop->contains(TrueSucc) ? TrueSucc : FalseSucc);